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) { 24 import std.conv : to; 25 26 return sqlite3_errmsg(db).to!string; 27 } 28 29 string errmsg(sqlite3_stmt* stmt) { 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() { 44 return !sql.length; 45 } 46 47 string front() { 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), ["CREATE TABLE test (dummy);", 90 "CREATE TRIGGER trig INSERT ON test BEGIN SELECT 1; SELECT 'a;b'; END;", 91 "SELECT 'c;d';", ";", "CREATE"])); 92 } 93 94 // getValue and setResult function templates 95 // used by createFunction and createAggregate 96 97 auto getValue(T)(sqlite3_value* argv) if (isBoolean!T) { 98 return sqlite3_value_int64(argv) != 0; 99 } 100 101 auto getValue(T)(sqlite3_value* argv) if (isIntegral!T) { 102 import std.conv : to; 103 104 return sqlite3_value_int64(argv).to!T; 105 } 106 107 auto getValue(T)(sqlite3_value* argv) if (isFloatingPoint!T) { 108 import std.conv : to; 109 110 if (sqlite3_value_type(argv) == SQLITE_NULL) 111 return double.nan; 112 return sqlite3_value_double(argv).to!T; 113 } 114 115 auto getValue(T)(sqlite3_value* argv) if (isSomeString!T) { 116 import std.conv : to; 117 118 return (cast(const(char)*) sqlite3_value_text(argv)).to!T; 119 } 120 121 auto getValue(T)(sqlite3_value* argv) if (isArray!T && !isSomeString!T) { 122 import std.conv : to; 123 import core.stdc.string : memcpy; 124 125 auto n = sqlite3_value_bytes(argv); 126 ubyte[] blob; 127 blob.length = n; 128 memcpy(blob.ptr, sqlite3_value_blob(argv), n); 129 return cast(T) blob; 130 } 131 132 auto getValue(T : Nullable!U, U...)(sqlite3_value* argv) { 133 if (sqlite3_value_type(argv) == SQLITE_NULL) 134 return T.init; 135 return T(getValue!(U[0])(argv)); 136 } 137 138 void setResult(T)(sqlite3_context* context, T value) 139 if (isIntegral!T || isBoolean!T) { 140 import std.conv : to; 141 142 sqlite3_result_int64(context, value.to!long); 143 } 144 145 void setResult(T)(sqlite3_context* context, T value) if (isFloatingPoint!T) { 146 import std.conv : to; 147 148 sqlite3_result_double(context, value.to!double); 149 } 150 151 void setResult(T)(sqlite3_context* context, T value) if (isSomeString!T) { 152 import std.conv : to; 153 154 auto val = value.to!string; 155 sqlite3_result_text64(context, cast(const(char)*) anchorMem(cast(void*) val.ptr), 156 val.length, &releaseMem, SQLITE_UTF8); 157 } 158 159 void setResult(T)(sqlite3_context* context, T value) 160 if (isDynamicArray!T && !isSomeString!T) { 161 auto val = cast(void[]) value; 162 sqlite3_result_blob64(context, anchorMem(val.ptr), val.length, &releaseMem); 163 } 164 165 void setResult(T)(sqlite3_context* context, T value) if (isStaticArray!T) { 166 auto val = cast(void[]) value; 167 sqlite3_result_blob64(context, val.ptr, val.sizeof, SQLITE_TRANSIENT); 168 } 169 170 void setResult(T : Nullable!U, U...)(sqlite3_context* context, T value) { 171 if (value.isNull) 172 sqlite3_result_null(context); 173 else 174 setResult(context, value.get); 175 } 176 177 string nothrowFormat(Args...)(string fmt, Args args) nothrow { 178 import std.string : format; 179 180 try 181 return fmt.format(args); 182 catch (Exception e) 183 throw new Error("Error: " ~ e.msg); 184 }