1 /++
2 This module is part of d2sqlite3.
3 
4 Authors:
5     Nicolas Sicard (biozic) and other contributors at $(LINK https://github.com/biozic/d2sqlite3)
6 
7 Copyright:
8     Copyright 2011-17 Nicolas Sicard.
9 
10 License:
11     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
12 +/
13 module d2sqlite3.statement;
14 
15 import d2sqlite3.database;
16 import d2sqlite3.results;
17 import d2sqlite3.sqlite3;
18 import d2sqlite3.internal.memory;
19 import d2sqlite3.internal.util;
20 
21 import std.conv : to;
22 import std.exception : enforce;
23 import std..string : format, toStringz;
24 import std.typecons : Nullable;
25 
26 /// Set _UnlockNotify version if compiled with SqliteEnableUnlockNotify or SqliteFakeUnlockNotify
27 version (SqliteEnableUnlockNotify) version = _UnlockNotify;
28 else version (SqliteFakeUnlockNotify) version = _UnlockNotify;
29 
30 /++
31 A prepared statement.
32 
33 This struct is a reference-counted wrapper around a `sqlite3_stmt*` pointer.
34 Instances of this struct are typically returned by `Database.prepare()`.
35 +/
36 struct Statement
37 {
38     import std.meta : allSatisfy;
39     import std.traits : isIntegral, isSomeChar, isBoolean, isFloatingPoint,
40         isSomeString, isStaticArray, isDynamicArray, isIterable;
41     import std.typecons : RefCounted, RefCountedAutoInitialize;
42 
43 private:
44 
45     /// Returns $(D true) if the value can be directly bound to the statement
46     enum bool isBindable(T) =
47         is(T == typeof(null)) || is(T == void*) || isIntegral!T || isSomeChar!T
48         || isBoolean!T || isFloatingPoint!T || isSomeString!T || isStaticArray!T
49         || isDynamicArray!T || is(T == Nullable!U, U...);
50 
51     struct Payload
52     {
53         Database db;
54         sqlite3_stmt* handle; // null if error or empty statement
55         int paramCount;
56         debug string sql;
57 
58         ~this()
59         {
60             debug ensureNotInGC!Statement(sql);
61             finalize();
62         }
63 
64         void finalize()
65         {
66             sqlite3_finalize(handle);
67             handle = null;
68         }
69     }
70 
71     RefCounted!(Payload, RefCountedAutoInitialize.no) p;
72 
73     void checkResult(int result)
74     {
75         enforce(result == SQLITE_OK, new SqliteException(errmsg(p.handle), result));
76     }
77 
78     version (_UnlockNotify)
79     {
80         auto sqlite3_blocking_prepare_v2(Database db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail)
81         {
82             int rc;
83             while(SQLITE_LOCKED == (rc = sqlite3_prepare_v2(db.handle(), zSql, nByte, ppStmt, pzTail)))
84             {
85                 rc = db.waitForUnlockNotify();
86                 if(rc != SQLITE_OK) break;
87             }
88             return rc;
89         }
90     }
91 
92 package(d2sqlite3):
93     this(Database db, string sql)
94     {
95         sqlite3_stmt* handle;
96         version (_UnlockNotify)
97         {
98             auto result = sqlite3_blocking_prepare_v2(db, sql.toStringz, sql.length.to!int,
99                 &handle, null);
100         }
101         else
102         {
103             auto result = sqlite3_prepare_v2(db.handle(), sql.toStringz, sql.length.to!int,
104                 &handle, null);
105         }
106         enforce(result == SQLITE_OK, new SqliteException(errmsg(db.handle()), result, sql));
107         p = Payload(db, handle);
108         p.paramCount = sqlite3_bind_parameter_count(p.handle);
109         debug p.sql = sql;
110     }
111 
112     version (_UnlockNotify)
113     {
114         /// Setup and waits for unlock notify using the provided `IUnlockNotifyHandler`
115         auto waitForUnlockNotify()
116         {
117             return p.db.waitForUnlockNotify();
118         }
119     }
120 
121 public:
122     /++
123     Gets the SQLite internal _handle of the statement.
124     +/
125     sqlite3_stmt* handle() @property nothrow
126     {
127         return p.handle;
128     }
129 
130     /++
131     Explicitly finalizes the prepared statement.
132 
133     After a call to `finalize()`, the `Statement` object is destroyed and cannot be used.
134     +/
135     void finalize()
136     {
137         p.finalize();
138         destroy(p);
139     }
140 
141     /++
142     Tells whether the statement is empty (no SQL statement).
143     +/
144     bool empty() @property nothrow
145     {
146         return p.handle is null;
147     }
148     ///
149     unittest
150     {
151         auto db = Database(":memory:");
152         auto statement = db.prepare(" ; ");
153         assert(statement.empty);
154     }
155 
156     /++
157     Binds values to parameters of this statement, using parameter index.
158 
159     Params:
160         index = The index of the parameter (starting from 1).
161 
162         value = The bound _value. The type of value must be compatible with the SQLite
163         types: it must be a boolean or numeric type, a string, an array, null,
164         or a Nullable!T where T is any of the previous types.
165     +/
166     void bind(T)(int index, T value)
167         if (is(T == typeof(null)) || is(T == void*))
168     in
169     {
170         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
171     }
172     body
173     {
174         assert(p.handle);
175         checkResult(sqlite3_bind_null(p.handle, index));
176     }
177 
178     /// ditto
179     void bind(T)(int index, T value)
180         if (isIntegral!T || isSomeChar!T || isBoolean!T)
181     in
182     {
183         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
184     }
185     body
186     {
187         assert(p.handle);
188         checkResult(sqlite3_bind_int64(p.handle, index, value.to!long));
189     }
190 
191     /// ditto
192     void bind(T)(int index, T value)
193         if (isFloatingPoint!T)
194     in
195     {
196         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
197     }
198     body
199     {
200         assert(p.handle);
201         checkResult(sqlite3_bind_double(p.handle, index, value.to!double));
202     }
203 
204     /// ditto
205     void bind(T)(int index, T value)
206         if (isSomeString!T)
207     in
208     {
209         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
210     }
211     body
212     {
213         assert(p.handle);
214         string str = value.to!string;
215         auto ptr = anchorMem(cast(void*) str.ptr);
216         checkResult(sqlite3_bind_text64(p.handle, index, cast(const(char)*) ptr, str.length, &releaseMem, SQLITE_UTF8));
217     }
218 
219     /// ditto
220     void bind(T)(int index, T value)
221         if (isStaticArray!T)
222     in
223     {
224         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
225     }
226     body
227     {
228         assert(p.handle);
229         checkResult(sqlite3_bind_blob64(p.handle, index, cast(void*) value.ptr, value.sizeof, SQLITE_TRANSIENT));
230     }
231 
232     /// ditto
233     void bind(T)(int index, T value)
234         if (isDynamicArray!T && !isSomeString!T)
235     in
236     {
237         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
238     }
239     body
240     {
241         assert(p.handle);
242         auto arr = cast(void[]) value;
243         checkResult(sqlite3_bind_blob64(p.handle, index, anchorMem(arr.ptr), arr.length, &releaseMem));
244     }
245 
246     /// ditto
247     void bind(T)(int index, T value)
248         if (is(T == Nullable!U, U...))
249     in
250     {
251         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
252     }
253     body
254     {
255         if (value.isNull)
256         {
257             assert(p.handle);
258             checkResult(sqlite3_bind_null(p.handle, index));
259         }
260         else
261             bind(index, value.get);
262     }
263 
264     /++
265     Binds values to parameters of this statement, using parameter names.
266 
267     Params:
268         name = The name of the parameter, including the ':', '@' or '$' that introduced it.
269 
270         value = The bound _value. The type of value must be compatible with the SQLite
271         types: it must be a boolean or numeric type, a string, an array, null,
272         or a Nullable!T where T is any of the previous types.
273 
274     Warning:
275         While convenient, this overload of `bind` is less performant, because it has to
276         retrieve the column index with a call to the SQLite function
277         `sqlite3_bind_parameter_index`.
278     +/
279     void bind(T)(string name, T value)
280     in
281     {
282         assert(name.length);
283     }
284     body
285     {
286         assert(p.handle);
287         auto index = sqlite3_bind_parameter_index(p.handle, name.toStringz);
288         assert(index > 0, "no parameter named '%s'".format(name));
289         bind(index, value);
290     }
291 
292     /++
293     Binds all the arguments at once in order.
294     +/
295     void bindAll(Args...)(Args args)
296     in
297     {
298         assert(Args.length == this.parameterCount, "parameter count mismatch");
299     }
300     body
301     {
302         foreach (index, _; Args)
303             bind(index + 1, args[index]);
304     }
305 
306     /++
307     Clears the bindings.
308 
309     This does not reset the statement. Use `Statement.reset()` for this.
310     +/
311     void clearBindings()
312     {
313         assert(p.handle);
314         checkResult(sqlite3_clear_bindings(p.handle));
315     }
316 
317     /++
318     Executes the statement and return a (possibly empty) range of results.
319     +/
320     ResultRange execute()
321     {
322         return ResultRange(this);
323     }
324 
325     /++
326     Resets a this statement before a new execution.
327 
328     Calling this method invalidates any `ResultRange` struct returned by a previous call
329     to `Database.execute()` or `Statement.execute()`.
330 
331     This does not clear the bindings. Use `Statement.clearBindings()` for this.
332     +/
333     void reset()
334     {
335         assert(p.handle);
336         checkResult(sqlite3_reset(p.handle));
337     }
338 
339     /++
340     Binds arguments, executes and resets the statement, in one call.
341 
342     This convenience function is equivalent to:
343     ---
344     bindAll(args);
345     execute();
346     reset();
347     ---
348     +/
349     void inject(Args...)(Args args)
350         if (allSatisfy!(isBindable, Args))
351     {
352         bindAll(args);
353         execute();
354         reset();
355     }
356 
357     /++
358     Binds the fields of a struct in order, executes and resets the statement, in one call.
359     +/
360     void inject(T)(auto ref const T obj)
361         if (is(T == struct))
362     {
363         import std.meta : Filter;
364         import std.traits : FieldNameTuple;
365 
366         enum accesible(string F) = __traits(compiles, __traits(getMember, obj, F));
367         enum bindable(string F) = isBindable!(typeof(__traits(getMember, obj, F)));
368 
369         alias FieldNames = Filter!(bindable, Filter!(accesible, FieldNameTuple!T));
370         assert(FieldNames.length == this.parameterCount, "parameter count mismatch");
371         foreach (i, field; FieldNames)
372             bind(i + 1, __traits(getMember, obj, field));
373         execute();
374         reset();
375     }
376 
377     /++
378     Binds iterable values in order, executes and resets the statement, in one call.
379     +/
380     void inject(T)(auto ref T obj)
381         if (!isBindable!T && isIterable!T)
382     in
383     {
384         static if (__traits(compiles, obj.length))
385             assert(obj.length == this.parameterCount, "parameter count mismatch");
386     }
387     body
388     {
389         static if (__traits(compiles, { foreach (string k, ref v; obj) {} }))
390         {
391             foreach (string k, ref v; obj) bind(k, v);
392         }
393         else
394         {
395             int i = 1;
396             foreach (ref v; obj) bind(i++, v);
397         }
398         execute();
399         reset();
400     }
401 
402     /// Gets the count of bind parameters.
403     int parameterCount() nothrow
404     {
405         assert(p.handle);
406         return p.paramCount;
407     }
408 
409     /++
410     Gets the name of the bind parameter at the given index.
411 
412     Params:
413         index = The index of the parameter (the first parameter has the index 1).
414 
415     Returns: The name of the parameter or null is not found or out of range.
416     +/
417     string parameterName(int index)
418     in
419     {
420         assert(index > 0 && index <= p.paramCount, "parameter index out of range");
421     }
422     body
423     {
424         assert(p.handle);
425         return sqlite3_bind_parameter_name(p.handle, index).to!string;
426     }
427 
428     /++
429     Gets the index of a bind parameter.
430 
431     Returns: The index of the parameter (the first parameter has the index 1)
432     or 0 is not found or out of range.
433     +/
434     int parameterIndex(string name)
435     in
436     {
437         assert(name.length);
438     }
439     body
440     {
441         assert(p.handle);
442         return sqlite3_bind_parameter_index(p.handle, name.toStringz);
443     }
444 }
445 
446 /++
447 Turns $(D_PARAM value) into a _literal that can be used in an SQLite expression.
448 +/
449 string literal(T)(T value)
450 {
451     import std..string : replace;
452     import std.traits : isBoolean, isNumeric, isSomeString, isArray;
453 
454     static if (is(T == typeof(null)))
455         return "NULL";
456     else static if (isBoolean!T)
457         return value ? "1" : "0";
458     else static if (isNumeric!T)
459         return value.to!string();
460     else static if (isSomeString!T)
461         return format("'%s'", value.replace("'", "''"));
462     else static if (isArray!T)
463         return "'X%(%X%)'".format(cast(Blob) value);
464     else
465         static assert(false, "cannot make a literal of a value of type " ~ T.stringof);
466 }
467 ///
468 unittest
469 {
470     assert(null.literal == "NULL");
471     assert(false.literal == "0");
472     assert(true.literal == "1");
473     assert(4.literal == "4");
474     assert(4.1.literal == "4.1");
475     assert("foo".literal == "'foo'");
476     assert("a'b'".literal == "'a''b'''");
477     auto a = cast(Blob) x"DEADBEEF";
478     assert(a.literal == "'XDEADBEEF'");
479 }