Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Statement.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Database_SQL_Statement_h_
5#define _Stroika_Foundation_Database_SQL_Statement_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <optional>
10
12#include "Stroika/Foundation/Common/Property.h"
13#include "Stroika/Foundation/Containers/Mapping.h"
14#include "Stroika/Foundation/Containers/Sequence.h"
18
19/**
20 * \file
21 *
22 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
23 */
24
25namespace Stroika::Foundation::Database::SQL {
26
27 using Characters::String;
28 using Containers::Mapping;
29 using Containers::Sequence;
30 using DataExchange::VariantValue;
31
32 /**
33 * 'Statement' is a non-copyable (but moveable) object, referencing a particular SQL Connection object.
34 *
35 * \note - Design Note - we use String for the result-column-name - and could use int or Atom. But
36 * String slightly simpler, and nearly as performant, so going with that for now.
37 *
38 * \todo CONSIDER redo Row as iterator; or maybe GetResults () method that returns iterable of Rows? and lazy pulls them?
39 *
40 * \todo CONSIDER if this should be a namespace (like Connection) with Ptr and IRep class members).
41 */
42 class Statement {
43 public:
44 class IRep;
45
46 public:
47 /**
48 */
49 Statement () = delete;
50 Statement (Statement&&) = default;
51 Statement (const Statement&) = delete;
52
53 protected:
54 Statement (unique_ptr<IRep>&& rep);
55
56 public:
57 /**
58 */
59 ~Statement () = default;
60
61 public:
62 /**
63 */
64 nonvirtual Statement& operator= (const Statement&) = delete;
65
66 public:
67 /**
68 * Could use 'int' index for this and faster, but tracking names maybe slightly better for readability and logging,
69 * and given that string shared_ptr, not too bad to copy around/compare
70 * COULD use Atom<> - which would be a good performance/funcitonality compromise, but would want to use private atomMgr,
71 * so scope of names limited (else list of interned strings could become large). Not worth the efforts/risk for small benefit for now.
72 */
74
75 public:
76 /**
77 * This describes an SQL column. The 'type' is a string (and optional at that), and refers to the SQLite type system.
78 */
80 /**
81 */
82 ColumnName fName;
83
84 /**
85 * sqlite3_column_decltype
86 */
87 optional<String> fType;
88
89 /**
90 * @see Characters::ToString ()
91 */
92 nonvirtual String ToString () const;
93 };
94
95 public:
96 /**
97 * \note the types returned in .fType are generally wrong until we've run our first query).
98 *
99 * @ todo consider rename to GetResultColumns
100 */
101 nonvirtual Sequence<ColumnDescription> GetColumns () const;
102
103 public:
104 /**
105 * Parameters are set with a call to "Bind" so maybe also called parameter bindings.
106 */
108 /**
109 * name is optional - bindings can be specified by index
110 */
111 optional<String> fName;
112
113 /**
114 */
115 VariantValue fValue;
116
117 /**
118 * @see Characters::ToString ()
119 */
120 nonvirtual String ToString () const;
121 };
122
123 public:
124 /**
125 * Gets the names and values of all the current parameters to this sql statement.
126 *
127 * \see Bind ()
128 */
130
131 public:
132 /**
133 * Specify one, or a collection of parameter bindings. This never changes the order of the bindings, just
134 * applies them to the appropriate binding elements.
135 *
136 * \note the paramterIndex is 'zero-based' unlike sqlite native APIs
137 *
138 * \pre parameterIndex < GetParameters ().length ()
139 * \pre paramterName FOUND in GetParameters ().fName's
140 * and similarly for other overloads
141 *
142 * \note - parameterName can be the name of the variable with or without the prefixing :
143 *
144 * If iterable argument to Bind (), the if the arguments have parameter names, the association will be done by name.
145 * if they do not have names, the order in the bind argument list will be interpretted as argument order (parameter order) for that item)
146 *
147 * The overload of Bind() with zero parameters, clears all bindings.
148 * Bind with an Iterable argument first calls Bind() - to clear all bindings - before calling Bind(argi) of each
149 * individual argument.
150 *
151 * \see GetParameters ()
152 */
153 nonvirtual void Bind ();
154 nonvirtual void Bind (unsigned int parameterIndex, const VariantValue& v);
155 nonvirtual void Bind (const String& parameterName, const VariantValue& v);
156 nonvirtual void Bind (const Traversal::Iterable<ParameterDescription>& parameters);
157 nonvirtual void Bind (const Traversal::Iterable<Common::KeyValuePair<String, VariantValue>>& parameters);
158
159 public:
160 enum class WhichSQLFlag {
161 /**
162 * This is the original SQL passed in as argument to the statement.
163 */
164 eOriginal,
165
166 /**
167 * string containing the SQL text of prepared statement P with [bound parameters] expanded
168 */
169 eExpanded,
170
171 /**
172 * This option is available iff CompiledOptions::kThe.ENABLE_NORMALIZE
173 */
175 };
176
177 public:
178 /**
179 * Return the original (or normalized or expanded with bindings) SQL associated with this statement.
180 */
181 nonvirtual String GetSQL (WhichSQLFlag whichSQL = WhichSQLFlag::eOriginal) const;
182
183 public:
184 /**
185 * Execute the given statement, and ignore its result value. Do NOT mix Execute() with GetNextRow() or GetAllRows ().
186 * It is legal to call this on an SQL statement that returns results, but you will not see the results.
187 *
188 * Execute () with a list of ParameterDescriptions is like:
189 * > Reset
190 * > Bind () with that list of parameters and then (can be empty list/missing)
191 * > Execute ()
192 *
193 * No need to call Reset() before calling Execute () as it calls it internally.
194 */
195 nonvirtual void Execute ();
196 nonvirtual void Execute (const Traversal::Iterable<ParameterDescription>& parameters);
198
199 public:
200 /**
201 * \brief resets the prepared statement back to the beginning of its program (this does NOT clear bindings)
202 *
203 * \note This mimics the sqlite3_reset () functionality/API.
204 *
205 * This clears any ongoing query, so the next call to GetNextRow () will start with the first row from the current query.
206 * This does NOT affect any values currently bound.
207 *
208 * BUT NOTE, it is required to call Reset() (if there are any ongoing queries) before calling Bind.
209 */
210 nonvirtual void Reset ();
211
212 public:
213 /**
214 * \brief Each row returned by a statement consists of a mapping of column name to its actual value.
215 */
217
218 public:
219 /**
220 * If called on a new Statement, or on a statement that has been reset (since the last call to GetNextRow() - this re-runs the query.
221 * But either way, it returns the next row.
222 *
223 * returns 'missing' on EOF, exception on error
224 */
225 nonvirtual optional<Row> GetNextRow ();
226
227 public:
228 /**
229 * \brief - Call GetNextRow () repeatedly, and accumulate Rows into a Sequence (@see GetAllRows ())
230 *
231 * The overload returning 'Row's is the default, and probably most intuitive.
232 *
233 * The overloads that take a sequence of column numbers return each row as a tuple of columns (VariantValue)
234 * for just the specified column numbers.
235 *
236 * ... @todo use variadic templates to generatelas GetAllRows()
237 * ... @todo COULD overload so columns named by 'name' instead of index, but simple to use index (as specified by result of
238 * GetColumns ()
239 */
241 nonvirtual Sequence<VariantValue> GetAllRemainingRows (size_t restrictToColumn);
242 nonvirtual Sequence<tuple<VariantValue, VariantValue>> GetAllRemainingRows (size_t restrictToColumn1, size_t restrictToColumn2);
243 nonvirtual Sequence<tuple<VariantValue, VariantValue, VariantValue>> GetAllRemainingRows (size_t restrictToColumn1, size_t restrictToColumn2,
244 size_t restrictToColumn3);
245
246 public:
247 /**
248 * \brief - call Reset (), and then GetAllRemainingRows () - which always starts current statement with current bindings from the beginning.
249 *
250 * The overload returning 'Row's is the default, and probably most intuitive.
251 *
252 * The overloads that take a sequence of column numbers return each row as a tuple of columns (VariantValue)
253 * for just the specified column numbers.
254 *
255 * ... @todo use variadic templates to generatelas GetAllRows()
256 * ... @todo COULD overload so columns named by 'name' instead of index, but simple to use index (as specified by result of
257 * GetColumns ()
258 */
259 nonvirtual Sequence<Row> GetAllRows ();
260 nonvirtual Sequence<VariantValue> GetAllRows (size_t restrictToColumn);
261 nonvirtual Sequence<tuple<VariantValue, VariantValue>> GetAllRows (size_t restrictToColumn1, size_t restrictToColumn2);
262 nonvirtual Sequence<tuple<VariantValue, VariantValue, VariantValue>> GetAllRows (size_t restrictToColumn1, size_t restrictToColumn2,
263 size_t restrictToColumn3);
264
265 public:
266 /**
267 * @see Characters::ToString ()
268 */
269 nonvirtual String ToString () const;
270
271 protected:
272 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex _fAssertExternallySynchronizedMutex;
273
274 protected:
275 unique_ptr<IRep> _fRep;
276 };
277
278 /**
279 * Statement::IRep provides an (abstract) API for accessing an SQL database.
280 *
281 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter">C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter/a>
282 * But though each Statement can only be accessed from a single thread at a time, the underlying database may be
283 * threadsafe (even if accessed across processes).
284 */
286 public:
287 /**
288 */
289 virtual ~IRep () = default;
290
291 public:
292 /**
293 * Return the original (or normalized or expanded with bindings) SQL associated with this statement.
294 */
295 virtual String GetSQL (WhichSQLFlag whichSQL) const = 0;
296
297 public:
298 virtual Sequence<ColumnDescription> GetColumns () const = 0;
299
300 public:
301 virtual Sequence<ParameterDescription> GetParameters () const = 0;
302
303 public:
304 virtual void Bind () = 0;
305 virtual void Bind (unsigned int parameterIndex, const VariantValue& v) = 0;
306 virtual void Bind (const String& parameterName, const VariantValue& v) = 0;
307
308 public:
309 /**
310 * This mimics the sqlite3_reset () functionality/API.
311 *
312 * This clears any ongoing query, so the next call to GetNextRow () will start with the first row from the current query.
313 * This does NOT affect any values currently bound.
314 *
315 * BUT NOTE, it is required to call Reset() (if there are any ongoing queries) before calling Bind.
316 */
317 virtual void Reset () = 0;
318
319 public:
320 /**
321 * If called on a new Statement, or on a statement that has been reset (since the last call to GetNextRow() - this re-runs the query.
322 * But either way, it returns the next row.
323 *
324 * returns 'missing' on EOF, exception on error
325 */
326 virtual optional<Row> GetNextRow () = 0;
327
328 protected:
329 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex _fAssertExternallySynchronizedMutex;
330 };
331
332}
333
334/*
335 ********************************************************************************
336 ***************************** Implementation Details ***************************
337 ********************************************************************************
338 */
339#include "Statement.inl"
340
341#endif /*_Stroika_Foundation_Database_SQL_Statement_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
virtual String GetSQL(WhichSQLFlag whichSQL) const =0
nonvirtual void Reset()
resets the prepared statement back to the beginning of its program (this does NOT clear bindings)
Definition Statement.inl:52
nonvirtual optional< Row > GetNextRow()
Definition Statement.inl:58
nonvirtual String GetSQL(WhichSQLFlag whichSQL=WhichSQLFlag::eOriginal) const
Definition Statement.inl:46
nonvirtual Sequence< ColumnDescription > GetColumns() const
Definition Statement.inl:16
nonvirtual Sequence< ParameterDescription > GetParameters() const
Definition Statement.inl:22
nonvirtual Sequence< Row > GetAllRemainingRows()
Call GetNextRow () repeatedly, and accumulate Rows into a Sequence (
Definition Statement.cpp:60
nonvirtual Sequence< Row > GetAllRows()
call Reset (), and then GetAllRemainingRows () - which always starts current statement with current b...
Definition Statement.inl:64
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237