1 /+ 2 This module is part of d2sqlite3. 3 4 Authors: 5 Nicolas Sicard (biozic) and other contributors at $(LINK https://github.com/biozic/d2sqlite3) 6 7 Copyright: 8 Copyright 2011-18 Nicolas Sicard. 9 10 License: 11 $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 12 +/ 13 module d2sqlite3.internal.util; 14 15 import std.traits : isBoolean, isIntegral, isFloatingPoint, isSomeString, 16 isArray, isStaticArray, isDynamicArray; 17 import std.typecons : Nullable; 18 import d2sqlite3.sqlite3; 19 import d2sqlite3.internal.memory; 20 21 package(d2sqlite3): 22 23 string errmsg(sqlite3* db) nothrow { 24 import std.conv : to; 25 26 return sqlite3_errmsg(db).to!string; 27 } 28 29 string errmsg(sqlite3_stmt* stmt) nothrow { 30 return errmsg(sqlite3_db_handle(stmt)); 31 } 32 33 auto byStatement(string sql) { 34 static struct ByStatement { 35 string sql; 36 size_t end; 37 38 this(string sql) { 39 this.sql = sql; 40 end = findEnd(); 41 } 42 43 bool empty() const @safe pure nothrow @nogc { 44 return !sql.length; 45 } 46 47 string front() const @safe pure nothrow @nogc { 48 return sql[0 .. end]; 49 } 50 51 void popFront() { 52 sql = sql[end .. $]; 53 end = findEnd(); 54 } 55 56 private: 57 size_t findEnd() { 58 import std.algorithm : countUntil; 59 import std.string : toStringz; 60 import std.utf : byCodeUnit; 61 62 size_t pos; 63 bool complete; 64 do { 65 auto tail = sql[pos .. $]; 66 immutable offset = tail.byCodeUnit.countUntil(';') + 1; 67 pos += offset; 68 if (offset == 0) 69 pos = sql.length; 70 auto part = sql[0 .. pos]; 71 complete = cast(bool) sqlite3_complete(part.toStringz); 72 } 73 while (!complete && pos < sql.length); 74 return pos; 75 } 76 } 77 78 return ByStatement(sql); 79 } 80 81 unittest { 82 import std.algorithm : equal, map; 83 import std.string : strip; 84 85 auto sql = "CREATE TABLE test (dummy); 86 CREATE TRIGGER trig INSERT ON test BEGIN SELECT 1; SELECT 'a;b'; END; 87 SELECT 'c;d';; 88 CREATE"; 89 assert(equal(sql.byStatement.map!(s => s.strip), [ 90 "CREATE TABLE test (dummy);", 91 "CREATE TRIGGER trig INSERT ON test BEGIN SELECT 1; SELECT 'a;b'; END;", 92 "SELECT 'c;d';", ";", "CREATE" 93 ])); 94 } 95 96 // getValue and setResult function templates 97 // used by createFunction and createAggregate 98 99 auto getValue(T)(sqlite3_value* argv) if (isBoolean!T) { 100 return sqlite3_value_int64(argv) != 0; 101 } 102 103 auto getValue(T)(sqlite3_value* argv) if (isIntegral!T) { 104 import std.conv : to; 105 106 return sqlite3_value_int64(argv).to!T; 107 } 108 109 auto getValue(T)(sqlite3_value* argv) if (isFloatingPoint!T) { 110 import std.conv : to; 111 112 if (sqlite3_value_type(argv) == SQLITE_NULL) 113 return double.nan; 114 return sqlite3_value_double(argv).to!T; 115 } 116 117 auto getValue(T)(sqlite3_value* argv) if (isSomeString!T) { 118 import std.conv : to; 119 120 return (cast(const(char)*) sqlite3_value_text(argv)).to!T; 121 } 122 123 auto getValue(T)(sqlite3_value* argv) if (isArray!T && !isSomeString!T) { 124 import std.conv : to; 125 import core.stdc.string : memcpy; 126 127 auto n = sqlite3_value_bytes(argv); 128 ubyte[] blob; 129 blob.length = n; 130 memcpy(blob.ptr, sqlite3_value_blob(argv), n); 131 return cast(T) blob; 132 } 133 134 auto getValue(T : Nullable!U, U...)(sqlite3_value* argv) { 135 if (sqlite3_value_type(argv) == SQLITE_NULL) 136 return T.init; 137 return T(getValue!(U[0])(argv)); 138 } 139 140 void setResult(T)(sqlite3_context* context, T value) 141 if (isIntegral!T || isBoolean!T) { 142 import std.conv : to; 143 144 sqlite3_result_int64(context, value.to!long); 145 } 146 147 void setResult(T)(sqlite3_context* context, T value) if (isFloatingPoint!T) { 148 import std.conv : to; 149 150 sqlite3_result_double(context, value.to!double); 151 } 152 153 void setResult(T)(sqlite3_context* context, T value) if (isSomeString!T) { 154 import std.conv : to; 155 156 auto val = value.to!string; 157 sqlite3_result_text64(context, cast(const(char)*) anchorMem(cast(void*) val.ptr), 158 val.length, &releaseMem, SQLITE_UTF8); 159 } 160 161 void setResult(T)(sqlite3_context* context, T value) 162 if (isDynamicArray!T && !isSomeString!T) { 163 auto val = cast(void[]) value; 164 sqlite3_result_blob64(context, anchorMem(val.ptr), val.length, &releaseMem); 165 } 166 167 void setResult(T)(sqlite3_context* context, T value) if (isStaticArray!T) { 168 auto val = cast(void[]) value; 169 sqlite3_result_blob64(context, val.ptr, val.sizeof, SQLITE_TRANSIENT); 170 } 171 172 void setResult(T : Nullable!U, U...)(sqlite3_context* context, T value) { 173 if (value.isNull) 174 sqlite3_result_null(context); 175 else 176 setResult(context, value.get); 177 } 178 179 string nothrowFormat(Args...)(string fmt, Args args) nothrow { 180 import std.string : format; 181 182 try 183 return fmt.format(args); 184 catch (Exception e) 185 throw new Error("Error: " ~ e.msg); 186 }