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-17 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 { 25 import std.conv : to; 26 return sqlite3_errmsg(db).to!string; 27 } 28 29 string errmsg(sqlite3_stmt* stmt) 30 { 31 return errmsg(sqlite3_db_handle(stmt)); 32 } 33 34 auto byStatement(string sql) 35 { 36 static struct ByStatement 37 { 38 string sql; 39 size_t end; 40 41 this(string sql) 42 { 43 this.sql = sql; 44 end = findEnd(); 45 } 46 47 bool empty() 48 { 49 return !sql.length; 50 } 51 52 string front() 53 { 54 return sql[0 .. end]; 55 } 56 57 void popFront() 58 { 59 sql = sql[end .. $]; 60 end = findEnd(); 61 } 62 63 private: 64 size_t findEnd() 65 { 66 import std.algorithm : countUntil; 67 import std..string : toStringz; 68 import std.utf : byCodeUnit; 69 70 size_t pos; 71 bool complete; 72 do 73 { 74 auto tail = sql[pos .. $]; 75 immutable offset = tail.byCodeUnit.countUntil(';') + 1; 76 pos += offset; 77 if (offset == 0) 78 pos = sql.length; 79 auto part = sql[0 .. pos]; 80 complete = cast(bool) sqlite3_complete(part.toStringz); 81 } 82 while (!complete && pos < sql.length); 83 return pos; 84 } 85 } 86 87 return ByStatement(sql); 88 } 89 unittest 90 { 91 import std.algorithm : equal, map; 92 import std..string : strip; 93 94 auto sql = "CREATE TABLE test (dummy); 95 CREATE TRIGGER trig INSERT ON test BEGIN SELECT 1; SELECT 'a;b'; END; 96 SELECT 'c;d';; 97 CREATE"; 98 assert(equal(sql.byStatement.map!(s => s.strip), [ 99 "CREATE TABLE test (dummy);", 100 "CREATE TRIGGER trig INSERT ON test BEGIN SELECT 1; SELECT 'a;b'; END;", 101 "SELECT 'c;d';", 102 ";", 103 "CREATE" 104 ])); 105 } 106 107 // getValue and setResult function templates 108 // used by createFunction and createAggregate 109 110 auto getValue(T)(sqlite3_value* argv) 111 if (isBoolean!T) 112 { 113 return sqlite3_value_int64(argv) != 0; 114 } 115 116 auto getValue(T)(sqlite3_value* argv) 117 if (isIntegral!T) 118 { 119 import std.conv : to; 120 return sqlite3_value_int64(argv).to!T; 121 } 122 123 auto getValue(T)(sqlite3_value* argv) 124 if (isFloatingPoint!T) 125 { 126 import std.conv : to; 127 if (sqlite3_value_type(argv) == SQLITE_NULL) 128 return double.nan; 129 return sqlite3_value_double(argv).to!T; 130 } 131 132 auto getValue(T)(sqlite3_value* argv) 133 if (isSomeString!T) 134 { 135 import std.conv : to; 136 return (cast(const(char)*) sqlite3_value_text(argv)).to!T; 137 } 138 139 auto getValue(T)(sqlite3_value* argv) 140 if (isArray!T && !isSomeString!T) 141 { 142 import std.conv : to; 143 import core.stdc..string : memcpy; 144 145 auto n = sqlite3_value_bytes(argv); 146 ubyte[] blob; 147 blob.length = n; 148 memcpy(blob.ptr, sqlite3_value_blob(argv), n); 149 return cast(T) blob; 150 } 151 152 auto getValue(T : Nullable!U, U...)(sqlite3_value* argv) 153 { 154 if (sqlite3_value_type(argv) == SQLITE_NULL) 155 return T.init; 156 return T(getValue!(U[0])(argv)); 157 } 158 159 void setResult(T)(sqlite3_context* context, T value) 160 if (isIntegral!T || isBoolean!T) 161 { 162 import std.conv : to; 163 sqlite3_result_int64(context, value.to!long); 164 } 165 166 void setResult(T)(sqlite3_context* context, T value) 167 if (isFloatingPoint!T) 168 { 169 import std.conv : to; 170 sqlite3_result_double(context, value.to!double); 171 } 172 173 void setResult(T)(sqlite3_context* context, T value) 174 if (isSomeString!T) 175 { 176 import std.conv : to; 177 auto val = value.to!string; 178 sqlite3_result_text64(context, cast(const(char)*) anchorMem(cast(void*) val.ptr), 179 val.length, &releaseMem, SQLITE_UTF8); 180 } 181 182 void setResult(T)(sqlite3_context* context, T value) 183 if (isDynamicArray!T && !isSomeString!T) 184 { 185 auto val = cast(void[]) value; 186 sqlite3_result_blob64(context, anchorMem(val.ptr), val.length, &releaseMem); 187 } 188 189 void setResult(T)(sqlite3_context* context, T value) 190 if (isStaticArray!T) 191 { 192 auto val = cast(void[]) value; 193 sqlite3_result_blob64(context, val.ptr, val.sizeof, SQLITE_TRANSIENT); 194 } 195 196 void setResult(T : Nullable!U, U...)(sqlite3_context* context, T value) 197 { 198 if (value.isNull) 199 sqlite3_result_null(context); 200 else 201 setResult(context, value.get); 202 } 203 204 string nothrowFormat(Args...)(string fmt, Args args) nothrow 205 { 206 import std..string : format; 207 try 208 return fmt.format(args); 209 catch (Exception e) 210 throw new Error("Error: " ~ e.msg); 211 }