1 /++
2 Managing SQLite3 database connections.
3 
4 Authors:
5     Nicolas Sicard (biozic) and other contributors at $(LINK https://github.com/biozic/d2sqlite3)
6 
7 Copyright:
8     Copyright 2011-18 Nicolas Sicard.
9 
10 License:
11     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
12 +/
13 module d2sqlite3.database;
14 
15 import d2sqlite3.statement;
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 /// Type for the internal representation of blobs
31 alias Blob = immutable(ubyte)[];
32 
33 /// SQLite type codes
34 enum SqliteType
35 {
36     INTEGER = SQLITE_INTEGER, ///
37     FLOAT = SQLITE_FLOAT, ///
38     TEXT = SQLITE3_TEXT, ///
39     BLOB = SQLITE_BLOB, ///
40     NULL = SQLITE_NULL ///
41 }
42 
43 /++
44 A caracteristic of user-defined functions or aggregates.
45 +/
46 enum Deterministic
47 {
48     /++
49     The returned value is the same if the function is called with the same parameters.
50     +/
51     yes = 0x800,
52 
53     /++
54     The returned value can vary even if the function is called with the same parameters.
55     +/
56     no = 0
57 }
58 
59 /++
60 An database connection.
61 
62 This struct is a reference-counted wrapper around a `sqlite3*` pointer.
63 +/
64 struct Database
65 {
66     import std.traits : isFunctionPointer, isDelegate;
67     import std.typecons : RefCounted, RefCountedAutoInitialize;
68 
69 private:
70     struct Payload
71     {
72         sqlite3* handle;
73         void* updateHook;
74         void* commitHook;
75         void* rollbackHook;
76         void* progressHandler;
77         void* traceCallback;
78         void* profileCallback;
79         version (_UnlockNotify) IUnlockNotifyHandler unlockNotifyHandler;
80         debug string filename;
81 
82         this(sqlite3* handle) nothrow
83         {
84             this.handle = handle;
85         }
86 
87         ~this() nothrow
88         {
89             debug ensureNotInGC!Database(filename);
90             ptrFree(updateHook);
91             ptrFree(commitHook);
92             ptrFree(rollbackHook);
93             ptrFree(progressHandler);
94             ptrFree(traceCallback);
95             ptrFree(profileCallback);
96 
97             if (!handle)
98                 return;
99             sqlite3_progress_handler(handle, 0, null, null);
100             sqlite3_close(handle);
101         }
102     }
103 
104     RefCounted!(Payload, RefCountedAutoInitialize.no) p;
105 
106     void check(int result)
107     {
108         enforce(result == SQLITE_OK, new SqliteException(errmsg(p.handle), result));
109     }
110 
111 public:
112     /++
113     Opens a database connection.
114 
115     Params:
116         path = The path to the database file. In recent versions of SQLite, the path can be
117         an URI with options.
118 
119         flags = Options flags.
120 
121     See_Also: $(LINK http://www.sqlite.org/c3ref/open.html) to know how to use the flags
122     parameter or to use path as a file URI if the current configuration allows it.
123     +/
124     this(string path, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
125     {
126         sqlite3* hdl;
127         auto result = sqlite3_open_v2(path.toStringz, &hdl, flags, null);
128         enforce(result == SQLITE_OK, new SqliteException(hdl ? errmsg(hdl) : "Error opening the database", result));
129         p = Payload(hdl);
130         debug p.filename = path;
131     }
132 
133     /++
134     Explicitly closes the database connection.
135 
136     After a successful call to `close()`, using the database connection or one of its prepared
137     statement is an error. The `Database` object is destroyed and cannot be used any more.
138     +/
139     void close()
140     {
141         auto result = sqlite3_close(p.handle);
142         enforce(result == SQLITE_OK, new SqliteException(errmsg(p.handle), result));
143         p.handle = null;
144         destroy(p);
145     }
146 
147     /++
148     Gets the SQLite internal _handle of the database connection.
149     +/
150     sqlite3* handle() @property nothrow
151     {
152         return p.handle;
153     }
154 
155     /++
156     Gets the path associated with an attached database.
157 
158     Params:
159         database = The name of an attached database.
160 
161     Returns: The absolute path of the attached database.
162         If there is no attached database, or if database is a temporary or
163         in-memory database, then null is returned.
164     +/
165     string attachedFilePath(string database = "main")
166     {
167         assert(p.handle);
168         return sqlite3_db_filename(p.handle, database.toStringz).to!string;
169     }
170 
171     /++
172     Gets the read-only status of an attached database.
173 
174     Params:
175         database = The name of an attached database.
176     +/
177     bool isReadOnly(string database = "main")
178     {
179         assert(p.handle);
180         immutable ret = sqlite3_db_readonly(p.handle, database.toStringz);
181         enforce(ret >= 0, new SqliteException("Database not found: %s".format(database)));
182         return ret == 1;
183     }
184 
185     /++
186     Gets metadata for a specific table column of an attached database.
187 
188     Params:
189         table = The name of the table.
190 
191         column = The name of the column.
192 
193         database = The name of a database attached. If null, then all attached databases
194         are searched for the table using the same algorithm used by the database engine
195         to resolve unqualified table references.
196     +/
197     TableColumnMetadata tableColumnMetadata(string table, string column, string database = "main")
198     {
199         TableColumnMetadata data;
200         char* pzDataType, pzCollSeq;
201         int notNull, primaryKey, autoIncrement;
202         assert(p.handle);
203         check(sqlite3_table_column_metadata(p.handle, database.toStringz, table.toStringz,
204             column.toStringz, &pzDataType, &pzCollSeq, &notNull, &primaryKey, &autoIncrement));
205         data.declaredTypeName = pzDataType.to!string;
206         data.collationSequenceName = pzCollSeq.to!string;
207         data.isNotNull = cast(bool) notNull;
208         data.isPrimaryKey = cast(bool) primaryKey;
209         data.isAutoIncrement = cast(bool) autoIncrement;
210         return data;
211     }
212 
213     /++
214     Executes a single SQL statement and returns the results directly.
215 
216     It's the equivalent of `prepare(sql).execute()`.
217     Or when used with args the equivalent of:
218     ---
219     auto stm = prepare(sql);
220     stm.bindAll(args);
221     stm.execute();
222     ---
223 
224     The results become undefined when the Database goes out of scope and is destroyed.
225 
226     Params:
227         sql = The code of the SQL statement.
228         args = Optional arguments to bind to the SQL statement.
229     +/
230     ResultRange execute(Args...)(string sql, Args args)
231     {
232         auto stm = prepare(sql);
233         static if (Args.length) stm.bindAll(args);
234         return stm.execute();
235     }
236     ///
237     unittest
238     {
239         auto db = Database(":memory:");
240         db.execute("CREATE TABLE test (val INTEGER)");
241         db.execute("INSERT INTO test (val) VALUES (:v)", 1);
242         assert(db.execute("SELECT val FROM test WHERE val=:v", 1).oneValue!int == 1);
243     }
244 
245     /++
246     Runs an SQL script that can contain multiple statements.
247 
248     Params:
249         script = The code of the SQL script.
250 
251         dg = A delegate to call for each statement to handle the results. The passed
252         ResultRange will be empty if a statement doesn't return rows. If the delegate
253         return false, the execution is aborted.
254     +/
255     void run(string script, bool delegate(ResultRange) dg = null)
256     {
257         foreach (sql; script.byStatement)
258         {
259             auto stmt = prepare(sql);
260             auto results = stmt.execute();
261             if (dg && !dg(results))
262                 return;
263         }
264     }
265     ///
266     unittest
267     {
268         auto db = Database(":memory:");
269         db.run(`CREATE TABLE test1 (val INTEGER);
270                 CREATE TABLE test2 (val FLOAT);
271                 DROP TABLE test1;
272                 DROP TABLE test2;`);
273     }
274 
275     /++
276     Prepares (compiles) a single SQL statement and returns it, so that it can be bound to
277     values before execution.
278 
279     The statement becomes invalid if the Database goes out of scope and is destroyed.
280     +/
281     Statement prepare(string sql)
282     {
283         return Statement(this, sql);
284     }
285 
286     /// Convenience functions equivalent to an SQL statement.
287     void begin() { execute("BEGIN"); }
288     /// Ditto
289     void commit() { execute("COMMIT"); }
290     /// Ditto
291     void rollback() { execute("ROLLBACK"); }
292 
293     /++
294     Returns the rowid of the last INSERT statement.
295     +/
296     long lastInsertRowid()
297     {
298         assert(p.handle);
299         return sqlite3_last_insert_rowid(p.handle);
300     }
301 
302     /++
303     Gets the number of database rows that were changed, inserted or deleted by the most
304     recently executed SQL statement.
305     +/
306     int changes() @property nothrow
307     {
308         assert(p.handle);
309         return sqlite3_changes(p.handle);
310     }
311 
312     /++
313     Gets the number of database rows that were changed, inserted or deleted since the
314     database was opened.
315     +/
316     int totalChanges() @property nothrow
317     {
318         assert(p.handle);
319         return sqlite3_total_changes(p.handle);
320     }
321 
322     /++
323     Gets the SQLite error code of the last operation.
324     +/
325     int errorCode() @property nothrow
326     {
327         return p.handle ? sqlite3_errcode(p.handle) : 0;
328     }
329 
330     /++
331     Interrupts any pending database operations.
332 
333     It's safe to call this function from anouther thread.
334 
335     See_also: $(LINK http://www.sqlite.org/c3ref/interrupt.html).
336     +/
337     void interrupt()
338     {
339         assert(p.handle);
340         sqlite3_interrupt(p.handle);
341     }
342 
343     /++
344     Sets a connection configuration option.
345 
346     See_Also: $(LINK http://www.sqlite.org/c3ref/db_config.html).
347     +/
348     void config(Args...)(int code, Args args)
349     {
350         assert(p.handle);
351         auto result = sqlite3_db_config(p.handle, code, args);
352         enforce(result == SQLITE_OK, new SqliteException("Database configuration: error %s".format(result)));
353     }
354 
355     /++
356     Enables or disables loading extensions.
357     +/
358     void enableLoadExtensions(bool enable = true)
359     {
360         assert(p.handle);
361         enforce(sqlite3_enable_load_extension(p.handle, enable) == SQLITE_OK,
362             new SqliteException("Could not enable loading extensions."));
363     }
364 
365     /++
366     Loads an extension.
367 
368     Params:
369         path = The path of the extension file.
370 
371         entryPoint = The name of the entry point function. If null is passed, SQLite
372         uses the name of the extension file as the entry point.
373     +/
374     void loadExtension(string path, string entryPoint = null)
375     {
376         assert(p.handle);
377         immutable ret = sqlite3_load_extension(p.handle, path.toStringz, entryPoint.toStringz, null);
378         enforce(ret == SQLITE_OK, new SqliteException(
379                 "Could not load extension: %s:%s".format(entryPoint, path)));
380     }
381 
382     /++
383     Creates and registers a new function in the database.
384 
385     If a function with the same name and the same arguments already exists, it is replaced
386     by the new one.
387 
388     The memory associated with the function will be released when the database connection
389     is closed.
390 
391     Params:
392         name = The name that the function will have in the database.
393 
394         fun = a delegate or function that implements the function. $(D_PARAM fun)
395         must satisfy the following criteria:
396             $(UL
397                 $(LI It must not be variadic.)
398                 $(LI Its arguments must all have a type that is compatible with SQLite types:
399                 it must be a boolean or numeric type, a string, an array, `null`,
400                 or a `Nullable!T` where T is any of the previous types.)
401                 $(LI Its return value must also be of a compatible type.)
402             )
403             or
404             $(UL
405                 $(LI It must be a normal or type-safe variadic function where the arguments
406                 are of type `ColumnData`. In other terms, the signature of the function must be:
407                 `function(ColumnData[] args)` or `function(ColumnData[] args...)`)
408                 $(LI Its return value must be a boolean or numeric type, a string, an array, `null`,
409                 or a `Nullable!T` where T is any of the previous types.)
410             )
411         Pass a `null` function pointer to delete the function from the database connection.
412 
413         det = Tells SQLite whether the result of the function is deterministic, i.e. if the
414         result is the same when called with the same parameters. Recent versions of SQLite
415         perform optimizations based on this. Set to `Deterministic.no` otherwise.
416 
417     See_Also: $(LINK http://www.sqlite.org/c3ref/create_function.html).
418     +/
419     void createFunction(T)(string name, T fun, Deterministic det = Deterministic.yes)
420         if (isFunctionPointer!T || isDelegate!T)
421     {
422         import std.meta : AliasSeq, staticMap, EraseAll;
423         import std.traits : variadicFunctionStyle, Variadic, ParameterTypeTuple,
424             ParameterDefaultValueTuple, ReturnType, Unqual;
425 
426         static assert(variadicFunctionStyle!(fun) == Variadic.no
427             || is(ParameterTypeTuple!fun == AliasSeq!(ColumnData[])),
428             "only type-safe variadic functions with ColumnData arguments are supported");
429 
430         static if (is(ParameterTypeTuple!fun == AliasSeq!(ColumnData[])))
431         {
432             extern(C) static nothrow
433             void x_func(sqlite3_context* context, int argc, sqlite3_value** argv)
434             {
435                 string name;
436                 try
437                 {
438                     import std.array : appender;
439                     auto args = appender!(ColumnData[]);
440 
441                     foreach (i; 0 .. argc)
442                     {
443                         auto value = argv[i];
444                         immutable type = sqlite3_value_type(value);
445 
446                         final switch (type)
447                         {
448                             case SqliteType.INTEGER:
449                                 args.put(ColumnData(getValue!long(value)));
450                                 break;
451 
452                             case SqliteType.FLOAT:
453                                 args.put(ColumnData(getValue!double(value)));
454                                 break;
455 
456                             case SqliteType.TEXT:
457                                 args.put(ColumnData(getValue!string(value)));
458                                 break;
459 
460                             case SqliteType.BLOB:
461                                 args.put(ColumnData(getValue!Blob(value)));
462                                 break;
463 
464                             case SqliteType.NULL:
465                                 args.put(ColumnData(null));
466                                 break;
467                         }
468                     }
469 
470                     auto ptr = sqlite3_user_data(context);
471 
472                     auto wrappedDelegate = delegateUnwrap!T(ptr);
473                     auto dlg = wrappedDelegate.dlg;
474                     name = wrappedDelegate.name;
475                     setResult(context, dlg(args.data));
476                 }
477                 catch (Exception e)
478                 {
479                     sqlite3_result_error(context, "error in function %s(): %s"
480                         .nothrowFormat(name, e.msg).toStringz, -1);
481                 }
482             }
483         }
484         else
485         {
486             static assert(!is(ReturnType!fun == void), "function must not return void");
487 
488             alias PT = staticMap!(Unqual, ParameterTypeTuple!fun);
489             alias PD = ParameterDefaultValueTuple!fun;
490 
491             extern (C) static nothrow
492             void x_func(sqlite3_context* context, int argc, sqlite3_value** argv)
493             {
494                 string name;
495                 try
496                 {
497                     // Get the deledate and its name
498                     auto ptr = sqlite3_user_data(context);
499                     auto wrappedDelegate = delegateUnwrap!T(ptr);
500                     auto dlg = wrappedDelegate.dlg;
501                     name = wrappedDelegate.name;
502 
503                     enum maxArgc = PT.length;
504                     enum minArgc = PT.length - EraseAll!(void, PD).length;
505 
506                     if (argc > maxArgc)
507                     {
508                         auto txt = ("too many arguments in function %s(), expecting at most %s"
509                             ).format(name, maxArgc);
510                         sqlite3_result_error(context, txt.toStringz, -1);
511                     }
512                     else if (argc < minArgc)
513                     {
514                         auto txt = ("too few arguments in function %s(), expecting at least %s"
515                             ).format(name, minArgc);
516                         sqlite3_result_error(context, txt.toStringz, -1);
517                     }
518                     else
519                     {
520                         PT args;
521                         foreach (i, type; PT)
522                         {
523                             if (i < argc)
524                                 args[i] = getValue!type(argv[i]);
525                             else
526                                 static if (is(typeof(PD[i])))
527                                     args[i] = PD[i];
528                         }
529                         setResult(context, dlg(args));
530                     }
531                 }
532                 catch (Exception e)
533                 {
534                     sqlite3_result_error(context, "error in function %s(): %s"
535                         .nothrowFormat(name, e.msg).toStringz, -1);
536                 }
537             }
538         }
539 
540         assert(name.length, "function has an empty name");
541 
542         if (!fun)
543             createFunction(name, null);
544 
545         assert(p.handle);
546         check(sqlite3_create_function_v2(p.handle, name.toStringz, -1,
547               SQLITE_UTF8 | det, delegateWrap(fun, name), &x_func, null, null, &ptrFree));
548     }
549     ///
550     unittest
551     {
552         string star(int count, string starSymbol = "*")
553         {
554             import std.range : repeat;
555             import std.array : join;
556 
557             return starSymbol.repeat(count).join;
558         }
559 
560         auto db = Database(":memory:");
561         db.createFunction("star", &star);
562         assert(db.execute("SELECT star(5)").oneValue!string == "*****");
563         assert(db.execute("SELECT star(3, '♥')").oneValue!string == "♥♥♥");
564     }
565     ///
566     unittest
567     {
568         // The implementation of the new function
569         string myList(ColumnData[] args)
570         {
571             import std.array : appender;
572             import std..string : format, join;
573 
574             auto app = appender!(string[]);
575             foreach (arg; args)
576             {
577                 if (arg.type == SqliteType.TEXT)
578                     app.put(`"%s"`.format(arg));
579                 else
580                     app.put("%s".format(arg));
581             }
582             return app.data.join(", ");
583         }
584 
585         auto db = Database(":memory:");
586         db.createFunction("my_list", &myList);
587         auto list = db.execute("SELECT my_list(42, 3.14, 'text', NULL)").oneValue!string;
588         assert(list == `42, 3.14, "text", null`);
589     }
590 
591     /// Ditto
592     void createFunction(T)(string name, T fun = null)
593         if (is(T == typeof(null)))
594     {
595         assert(name.length, "function has an empty name");
596         assert(p.handle);
597         check(sqlite3_create_function_v2(p.handle, name.toStringz, -1, SQLITE_UTF8,
598                 null, fun, null, null, null));
599     }
600 
601     /++
602     Creates and registers a new aggregate function in the database.
603 
604     Params:
605         name = The name that the aggregate function will have in the database.
606 
607         agg = The struct of type T implementing the aggregate. T must implement
608         at least these two methods: `accumulate()` and `result()`.
609         Each parameter and the returned type of `accumulate()` and `result()` must be
610         a boolean or numeric type, a string, an array, `null`, or a `Nullable!T`
611         where T is any of the previous types. These methods cannot be variadic.
612 
613         det = Tells SQLite whether the result of the function is deterministic, i.e. if the
614         result is the same when called with the same parameters. Recent versions of SQLite
615         perform optimizations based on this. Set to `Deterministic.no` otherwise.
616 
617     See_Also: $(LINK http://www.sqlite.org/c3ref/create_function.html).
618     +/
619     void createAggregate(T)(string name, T agg, Deterministic det = Deterministic.yes)
620     {
621         import std.meta : staticMap;
622         import std.traits : isAggregateType, ReturnType, variadicFunctionStyle, Variadic,
623             Unqual, ParameterTypeTuple;
624         import core.stdc.stdlib : malloc;
625 
626         static assert(isAggregateType!T,
627             T.stringof ~ " should be an aggregate type");
628         static assert(is(typeof(T.accumulate) == function),
629             T.stringof ~ " should have a method named accumulate");
630         static assert(is(typeof(T.result) == function),
631             T.stringof ~ " should have a method named result");
632         static assert(is(typeof({
633                 alias RT = ReturnType!(T.result);
634                 setResult!RT(null, RT.init);
635             })), T.stringof ~ ".result should return an SQLite-compatible type");
636         static assert(variadicFunctionStyle!(T.accumulate) == Variadic.no,
637             "variadic functions are not supported");
638         static assert(variadicFunctionStyle!(T.result) == Variadic.no,
639             "variadic functions are not supported");
640 
641         alias PT = staticMap!(Unqual, ParameterTypeTuple!(T.accumulate));
642         alias RT = ReturnType!(T.result);
643 
644         static struct Context
645         {
646             T aggregate;
647             string functionName;
648         }
649 
650         extern(C) static nothrow
651         void x_step(sqlite3_context* context, int /* argc */, sqlite3_value** argv)
652         {
653             auto ctx = cast(Context*) sqlite3_user_data(context);
654             if (!ctx)
655             {
656                 sqlite3_result_error_nomem(context);
657                 return;
658             }
659 
660             PT args;
661             try
662             {
663                 foreach (i, type; PT)
664                     args[i] = getValue!type(argv[i]);
665 
666                 ctx.aggregate.accumulate(args);
667             }
668             catch (Exception e)
669             {
670                 sqlite3_result_error(context, "error in aggregate function %s(): %s"
671                     .nothrowFormat(ctx.functionName, e.msg).toStringz, -1);
672             }
673         }
674 
675         extern(C) static nothrow
676         void x_final(sqlite3_context* context)
677         {
678             auto ctx = cast(Context*) sqlite3_user_data(context);
679             if (!ctx)
680             {
681                 sqlite3_result_error_nomem(context);
682                 return;
683             }
684 
685             try
686             {
687                 setResult(context, ctx.aggregate.result());
688             }
689             catch (Exception e)
690             {
691                 sqlite3_result_error(context, "error in aggregate function %s(): %s"
692                     .nothrowFormat(ctx.functionName, e.msg).toStringz, -1);
693             }
694         }
695 
696         static if (is(T == class) || is(T == Interface))
697             assert(agg, "Attempt to create an aggregate function from a null reference");
698 
699         auto ctx = cast(Context*) malloc(Context.sizeof);
700         ctx.aggregate = agg;
701         ctx.functionName = name;
702 
703         assert(p.handle);
704         check(sqlite3_create_function_v2(p.handle, name.toStringz, PT.length, SQLITE_UTF8 | det,
705             cast(void*) ctx, null, &x_step, &x_final, &ptrFree));
706     }
707     ///
708     unittest // Aggregate creation
709     {
710         import std.array : Appender, join;
711 
712         // The implementation of the aggregate function
713         struct Joiner
714         {
715             private
716             {
717                 Appender!(string[]) stringList;
718                 string separator;
719             }
720 
721             this(string separator)
722             {
723                 this.separator = separator;
724             }
725 
726             void accumulate(string word)
727             {
728                 stringList.put(word);
729             }
730 
731             string result()
732             {
733                 return stringList.data.join(separator);
734             }
735         }
736 
737         auto db = Database(":memory:");
738         db.run("CREATE TABLE test (word TEXT);
739                 INSERT INTO test VALUES ('My');
740                 INSERT INTO test VALUES ('cat');
741                 INSERT INTO test VALUES ('is');
742                 INSERT INTO test VALUES ('black');");
743 
744         db.createAggregate("dash_join", Joiner("-"));
745         auto text = db.execute("SELECT dash_join(word) FROM test").oneValue!string;
746         assert(text == "My-cat-is-black");
747     }
748 
749     /++
750     Creates and registers a collation function in the database.
751 
752     Params:
753         name = The name that the function will have in the database.
754 
755         fun = a delegate or function that implements the collation. The function $(D_PARAM fun)
756         must be `nothrow`` and satisfy these criteria:
757             $(UL
758                 $(LI Takes two string arguments (s1 and s2). These two strings are slices of C-style strings
759                   that SQLite manages internally, so there is no guarantee that they are still valid
760                   when the function returns.)
761                 $(LI Returns an integer (ret).)
762                 $(LI If s1 is less than s2, ret < 0.)
763                 $(LI If s1 is equal to s2, ret == 0.)
764                 $(LI If s1 is greater than s2, ret > 0.)
765                 $(LI If s1 is equal to s2, then s2 is equal to s1.)
766                 $(LI If s1 is equal to s2 and s2 is equal to s3, then s1 is equal to s3.)
767                 $(LI If s1 is less than s2, then s2 is greater than s1.)
768                 $(LI If s1 is less than s2 and s2 is less than s3, then s1 is less than s3.)
769             )
770 
771     See_Also: $(LINK http://www.sqlite.org/lang_aggfunc.html)
772     +/
773     void createCollation(T)(string name, T fun)
774         if (isFunctionPointer!T || isDelegate!T)
775     {
776         import std.traits : isImplicitlyConvertible, functionAttributes, FunctionAttribute,
777             ParameterTypeTuple, isSomeString, ReturnType;
778 
779         static assert(isImplicitlyConvertible!(typeof(fun("a", "b")), int),
780             "the collation function has a wrong signature");
781 
782         static assert(functionAttributes!(T) & FunctionAttribute.nothrow_,
783             "only nothrow functions are allowed as collations");
784 
785         alias PT = ParameterTypeTuple!fun;
786         static assert(isSomeString!(PT[0]),
787             "the first argument of function " ~ name ~ " should be a string");
788         static assert(isSomeString!(PT[1]),
789             "the second argument of function " ~ name ~ " should be a string");
790         static assert(isImplicitlyConvertible!(ReturnType!fun, int),
791             "function " ~ name ~ " should return a value convertible to an int");
792 
793         extern (C) static nothrow
794         int x_compare(void* ptr, int n1, const(void)* str1, int n2, const(void)* str2)
795         {
796             static string slice(const(void)* str, int n) nothrow
797             {
798                 // The string data is owned by SQLite, so it should be safe
799                 // to take a slice of it.
800                 return str ? (cast(immutable) (cast(const(char)*) str)[0 .. n]) : null;
801             }
802 
803             return delegateUnwrap!T(ptr).dlg(slice(str1, n1), slice(str2, n2));
804         }
805 
806         assert(p.handle);
807         auto dgw = delegateWrap(fun, name);
808         auto result = sqlite3_create_collation_v2(p.handle, name.toStringz, SQLITE_UTF8,
809             delegateWrap(fun, name), &x_compare, &ptrFree);
810         if (result != SQLITE_OK)
811         {
812             ptrFree(dgw);
813             throw new SqliteException(errmsg(p.handle), result);
814         }
815     }
816     ///
817     unittest // Collation creation
818     {
819         // The implementation of the collation
820         int my_collation(string s1, string s2) nothrow
821         {
822             import std.uni : icmp;
823             import std.exception : assumeWontThrow;
824 
825             return assumeWontThrow(icmp(s1, s2));
826         }
827 
828         auto db = Database(":memory:");
829         db.createCollation("my_coll", &my_collation);
830         db.run("CREATE TABLE test (word TEXT);
831                 INSERT INTO test (word) VALUES ('straße');
832                 INSERT INTO test (word) VALUES ('strasses');");
833 
834         auto word = db.execute("SELECT word FROM test ORDER BY word COLLATE my_coll")
835                       .oneValue!string;
836         assert(word == "straße");
837     }
838 
839     /++
840     Registers a delegate of type `UpdateHookDelegate` as the database's update hook.
841 
842     Any previously set hook is released. Pass `null` to disable the callback.
843 
844     See_Also: $(LINK http://www.sqlite.org/c3ref/commit_hook.html).
845     +/
846     void setUpdateHook(UpdateHookDelegate updateHook)
847     {
848         extern(C) static nothrow
849         void callback(void* ptr, int type, const(char)* dbName, const(char)* tableName, long rowid)
850         {
851             WrappedDelegate!UpdateHookDelegate* dg;
852             dg = delegateUnwrap!UpdateHookDelegate(ptr);
853             dg.dlg(type, dbName.to!string, tableName.to!string, rowid);
854         }
855 
856         ptrFree(p.updateHook);
857         p.updateHook = delegateWrap(updateHook);
858         assert(p.handle);
859         sqlite3_update_hook(p.handle, &callback, p.updateHook);
860     }
861 
862     /++
863     Registers a delegate of type `CommitHookDelegate` as the database's commit hook.
864     Any previously set hook is released.
865 
866     Params:
867         commitHook = A delegate that should return a non-zero value
868         if the operation must be rolled back, or 0 if it can commit.
869         Pass `null` to disable the callback.
870 
871     See_Also: $(LINK http://www.sqlite.org/c3ref/commit_hook.html).
872     +/
873     void setCommitHook(CommitHookDelegate commitHook)
874     {
875         extern(C) static nothrow
876         int callback(void* ptr)
877         {
878             auto dlg = delegateUnwrap!CommitHookDelegate(ptr).dlg;
879             return dlg();
880         }
881 
882         ptrFree(p.commitHook);
883         p.commitHook = delegateWrap(commitHook);
884         assert(p.handle);
885         sqlite3_commit_hook(p.handle, &callback, p.commitHook);
886     }
887 
888     /++
889     Registers a delegate of type `RoolbackHookDelegate` as the database's rollback hook.
890 
891     Any previously set hook is released.
892     Pass `null` to disable the callback.
893 
894     See_Also: $(LINK http://www.sqlite.org/c3ref/commit_hook.html).
895     +/
896     void setRollbackHook(RoolbackHookDelegate rollbackHook)
897     {
898         extern(C) static nothrow
899         void callback(void* ptr)
900         {
901             auto dlg = delegateUnwrap!RoolbackHookDelegate(ptr).dlg;
902             dlg();
903         }
904 
905         ptrFree(p.rollbackHook);
906         p.rollbackHook = delegateWrap(rollbackHook);
907         assert(p.handle);
908         sqlite3_rollback_hook(p.handle, &callback, p.rollbackHook);
909     }
910 
911     /++
912     Registers a delegate of type `ProgressHandlerDelegate` as the progress handler.
913 
914     Any previously set handler is released.
915     Pass `null` to disable the callback.
916 
917     Params:
918         pace = The approximate number of virtual machine instructions that are
919         evaluated between successive invocations of the handler.
920 
921         progressHandler = A delegate that should return 0 if the operation can continue
922         or another value if it must be aborted.
923 
924     See_Also: $(LINK http://www.sqlite.org/c3ref/progress_handler.html).
925     +/
926     void setProgressHandler(int pace, ProgressHandlerDelegate progressHandler)
927     {
928         extern(C) static nothrow
929         int callback(void* ptr)
930         {
931             auto dlg = delegateUnwrap!ProgressHandlerDelegate(ptr).dlg;
932             return dlg();
933         }
934 
935         ptrFree(p.progressHandler);
936         p.progressHandler = delegateWrap(progressHandler);
937         assert(p.handle);
938         sqlite3_progress_handler(p.handle, pace, &callback, p.progressHandler);
939     }
940 
941     /++
942     Registers a delegate of type `TraceCallbackDelegate` as the trace callback.
943 
944     Any previously set trace callback is released.
945     Pass `null` to disable the callback.
946 
947     The string parameter that is passed to the callback is the SQL text of the statement being
948     executed.
949 
950     See_Also: $(LINK http://www.sqlite.org/c3ref/profile.html).
951     +/
952     void setTraceCallback(TraceCallbackDelegate traceCallback)
953     {
954         extern(C) static nothrow
955         void callback(void* ptr, const(char)* str)
956         {
957             auto dlg = delegateUnwrap!TraceCallbackDelegate(ptr).dlg;
958             dlg(str.to!string);
959         }
960 
961         ptrFree(p.traceCallback);
962         p.traceCallback = delegateWrap(traceCallback);
963         assert(p.handle);
964         sqlite3_trace(p.handle, &callback, p.traceCallback);
965     }
966 
967     /++
968     Registers a delegate of type `ProfileCallbackDelegate` as the profile callback.
969 
970     Any previously set profile callback is released.
971     Pass `null` to disable the callback.
972 
973     The string parameter that is passed to the callback is the SQL text of the statement being
974     executed. The time unit is defined in SQLite's documentation as nanoseconds (subject to change,
975     as the functionality is experimental).
976 
977     See_Also: $(LINK http://www.sqlite.org/c3ref/profile.html).
978     +/
979     void setProfileCallback(ProfileCallbackDelegate profileCallback)
980     {
981         extern(C) static nothrow
982         void callback(void* ptr, const(char)* str, sqlite3_uint64 time)
983         {
984             auto dlg = delegateUnwrap!ProfileCallbackDelegate(ptr).dlg;
985             dlg(str.to!string, time);
986         }
987 
988         ptrFree(p.profileCallback);
989         p.profileCallback = delegateWrap(profileCallback);
990         assert(p.handle);
991         sqlite3_profile(p.handle, &callback, p.profileCallback);
992     }
993 
994     version (_UnlockNotify)
995     {
996         /++
997         Registers a `IUnlockNotifyHandler` used to handle database locks.
998 
999         When running in shared-cache mode, a database operation may fail with an SQLITE_LOCKED error if
1000         the required locks on the shared-cache or individual tables within the shared-cache cannot be obtained.
1001         See SQLite Shared-Cache Mode for a description of shared-cache locking.
1002         This API may be used to register a callback that SQLite will invoke when the connection currently
1003         holding the required lock relinquishes it.
1004         This API can be used only if the SQLite library was compiled with the `SQLITE_ENABLE_UNLOCK_NOTIFY`
1005         C-preprocessor symbol defined.
1006 
1007         See_Also: $(LINK http://sqlite.org/c3ref/unlock_notify.html).
1008 
1009         Parameters:
1010             unlockNotifyHandler - custom handler used to control the unlocking mechanism
1011         +/
1012         void setUnlockNotifyHandler(IUnlockNotifyHandler unlockNotifyHandler)
1013         {
1014             p.unlockNotifyHandler = unlockNotifyHandler;
1015         }
1016 
1017         /// Setup and waits for unlock notify using the provided `IUnlockNotifyHandler`
1018         package (d2sqlite3) auto waitForUnlockNotify()
1019         {
1020             if (p.unlockNotifyHandler is null) return SQLITE_LOCKED;
1021 
1022             version (SqliteEnableUnlockNotify)
1023             {
1024                 extern(C) static nothrow
1025                 void callback(void** ntfPtr, int nPtr)
1026                 {
1027                     for (int i=0; i<nPtr; i++)
1028                     {
1029                         auto handler = cast(IUnlockNotifyHandler*)ntfPtr[i];
1030                         handler.emit(SQLITE_OK);
1031                     }
1032                 }
1033 
1034                 int rc = sqlite3_unlock_notify(p.handle, &callback, &p.unlockNotifyHandler);
1035                 assert(rc==SQLITE_LOCKED || rc==SQLITE_OK);
1036 
1037                 /+ The call to sqlite3_unlock_notify() always returns either SQLITE_LOCKED or SQLITE_OK.
1038 
1039                 If SQLITE_LOCKED was returned, then the system is deadlocked. In this case this function
1040                 needs to return SQLITE_LOCKED to the caller so that the current transaction can be rolled
1041                 back. Otherwise, block until the unlock-notify callback is invoked, then return SQLITE_OK.
1042                 +/
1043                 if(rc == SQLITE_OK)
1044                 {
1045                     p.unlockNotifyHandler.wait();
1046                     scope (exit) p.unlockNotifyHandler.reset();
1047                     return p.unlockNotifyHandler.result;
1048                 }
1049                 return rc;
1050             }
1051             else
1052             {
1053                 p.unlockNotifyHandler.waitOne();
1054                 auto res = p.unlockNotifyHandler.result;
1055                 if (res != SQLITE_OK) p.unlockNotifyHandler.reset();
1056                 return res;
1057             }
1058         }
1059     }
1060 }
1061 
1062 /// Delegate types
1063 alias UpdateHookDelegate = void delegate(int type, string dbName, string tableName, long rowid) nothrow;
1064 /// ditto
1065 alias CommitHookDelegate = int delegate() nothrow;
1066 /// ditto
1067 alias RoolbackHookDelegate = void delegate() nothrow;
1068 /// ditto
1069 alias ProgressHandlerDelegate = int delegate() nothrow;
1070 /// ditto
1071 alias TraceCallbackDelegate = void delegate(string sql) nothrow;
1072 /// ditto
1073 alias ProfileCallbackDelegate = void delegate(string sql, ulong time) nothrow;
1074 
1075 /// Information about a table column.
1076 struct TableColumnMetadata
1077 {
1078     string declaredTypeName; ///
1079     string collationSequenceName; ///
1080     bool isNotNull; ///
1081     bool isPrimaryKey; ///
1082     bool isAutoIncrement; ///
1083 }
1084 
1085 version (_UnlockNotify)
1086 {
1087     /++
1088     UnlockNotifyHandler interface to be used for custom implementations of UnlockNotify pattern with SQLite.
1089 
1090     Note:
1091     For the C API sqlite3_unlock_notify to be used, this library must be compiled with
1092     `-version=SqliteEnableUnlockNotify`.
1093     Otherwise only emulated solution is provided, that is based on retries for the defined amount of time.
1094 
1095     Implementation must be able to handle situation when emit is called sooner than the wait itself.
1096 
1097     See_Also: $(LINK http://sqlite.org/c3ref/unlock_notify.html).
1098     See_Also: $(LINK http://www.sqlite.org/unlock_notify.html).
1099     +/
1100     interface IUnlockNotifyHandler
1101     {
1102         version (SqliteEnableUnlockNotify)
1103         {
1104             /// Blocks until emit is called
1105             void wait();
1106 
1107             /++
1108             Unlocks the handler.
1109             This is called from registered callback from SQLite.
1110 
1111             Params:
1112                 state = Value to set as a handler result. It can be SQLITE_LOCKED or SQLITE_OK.
1113             +/
1114             void emit(int state) nothrow;
1115         }
1116         else
1117         {
1118             /++
1119             This is used as an alternative when SQLite is not compiled with SQLITE_ENABLE_UNLOCK_NOTIFY, and
1120             when the library is built with `-version=SqliteFakeUnlockNotify`.
1121             Using this, the handler tries to wait out the SQLITE_LOCKED state for some time.
1122             Implementation have to block for some amount of time and check if total amount is not greater than some constant afterwards.
1123             If there is still some time to try again, the handler must set the result to SQLITE_OK or to SQLITE_LOCKED otherwise.
1124             +/
1125             void waitOne();
1126         }
1127 
1128         /// Resets the handler for the next use
1129         void reset();
1130 
1131         /// Result after wait is finished
1132         @property int result() const;
1133     }
1134 
1135     version (SqliteEnableUnlockNotify)
1136     {
1137         /++
1138         UnlockNotifyHandler used when SQLite is compiled with SQLITE_ENABLE_UNLOCK_NOTIFY, and
1139         when the library is built with `-version=SqliteEnableUnlockNotify`.
1140         It is implemented using the standard `core.sync` package.
1141 
1142         Use setUnlockNotifyHandler method to handle the database lock.
1143 
1144         See_Also: $(LINK http://sqlite.org/c3ref/unlock_notify.html).
1145         See_Also: $(LINK http://www.sqlite.org/unlock_notify.html).
1146         +/
1147         final class UnlockNotifyHandler : IUnlockNotifyHandler
1148         {
1149             import core.sync.condition : Condition;
1150             import core.sync.mutex : Mutex;
1151 
1152             private
1153             {
1154                 __gshared Mutex mtx;
1155                 __gshared Condition cond;
1156                 __gshared int res;
1157                 __gshared bool fired;
1158             }
1159 
1160             /// Constructor
1161             this()
1162             {
1163                 mtx = new Mutex();
1164                 cond = new Condition(mtx);
1165             }
1166 
1167             /// Blocks until emit is called
1168             void wait()
1169             {
1170                 synchronized (mtx)
1171                 {
1172                     if (!fired) cond.wait();
1173                 }
1174             }
1175 
1176             /// Unlocks the handler, state is one of SQLITE_LOCKED or SQLITE_OK
1177             void emit(int res) nothrow
1178             in { assert(res == SQLITE_LOCKED || res == SQLITE_OK); }
1179             body
1180             {
1181                 try
1182                 {
1183                     synchronized (mtx)
1184                     {
1185                         this.res = res;
1186                         fired = true;
1187                         cond.notify();
1188                     }
1189                 }
1190                 catch (Exception) {}
1191             }
1192 
1193             /// Resets the handler for the next use
1194             void reset()
1195             {
1196                 res = SQLITE_LOCKED;
1197                 fired = false;
1198             }
1199 
1200             /// Result after wait is finished
1201             @property int result() const
1202             out (result) { assert(result == SQLITE_OK || result == SQLITE_LOCKED); }
1203             body { return res; }
1204         }
1205     }
1206     else
1207     {
1208         /++
1209         UnlockNotifyHandler that can be used when SQLite is not compiled with SQLITE_ENABLE_UNLOCK_NOTIFY,
1210         and when the library is built with `-version=SqliteFakeUnlockNotify`..
1211         It retries the statement execution for the provided amount of time before the SQLITE_LOCKED is returned.
1212 
1213         Use setUnlockNotifyHandler method to handle the database lock.
1214 
1215         See_Also: $(LINK http://sqlite.org/c3ref/unlock_notify.html).
1216         See_Also: $(LINK http://www.sqlite.org/unlock_notify.html).
1217         +/
1218         final class UnlockNotifyHandler : IUnlockNotifyHandler
1219         {
1220             import core.time : Duration, msecs;
1221             import std.datetime.stopwatch : StopWatch;
1222 
1223             private
1224             {
1225                 int res;
1226                 Duration maxDuration;
1227                 StopWatch sw;
1228             }
1229 
1230             /// Constructor
1231             this(Duration max = 1000.msecs)
1232             in { assert(max > Duration.zero); }
1233             body
1234             {
1235                 maxDuration = max;
1236             }
1237 
1238             /// Blocks for some time to retry the statement
1239             void waitOne()
1240             {
1241                 import core.thread : Thread;
1242                 import std.random : uniform;
1243 
1244                 if (!sw.running) sw.start;
1245 
1246                 Thread.sleep(uniform(50, 100).msecs);
1247 
1248                 if (sw.peek > maxDuration)
1249                 {
1250                     sw.stop;
1251                     res = SQLITE_LOCKED;
1252                 }
1253                 else res = SQLITE_OK;
1254             }
1255 
1256             /// Resets the handler for the next use
1257             void reset()
1258             {
1259                 res = SQLITE_LOCKED;
1260                 sw.reset();
1261             }
1262 
1263             /// Result after wait is finished
1264             @property int result() const
1265             out (result) { assert(result == SQLITE_OK || result == SQLITE_LOCKED); }
1266             body
1267             {
1268                 return res;
1269             }
1270         }
1271     }
1272 
1273     unittest
1274     {
1275         import core.time : Duration, msecs;
1276 
1277         /++
1278         Tests the unlock notify facility.
1279         Params:
1280             delay - time to wait in the transaction to block the other one
1281             expected - expected result (can be used to test timeout when fake unlock notify is used)
1282         +/
1283         void testUnlockNotify(Duration delay = 500.msecs, int expected = 3)
1284         {
1285             import core.thread : Thread;
1286             import core.time : msecs, seconds;
1287             import std.concurrency : spawn;
1288 
1289             static void test(int n, Duration delay)
1290             {
1291                 auto db = Database("file::memory:?cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI | SQLITE_OPEN_MEMORY);
1292                 db.setUnlockNotifyHandler = new UnlockNotifyHandler();
1293                 db.execute("BEGIN IMMEDIATE");
1294                 Thread.sleep(delay);
1295                 db.execute("INSERT INTO foo (bar) VALUES (?)", n);
1296                 db.commit();
1297             }
1298 
1299             auto db = Database("file::memory:?cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI | SQLITE_OPEN_MEMORY);
1300             db.execute(`CREATE TABLE foo (bar INTEGER);`);
1301 
1302             spawn(&test, 1, delay);
1303             Thread.sleep(100.msecs);
1304             spawn(&test, 2, delay);
1305             Thread.sleep(2*delay + 100.msecs);
1306             assert(db.execute("SELECT sum(bar) FROM foo").oneValue!int == expected, format!"%s != %s"(db.execute("SELECT sum(bar) FROM foo").oneValue!int, expected));
1307         }
1308 
1309         testUnlockNotify();
1310         version (SqliteFakeUnlockNotify) testUnlockNotify(1500.msecs, 1); //timeout test
1311     }
1312 }
1313 
1314 /++
1315 Exception thrown when SQLite functions return an error.
1316 +/
1317 class SqliteException : Exception
1318 {
1319     /++
1320     The _code of the error that raised the exception, or 0 if this _code is not known.
1321     +/
1322     int code;
1323 
1324     /++
1325     The SQL code that raised the exception, if applicable.
1326     +/
1327     string sql;
1328 
1329     private this(string msg, string sql, int code,
1330                  string file = __FILE__, size_t line = __LINE__, Throwable next = null)
1331     {
1332         this.sql = sql;
1333         this.code = code;
1334         super(msg, file, line, next);
1335     }
1336 
1337 package(d2sqlite3):
1338     this(string msg, int code, string sql = null,
1339          string file = __FILE__, size_t line = __LINE__, Throwable next = null)
1340     {
1341         this("error %d: %s".format(code, msg), sql, code, file, line, next);
1342     }
1343 
1344     this(string msg, string sql = null,
1345          string file = __FILE__, size_t line = __LINE__, Throwable next = null)
1346     {
1347         this(msg, sql, 0, file, line, next);
1348     }
1349 }