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