|
1 |
|
2 #include "evsql.h" |
|
3 |
|
4 /* |
|
5 * Initialize params->types/values/lengths/formats, params->count, params->result_format based on the given args |
|
6 */ |
|
7 static int _evsql_query_params_init_pq (struct evsql_query_params_pq *params, size_t param_count, enum evsql_item_format result_format) { |
|
8 // set count |
|
9 params->count = param_count; |
|
10 |
|
11 // allocate vertical storage for the parameters |
|
12 if (0 |
|
13 |
|
14 || !(query->params.types = calloc(query->params.count, sizeof(Oid))) |
|
15 || !(query->params.values = calloc(query->params.count, sizeof(char *))) |
|
16 || !(query->params.lengths = calloc(query->params.count, sizeof(int))) |
|
17 || !(query->params.formats = calloc(query->params.count, sizeof(int))) |
|
18 ) |
|
19 ERROR("calloc"); |
|
20 |
|
21 // result format |
|
22 switch (result_format) { |
|
23 case EVSQL_FMT_TEXT: |
|
24 params.result_format = 0; break; |
|
25 |
|
26 case EVSQL_FMT_BINARY: |
|
27 params.result_format = 1; break; |
|
28 |
|
29 default: |
|
30 FATAL("params.result_fmt: %d", result_format); |
|
31 } |
|
32 |
|
33 // good |
|
34 return 0; |
|
35 |
|
36 error: |
|
37 return -1; |
|
38 } |
|
39 |
|
40 struct evsql_query *evsql_query (struct evsql *evsql, struct evsql_trans *trans, const char *command, evsql_query_cb query_fn, void *cb_arg) { |
|
41 struct evsql_query *query = NULL; |
|
42 |
|
43 // alloc new query |
|
44 if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) |
|
45 goto error; |
|
46 |
|
47 // just execute the command string directly |
|
48 if (_evsql_query_enqueue(evsql, trans, query, command)) |
|
49 goto error; |
|
50 |
|
51 // ok |
|
52 return query; |
|
53 |
|
54 error: |
|
55 _evsql_query_free(query); |
|
56 |
|
57 return NULL; |
|
58 } |
|
59 |
|
60 struct evsql_query *evsql_query_params (struct evsql *evsql, struct evsql_trans *trans, |
|
61 const char *command, const struct evsql_query_params *params, |
|
62 evsql_query_cb query_fn, void *cb_arg |
|
63 ) { |
|
64 struct evsql_query *query = NULL; |
|
65 const struct evsql_item *param; |
|
66 size_t count = 0, idx; |
|
67 |
|
68 // alloc new query |
|
69 if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) |
|
70 goto error; |
|
71 |
|
72 // count the params |
|
73 for (param = params->list; param->info.type; param++) |
|
74 count++; |
|
75 |
|
76 // initialize params |
|
77 evsql_query_params_init_pq(&query->params, count, params->result_format); |
|
78 |
|
79 // transform |
|
80 for (param = params->list, idx = 0; param->info.type; param++, idx++) { |
|
81 // `set for NULLs, otherwise not |
|
82 query->params.types[idx] = param->bytes ? 0 : EVSQL_PQ_ARBITRARY_TYPE_OID; |
|
83 |
|
84 // values |
|
85 query->params.values[idx] = param->bytes; |
|
86 |
|
87 // lengths |
|
88 query->params.lengths[idx] = param->length; |
|
89 |
|
90 // formats, binary if length is nonzero, but text for NULLs |
|
91 query->params.formats[idx] = param->length && param->bytes ? 1 : 0; |
|
92 } |
|
93 |
|
94 // execute it |
|
95 if (_evsql_query_enqueue(evsql, trans, query, command)) |
|
96 goto error; |
|
97 |
|
98 #ifdef DEBUG_ENABLED |
|
99 // debug it? |
|
100 DEBUG("evsql.%p: enqueued query=%p on trans=%p", evsql, query, trans); |
|
101 evsql_query_debug(command, params); |
|
102 #endif /* DEBUG_ENABLED */ |
|
103 |
|
104 // ok |
|
105 return query; |
|
106 |
|
107 error: |
|
108 _evsql_query_free(query); |
|
109 |
|
110 return NULL; |
|
111 } |
|
112 |
|
113 struct evsql_query *evsql_query_exec (struct evsql *evsql, struct evsql_trans *trans, |
|
114 const struct evsql_query_info *query_info, |
|
115 evsql_query_cb query_fn, void *cb_arg, |
|
116 ... |
|
117 ) { |
|
118 va_list vargs; |
|
119 struct evsql_query *query = NULL; |
|
120 const struct evsql_item_info *param; |
|
121 size_t count = 0, idx; |
|
122 err_t err = 1; |
|
123 |
|
124 // varargs |
|
125 va_start(vargs, cb_arg); |
|
126 |
|
127 // alloc new query |
|
128 if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) |
|
129 goto error; |
|
130 |
|
131 // count the params |
|
132 for (param = query_info->params; param->type; param++) |
|
133 count++; |
|
134 |
|
135 // initialize params |
|
136 evsql_query_params_init_pq(&query->params, count, EVSQL_FMT_BINARY); |
|
137 |
|
138 // transform |
|
139 for (param = params->params, idx = 0; param->info.type; param++, idx++) { |
|
140 // default type to 0 (implicit) |
|
141 query->params.types[idx] = 0; |
|
142 |
|
143 // default format to binary |
|
144 query->params.formats[idx] = EVSQL_FMT_BINARY; |
|
145 |
|
146 // consume argument |
|
147 switch (param->info.type) { |
|
148 case EVSQL_TYPE_NULL_: { |
|
149 // explicit type + text fmt |
|
150 query->params.types[idx] = EVSQL_PQ_ARBITRARY_TYPE_OID; |
|
151 query->params.values[idx] = NULL; |
|
152 query->params.lengths[idx] = 0; |
|
153 query->params.formats[idx] = EVSQL_FMT_TEXT; |
|
154 } break; |
|
155 |
|
156 case EVSQL_TYPE_BINARY: { |
|
157 struct evsql_item_binary item = va_arg(vargs, struct evsql_item_binary); |
|
158 |
|
159 // value + explicit len |
|
160 query->params.values[idx] = item->ptr; |
|
161 query->params.lengths[idx] = item->len; |
|
162 } break; |
|
163 |
|
164 case EVSQL_TYPE_STRING: { |
|
165 const char *str = va_arg(vargs, const char *); |
|
166 |
|
167 // value + automatic length, text format |
|
168 query->params.values[idx] = str; |
|
169 query->params.lengths[idx] = 0; |
|
170 query->params.formats[idx] = EVSQL_FMT_TEXT; |
|
171 } break; |
|
172 |
|
173 case EVSQL_TYPE_UINT16: { |
|
174 uint16_t uval = va_arg(vargs, uint16_t); |
|
175 |
|
176 if (uval != (int16_t) uval) |
|
177 ERROR("param $%zu: uint16 overflow: %d", idx + 1, uval); |
|
178 |
|
179 // network-byte-order value + explicit len |
|
180 query->params.values[idx] = htons(uval); |
|
181 query->params.lengths[idx] = sizeof(uint16_t); |
|
182 } break; |
|
183 |
|
184 case EVSQL_TYPE_UINT32: { |
|
185 uint32_t uval = va_arg(vargs, uint32_t); |
|
186 |
|
187 if (uval != (int32_t) uval) |
|
188 ERROR("param $%zu: uint32 overflow: %ld", idx + 1, uval); |
|
189 |
|
190 // network-byte-order value + explicit len |
|
191 query->params.values[idx] = htonl(uval); |
|
192 query->params.lengths[idx] = sizeof(uint32_t); |
|
193 } break; |
|
194 |
|
195 case EVSQL_TYPE_UINT64: { |
|
196 uint64_t uval = va_arg(vargs, uint64_t); |
|
197 |
|
198 if (uval != (int64_t) uval) |
|
199 ERROR("param $%zu: uint16 overflow: %lld", idx + 1, uval); |
|
200 |
|
201 // network-byte-order value + explicit len |
|
202 query->params.values[idx] = htonq(uval); |
|
203 query->params.lengths[idx] = sizeof(uint64_t); |
|
204 } break; |
|
205 |
|
206 default: |
|
207 FATAL("param $%zu: invalid type: %d", idx + 1, param->info.type); |
|
208 } |
|
209 } |
|
210 |
|
211 // execute it |
|
212 if (_evsql_query_enqueue(evsql, trans, query, command)) |
|
213 goto error; |
|
214 |
|
215 // no error, fallthrough for va_end |
|
216 err = 0; |
|
217 |
|
218 error: |
|
219 // possible cleanup |
|
220 if (err) |
|
221 _evsql_query_free(query); |
|
222 |
|
223 // end varargs |
|
224 va_end(vargs); |
|
225 |
|
226 // return |
|
227 return err ? NULL : query; |
|
228 } |
|
229 |
|
230 |
|
231 void evsql_query_abort (struct evsql_trans *trans, struct evsql_query *query) { |
|
232 assert(query); |
|
233 |
|
234 if (trans) { |
|
235 // must be the right query |
|
236 assert(trans->query == query); |
|
237 } |
|
238 |
|
239 // just strip the callback and wait for it to complete as normal |
|
240 query->cb_fn = NULL; |
|
241 } |
|
242 |