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