1111 */
1212#pragma once
1313
14- // #include <SQLiteCpp/Database .h>
15- #include < SQLiteCpp/Exception.h>
14+ #include < SQLiteCpp/Row .h>
15+ #include < SQLiteCpp/Exception.h>
1616
1717#include < memory>
1818#include < string>
@@ -26,7 +26,21 @@ namespace SQLite
2626
2727extern const int OK; // /< SQLITE_OK
2828
29-
29+ /* *
30+ * @brief Base class for prepared SQLite Statement.
31+ *
32+ * You should use SQLite::Statement or (if you had a reson)
33+ * inherit this class to create your own Statement executor class.
34+ * Either way you should look at SQLite::Statement documentation
35+ *
36+ * Thread-safety: a RowExecutor object shall not be shared by multiple threads, because :
37+ * 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
38+ * provided that no single database connection is used simultaneously in two or more threads."
39+ * 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
40+ * because of the way it shares the underling SQLite precompiled statement
41+ * in a custom shared pointer (See the inner class "Statement::Ptr").
42+ * TODO Test Serialized mode after all changes to pointers
43+ */
3044class RowExecutor
3145{
3246public:
@@ -41,7 +55,7 @@ class RowExecutor
4155
4256 // / Weak pointer to SQLite RowExecutor
4357 using TRowWeakPtr = std::weak_ptr<RowExecutor>;
44-
58+
4559 // / Type to store columns names and indexes
4660 using TColumnsMap = std::map<std::string, int , std::less<>>;
4761
@@ -112,25 +126,6 @@ class RowExecutor
112126
113127 // //////////////////////////////////////////////////////////////////////////
114128
115- /* *
116- * @brief Execute a step of the prepared query to fetch one row of results.
117- *
118- * While true is returned, a row of results is available, and can be accessed
119- * through the getColumn() method
120- *
121- * @see exec() execute a one-step prepared statement with no expected result
122- * @see tryExecuteStep() try to execute a step of the prepared query to fetch one row of results, returning the sqlite result code.
123- * @see Database::exec() is a shortcut to execute one or multiple statements without results
124- *
125- * @return - true (SQLITE_ROW) if there is another row ready : you can call getColumn(N) to get it
126- * then you have to call executeStep() again to fetch more rows until the query is finished
127- * - false (SQLITE_DONE) if the query has finished executing : there is no (more) row of result
128- * (case of a query with no result, or after N rows fetched successfully)
129- *
130- * @throw SQLite::Exception in case of error
131- */
132- const TColumnsMap& getColumnsNames () const ;
133-
134129 // / Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
135130 int getChanges () const noexcept ;
136131
@@ -139,6 +134,13 @@ class RowExecutor
139134 {
140135 return mColumnCount ;
141136 }
137+
138+ // / Get columns names with theirs ids
139+ const TColumnsMap& getColumnsNames () const
140+ {
141+ return mColumnNames ;
142+ }
143+
142144 // / true when a row has been fetched with executeStep()
143145 bool hasRow () const noexcept
144146 {
@@ -161,10 +163,92 @@ class RowExecutor
161163 // / Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
162164 const char * getErrorMsg () const noexcept ;
163165
164- protected:
166+ // //////////////////////////////////////////////////////////////////////////
167+
165168 /* *
166- *
169+ * @brief InputIterator for statement steps.
170+ *
171+ * Remember that this iterator is changing state of RowExecutor.
167172 */
173+ class RowIterator
174+ {
175+ public:
176+ using iterator_category = std::input_iterator_tag;
177+ using value_type = Row;
178+ using reference = const Row&;
179+ using pointer = const Row*;
180+ using difference_type = std::ptrdiff_t ;
181+
182+ RowIterator () = default ;
183+ RowIterator (TStatementWeakPtr apStatement, TRowWeakPtr apRow, uint16_t aID) :
184+ mpStatement (apStatement), mpRow(apRow), mID (aID), mRow (apStatement, aID) {}
185+
186+ reference operator *() const
187+ {
188+ return mRow ;
189+ }
190+ pointer operator ->() const noexcept
191+ {
192+ return &mRow ;
193+ }
194+
195+ reference operator ++() noexcept
196+ {
197+ mRow = Row (mpStatement, ++mID );
198+ advance ();
199+ return mRow ;
200+ }
201+ value_type operator ++(int )
202+ {
203+ Row copy{ mRow };
204+ mRow = Row (mpStatement, ++mID );
205+ advance ();
206+ return copy;
207+ }
208+
209+ bool operator ==(const RowIterator& aIt) const ;
210+ bool operator !=(const RowIterator& aIt) const
211+ {
212+ return !(*this == aIt);
213+ }
214+
215+ private:
216+ // / Executing next statement step
217+ void advance () noexcept ;
218+
219+ TStatementWeakPtr mpStatement{}; // !< Weak pointer to SQLite Statement Object
220+ TRowWeakPtr mpRow{}; // !< Weak pointer to RowExecutor Object
221+ uint16_t mID {}; // !< Current row number
222+
223+ // / Internal row object storage
224+ Row mRow { mpStatement, mID };
225+ };
226+
227+ /* *
228+ * @brief Start execution of SQLite Statement Object and return iterator to first row.
229+ *
230+ * This function calls resets SQLite Statement Object.
231+ *
232+ * @return RowIterator for first row of this prepared statement
233+ *
234+ * @throws Exception is thrown in case of error, then the RowIterator object is NOT constructed.
235+ */
236+ RowIterator begin ();
237+
238+ /* *
239+ * @return RowIterator to non-exisitng step
240+ */
241+ RowIterator end ();
242+
243+ protected:
244+ /* *
245+ * @brief Proteced construtor to ensure that this class is only created in derived objects
246+ *
247+ * @param[in] apSQLite the SQLite Database Connection
248+ * @param[in] aQuery an UTF-8 encoded query string
249+ *
250+ * @throws Exception is thrown in case of error, then the RowExecutor object is NOT constructed.
251+ */
168252 explicit RowExecutor (sqlite3* apSQLite, const std::string& aQuery);
169253
170254 /* *
@@ -176,15 +260,15 @@ class RowExecutor
176260 {
177261 return mpStatement;
178262 }
179-
263+
180264 /* *
181265 * @brief Return a prepared SQLite Statement Object.
182266 *
183267 * Throw an exception if the statement object was not prepared.
184268 * @return raw pointer to Prepared Statement Object
185269 */
186270 sqlite3_stmt* getPreparedStatement () const ;
187-
271+
188272 /* *
189273 * @brief Return a prepared SQLite Statement Object.
190274 *
@@ -236,20 +320,20 @@ class RowExecutor
236320private:
237321 // / Create prepared SQLite Statement Object
238322 void prepareStatement (const std::string& aQuery);
239-
323+
240324 // / Get column number and create map with columns names
241325 void createColumnInfo ();
242326
243- sqlite3* mpSQLite{}; // !< Pointer to SQLite Database Connection Handle
244- TStatementPtr mpStatement{}; // !< Shared Pointer to the prepared SQLite Statement Object
327+ sqlite3* mpSQLite{}; // !< Pointer to SQLite Database Connection Handle
328+ TStatementPtr mpStatement{}; // !< Shared Pointer to the prepared SQLite Statement Object
245329
246330 // / Shared Pointer to this object.
247331 // / Allows RowIterator to execute next step
248332 TRowPtr mpRowExecutor{};
249333
250- int mColumnCount = 0 ; // !< Number of columns in the result of the prepared statement
251- bool mbHasRow = false ; // !< true when a row has been fetched with executeStep()
252- bool mbDone = false ; // !< true when the last executeStep() had no more row to fetch
334+ int mColumnCount = 0 ; // !< Number of columns in the result of the prepared statement
335+ bool mbHasRow = false ; // !< true when a row has been fetched with executeStep()
336+ bool mbDone = false ; // !< true when the last executeStep() had no more row to fetch
253337
254338 // / Map of columns index by name (mutable so getColumnIndex can be const)
255339 mutable TColumnsMap mColumnNames {};
0 commit comments