1 /++ 2 D2SQLite3 provides a thin and convenient wrapper around the SQLite C API. 3 4 Features: 5 $(UL 6 $(LI Use reference-counted structs (`Database`, `Statement`) instead of SQLite objects 7 pointers.) 8 $(LI Run multistatement SQL code with `Database.run()`.) 9 $(LI Use built-in integral types, floating point types, `string`, `immutable(ubyte)[]` and 10 `Nullable` types directly: conversions to and from SQLite types is automatic and GC-safe.) 11 $(LI Bind multiple values to a prepare statement with `Statement.bindAll()` or 12 `Statement.inject()`. It's also possible to bind the fields of a struct automatically with 13 `Statement.inject()`.) 14 $(LI Handle the results of a query as a range of `Row`s, and the columns of a row 15 as a range of `ColumnData` (equivalent of a `Variant` fit for SQLite types).) 16 $(LI Access the data in a result row directly, by index or by name, 17 with the `Row.peek!T()` methods.) 18 $(LI Make a struct out of the data of a row with `Row.as!T()`.) 19 $(LI Register D functions as SQLite callbacks, with `Database.setUpdateHook()` $(I et al).) 20 $(LI Create new SQLite functions, aggregates or collations out of D functions or delegate, 21 with automatic type converions, with `Database.createFunction()` $(I et al).) 22 $(LI Store all the rows and columns resulting from a query at once with the `cached` function 23 (sometimes useful even if not memory-friendly...).) 24 $(LI Use an unlock notification when two or more connections access the same database in 25 shared-cache mode, either using SQLite's dedicated API (sqlite_unlock_notify) or using an 26 emulated equivalent.) 27 ) 28 29 Modules: 30 $(UL 31 $(LI `d2sqlite3.database`: database connections and library global data.) 32 $(LI `d2sqlite3.statement`: prepared statements creation and parameter binding.) 33 $(LI `d2sqlite3.results`: query results.) 34 $(LI `d2sqlite3.sqlite3`: autogenerated C API bindings.) 35 ) 36 37 Authors: 38 Nicolas Sicard (biozic) and other contributors at $(LINK https://github.com/biozic/d2sqlite3) 39 40 Copyright: 41 Copyright 2011-17 Nicolas Sicard. 42 43 License: 44 $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 45 +/ 46 module d2sqlite3; 47 48 public import d2sqlite3.database; 49 public import d2sqlite3.statement; 50 public import d2sqlite3.results; 51 public import d2sqlite3.sqlite3; 52 53 import std.exception : enforce; 54 import std..string : format; 55 56 /// 57 unittest // Documentation example 58 { 59 // Note: exception handling is left aside for clarity. 60 import d2sqlite3; 61 import std.typecons : Nullable; 62 63 // Open a database in memory. 64 auto db = Database(":memory:"); 65 66 // Create a table 67 db.run("DROP TABLE IF EXISTS person; 68 CREATE TABLE person ( 69 id INTEGER PRIMARY KEY, 70 name TEXT NOT NULL, 71 score FLOAT 72 )"); 73 74 // Prepare an INSERT statement 75 Statement statement = db.prepare( 76 "INSERT INTO person (name, score) 77 VALUES (:name, :score)" 78 ); 79 80 // Bind values one by one (by parameter name or index) 81 statement.bind(":name", "John"); 82 statement.bind(2, 77.5); 83 statement.execute(); 84 statement.reset(); // Need to reset the statement after execution. 85 86 // Bind muliple values at the same time 87 statement.bindAll("John", null); 88 statement.execute(); 89 statement.reset(); 90 91 // Bind, execute and reset in one call 92 statement.inject("Clara", 88.1); 93 94 // Count the changes 95 assert(db.totalChanges == 3); 96 97 // Count the Johns in the table. 98 auto count = db.execute("SELECT count(*) FROM person WHERE name == 'John'") 99 .oneValue!long; 100 assert(count == 2); 101 102 // Read the data from the table lazily 103 ResultRange results = db.execute("SELECT * FROM person"); 104 foreach (Row row; results) 105 { 106 // Retrieve "id", which is the column at index 0, and contains an int, 107 // e.g. using the peek function (best performance). 108 auto id = row.peek!long(0); 109 110 // Retrieve "name", e.g. using opIndex(string), which returns a ColumnData. 111 auto name = row["name"].as!string; 112 113 // Retrieve "score", which is at index 2, e.g. using the peek function, 114 // using a Nullable type 115 auto score = row.peek!(Nullable!double)(2); 116 if (!score.isNull) 117 { 118 // ... 119 } 120 } 121 } 122 123 /++ 124 Gets the library's version string (e.g. "3.8.7"), version number (e.g. 3_008_007) 125 or source ID. 126 127 These values are returned by the linked SQLite C library. They can be checked against 128 the values of the enums defined by the `d2sqlite3` package (`SQLITE_VERSION`, 129 `SQLITE_VERSION_NUMBER` and `SQLITE_SOURCE_ID`). 130 131 See_Also: $(LINK http://www.sqlite.org/c3ref/libversion.html). 132 +/ 133 string versionString() 134 { 135 import std.conv : to; 136 return sqlite3_libversion().to!string; 137 } 138 139 /// Ditto 140 int versionNumber() nothrow 141 { 142 return sqlite3_libversion_number(); 143 } 144 145 /// Ditto 146 string sourceID() 147 { 148 import std.conv : to; 149 return sqlite3_sourceid().to!string; 150 } 151 152 /++ 153 Tells whether SQLite was compiled with the thread-safe options. 154 155 See_also: $(LINK http://www.sqlite.org/c3ref/threadsafe.html). 156 +/ 157 bool threadSafe() nothrow 158 { 159 return cast(bool) sqlite3_threadsafe(); 160 } 161 162 /++ 163 Manually initializes (or shuts down) SQLite. 164 165 SQLite initializes itself automatically on the first request execution, so this 166 usually wouldn't be called. Use for instance before a call to config(). 167 +/ 168 void initialize() 169 { 170 auto result = sqlite3_initialize(); 171 enforce(result == SQLITE_OK, new SqliteException("Initialization: error %s".format(result))); 172 } 173 /// Ditto 174 void shutdown() 175 { 176 auto result = sqlite3_shutdown(); 177 enforce(result == SQLITE_OK, new SqliteException("Shutdown: error %s".format(result))); 178 } 179 180 /++ 181 Sets a configuration option. 182 183 Use before initialization, e.g. before the first 184 call to initialize and before execution of the first statement. 185 186 See_Also: $(LINK http://www.sqlite.org/c3ref/config.html). 187 +/ 188 void config(Args...)(int code, Args args) 189 { 190 auto result = sqlite3_config(code, args); 191 enforce(result == SQLITE_OK, new SqliteException("Configuration: error %s".format(result))); 192 } 193 194 /++ 195 Tests if an SQLite compile option is set 196 197 See_Also: $(LINK http://sqlite.org/c3ref/compileoption_get.html). 198 +/ 199 bool isCompiledWith(string option) 200 { 201 import std..string : toStringz; 202 return cast(bool) sqlite3_compileoption_used(option.toStringz); 203 } 204 /// 205 version (SqliteEnableUnlockNotify) 206 unittest 207 { 208 assert(isCompiledWith("SQLITE_ENABLE_UNLOCK_NOTIFY")); 209 assert(!isCompiledWith("SQLITE_UNKNOWN_COMPILE_OPTION")); 210 }