1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
#pragma once
#include "SQL.h"
namespace sql {
class SequentialStatement;
/**
* Wrapper over the connection interface for database connections that communicate with the
* database over a sequential connection (e.g. a socket). This type of connections typically
* typically disallow performing any other operations while the results from a prepared
* statement are fetched. As such, the implementation adapts the standard interface to a
* "sequential interface" and introduces buffering and delays as necessary.
*
* The class does two things to make operations sequential:
* - Store the results from a query in RAM if the user of the interface attempts to do
* anything before results are fetched to completion.
* - Delay finalization of prepared statements if results are being fetched.
*/
class SequentialConnection : public DBConnection {
STORM_ABSTRACT_CLASS;
public:
// Create.
STORM_CTOR SequentialConnection();
protected:
// May be called at any time to ensure that no fetches are underway. This causes us to store
// the remaining rows in RAM until they are either consumed or discarded.
void clearFetch();
// Same as 'clearFetch', but does nothing if we are the statement currently fetching data.
void clearFetch(SequentialStatement *stmt);
// Is the specified statement free to fetch at the moment?
Bool isFetching(SequentialStatement *stmt);
/**
* Additional interface that should be implemented by derived classes.
*/
// Called to finalize a prepared statement. This logic needs to be implemented here since
// vtables don't work after the destructor of SequentialStatement have been executed.
virtual void STORM_FN finalizeStmt(SequentialStatement *stmt) ABSTRACT;
private:
// Interface intended to be used from SequentialStatement.
friend class SequentialStatement;
// Called by Stmt when we start fetching data.
void startFetch(SequentialStatement *stmt);
// Called by Stmt when it is done fetching data.
void doneFetch(SequentialStatement *stmt);
// Called by Stmt when it wishes to be finalize.
void onFinalize(SequentialStatement *stmt);
private:
// Queue of statements that should be finalized when the opportunity arises, forming a
// linked list.
SequentialStatement *toFinalize;
// Statement that is currently fetching data, if any.
SequentialStatement *currentFetching;
// Keep track of active statements
// Run finalizers.
void finalizeAll();
};
/**
* Custom statement for sequential connections.
*
* Most operations call back into SequentialConnection. Each database connection will however
* need to handle binding parameters since that is expected to be possible without communicating
* to the database itself.
*/
class SequentialStatement : public Statement {
STORM_ABSTRACT_CLASS;
public:
// Create.
STORM_CTOR SequentialStatement(SequentialConnection *connection);
// Destroy, automatically call finalize if necessary.
virtual ~SequentialStatement();
// Execute the statement. Derived classes should override 'executeSeq' instead.
Statement::Result STORM_FN execute() override;
// Finalize the statement. Derived classes should override 'finalizeStmt' in the base class instead.
void STORM_FN finalize() override;
protected:
/**
* New functionality for derived classes.
*/
// Get owning connection.
SequentialConnection *connection() const { return owner; }
// Derived classes should call this function when an execute call is known to not produce
// any data. Otherwise returning null from 'nextRowSeq' is enough.
void STORM_FN fetchDone();
/**
* Interception of existing interface.
*/
// Called when the result should be disposed.
void STORM_FN disposeResult() override;
// Called to get the next result. Override 'nextRowSeq' instead.
Maybe<Row> STORM_FN nextRow() override;
/**
* New interface.
*/
// Called when the statement should be executed. Returns 'true' if there may be something to
// get through 'nextRowSeq'.
virtual Bool STORM_FN executeSeq() ABSTRACT;
// Called when any remaining results should be disposed.
virtual void STORM_FN disposeResultSeq() ABSTRACT;
// Called to get the next row.
virtual Maybe<Row> STORM_FN nextRowSeq() ABSTRACT;
private:
friend class SequentialConnection;
// Linked list of statements that the connection should finalize. Note that the objects in
// here might be destroyed, and virtual functions may not work as expected.
SequentialStatement *toFinalize;
// Associated connection.
SequentialConnection *owner;
// Buffered rows if necessary.
Array<Row> *buffer;
// Reached the end of the actual DB connection's stream?
Bool atEnd;
// Buffer all elements. Called by SequentialConnection.
void fetchAll();
};
}
|