1 /// Dealing with query arguments 2 module dpq2.args; 3 4 @safe: 5 6 public import dpq2.conv.from_d_types; 7 public import dpq2.conv.from_bson; 8 9 import dpq2.value; 10 import dpq2.oids: Oid; 11 import std.conv: to; 12 import std.string: toStringz; 13 14 /// Query parameters 15 struct QueryParams 16 { 17 string sqlCommand; /// SQL command 18 ValueFormat resultFormat = ValueFormat.BINARY; /// Result value format 19 private Value[] _args; // SQL command arguments 20 21 /// SQL command arguments 22 @property void args(Value[] vargs) 23 { 24 _args = vargs; 25 } 26 27 /// ditto 28 @property ref inout (Value[]) args() inout pure 29 { 30 return _args; 31 } 32 33 /// Fills out arguments from array 34 /// 35 /// Useful for simple text-only query params 36 /// Postgres infers a data type for the parameter in the same way it would do for an untyped literal string. 37 @property void argsFromArray(in string[] arr) 38 { 39 _args.length = arr.length; 40 41 foreach(i, ref a; _args) 42 a = toValue(arr[i], ValueFormat.TEXT); 43 } 44 45 /// Fills out arguments from variadic arguments 46 void argsVariadic(Targs ...)(Targs t_args) 47 { 48 _args.length = t_args.length; 49 50 static foreach(i, T; Targs) 51 { 52 _args[i] = toValue!T(t_args[i]); 53 } 54 } 55 56 /// Access to prepared statement name 57 /// 58 /// Use it to prepare queries 59 // FIXME: it is need to check in debug mode what sqlCommand is used in "SQL command" or "prepared statement" mode 60 @property string preparedStatementName() const { return sqlCommand; } 61 /// ditto 62 @property void preparedStatementName(string s){ sqlCommand = s; } 63 } 64 65 unittest 66 { 67 QueryParams qp; 68 qp.argsVariadic(123, "asd", true); 69 70 assert(qp.args[0] == 123.toValue); 71 assert(qp.args[1] == "asd".toValue); 72 assert(qp.args[2] == true.toValue); 73 } 74 75 /// Used as parameters by PQexecParams-like functions 76 package struct InternalQueryParams 77 { 78 private 79 { 80 const(string)* sqlCommand; 81 Oid[] oids; 82 int[] formats; 83 int[] lengths; 84 const(ubyte)*[] values; 85 } 86 87 ValueFormat resultFormat; 88 89 this(in QueryParams* qp) pure 90 { 91 sqlCommand = &qp.sqlCommand; 92 resultFormat = qp.resultFormat; 93 94 oids = new Oid[qp.args.length]; 95 formats = new int[qp.args.length]; 96 lengths = new int[qp.args.length]; 97 values = new const(ubyte)* [qp.args.length]; 98 99 for(int i = 0; i < qp.args.length; ++i) 100 { 101 oids[i] = qp.args[i].oidType; 102 formats[i] = qp.args[i].format; 103 104 if(!qp.args[i].isNull) 105 { 106 lengths[i] = qp.args[i].data.length.to!int; 107 108 immutable ubyte[] zeroLengthArg = [123]; // fake value, isn't used as argument 109 110 if(qp.args[i].data.length == 0) 111 values[i] = &zeroLengthArg[0]; 112 else 113 values[i] = &qp.args[i].data[0]; 114 } 115 } 116 } 117 118 /// Values used by PQexecParams-like functions 119 const(char)* command() pure const 120 { 121 return cast(const(char)*) (*sqlCommand).toStringz; 122 } 123 124 /// ditto 125 const(char)* stmtName() pure const 126 { 127 return command(); 128 } 129 130 /// ditto 131 int nParams() pure const 132 { 133 return values.length.to!int; 134 } 135 136 /// ditto 137 const(Oid)* paramTypes() pure 138 { 139 if(oids.length == 0) 140 return null; 141 else 142 return &oids[0]; 143 } 144 145 /// ditto 146 const(ubyte*)* paramValues() pure 147 { 148 if(values.length == 0) 149 return null; 150 else 151 return &values[0]; 152 } 153 154 /// ditto 155 const(int)* paramLengths() pure 156 { 157 if(lengths.length == 0) 158 return null; 159 else 160 return &lengths[0]; 161 } 162 163 /// ditto 164 const(int)* paramFormats() pure 165 { 166 if(formats.length == 0) 167 return null; 168 else 169 return &formats[0]; 170 } 171 }