summaryrefslogtreecommitdiffhomepage
path: root/src/ext_depends_cgi/d2sqlite3/source/d2sqlite3/results.d
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext_depends_cgi/d2sqlite3/source/d2sqlite3/results.d')
-rw-r--r--src/ext_depends_cgi/d2sqlite3/source/d2sqlite3/results.d874
1 files changed, 0 insertions, 874 deletions
diff --git a/src/ext_depends_cgi/d2sqlite3/source/d2sqlite3/results.d b/src/ext_depends_cgi/d2sqlite3/source/d2sqlite3/results.d
deleted file mode 100644
index 5b1dadf..0000000
--- a/src/ext_depends_cgi/d2sqlite3/source/d2sqlite3/results.d
+++ /dev/null
@@ -1,874 +0,0 @@
-/++
-Managing query results.
-
-Authors:
- Nicolas Sicard (biozic) and other contributors at $(LINK https://github.com/biozic/d2sqlite3)
-
-Copyright:
- Copyright 2011-18 Nicolas Sicard.
-
-License:
- $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
-+/
-module d2sqlite3.results;
-
-import d2sqlite3.database;
-import d2sqlite3.statement;
-import d2sqlite3.sqlite3;
-import d2sqlite3.internal.util;
-
-import std.conv : to;
-import std.exception : enforce;
-import std.string : format;
-import std.typecons : Nullable;
-
-/// Set _UnlockNotify version if compiled with SqliteEnableUnlockNotify or SqliteFakeUnlockNotify
-version (SqliteEnableUnlockNotify) version = _UnlockNotify;
-else version (SqliteFakeUnlockNotify) version = _UnlockNotify;
-
-/++
-An input range interface to access the rows resulting from an SQL query.
-
-The elements of the range are `Row` structs. A `Row` is just a view of the current
-row when iterating the results of a `ResultRange`. It becomes invalid as soon as
-`ResultRange.popFront()` is called (it contains undefined data afterwards). Use
-`cached` to store the content of rows past the execution of the statement.
-
-Instances of this struct are typically returned by `Database.execute()` or
-`Statement.execute()`.
-+/
-struct ResultRange
-{
-private:
- Statement statement;
- int state = SQLITE_DONE;
- int colCount = 0;
- Row current;
-
-package(d2sqlite3):
- this(Statement statement)
- {
- if (!statement.empty)
- {
- version (_UnlockNotify) state = sqlite3_blocking_step(statement);
- else state = sqlite3_step(statement.handle);
- }
- else
- state = SQLITE_DONE;
-
- enforce(state == SQLITE_ROW || state == SQLITE_DONE,
- new SqliteException(errmsg(statement.handle), state));
-
- this.statement = statement;
- colCount = sqlite3_column_count(statement.handle);
- current = Row(statement, colCount);
- }
-
- version (_UnlockNotify)
- {
- auto sqlite3_blocking_step(Statement statement)
- {
- int rc;
- while(SQLITE_LOCKED == (rc = sqlite3_step(statement.handle)))
- {
- rc = statement.waitForUnlockNotify();
- if(rc != SQLITE_OK) break;
- sqlite3_reset(statement.handle);
- }
- return rc;
- }
- }
-
-public:
- /++
- Range interface.
- +/
- bool empty() @property
- {
- return state == SQLITE_DONE;
- }
-
- /// ditto
- ref Row front() return @property
- {
- assert(!empty, "no rows available");
- return current;
- }
-
- /// ditto
- void popFront()
- {
- assert(!empty, "no rows available");
- version (_UnlockNotify) state = sqlite3_blocking_step(statement);
- else state = sqlite3_step(statement.handle);
- current = Row(statement, colCount);
- enforce(state == SQLITE_DONE || state == SQLITE_ROW,
- new SqliteException(errmsg(statement.handle), state));
- }
-
- /++
- Gets only the first value of the first row returned by the execution of the statement.
- +/
- auto oneValue(T)()
- {
- return front.peek!T(0);
- }
- ///
- unittest
- {
- auto db = Database(":memory:");
- db.execute("CREATE TABLE test (val INTEGER)");
- auto count = db.execute("SELECT count(*) FROM test").oneValue!long;
- assert(count == 0);
- }
-}
-///
-unittest
-{
- auto db = Database(":memory:");
- db.run("CREATE TABLE test (i INTEGER);
- INSERT INTO test VALUES (1);
- INSERT INTO test VALUES (2);");
-
- auto results = db.execute("SELECT * FROM test");
- assert(!results.empty);
- assert(results.front.peek!long(0) == 1);
- results.popFront();
- assert(!results.empty);
- assert(results.front.peek!long(0) == 2);
- results.popFront();
- assert(results.empty);
-}
-
-/++
-A row returned when stepping over an SQLite prepared statement.
-
-The data of each column can be retrieved:
-$(UL
- $(LI using Row as a random-access range of ColumnData.)
- $(LI using the more direct peek functions.)
-)
-
-Warning:
- The data of the row is invalid when the next row is accessed (after a call to
- `ResultRange.popFront()`).
-+/
-struct Row
-{
- import std.traits : isBoolean, isIntegral, isSomeChar, isFloatingPoint, isSomeString, isArray;
- import std.traits : isInstanceOf, TemplateArgsOf;
-
-private:
- Statement statement;
- int frontIndex = 0;
- int backIndex = -1;
-
- this(Statement statement, int colCount) nothrow
- {
- this.statement = statement;
- backIndex = colCount - 1;
- }
-
-public:
- /// Range interface.
- bool empty() const @property nothrow
- {
- return length == 0;
- }
-
- /// ditto
- ColumnData front() @property
- {
- assertInitialized();
- return opIndex(0);
- }
-
- /// ditto
- void popFront() nothrow
- {
- assertInitialized();
- frontIndex++;
- }
-
- /// ditto
- Row save() @property
- {
- return this;
- }
-
- /// ditto
- ColumnData back() @property
- {
- assertInitialized();
- return opIndex(backIndex - frontIndex);
- }
-
- /// ditto
- void popBack() nothrow
- {
- assertInitialized();
- backIndex--;
- }
-
- /// ditto
- size_t length() const @property nothrow
- {
- return backIndex - frontIndex + 1;
- }
-
- /// ditto
- ColumnData opIndex(size_t index)
- {
- assertInitialized();
- auto i = internalIndex(index);
- auto type = sqlite3_column_type(statement.handle, i);
- final switch (type)
- {
- case SqliteType.INTEGER:
- return ColumnData(peek!long(index));
-
- case SqliteType.FLOAT:
- return ColumnData(peek!double(index));
-
- case SqliteType.TEXT:
- return ColumnData(peek!string(index));
-
- case SqliteType.BLOB:
- return ColumnData(peek!(Blob, PeekMode.copy)(index));
-
- case SqliteType.NULL:
- return ColumnData(null);
- }
- }
-
- /// Ditto
- ColumnData opIndex(string columnName)
- {
- return opIndex(indexForName(columnName));
- }
-
- /++
- Returns the data of a column directly.
-
- Contrary to `opIndex`, the `peek` functions return the data directly, automatically cast to T,
- without the overhead of using a wrapping type (`ColumnData`).
-
- When using `peek` to retrieve an array or a string, you can use either:
- $(UL
- $(LI `peek!(..., PeekMode.copy)(index)`,
- in which case the function returns a copy of the data that will outlive the step
- to the next row,
- or)
- $(LI `peek!(..., PeekMode.slice)(index)`,
- in which case a slice of SQLite's internal buffer is returned (see Warnings).)
- )
-
- Params:
- T = The type of the returned data. T must be a boolean, a built-in numeric type, a
- string, an array or a `Nullable`.
- $(TABLE
- $(TR
- $(TH Condition on T)
- $(TH Requested database type)
- )
- $(TR
- $(TD `isIntegral!T || isBoolean!T`)
- $(TD INTEGER)
- )
- $(TR
- $(TD `isFloatingPoint!T`)
- $(TD FLOAT)
- )
- $(TR
- $(TD `isSomeString!T`)
- $(TD TEXT)
- )
- $(TR
- $(TD `isArray!T`)
- $(TD BLOB)
- )
- $(TR
- $(TD `is(T == Nullable!U, U...)`)
- $(TD NULL or U)
- )
- )
-
- index = The index of the column in the prepared statement or
- the name of the column, as specified in the prepared statement
- with an AS clause. The index of the first column is 0.
-
- Returns:
- A value of type T. The returned value results from SQLite's own conversion rules:
- see $(LINK http://www.sqlite.org/c3ref/column_blob.html) and
- $(LINK http://www.sqlite.org/lang_expr.html#castexpr). It's then converted
- to T using `std.conv.to!T`.
-
- Warnings:
- When using `PeekMode.slice`, the data of the slice will be $(B invalidated)
- when the next row is accessed. A copy of the data has to be made somehow for it to
- outlive the next step on the same statement.
-
- When using referring to the column by name, the names of all the columns are
- tested each time this function is called: use
- numeric indexing for better performance.
- +/
- T peek(T)(size_t index)
- if (isBoolean!T || isIntegral!T || isSomeChar!T)
- {
- assertInitialized();
- return sqlite3_column_int64(statement.handle, internalIndex(index)).to!T;
- }
-
- /// ditto
- T peek(T)(size_t index)
- if (isFloatingPoint!T)
- {
- assertInitialized();
- return sqlite3_column_double(statement.handle, internalIndex(index)).to!T;
- }
-
- /// ditto
- T peek(T, PeekMode mode = PeekMode.copy)(size_t index)
- if (isSomeString!T)
- {
- import core.stdc.string : strlen, memcpy;
-
- assertInitialized();
- auto i = internalIndex(index);
- auto str = cast(const(char)*) sqlite3_column_text(statement.handle, i);
-
- if (str is null)
- return null;
-
- auto length = strlen(str);
- static if (mode == PeekMode.copy)
- {
- char[] text;
- text.length = length;
- memcpy(text.ptr, str, length);
- return text.to!T;
- }
- else static if (mode == PeekMode.slice)
- return cast(T) str[0..length];
- else
- static assert(false);
- }
-
- /// ditto
- T peek(T, PeekMode mode = PeekMode.copy)(size_t index)
- if (isArray!T && !isSomeString!T)
- {
- assertInitialized();
- auto i = internalIndex(index);
- auto ptr = sqlite3_column_blob(statement.handle, i);
- auto length = sqlite3_column_bytes(statement.handle, i);
- static if (mode == PeekMode.copy)
- {
- import core.stdc.string : memcpy;
- ubyte[] blob;
- blob.length = length;
- memcpy(blob.ptr, ptr, length);
- return cast(T) blob;
- }
- else static if (mode == PeekMode.slice)
- return cast(T) ptr[0..length];
- else
- static assert(false);
- }
-
- /// ditto
- T peek(T)(size_t index)
- if (isInstanceOf!(Nullable, T)
- && !isArray!(TemplateArgsOf!T[0]) && !isSomeString!(TemplateArgsOf!T[0]))
- {
- assertInitialized();
- alias U = TemplateArgsOf!T[0];
- if (sqlite3_column_type(statement.handle, internalIndex(index)) == SqliteType.NULL)
- return T.init;
- return T(peek!U(index));
- }
-
- /// ditto
- T peek(T, PeekMode mode = PeekMode.copy)(size_t index)
- if (isInstanceOf!(Nullable, T)
- && (isArray!(TemplateArgsOf!T[0]) || isSomeString!(TemplateArgsOf!T[0])))
- {
- assertInitialized();
- alias U = TemplateArgsOf!T[0];
- if (sqlite3_column_type(statement.handle, internalIndex(index)) == SqliteType.NULL)
- return T.init;
- return T(peek!(U, mode)(index));
- }
-
- /// ditto
- T peek(T)(string columnName)
- {
- return peek!T(indexForName(columnName));
- }
-
- /++
- Determines the type of the data in a particular column.
-
- `columnType` returns the type of the actual data in that column, whereas
- `columnDeclaredTypeName` returns the name of the type as declared in the SELECT statement.
-
- See_Also: $(LINK http://www.sqlite.org/c3ref/column_blob.html) and
- $(LINK http://www.sqlite.org/c3ref/column_decltype.html).
- +/
- SqliteType columnType(size_t index)
- {
- assertInitialized();
- return cast(SqliteType) sqlite3_column_type(statement.handle, internalIndex(index));
- }
- /// Ditto
- SqliteType columnType(string columnName)
- {
- return columnType(indexForName(columnName));
- }
- /// Ditto
- string columnDeclaredTypeName(size_t index)
- {
- assertInitialized();
- return sqlite3_column_decltype(statement.handle, internalIndex(index)).to!string;
- }
- /// Ditto
- string columnDeclaredTypeName(string columnName)
- {
- return columnDeclaredTypeName(indexForName(columnName));
- }
- ///
- unittest
- {
- auto db = Database(":memory:");
- db.run("CREATE TABLE items (name TEXT, price REAL);
- INSERT INTO items VALUES ('car', 20000);
- INSERT INTO items VALUES ('air', 'free');");
-
- auto results = db.execute("SELECT name, price FROM items");
-
- auto row = results.front;
- assert(row.columnType(0) == SqliteType.TEXT);
- assert(row.columnType("price") == SqliteType.FLOAT);
- assert(row.columnDeclaredTypeName(0) == "TEXT");
- assert(row.columnDeclaredTypeName("price") == "REAL");
-
- results.popFront();
- row = results.front;
- assert(row.columnType(0) == SqliteType.TEXT);
- assert(row.columnType("price") == SqliteType.TEXT);
- assert(row.columnDeclaredTypeName(0) == "TEXT");
- assert(row.columnDeclaredTypeName("price") == "REAL");
- }
-
- /++
- Determines the name of a particular column.
-
- See_Also: $(LINK http://www.sqlite.org/c3ref/column_name.html).
- +/
- string columnName(size_t index)
- {
- assertInitialized();
- return sqlite3_column_name(statement.handle, internalIndex(index)).to!string;
- }
- ///
- unittest
- {
- auto db = Database(":memory:");
- db.run("CREATE TABLE items (name TEXT, price REAL);
- INSERT INTO items VALUES ('car', 20000);");
-
- auto row = db.execute("SELECT name, price FROM items").front;
- assert(row.columnName(1) == "price");
- }
-
- version (SqliteEnableColumnMetadata)
- {
- /++
- Determines the name of the database, table, or column that is the origin of a
- particular result column in SELECT statement.
-
- Warning:
- These methods are defined only when this library is compiled with
- `-version=SqliteEnableColumnMetadata`, and SQLite compiled with the
- `SQLITE_ENABLE_COLUMN_METADATA` option defined.
-
- See_Also: $(LINK http://www.sqlite.org/c3ref/column_database_name.html).
- +/
- string columnDatabaseName(size_t index)
- {
- assertInitialized();
- return sqlite3_column_database_name(statement.handle, internalIndex(index)).to!string;
- }
- /// Ditto
- string columnDatabaseName(string columnName)
- {
- return columnDatabaseName(indexForName(columnName));
- }
- /// Ditto
- string columnTableName(size_t index)
- {
- assertInitialized();
- return sqlite3_column_database_name(statement.handle, internalIndex(index)).to!string;
- }
- /// Ditto
- string columnTableName(string columnName)
- {
- return columnTableName(indexForName(columnName));
- }
- /// Ditto
- string columnOriginName(size_t index)
- {
- assertInitialized();
- return sqlite3_column_origin_name(statement.handle, internalIndex(index)).to!string;
- }
- /// Ditto
- string columnOriginName(string columnName)
- {
- return columnOriginName(indexForName(columnName));
- }
- }
-
- /++
- Returns a struct with field members populated from the row's data.
-
- Neither the names of the fields nor the names of the columns are checked. The fields
- are filled with the columns' data in order. Thus, the order of the struct members must be the
- same as the order of the columns in the prepared statement.
-
- SQLite's conversion rules will be used. For instance, if a string field has the same rank
- as an INTEGER column, the field's data will be the string representation of the integer.
- +/
- T as(T)()
- if (is(T == struct))
- {
- import std.traits : FieldTypeTuple, FieldNameTuple;
-
- alias FieldTypes = FieldTypeTuple!T;
- T obj;
- foreach (i, fieldName; FieldNameTuple!T)
- __traits(getMember, obj, fieldName) = peek!(FieldTypes[i])(i);
- return obj;
- }
- ///
- unittest
- {
- struct Item
- {
- int _id;
- string name;
- }
-
- auto db = Database(":memory:");
- db.run("CREATE TABLE items (name TEXT);
- INSERT INTO items VALUES ('Light bulb')");
-
- auto results = db.execute("SELECT rowid AS id, name FROM items");
- auto row = results.front;
- auto thing = row.as!Item();
-
- assert(thing == Item(1, "Light bulb"));
- }
-
-private:
- int internalIndex(size_t index)
- {
- assertInitialized();
- auto i = index + frontIndex;
- assert(i >= 0 && i <= backIndex, "invalid column index: %d".format(i));
- assert(i <= int.max, "invalid index value: %d".format(i));
- return cast(int) i;
- }
-
- int indexForName(string name)
- {
- assertInitialized();
- assert(name.length, "column with no name");
- foreach (i; frontIndex .. backIndex + 1)
- {
- assert(i <= int.max, "invalid index value: %d".format(i));
- if (sqlite3_column_name(statement.handle, cast(int) i).to!string == name)
- return i;
- }
-
- assert(false, "invalid column name: '%s'".format(name));
- }
-
- void assertInitialized() nothrow
- {
- assert(!empty, "Accessing elements of an empty row");
- assert(statement.handle !is null, "operation on an empty statement");
- }
-}
-
-/// Behavior of the `Row.peek()` method for arrays/strings
-enum PeekMode
-{
- /++
- Return a copy of the data into a new array/string.
- The copy is safe to use after stepping to the next row.
- +/
- copy,
-
- /++
- Return a slice of the data.
- The slice can point to invalid data after stepping to the next row.
- +/
- slice
-}
-
-/++
-Some data retrieved from a column.
-+/
-struct ColumnData
-{
- import std.traits : isBoolean, isIntegral, isNumeric, isFloatingPoint,
- isSomeString, isArray;
- import std.variant : Algebraic, VariantException;
-
- alias SqliteVariant = Algebraic!(long, double, string, Blob, typeof(null));
-
- private
- {
- SqliteVariant _value;
- SqliteType _type;
- }
-
- /++
- Creates a new `ColumnData` from the value.
- +/
- this(T)(inout T value) inout
- if (isBoolean!T || isIntegral!T)
- {
- _value = SqliteVariant(value.to!long);
- _type = SqliteType.INTEGER;
- }
-
- /// ditto
- this(T)(T value)
- if (isFloatingPoint!T)
- {
- _value = SqliteVariant(value.to!double);
- _type = SqliteType.FLOAT;
- }
-
- /// ditto
- this(T)(T value)
- if (isSomeString!T)
- {
- if (value is null)
- {
- _value = SqliteVariant(null);
- _type = SqliteType.NULL;
- }
- else
- {
- _value = SqliteVariant(value.to!string);
- _type = SqliteType.TEXT;
- }
- }
-
- /// ditto
- this(T)(T value)
- if (isArray!T && !isSomeString!T)
- {
- if (value is null)
- {
- _value = SqliteVariant(null);
- _type = SqliteType.NULL;
- }
- else
- {
- _value = SqliteVariant(value.to!Blob);
- _type = SqliteType.BLOB;
- }
- }
- /// ditto
- this(T)(T value)
- if (is(T == typeof(null)))
- {
- _value = SqliteVariant(null);
- _type = SqliteType.NULL;
- }
-
- /++
- Returns the Sqlite type of the column.
- +/
- SqliteType type() const nothrow
- {
- assertInitialized();
- return _type;
- }
-
- /++
- Returns the data converted to T.
-
- If the data is NULL, defaultValue is returned.
-
- Throws:
- VariantException if the value cannot be converted
- to the desired type.
- +/
- auto as(T)(T defaultValue = T.init)
- if (isBoolean!T || isNumeric!T || isSomeString!T)
- {
- assertInitialized();
-
- if (_type == SqliteType.NULL)
- return defaultValue;
-
- return _value.coerce!T;
- }
-
- /// ditto
- auto as(T)(T defaultValue = T.init)
- if (isArray!T && !isSomeString!T)
- {
- assertInitialized();
-
- if (_type == SqliteType.NULL)
- return defaultValue;
-
- Blob data = _value.get!Blob;
- return cast(T) data;
- }
-
- /// ditto
- auto as(T : Nullable!U, U...)(T defaultValue = T.init)
- {
- assertInitialized();
-
- if (_type == SqliteType.NULL)
- return defaultValue;
-
- return T(as!U());
- }
-
- void toString(scope void delegate(const(char)[]) sink)
- {
- assertInitialized();
-
- if (_type == SqliteType.NULL)
- sink("null");
- else
- sink(_value.toString);
- }
-
-private:
- void assertInitialized() const nothrow
- {
- assert(_value.hasValue, "Accessing uninitialized ColumnData");
- }
-}
-
-/++
-Caches all the results of a query into memory at once.
-
-This allows to keep all the rows returned from a query accessible in any order
-and indefinitely.
-
-Returns:
- A `CachedResults` struct that allows to iterate on the rows and their
- columns with an array-like interface.
-
- The `CachedResults` struct is equivalent to an array of 'rows', which in
- turn can be viewed as either an array of `ColumnData` or as an associative
- array of `ColumnData` indexed by the column names.
-+/
-CachedResults cached(ResultRange results)
-{
- return CachedResults(results);
-}
-///
-unittest
-{
- auto db = Database(":memory:");
- db.run("CREATE TABLE test (msg TEXT, num FLOAT);
- INSERT INTO test (msg, num) VALUES ('ABC', 123);
- INSERT INTO test (msg, num) VALUES ('DEF', 456);");
-
- auto results = db.execute("SELECT * FROM test").cached;
- assert(results.length == 2);
- assert(results[0][0].as!string == "ABC");
- assert(results[0][1].as!int == 123);
- assert(results[1]["msg"].as!string == "DEF");
- assert(results[1]["num"].as!int == 456);
-}
-
-/++
-Stores all the results of a query.
-
-The `CachedResults` struct is equivalent to an array of 'rows', which in
-turn can be viewed as either an array of `ColumnData` or as an associative
-array of `ColumnData` indexed by the column names.
-
-Unlike `ResultRange`, `CachedResults` is a random-access range of rows, and its
-data always remain available.
-
-See_Also:
- `cached` for an example.
-+/
-struct CachedResults
-{
- import std.array : appender;
-
- // A row of retrieved data
- struct CachedRow
- {
- ColumnData[] columns;
- alias columns this;
-
- size_t[string] columnIndexes;
-
- private this(Row row, size_t[string] columnIndexes)
- {
- this.columnIndexes = columnIndexes;
-
- auto colapp = appender!(ColumnData[]);
- foreach (i; 0 .. row.length)
- colapp.put(row[i]);
- columns = colapp.data;
- }
-
- // Returns the data at the given index in the row.
- ColumnData opIndex(size_t index)
- {
- return columns[index];
- }
-
- // Returns the data at the given column.
- ColumnData opIndex(string name)
- {
- auto index = name in columnIndexes;
- assert(index, "unknown column name: %s".format(name));
- return columns[*index];
- }
- }
-
- // All the rows returned by the query.
- CachedRow[] rows;
- alias rows this;
-
- private size_t[string] columnIndexes;
-
- this(ResultRange results)
- {
- if (!results.empty)
- {
- auto first = results.front;
- foreach (i; 0 .. first.length)
- {
- assert(i <= int.max, "invalid column index value: %d".format(i));
- auto name = sqlite3_column_name(results.statement.handle, cast(int) i).to!string;
- columnIndexes[name] = i;
- }
- }
-
- auto rowapp = appender!(CachedRow[]);
- while (!results.empty)
- {
- rowapp.put(CachedRow(results.front, columnIndexes));
- results.popFront();
- }
- rows = rowapp.data;
- }
-}