58.2.1
by Andrew Hutchings
Initial prepared statement support |
1 |
/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
2 |
*
|
|
3 |
* Drizzle Client & Protocol Library
|
|
4 |
*
|
|
5 |
* Copyright (C) 2012 Andrew Hutchings (andrew@linuxjedi.co.uk)
|
|
6 |
* All rights reserved.
|
|
7 |
*
|
|
8 |
* Redistribution and use in source and binary forms, with or without
|
|
9 |
* modification, are permitted provided that the following conditions are
|
|
10 |
* met:
|
|
11 |
*
|
|
12 |
* * Redistributions of source code must retain the above copyright
|
|
13 |
* notice, this list of conditions and the following disclaimer.
|
|
14 |
*
|
|
15 |
* * Redistributions in binary form must reproduce the above
|
|
16 |
* copyright notice, this list of conditions and the following disclaimer
|
|
17 |
* in the documentation and/or other materials provided with the
|
|
18 |
* distribution.
|
|
19 |
*
|
|
20 |
* * The names of its contributors may not be used to endorse or
|
|
21 |
* promote products derived from this software without specific prior
|
|
22 |
* written permission.
|
|
23 |
*
|
|
24 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
25 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
26 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
27 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
28 |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
29 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
30 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
31 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
32 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
33 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
34 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35 |
*
|
|
36 |
*/
|
|
37 |
||
38 |
#include "config.h" |
|
39 |
#include "libdrizzle/common.h" |
|
40 |
||
41 |
drizzle_stmt_st *drizzle_stmt_prepare(drizzle_st *con, const char *statement, size_t size, drizzle_return_t *ret_ptr) |
|
42 |
{
|
|
43 |
drizzle_stmt_st *stmt= (drizzle_stmt_st*)malloc(sizeof(drizzle_stmt_st)); |
|
44 |
if (stmt == NULL) |
|
45 |
{
|
|
46 |
*ret_ptr= DRIZZLE_RETURN_MEMORY; |
|
47 |
drizzle_set_error(con, __func__, "malloc"); |
|
48 |
return NULL; |
|
49 |
}
|
|
50 |
stmt->execute_result= NULL; |
|
51 |
stmt->param_count= 0; |
|
52 |
stmt->id= 0; |
|
53 |
stmt->query_params= NULL; |
|
54 |
stmt->result_params= NULL; |
|
55 |
stmt->null_bitmap_length= 0; |
|
56 |
stmt->null_bitmap= NULL; |
|
57 |
stmt->new_bind= true; |
|
58 |
con->stmt= stmt; |
|
59 |
stmt->con= con; |
|
60 |
||
61 |
stmt->prepare_result= drizzle_command_write(con, NULL, DRIZZLE_COMMAND_STMT_PREPARE, |
|
62 |
statement, size, size, ret_ptr); |
|
63 |
if (*ret_ptr != DRIZZLE_RETURN_OK) |
|
64 |
{
|
|
65 |
free(stmt); |
|
66 |
con->stmt= NULL; |
|
67 |
return NULL; |
|
68 |
}
|
|
69 |
||
70 |
/* Don't get the unused parameter packets. Format is the same as column
|
|
71 |
* packets. Deliberate off-by-one for the EOF packet */
|
|
72 |
if (stmt->param_count) |
|
73 |
{
|
|
74 |
uint16_t param_num; |
|
75 |
for (param_num= 0; param_num <= stmt->param_count; param_num++) |
|
76 |
{
|
|
77 |
*ret_ptr= drizzle_column_skip(stmt->prepare_result); |
|
78 |
if ((*ret_ptr != DRIZZLE_RETURN_OK) && (*ret_ptr != DRIZZLE_RETURN_EOF)) |
|
79 |
{
|
|
80 |
free(stmt); |
|
81 |
return NULL; |
|
82 |
}
|
|
83 |
}
|
|
84 |
}
|
|
85 |
||
86 |
/* Reset column counter which is incremented when skipping parameter packets
|
|
87 |
* and then buffer the columns */
|
|
88 |
||
89 |
stmt->prepare_result->column_current= 0; |
|
90 |
drizzle_column_buffer(stmt->prepare_result); |
|
91 |
||
92 |
/* Parameter count can then be used to figure out the length of the null
|
|
93 |
* bitmap mask */
|
|
94 |
||
95 |
stmt->null_bitmap_length= (stmt->param_count + 7) / 8; |
|
96 |
stmt->null_bitmap= (uint8_t*)calloc(stmt->null_bitmap_length, 1); |
|
97 |
if (stmt->null_bitmap == NULL) |
|
98 |
{
|
|
99 |
free(stmt); |
|
100 |
*ret_ptr= DRIZZLE_RETURN_MEMORY; |
|
101 |
drizzle_set_error(con, __func__, "malloc"); |
|
102 |
return NULL; |
|
103 |
}
|
|
104 |
||
105 |
/* Also use the parameter count to allocate the parameters */
|
|
106 |
stmt->query_params= (drizzle_bind_st*)calloc(stmt->param_count, sizeof(drizzle_bind_st)); |
|
107 |
stmt->state= DRIZZLE_STMT_PREPARED; |
|
108 |
stmt->fields= stmt->prepare_result->column_buffer; |
|
109 |
||
110 |
return stmt; |
|
111 |
}
|
|
112 |
||
113 |
drizzle_return_t drizzle_stmt_bind_param(drizzle_stmt_st *stmt, uint16_t param_num, drizzle_column_type_t type, void *data, uint32_t length, drizzle_bind_options_t options) |
|
114 |
{
|
|
115 |
if ((stmt == NULL) || (param_num >= stmt->param_count) || (data == NULL)) |
|
116 |
{
|
|
117 |
return DRIZZLE_RETURN_INVALID_ARGUMENT; |
|
118 |
}
|
|
119 |
if (stmt->state < DRIZZLE_STMT_PREPARED) |
|
120 |
{
|
|
121 |
drizzle_set_error(stmt->con, __func__, "stmt object has bot been prepared"); |
|
122 |
return DRIZZLE_RETURN_STMT_ERROR; |
|
123 |
}
|
|
124 |
||
125 |
stmt->query_params[param_num].type= type; |
|
126 |
stmt->query_params[param_num].data= data; |
|
127 |
stmt->query_params[param_num].length= length; |
|
128 |
stmt->query_params[param_num].options= options; |
|
129 |
stmt->query_params[param_num].is_bound= true; |
|
130 |
||
131 |
return DRIZZLE_RETURN_OK; |
|
132 |
}
|
|
133 |
||
134 |
drizzle_return_t drizzle_stmt_execute(drizzle_stmt_st *stmt) |
|
135 |
{
|
|
136 |
uint16_t current_param; |
|
137 |
drizzle_bind_st *param_ptr; |
|
138 |
size_t param_lengths= 0; |
|
139 |
size_t buffer_size= 0; |
|
140 |
uint8_t *buffer; |
|
141 |
uint8_t *buffer_pos; |
|
142 |
uint8_t *data_pos; |
|
143 |
drizzle_return_t ret; |
|
144 |
||
145 |
/* Calculate param lengths */
|
|
146 |
for (current_param= 0; current_param < stmt->param_count; current_param++) |
|
147 |
{
|
|
148 |
if (!stmt->query_params[current_param].is_bound) |
|
149 |
{
|
|
150 |
drizzle_set_error(stmt->con, __func__, "parameter %d has not been bound", current_param); |
|
151 |
return DRIZZLE_RETURN_STMT_ERROR; |
|
152 |
}
|
|
153 |
/* parameter length + 8 byte header */
|
|
154 |
param_lengths+= stmt->query_params[current_param].length + 8; |
|
155 |
}
|
|
156 |
||
157 |
buffer_size= 4 /* Statement ID */ |
|
158 |
+ 1 /* Flags */ |
|
159 |
+ 4 /* Reserved (always set to 1) */ |
|
160 |
+ stmt->null_bitmap_length /* Null bitmap length */ |
|
161 |
+ 1 /* New parameters bound flag */ |
|
162 |
+ (stmt->param_count * 2) /* Parameter type data */ |
|
163 |
+ param_lengths; /* Parameter data */ |
|
164 |
||
165 |
buffer = (uint8_t*)malloc(buffer_size); |
|
166 |
if (buffer == NULL) |
|
167 |
{
|
|
168 |
drizzle_set_error(stmt->con, __func__, "malloc"); |
|
169 |
return DRIZZLE_RETURN_MEMORY; |
|
170 |
}
|
|
171 |
buffer_pos= buffer; |
|
172 |
||
173 |
/* Statement ID */
|
|
174 |
drizzle_set_byte4(buffer, stmt->id); |
|
175 |
/* Flags (not currently used) */
|
|
176 |
buffer[4]= 0; |
|
177 |
/* Reserved, protocol specifies set to 1 */
|
|
178 |
drizzle_set_byte4(&buffer[5], 1); |
|
179 |
buffer_pos+= 9; |
|
180 |
/* Null bitmap */
|
|
181 |
memcpy(buffer_pos, stmt->null_bitmap, stmt->null_bitmap_length); |
|
182 |
buffer_pos+= stmt->null_bitmap_length; |
|
183 |
/* New parameters bound flag
|
|
184 |
* If set to 1 then we need to leave a gap between the parameters type data
|
|
185 |
* and the actually data, so we keep track of a second pointer in the
|
|
186 |
* buffer for this
|
|
187 |
* */
|
|
188 |
if (stmt->new_bind) |
|
189 |
{
|
|
190 |
*buffer_pos= 1; |
|
191 |
buffer_pos++; |
|
192 |
/* Each param has a 2 byte data type header so the data pointer should be
|
|
193 |
* moved to this */
|
|
194 |
data_pos= buffer_pos + (stmt->param_count * 2); |
|
195 |
}
|
|
196 |
else
|
|
197 |
{
|
|
198 |
*buffer_pos= 0; |
|
199 |
buffer_pos++; |
|
200 |
data_pos= buffer_pos; |
|
201 |
}
|
|
202 |
||
203 |
/* Go through each param copying to buffer
|
|
204 |
* In an ideal world we would do this without the copy
|
|
205 |
* */
|
|
206 |
for (current_param= 0; current_param < stmt->param_count; current_param++) |
|
207 |
{
|
|
208 |
uint16_t short_value; |
|
209 |
uint32_t long_value; |
|
210 |
uint64_t longlong_value; |
|
211 |
param_ptr= &stmt->query_params[current_param]; |
|
212 |
||
213 |
if (stmt->new_bind) |
|
214 |
{
|
|
215 |
uint16_t type= (uint16_t)param_ptr->type; |
|
216 |
if (param_ptr->options & DRIZZLE_BIND_OPTION_UNSIGNED) |
|
217 |
{
|
|
218 |
/* Set the unsigned bit flag on the type data */
|
|
219 |
type |= 0x8000; |
|
220 |
}
|
|
221 |
drizzle_set_byte2(buffer_pos, type); |
|
222 |
buffer_pos+= 2; |
|
223 |
}
|
|
224 |
||
225 |
if (param_ptr->options & DRIZZLE_BIND_OPTION_LONG_DATA) |
|
226 |
{
|
|
227 |
/* Long data is sent separately, not in this buffer */
|
|
228 |
continue; |
|
229 |
}
|
|
230 |
||
231 |
switch(param_ptr->type) |
|
232 |
{
|
|
233 |
case DRIZZLE_COLUMN_TYPE_NULL: |
|
234 |
/* Toggle the bit for this column in the bitmap */
|
|
235 |
*stmt->null_bitmap |= (current_param ^ 2); |
|
236 |
break; |
|
237 |
case DRIZZLE_COLUMN_TYPE_TINY: |
|
238 |
*data_pos= *(uint8_t*)param_ptr->data; |
|
239 |
data_pos++; |
|
240 |
break; |
|
241 |
case DRIZZLE_COLUMN_TYPE_SHORT: |
|
242 |
short_value= *(uint16_t*)param_ptr->data; |
|
243 |
drizzle_set_byte2(data_pos, short_value); |
|
244 |
data_pos+= 2; |
|
245 |
break; |
|
246 |
case DRIZZLE_COLUMN_TYPE_LONG: |
|
247 |
long_value= *(uint32_t*)param_ptr->data; |
|
248 |
drizzle_set_byte4(data_pos, long_value); |
|
249 |
data_pos+= 4; |
|
250 |
break; |
|
251 |
case DRIZZLE_COLUMN_TYPE_LONGLONG: |
|
252 |
longlong_value= *(uint64_t*)param_ptr->data; |
|
253 |
drizzle_set_byte8(data_pos, longlong_value); |
|
254 |
data_pos+= 8; |
|
255 |
break; |
|
256 |
case DRIZZLE_COLUMN_TYPE_FLOAT: |
|
257 |
/* Float and double don't need to be packed apparently */
|
|
258 |
memcpy(data_pos, param_ptr->data, 4); |
|
259 |
data_pos+= 4; |
|
260 |
break; |
|
261 |
case DRIZZLE_COLUMN_TYPE_DOUBLE: |
|
262 |
memcpy(data_pos, param_ptr->data, 8); |
|
263 |
data_pos+= 8; |
|
264 |
break; |
|
265 |
case DRIZZLE_COLUMN_TYPE_TIME: |
|
266 |
data_pos= drizzle_pack_time((drizzle_datetime_st*)param_ptr->data, data_pos); |
|
267 |
break; |
|
268 |
case DRIZZLE_COLUMN_TYPE_DATE: |
|
269 |
case DRIZZLE_COLUMN_TYPE_DATETIME: |
|
270 |
case DRIZZLE_COLUMN_TYPE_TIMESTAMP: |
|
271 |
data_pos= drizzle_pack_datetime((drizzle_datetime_st*)param_ptr->data, data_pos); |
|
272 |
break; |
|
273 |
case DRIZZLE_COLUMN_TYPE_TINY_BLOB: |
|
274 |
case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB: |
|
275 |
case DRIZZLE_COLUMN_TYPE_LONG_BLOB: |
|
276 |
case DRIZZLE_COLUMN_TYPE_BLOB: |
|
277 |
case DRIZZLE_COLUMN_TYPE_VARCHAR: |
|
278 |
case DRIZZLE_COLUMN_TYPE_VAR_STRING: |
|
279 |
case DRIZZLE_COLUMN_TYPE_STRING: |
|
280 |
case DRIZZLE_COLUMN_TYPE_DECIMAL: |
|
281 |
case DRIZZLE_COLUMN_TYPE_NEWDECIMAL: |
|
282 |
data_pos= drizzle_pack_binary((uint8_t*)param_ptr->data, param_ptr->length, data_pos); |
|
283 |
break; |
|
284 |
/* These types aren't handled yet, most are for older MySQL versions */
|
|
285 |
case DRIZZLE_COLUMN_TYPE_INT24: |
|
286 |
case DRIZZLE_COLUMN_TYPE_YEAR: |
|
287 |
case DRIZZLE_COLUMN_TYPE_NEWDATE: |
|
288 |
case DRIZZLE_COLUMN_TYPE_ENUM: |
|
289 |
case DRIZZLE_COLUMN_TYPE_SET: |
|
290 |
case DRIZZLE_COLUMN_TYPE_GEOMETRY: |
|
291 |
case DRIZZLE_COLUMN_TYPE_BIT: |
|
292 |
default: |
|
293 |
drizzle_set_error(stmt->con, __func__, "unknown type when filling buffer"); |
|
294 |
free(buffer); |
|
295 |
return DRIZZLE_RETURN_UNEXPECTED_DATA; |
|
296 |
break; |
|
297 |
}
|
|
298 |
}
|
|
299 |
if (stmt->execute_result) |
|
300 |
{
|
|
301 |
drizzle_result_free(stmt->execute_result); |
|
302 |
stmt->execute_result= NULL; |
|
303 |
}
|
|
304 |
||
305 |
/* Set buffer size to what we actually used */
|
|
306 |
buffer_size= data_pos - buffer; |
|
307 |
||
308 |
stmt->execute_result= drizzle_command_write(stmt->con, stmt->execute_result, DRIZZLE_COMMAND_STMT_EXECUTE, buffer, buffer_size, buffer_size, &ret); |
|
309 |
||
310 |
if (ret == DRIZZLE_RETURN_OK) |
|
311 |
{
|
|
312 |
stmt->state= DRIZZLE_STMT_EXECUTED; |
|
313 |
}
|
|
314 |
else
|
|
315 |
{
|
|
316 |
free(buffer); |
|
317 |
return ret; |
|
318 |
}
|
|
319 |
||
320 |
stmt->new_bind= false; |
|
321 |
||
322 |
stmt->execute_result->binary_rows= true; |
|
323 |
||
324 |
stmt->execute_result->options= (drizzle_result_options_t)((uint8_t)stmt->execute_result->options | (uint8_t)DRIZZLE_RESULT_BINARY_ROWS); |
|
325 |
||
326 |
if (stmt->execute_result->column_count > 0) |
|
327 |
{
|
|
328 |
ret= drizzle_column_buffer(stmt->execute_result); |
|
329 |
stmt->result_params= (drizzle_bind_st*)calloc(stmt->execute_result->column_count, sizeof(drizzle_bind_st)); |
|
330 |
}
|
|
331 |
||
332 |
free(buffer); |
|
333 |
return ret; |
|
334 |
}
|
|
335 |
||
336 |
drizzle_return_t drizzle_stmt_send_long_data(drizzle_stmt_st *stmt, uint16_t param_num, uint8_t *data, size_t len) |
|
337 |
{
|
|
338 |
drizzle_return_t ret; |
|
339 |
uint8_t *buffer; |
|
340 |
||
341 |
if ((stmt == NULL) || (param_num >= stmt->param_count)) |
|
342 |
{
|
|
343 |
return DRIZZLE_RETURN_INVALID_ARGUMENT; |
|
344 |
}
|
|
345 |
||
346 |
if (stmt->state < DRIZZLE_STMT_PREPARED) |
|
347 |
{
|
|
348 |
drizzle_set_error(stmt->con, __func__, "stmt object has bot been prepared"); |
|
349 |
return DRIZZLE_RETURN_STMT_ERROR; |
|
350 |
}
|
|
351 |
||
352 |
||
353 |
/* TODO: rework drizzle_command_write so we can send a header and we don't
|
|
354 |
* need this copy
|
|
355 |
* */
|
|
356 |
buffer= (uint8_t*)malloc(len + 6); |
|
357 |
||
358 |
drizzle_set_byte4(buffer, stmt->id); |
|
359 |
drizzle_set_byte2(&buffer[4], param_num); |
|
360 |
memcpy(&buffer[6], data, len); |
|
361 |
||
362 |
stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options | (uint8_t)DRIZZLE_CON_NO_RESULT_READ); |
|
363 |
drizzle_command_write(stmt->con, NULL, DRIZZLE_COMMAND_STMT_SEND_LONG_DATA, |
|
364 |
buffer, len+6, len+6, &ret); |
|
365 |
stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options & (uint8_t)~DRIZZLE_CON_NO_RESULT_READ); |
|
366 |
stmt->query_params[param_num].options= (drizzle_bind_options_t)((uint8_t)stmt->query_params[param_num].options | (uint8_t)DRIZZLE_BIND_OPTION_LONG_DATA); |
|
367 |
||
368 |
free(buffer); |
|
369 |
return ret; |
|
370 |
}
|
|
371 |
||
372 |
drizzle_return_t drizzle_stmt_reset(drizzle_stmt_st *stmt) |
|
373 |
{
|
|
374 |
drizzle_return_t ret; |
|
375 |
uint8_t buffer[4]; |
|
376 |
uint16_t current_param; |
|
377 |
||
378 |
if (stmt == NULL) |
|
379 |
{
|
|
380 |
return DRIZZLE_RETURN_INVALID_ARGUMENT; |
|
381 |
}
|
|
382 |
||
383 |
for (current_param= 0; current_param < stmt->param_count; current_param++) |
|
384 |
{
|
|
385 |
stmt->query_params[current_param].options= (drizzle_bind_options_t)((uint8_t)stmt->query_params[current_param].options & (uint8_t)~DRIZZLE_BIND_OPTION_LONG_DATA); |
|
386 |
}
|
|
387 |
||
388 |
drizzle_set_byte4(buffer, stmt->id); |
|
389 |
stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options | (uint8_t)DRIZZLE_CON_NO_RESULT_READ); |
|
390 |
drizzle_command_write(stmt->con, NULL, DRIZZLE_COMMAND_STMT_RESET, buffer, 4, |
|
391 |
4, &ret); |
|
392 |
stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options & (uint8_t)~DRIZZLE_CON_NO_RESULT_READ); |
|
393 |
if (stmt->execute_result) |
|
394 |
{
|
|
395 |
drizzle_result_free(stmt->execute_result); |
|
396 |
stmt->execute_result= NULL; |
|
397 |
}
|
|
398 |
stmt->state= DRIZZLE_STMT_PREPARED; |
|
399 |
free(stmt->result_params); |
|
400 |
||
401 |
return ret; |
|
402 |
}
|
|
403 |
||
404 |
drizzle_return_t drizzle_stmt_fetch(drizzle_stmt_st *stmt) |
|
405 |
{
|
|
406 |
drizzle_return_t ret= DRIZZLE_RETURN_OK; |
|
407 |
uint16_t column_counter= 0; |
|
408 |
drizzle_row_t row; |
|
409 |
drizzle_column_st *column; |
|
410 |
||
411 |
if (stmt == NULL) |
|
412 |
{
|
|
413 |
return DRIZZLE_RETURN_INVALID_ARGUMENT; |
|
414 |
}
|
|
415 |
||
416 |
if (stmt->state < DRIZZLE_STMT_EXECUTED) |
|
417 |
{
|
|
418 |
drizzle_set_error(stmt->con, __func__, "statement has not been executed"); |
|
419 |
return DRIZZLE_RETURN_UNEXPECTED_DATA; |
|
420 |
}
|
|
421 |
stmt->con->result= stmt->execute_result; |
|
422 |
||
423 |
/* Determine how to read the row based on whether or not it is already
|
|
424 |
* buffered */
|
|
425 |
||
426 |
if (stmt->execute_result->options & DRIZZLE_RESULT_BUFFER_ROW) |
|
427 |
{
|
|
428 |
row= drizzle_row_next(stmt->execute_result); |
|
429 |
}
|
|
430 |
else
|
|
431 |
{
|
|
432 |
row= drizzle_row_buffer(stmt->execute_result, &ret); |
|
433 |
}
|
|
434 |
||
435 |
if (row == NULL) |
|
436 |
{
|
|
437 |
return DRIZZLE_RETURN_ROW_END; |
|
438 |
}
|
|
439 |
drizzle_column_seek(stmt->execute_result, 0); |
|
440 |
||
441 |
while((column= drizzle_column_next(stmt->execute_result))) |
|
442 |
{
|
|
443 |
drizzle_bind_st *param= &stmt->result_params[column_counter]; |
|
444 |
/* if this row is null in the result bitmap */
|
|
445 |
if (*stmt->execute_result->null_bitmap & ((column_counter^2) << 2)) |
|
446 |
{
|
|
447 |
param->options = (drizzle_bind_options_t)((uint8_t)param->options | (uint8_t) DRIZZLE_BIND_OPTION_NULL); |
|
448 |
param->length= 0; |
|
449 |
}
|
|
450 |
else
|
|
451 |
{
|
|
452 |
uint16_t short_data; |
|
453 |
uint32_t long_data; |
|
454 |
uint64_t longlong_data; |
|
455 |
param->length= stmt->execute_result->field_sizes[column_counter]; |
|
456 |
if (column->flags & DRIZZLE_COLUMN_FLAGS_UNSIGNED) |
|
457 |
{
|
|
458 |
param->options = (drizzle_bind_options_t)((uint8_t)param->options | (uint8_t) DRIZZLE_BIND_OPTION_UNSIGNED); |
|
459 |
}
|
|
460 |
||
461 |
param->data= realloc(param->data, param->length); |
|
58.2.2
by Andrew Hutchings
Fixups to statement and column |
462 |
param->type= column->type; |
58.2.1
by Andrew Hutchings
Initial prepared statement support |
463 |
|
464 |
switch(column->type) |
|
465 |
{
|
|
466 |
case DRIZZLE_COLUMN_TYPE_NULL: |
|
467 |
/* I don't think this one should happen, but cover it anyway */
|
|
468 |
param->length= 0; |
|
469 |
break; |
|
470 |
case DRIZZLE_COLUMN_TYPE_TINY: |
|
471 |
*(uint8_t*)param->data= *row[column_counter]; |
|
472 |
break; |
|
473 |
case DRIZZLE_COLUMN_TYPE_SHORT: |
|
474 |
case DRIZZLE_COLUMN_TYPE_YEAR: |
|
475 |
short_data= drizzle_get_byte2(row[column_counter]); |
|
476 |
memcpy(param->data, &short_data, 2); |
|
477 |
break; |
|
478 |
case DRIZZLE_COLUMN_TYPE_INT24: |
|
479 |
case DRIZZLE_COLUMN_TYPE_LONG: |
|
480 |
long_data= drizzle_get_byte4(row[column_counter]); |
|
481 |
memcpy(param->data, &long_data, 4); |
|
482 |
break; |
|
483 |
case DRIZZLE_COLUMN_TYPE_LONGLONG: |
|
484 |
longlong_data= drizzle_get_byte8(row[column_counter]); |
|
485 |
memcpy(param->data, &longlong_data, 8); |
|
486 |
break; |
|
487 |
case DRIZZLE_COLUMN_TYPE_FLOAT: |
|
488 |
memcpy(param->data, row[column_counter], 4); |
|
489 |
break; |
|
490 |
case DRIZZLE_COLUMN_TYPE_DOUBLE: |
|
491 |
memcpy(param->data, row[column_counter], 8); |
|
492 |
break; |
|
493 |
case DRIZZLE_COLUMN_TYPE_TIME: |
|
494 |
drizzle_unpack_time(row[column_counter], param->length, (uint8_t*)param->data); |
|
495 |
break; |
|
496 |
case DRIZZLE_COLUMN_TYPE_DATE: |
|
497 |
case DRIZZLE_COLUMN_TYPE_DATETIME: |
|
498 |
case DRIZZLE_COLUMN_TYPE_TIMESTAMP: |
|
499 |
drizzle_unpack_datetime(row[column_counter], param->length, (uint8_t*)param->data); |
|
500 |
break; |
|
501 |
case DRIZZLE_COLUMN_TYPE_TINY_BLOB: |
|
502 |
case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB: |
|
503 |
case DRIZZLE_COLUMN_TYPE_LONG_BLOB: |
|
504 |
case DRIZZLE_COLUMN_TYPE_BLOB: |
|
505 |
case DRIZZLE_COLUMN_TYPE_BIT: |
|
506 |
case DRIZZLE_COLUMN_TYPE_STRING: |
|
507 |
case DRIZZLE_COLUMN_TYPE_VAR_STRING: |
|
508 |
case DRIZZLE_COLUMN_TYPE_DECIMAL: |
|
509 |
case DRIZZLE_COLUMN_TYPE_NEWDECIMAL: |
|
510 |
case DRIZZLE_COLUMN_TYPE_NEWDATE: |
|
511 |
memcpy(param->data, row[column_counter], param->length); |
|
512 |
break; |
|
513 |
/* These types aren't handled yet, most are for older MySQL versions */
|
|
514 |
case DRIZZLE_COLUMN_TYPE_VARCHAR: |
|
515 |
case DRIZZLE_COLUMN_TYPE_ENUM: |
|
516 |
case DRIZZLE_COLUMN_TYPE_SET: |
|
517 |
case DRIZZLE_COLUMN_TYPE_GEOMETRY: |
|
518 |
default: |
|
519 |
drizzle_set_error(stmt->con, __func__, "Unknown data type found"); |
|
520 |
ret= DRIZZLE_RETURN_UNEXPECTED_DATA; |
|
521 |
break; |
|
522 |
}
|
|
523 |
}
|
|
524 |
column_counter++; |
|
525 |
if (ret == DRIZZLE_RETURN_UNEXPECTED_DATA) |
|
526 |
{
|
|
527 |
break; |
|
528 |
}
|
|
529 |
||
530 |
}
|
|
531 |
stmt->state= DRIZZLE_STMT_FETCHED; |
|
532 |
if (!(stmt->execute_result->options & DRIZZLE_RESULT_BUFFER_ROW)) |
|
533 |
{
|
|
534 |
drizzle_row_free(stmt->execute_result, row); |
|
535 |
}
|
|
536 |
||
537 |
return ret; |
|
538 |
}
|
|
539 |
||
540 |
drizzle_return_t drizzle_stmt_buffer(drizzle_stmt_st *stmt) |
|
541 |
{
|
|
542 |
if (stmt == NULL) |
|
543 |
{
|
|
544 |
return DRIZZLE_RETURN_INVALID_ARGUMENT; |
|
545 |
}
|
|
546 |
if (stmt->state >= DRIZZLE_STMT_FETCHED) |
|
547 |
{
|
|
548 |
drizzle_set_error(stmt->con, __func__, "data set has already been read"); |
|
549 |
return DRIZZLE_RETURN_UNEXPECTED_DATA; |
|
550 |
}
|
|
551 |
||
552 |
stmt->con->result= stmt->execute_result; |
|
553 |
stmt->state= DRIZZLE_STMT_FETCHED; |
|
554 |
||
555 |
return drizzle_result_buffer(stmt->execute_result); |
|
556 |
}
|
|
557 |
||
558 |
drizzle_return_t drizzle_stmt_close(drizzle_stmt_st *stmt) |
|
559 |
{
|
|
560 |
uint8_t buffer[4]; |
|
561 |
drizzle_return_t ret; |
|
562 |
||
563 |
if (stmt == NULL) |
|
564 |
{
|
|
565 |
return DRIZZLE_RETURN_INVALID_ARGUMENT; |
|
566 |
}
|
|
567 |
||
568 |
free(stmt->null_bitmap); |
|
569 |
free(stmt->query_params); |
|
64.1.1
by Andrew Hutchings
Fix valgrind errors and leaks |
570 |
if (stmt->result_params) |
571 |
{
|
|
572 |
free(stmt->result_params->data); |
|
573 |
free(stmt->result_params); |
|
574 |
}
|
|
58.2.1
by Andrew Hutchings
Initial prepared statement support |
575 |
if (stmt->execute_result) |
576 |
{
|
|
577 |
drizzle_result_free(stmt->execute_result); |
|
578 |
}
|
|
579 |
if (stmt->prepare_result) |
|
580 |
{
|
|
581 |
drizzle_result_free(stmt->prepare_result); |
|
582 |
}
|
|
583 |
||
584 |
drizzle_set_byte4(buffer, stmt->id); |
|
585 |
stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options | (uint8_t)DRIZZLE_CON_NO_RESULT_READ); |
|
586 |
drizzle_command_write(stmt->con, NULL, DRIZZLE_COMMAND_STMT_CLOSE, buffer, 4, |
|
587 |
4, &ret); |
|
588 |
stmt->con->options= (drizzle_options_t)((uint8_t)stmt->con->options & (uint8_t)~DRIZZLE_CON_NO_RESULT_READ); |
|
589 |
free(stmt); |
|
590 |
return ret; |
|
591 |
}
|
|
592 |
||
593 |
drizzle_column_type_t drizzle_stmt_item_type(drizzle_stmt_st *stmt, uint16_t column_number) |
|
594 |
{
|
|
595 |
if ((stmt == NULL) || (stmt->result_params == NULL)) |
|
596 |
{
|
|
597 |
return DRIZZLE_COLUMN_TYPE_NONE; |
|
598 |
}
|
|
599 |
return stmt->result_params[column_number].type; |
|
600 |
}
|
|
601 |
||
602 |
void *drizzle_stmt_item_data(drizzle_stmt_st *stmt, uint16_t column_number) |
|
603 |
{
|
|
604 |
if ((stmt == NULL) || (stmt->result_params == NULL)) |
|
605 |
{
|
|
606 |
return NULL; |
|
607 |
}
|
|
608 |
return stmt->result_params[column_number].data; |
|
609 |
}
|
|
610 |
||
611 |
uint32_t drizzle_stmt_item_length(drizzle_stmt_st *stmt, uint16_t column_number) |
|
612 |
{
|
|
613 |
if ((stmt == NULL) || (stmt->result_params == NULL)) |
|
614 |
{
|
|
615 |
return 0; |
|
616 |
}
|
|
617 |
return stmt->result_params[column_number].length; |
|
618 |
}
|
|
619 |
||
620 |
drizzle_bind_options_t drizzle_stmt_item_options(drizzle_stmt_st *stmt, uint16_t column_number) |
|
621 |
{
|
|
622 |
if ((stmt == NULL) || (stmt->result_params == NULL)) |
|
623 |
{
|
|
624 |
return DRIZZLE_BIND_OPTION_NONE; |
|
625 |
}
|
|
626 |
return stmt->result_params[column_number].options; |
|
627 |
}
|
|
628 |
||
629 |
uint16_t drizzle_stmt_column_count(drizzle_stmt_st *stmt) |
|
630 |
{
|
|
631 |
if ((stmt == NULL) || (stmt->prepare_result == NULL)) |
|
632 |
{
|
|
633 |
return 0; |
|
634 |
}
|
|
635 |
||
636 |
return stmt->prepare_result->column_count; |
|
637 |
}
|
|
638 |
||
639 |
uint64_t drizzle_stmt_affected_rows(drizzle_stmt_st *stmt) |
|
640 |
{
|
|
641 |
if ((stmt == NULL) || (stmt->execute_result == NULL)) |
|
642 |
{
|
|
643 |
return 0; |
|
644 |
}
|
|
645 |
||
646 |
return stmt->execute_result->affected_rows; |
|
647 |
}
|
|
648 |
||
649 |
uint64_t drizzle_stmt_insert_id(drizzle_stmt_st *stmt) |
|
650 |
{
|
|
651 |
if ((stmt == NULL) || (stmt->execute_result == NULL)) |
|
652 |
{
|
|
653 |
return 0; |
|
654 |
}
|
|
655 |
||
656 |
return stmt->execute_result->insert_id; |
|
657 |
}
|
|
658 |
||
659 |
uint16_t drizzle_stmt_param_count(drizzle_stmt_st *stmt) |
|
660 |
{
|
|
661 |
if (stmt == NULL) |
|
662 |
{
|
|
663 |
return 0; |
|
664 |
}
|
|
665 |
||
666 |
return stmt->param_count; |
|
667 |
}
|
|
668 |
||
669 |
uint64_t drizzle_stmt_row_count(drizzle_stmt_st *stmt) |
|
670 |
{
|
|
671 |
if ((stmt == NULL) || (stmt->execute_result == NULL)) |
|
672 |
{
|
|
673 |
return 0; |
|
674 |
}
|
|
675 |
||
676 |
return stmt->execute_result->row_count; |
|
677 |
}
|