1 /****************************************************************************
2 Copyright (C) 2012 Monty Program AB
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not see <http://www.gnu.org/licenses>
16 or write to the Free Software Foundation, Inc.,
17 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18
19 Part of this code includes code from the PHP project which
20 is freely available from http://www.php.net
21 *****************************************************************************/
22
23 /* The implementation for prepared statements was ported from PHP's mysqlnd
24 extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
25
26 Original file header:
27 +----------------------------------------------------------------------+
28 | PHP Version 5 |
29 +----------------------------------------------------------------------+
30 | Copyright (c) 2006-2011 The PHP Group |
31 +----------------------------------------------------------------------+
32 | This source file is subject to version 3.01 of the PHP license, |
33 | that is bundled with this package in the file LICENSE, and is |
34 | available through the world-wide-web at the following url: |
35 | http://www.php.net/license/3_01.txt |
36 | If you did not receive a copy of the PHP license and are unable to |
37 | obtain it through the world-wide-web, please send a note to |
38 | license@php.net so we can mail you a copy immediately. |
39 +----------------------------------------------------------------------+
40 | Authors: Georg Richter <georg@mysql.com> |
41 | Andrey Hristov <andrey@mysql.com> |
42 | Ulf Wendel <uwendel@mysql.com> |
43 +----------------------------------------------------------------------+
44 */
45
46 #include "ma_global.h"
47 #include <ma_sys.h>
48 #include <ma_string.h>
49 #include <mariadb_ctype.h>
50 #include "mysql.h"
51 #include "errmsg.h"
52 #include <ma_pvio.h>
53 #include <sys/stat.h>
54 #include <signal.h>
55 #include <time.h>
56 #include <mysql/client_plugin.h>
57 #include <ma_common.h>
58 #include "ma_priv.h"
59
60
61 #define UPDATE_STMT_ERROR(stmt)\
62 SET_CLIENT_STMT_ERROR((stmt), (stmt)->mysql->net.last_errno, (stmt)->mysql->net.sqlstate, (stmt)->mysql->net.last_error)
63
64 #define STMT_NUM_OFS(type, a, r) (((type *)(a))[r])
65 #define MADB_RESET_ERROR 1
66 #define MADB_RESET_LONGDATA 2
67 #define MADB_RESET_SERVER 4
68 #define MADB_RESET_BUFFER 8
69 #define MADB_RESET_STORED 16
70
71 #define MAX_TIME_STR_LEN 13
72 #define MAX_DATE_STR_LEN 5
73 #define MAX_DATETIME_STR_LEN 12
74
75 typedef struct
76 {
77 MA_MEM_ROOT fields_ma_alloc_root;
78 } MADB_STMT_EXTENSION;
79
80 static my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove);
81
82 static my_bool is_not_null= 0;
83 static my_bool is_null= 1;
84
stmt_set_error(MYSQL_STMT * stmt,unsigned int error_nr,const char * sqlstate,const char * format,...)85 void stmt_set_error(MYSQL_STMT *stmt,
86 unsigned int error_nr,
87 const char *sqlstate,
88 const char *format,
89 ...)
90 {
91 va_list ap;
92 const char *error= NULL;
93
94 if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR)
95 error= ER(error_nr);
96 else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR)
97 error= CER(error_nr);
98
99 stmt->last_errno= error_nr;
100 ma_strmake(stmt->sqlstate, sqlstate, SQLSTATE_LENGTH);
101 va_start(ap, format);
102 vsnprintf(stmt->last_error, MYSQL_ERRMSG_SIZE,
103 format ? format : error ? error : "", ap);
104 va_end(ap);
105 return;
106 }
107
mthd_supported_buffer_type(enum enum_field_types type)108 my_bool mthd_supported_buffer_type(enum enum_field_types type)
109 {
110 switch (type) {
111 case MYSQL_TYPE_BIT:
112 case MYSQL_TYPE_BLOB:
113 case MYSQL_TYPE_DATE:
114 case MYSQL_TYPE_DATETIME:
115 case MYSQL_TYPE_DECIMAL:
116 case MYSQL_TYPE_DOUBLE:
117 case MYSQL_TYPE_FLOAT:
118 case MYSQL_TYPE_GEOMETRY:
119 case MYSQL_TYPE_INT24:
120 case MYSQL_TYPE_LONG:
121 case MYSQL_TYPE_LONG_BLOB:
122 case MYSQL_TYPE_LONGLONG:
123 case MYSQL_TYPE_MEDIUM_BLOB:
124 case MYSQL_TYPE_NEWDATE:
125 case MYSQL_TYPE_NEWDECIMAL:
126 case MYSQL_TYPE_NULL:
127 case MYSQL_TYPE_SHORT:
128 case MYSQL_TYPE_STRING:
129 case MYSQL_TYPE_JSON:
130 case MYSQL_TYPE_TIME:
131 case MYSQL_TYPE_TIMESTAMP:
132 case MYSQL_TYPE_TINY:
133 case MYSQL_TYPE_TINY_BLOB:
134 case MYSQL_TYPE_VAR_STRING:
135 case MYSQL_TYPE_YEAR:
136 return 1;
137 break;
138 default:
139 return 0;
140 break;
141 }
142 }
143
144 static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags);
145 static my_bool mysql_stmt_internal_reset(MYSQL_STMT *stmt, my_bool is_close);
stmt_unbuffered_eof(MYSQL_STMT * stmt,uchar ** row)146 static int stmt_unbuffered_eof(MYSQL_STMT *stmt __attribute__((unused)),
147 uchar **row __attribute__((unused)))
148 {
149 return MYSQL_NO_DATA;
150 }
151
stmt_unbuffered_fetch(MYSQL_STMT * stmt,uchar ** row)152 static int stmt_unbuffered_fetch(MYSQL_STMT *stmt, uchar **row)
153 {
154 ulong pkt_len;
155
156 pkt_len= ma_net_safe_read(stmt->mysql);
157
158 if (pkt_len == packet_error)
159 {
160 stmt->fetch_row_func= stmt_unbuffered_eof;
161 return(1);
162 }
163
164 if (stmt->mysql->net.read_pos[0] == 254)
165 {
166 *row = NULL;
167 stmt->fetch_row_func= stmt_unbuffered_eof;
168 return(MYSQL_NO_DATA);
169 }
170 else
171 *row = stmt->mysql->net.read_pos;
172 stmt->result.rows++;
173 return(0);
174 }
175
stmt_buffered_fetch(MYSQL_STMT * stmt,uchar ** row)176 static int stmt_buffered_fetch(MYSQL_STMT *stmt, uchar **row)
177 {
178 if (!stmt->result_cursor)
179 {
180 *row= NULL;
181 stmt->state= MYSQL_STMT_FETCH_DONE;
182 return MYSQL_NO_DATA;
183 }
184 stmt->state= MYSQL_STMT_USER_FETCHING;
185 *row= (uchar *)stmt->result_cursor->data;
186
187 stmt->result_cursor= stmt->result_cursor->next;
188 return 0;
189 }
190
mthd_stmt_read_all_rows(MYSQL_STMT * stmt)191 int mthd_stmt_read_all_rows(MYSQL_STMT *stmt)
192 {
193 MYSQL_DATA *result= &stmt->result;
194 MYSQL_ROWS *current, **pprevious;
195 ulong packet_len;
196 unsigned char *p;
197
198 pprevious= &result->data;
199
200 while ((packet_len = ma_net_safe_read(stmt->mysql)) != packet_error)
201 {
202 p= stmt->mysql->net.read_pos;
203 if (packet_len > 7 || p[0] != 254)
204 {
205 /* allocate space for rows */
206 if (!(current= (MYSQL_ROWS *)ma_alloc_root(&result->alloc, sizeof(MYSQL_ROWS) + packet_len)))
207 {
208 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
209 return(1);
210 }
211 current->data= (MYSQL_ROW)(current + 1);
212 *pprevious= current;
213 pprevious= ¤t->next;
214
215 /* copy binary row, we will encode it during mysql_stmt_fetch */
216 memcpy((char *)current->data, (char *)p, packet_len);
217
218 if (stmt->update_max_length)
219 {
220 uchar *null_ptr, bit_offset= 4;
221 uchar *cp= p;
222 unsigned int i;
223
224 cp++; /* skip first byte */
225 null_ptr= cp;
226 cp+= (stmt->field_count + 9) / 8;
227
228 for (i=0; i < stmt->field_count; i++)
229 {
230 if (!(*null_ptr & bit_offset))
231 {
232 if (mysql_ps_fetch_functions[stmt->fields[i].type].pack_len < 0)
233 {
234 /* We need to calculate the sizes for date and time types */
235 size_t len= net_field_length(&cp);
236 switch(stmt->fields[i].type) {
237 case MYSQL_TYPE_TIME:
238 case MYSQL_TYPE_DATE:
239 case MYSQL_TYPE_DATETIME:
240 case MYSQL_TYPE_TIMESTAMP:
241 stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len;
242 break;
243 default:
244 if (len > stmt->fields[i].max_length)
245 stmt->fields[i].max_length= (ulong)len;
246 break;
247 }
248 cp+= len;
249 }
250 else
251 {
252 if (stmt->fields[i].flags & ZEROFILL_FLAG)
253 {
254 /* The -1 is because a ZEROFILL:ed field is always unsigned */
255 size_t len= MAX(stmt->fields[i].length, mysql_ps_fetch_functions[stmt->fields[i].type].max_len-1);
256 if (len > stmt->fields[i].max_length)
257 stmt->fields[i].max_length= (unsigned long)len;
258 }
259 else if (!stmt->fields[i].max_length)
260 {
261 stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len;
262 if (stmt->fields[i].flags & UNSIGNED_FLAG &&
263 stmt->fields[i].type != MYSQL_TYPE_INT24 &&
264 stmt->fields[i].type != MYSQL_TYPE_LONGLONG)
265 {
266 /*
267 Unsigned integers has one character less than signed integers
268 as '-' is counted as part of max_length
269 */
270 stmt->fields[i].max_length--;
271 }
272 }
273 cp+= mysql_ps_fetch_functions[stmt->fields[i].type].pack_len;
274 }
275 }
276 if (!((bit_offset <<=1) & 255))
277 {
278 bit_offset= 1; /* To next byte */
279 null_ptr++;
280 }
281 }
282 }
283 current->length= packet_len;
284 result->rows++;
285 } else /* end of stream */
286 {
287 *pprevious= 0;
288 /* sace status info */
289 p++;
290 stmt->upsert_status.warning_count= stmt->mysql->warning_count= uint2korr(p);
291 p+=2;
292 stmt->upsert_status.server_status= stmt->mysql->server_status= uint2korr(p);
293 stmt->result_cursor= result->data;
294 return(0);
295 }
296 }
297 stmt->result_cursor= 0;
298 SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
299 stmt->mysql->net.last_error);
300 return(1);
301 }
302
stmt_cursor_fetch(MYSQL_STMT * stmt,uchar ** row)303 static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
304 {
305 uchar buf[STMT_ID_LENGTH + 4];
306 MYSQL_DATA *result= &stmt->result;
307
308 if (stmt->state < MYSQL_STMT_USE_OR_STORE_CALLED)
309 {
310 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
311 return(1);
312 }
313
314 /* do we have some prefetched rows available ? */
315 if (stmt->result_cursor)
316 return(stmt_buffered_fetch(stmt, row));
317 if (stmt->upsert_status.server_status & SERVER_STATUS_LAST_ROW_SENT)
318 stmt->upsert_status.server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
319 else
320 {
321 int4store(buf, stmt->stmt_id);
322 int4store(buf + STMT_ID_LENGTH, stmt->prefetch_rows);
323
324 if (stmt->mysql->methods->db_command(stmt->mysql, COM_STMT_FETCH, (char *)buf, sizeof(buf), 1, stmt))
325 {
326 UPDATE_STMT_ERROR(stmt);
327 return(1);
328 }
329
330 /* free previously allocated buffer */
331 ma_free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
332 result->data= 0;
333 result->rows= 0;
334
335 if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
336 return(1);
337
338 return(stmt_buffered_fetch(stmt, row));
339 }
340 /* no more cursor data available */
341 *row= NULL;
342 return(MYSQL_NO_DATA);
343 }
344
345 /* flush one result set */
mthd_stmt_flush_unbuffered(MYSQL_STMT * stmt)346 void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt)
347 {
348 ulong packet_len;
349 int in_resultset= stmt->state > MYSQL_STMT_EXECUTED &&
350 stmt->state < MYSQL_STMT_FETCH_DONE;
351 while ((packet_len = ma_net_safe_read(stmt->mysql)) != packet_error)
352 {
353 uchar *pos= stmt->mysql->net.read_pos;
354 if (!in_resultset && *pos == 0) /* OK */
355 {
356 pos++;
357 net_field_length(&pos);
358 net_field_length(&pos);
359 stmt->mysql->server_status= uint2korr(pos);
360 goto end;
361 }
362 if (packet_len < 8 && *pos == 254) /* EOF */
363 {
364 if (mariadb_connection(stmt->mysql))
365 {
366 stmt->mysql->server_status= uint2korr(pos + 3);
367 if (in_resultset)
368 goto end;
369 in_resultset= 1;
370 }
371 else
372 goto end;
373 }
374 }
375 end:
376 stmt->state= MYSQL_STMT_FETCH_DONE;
377 }
378
mthd_stmt_fetch_to_bind(MYSQL_STMT * stmt,unsigned char * row)379 int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row)
380 {
381 uint i;
382 size_t truncations= 0;
383 unsigned char *null_ptr, bit_offset= 4;
384 row++; /* skip status byte */
385 null_ptr= row;
386 row+= (stmt->field_count + 9) / 8;
387
388 for (i=0; i < stmt->field_count; i++)
389 {
390 /* save row position for fetching values in pieces */
391 if (*null_ptr & bit_offset)
392 {
393 if (stmt->result_callback)
394 stmt->result_callback(stmt->user_data, i, NULL);
395 else
396 {
397 if (!stmt->bind[i].is_null)
398 stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
399 *stmt->bind[i].is_null= 1;
400 stmt->bind[i].u.row_ptr= NULL;
401 }
402 } else
403 {
404 stmt->bind[i].u.row_ptr= row;
405 if (!stmt->bind_result_done ||
406 stmt->bind[i].flags & MADB_BIND_DUMMY)
407 {
408 unsigned long length;
409
410 if (stmt->result_callback)
411 stmt->result_callback(stmt->user_data, i, &row);
412 else {
413 if (mysql_ps_fetch_functions[stmt->fields[i].type].pack_len >= 0)
414 length= mysql_ps_fetch_functions[stmt->fields[i].type].pack_len;
415 else
416 length= net_field_length(&row);
417 row+= length;
418 if (!stmt->bind[i].length)
419 stmt->bind[i].length= &stmt->bind[i].length_value;
420 *stmt->bind[i].length= stmt->bind[i].length_value= length;
421 }
422 }
423 else
424 {
425 if (!stmt->bind[i].length)
426 stmt->bind[i].length= &stmt->bind[i].length_value;
427 if (!stmt->bind[i].is_null)
428 stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
429 *stmt->bind[i].is_null= 0;
430 mysql_ps_fetch_functions[stmt->fields[i].type].func(&stmt->bind[i], &stmt->fields[i], &row);
431 if (stmt->mysql->options.report_data_truncation)
432 truncations+= *stmt->bind[i].error;
433 }
434 }
435
436 if (!((bit_offset <<=1) & 255)) {
437 bit_offset= 1; /* To next byte */
438 null_ptr++;
439 }
440 }
441 return((truncations) ? MYSQL_DATA_TRUNCATED : 0);
442 }
443
_mysql_stmt_use_result(MYSQL_STMT * stmt)444 MYSQL_RES *_mysql_stmt_use_result(MYSQL_STMT *stmt)
445 {
446 MYSQL *mysql= stmt->mysql;
447
448 if (!stmt->field_count ||
449 (!stmt->cursor_exists && mysql->status != MYSQL_STATUS_STMT_RESULT) ||
450 (stmt->cursor_exists && mysql->status != MYSQL_STATUS_READY) ||
451 (stmt->state != MYSQL_STMT_WAITING_USE_OR_STORE))
452 {
453 SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
454 return(NULL);
455 }
456
457 CLEAR_CLIENT_STMT_ERROR(stmt);
458
459 stmt->state = MYSQL_STMT_USE_OR_STORE_CALLED;
460 if (!stmt->cursor_exists)
461 stmt->fetch_row_func= stmt_unbuffered_fetch; //mysql_stmt_fetch_unbuffered_row;
462 else
463 stmt->fetch_row_func= stmt_cursor_fetch;
464
465 return(NULL);
466 }
467
mysql_net_store_length(unsigned char * packet,size_t length)468 unsigned char *mysql_net_store_length(unsigned char *packet, size_t length)
469 {
470 if (length < (unsigned long long) L64(251)) {
471 *packet = (unsigned char) length;
472 return packet + 1;
473 }
474
475 if (length < (unsigned long long) L64(65536)) {
476 *packet++ = 252;
477 int2store(packet,(uint) length);
478 return packet + 2;
479 }
480
481 if (length < (unsigned long long) L64(16777216)) {
482 *packet++ = 253;
483 int3store(packet,(ulong) length);
484 return packet + 3;
485 }
486 *packet++ = 254;
487 int8store(packet, length);
488 return packet + 8;
489 }
490
ma_get_length(MYSQL_STMT * stmt,unsigned int param_nr,unsigned long row_nr)491 static long ma_get_length(MYSQL_STMT *stmt, unsigned int param_nr, unsigned long row_nr)
492 {
493 if (!stmt->params[param_nr].length)
494 return 0;
495 if (stmt->param_callback)
496 return (long)*stmt->params[param_nr].length;
497 if (stmt->row_size)
498 return *(long *)((char *)stmt->params[param_nr].length + row_nr * stmt->row_size);
499 else
500 return stmt->params[param_nr].length[row_nr];
501 }
502
ma_get_indicator(MYSQL_STMT * stmt,unsigned int param_nr,unsigned long row_nr)503 static signed char ma_get_indicator(MYSQL_STMT *stmt, unsigned int param_nr, unsigned long row_nr)
504 {
505 if (!MARIADB_STMT_BULK_SUPPORTED(stmt) ||
506 !stmt->array_size ||
507 !stmt->params[param_nr].u.indicator)
508 return 0;
509 if (stmt->param_callback)
510 return *stmt->params[param_nr].u.indicator;
511 if (stmt->row_size)
512 return *((char *)stmt->params[param_nr].u.indicator + (row_nr * stmt->row_size));
513 return stmt->params[param_nr].u.indicator[row_nr];
514 }
515
ma_get_buffer_offset(MYSQL_STMT * stmt,enum enum_field_types type,void * buffer,unsigned long row_nr)516 static void *ma_get_buffer_offset(MYSQL_STMT *stmt, enum enum_field_types type,
517 void *buffer, unsigned long row_nr)
518 {
519 if (stmt->param_callback)
520 return buffer;
521
522 if (stmt->array_size)
523 {
524 int len;
525 if (stmt->row_size)
526 return (void *)((char *)buffer + stmt->row_size * row_nr);
527 len= mysql_ps_fetch_functions[type].pack_len;
528 if (len > 0)
529 return (void *)((char *)buffer + len * row_nr);
530 return ((void **)buffer)[row_nr];
531 }
532 return buffer;
533 }
534
store_param(MYSQL_STMT * stmt,int column,unsigned char ** p,unsigned long row_nr)535 int store_param(MYSQL_STMT *stmt, int column, unsigned char **p, unsigned long row_nr)
536 {
537 void *buf= ma_get_buffer_offset(stmt, stmt->params[column].buffer_type,
538 stmt->params[column].buffer, row_nr);
539 signed char indicator= ma_get_indicator(stmt, column, row_nr);
540
541 switch (stmt->params[column].buffer_type) {
542 case MYSQL_TYPE_TINY:
543 int1store(*p, (*(uchar *)buf));
544 (*p) += 1;
545 break;
546 case MYSQL_TYPE_SHORT:
547 case MYSQL_TYPE_YEAR:
548 int2store(*p, (*(short *)buf));
549 (*p) += 2;
550 break;
551 case MYSQL_TYPE_FLOAT:
552 float4store(*p, (*(float *)buf));
553 (*p) += 4;
554 break;
555 case MYSQL_TYPE_DOUBLE:
556 float8store(*p, (*(double *)buf));
557 (*p) += 8;
558 break;
559 case MYSQL_TYPE_LONGLONG:
560 int8store(*p, (*(ulonglong *)buf));
561 (*p) += 8;
562 break;
563 case MYSQL_TYPE_LONG:
564 case MYSQL_TYPE_INT24:
565 int4store(*p, (*(int32 *)buf));
566 (*p)+= 4;
567 break;
568 case MYSQL_TYPE_TIME:
569 {
570 /* binary encoding:
571 Offset Length Field
572 0 1 Length
573 1 1 negative
574 2-5 4 day
575 6 1 hour
576 7 1 ninute
577 8 1 second;
578 9-13 4 second_part
579 */
580 MYSQL_TIME *t= (MYSQL_TIME *)ma_get_buffer_offset(stmt, stmt->params[column].buffer_type,
581 stmt->params[column].buffer, row_nr);
582 char t_buffer[MAX_TIME_STR_LEN];
583 uint len= 0;
584
585 t_buffer[1]= t->neg ? 1 : 0;
586 int4store(t_buffer + 2, t->day);
587 t_buffer[6]= (uchar) t->hour;
588 t_buffer[7]= (uchar) t->minute;
589 t_buffer[8]= (uchar) t->second;
590 if (t->second_part)
591 {
592 int4store(t_buffer + 9, t->second_part);
593 len= 12;
594 }
595 else if (t->day || t->hour || t->minute || t->second)
596 len= 8;
597 t_buffer[0]= len++;
598 memcpy(*p, t_buffer, len);
599 (*p)+= len;
600 break;
601 }
602 case MYSQL_TYPE_DATE:
603 case MYSQL_TYPE_TIMESTAMP:
604 case MYSQL_TYPE_DATETIME:
605 {
606 /* binary format for date, timestamp and datetime
607 Offset Length Field
608 0 1 Length
609 1-2 2 Year
610 3 1 Month
611 4 1 Day
612 5 1 Hour
613 6 1 minute
614 7 1 second
615 8-11 4 secondpart
616 */
617 MYSQL_TIME *t= (MYSQL_TIME *)ma_get_buffer_offset(stmt, stmt->params[column].buffer_type,
618 stmt->params[column].buffer, row_nr);
619 char t_buffer[MAX_DATETIME_STR_LEN];
620 uint len= 0;
621
622 int2store(t_buffer + 1, t->year);
623 t_buffer[3]= (char) t->month;
624 t_buffer[4]= (char) t->day;
625 t_buffer[5]= (char) t->hour;
626 t_buffer[6]= (char) t->minute;
627 t_buffer[7]= (char) t->second;
628 if (t->second_part)
629 {
630 int4store(t_buffer + 8, t->second_part);
631 len= 11;
632 }
633 else if (t->hour || t->minute || t->second)
634 len= 7;
635 else if (t->year || t->month || t->day)
636 len= 4;
637 else
638 len=0;
639 t_buffer[0]= len++;
640 memcpy(*p, t_buffer, len);
641 (*p)+= len;
642 break;
643 }
644 case MYSQL_TYPE_TINY_BLOB:
645 case MYSQL_TYPE_MEDIUM_BLOB:
646 case MYSQL_TYPE_LONG_BLOB:
647 case MYSQL_TYPE_BLOB:
648 case MYSQL_TYPE_VARCHAR:
649 case MYSQL_TYPE_VAR_STRING:
650 case MYSQL_TYPE_STRING:
651 case MYSQL_TYPE_JSON:
652 case MYSQL_TYPE_DECIMAL:
653 case MYSQL_TYPE_NEWDECIMAL:
654 {
655 ulong len;
656 /* to is after p. The latter hasn't been moved */
657 uchar *to;
658
659 if (indicator == STMT_INDICATOR_NTS)
660 len= -1;
661 else
662 len= ma_get_length(stmt, column, row_nr);
663
664 if (len == (ulong)-1)
665 len= (ulong)strlen((char *)buf);
666
667 to = mysql_net_store_length(*p, len);
668
669 if (len)
670 memcpy(to, buf, len);
671 (*p) = to + len;
672 break;
673 }
674
675 default:
676 /* unsupported parameter type */
677 SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
678 return 1;
679 }
680 return 0;
681 }
682
683 /* {{{ mysqlnd_stmt_execute_generate_simple_request */
mysql_stmt_execute_generate_simple_request(MYSQL_STMT * stmt,size_t * request_len)684 unsigned char* mysql_stmt_execute_generate_simple_request(MYSQL_STMT *stmt, size_t *request_len)
685 {
686 /* execute packet has the following format:
687 Offset Length Description
688 -----------------------------------------
689 0 4 Statement id
690 4 1 Flags (cursor type)
691 5 4 Iteration count
692 -----------------------------------------
693 if (stmt->param_count):
694 6 (paramcount+7)/8 null bitmap
695 ------------------------------------------
696 if (stmt->send_types_to_server):
697 param_count*2 parameter types
698 1st byte: parameter type
699 2nd byte flag:
700 unsigned flag (32768)
701 indicator variable exists (16384)
702 ------------------------------------------
703 n data from bind_buffer
704
705 */
706
707 size_t length= 1024;
708 size_t free_bytes= 0;
709 size_t null_byte_offset= 0;
710 uint i;
711
712 uchar *start= NULL, *p;
713
714 /* preallocate length bytes */
715 /* check: gr */
716 if (!(start= p= (uchar *)malloc(length)))
717 goto mem_error;
718
719 int4store(p, stmt->stmt_id);
720 p += STMT_ID_LENGTH;
721
722 /* flags is 4 bytes, we store just 1 */
723 int1store(p, (unsigned char) stmt->flags);
724 p++;
725
726 int4store(p, 1);
727 p+= 4;
728
729 if (stmt->param_count)
730 {
731 size_t null_count= (stmt->param_count + 7) / 8;
732
733 free_bytes= length - (p - start);
734 if (null_count + 20 > free_bytes)
735 {
736 size_t offset= p - start;
737 length+= offset + null_count + 20;
738 if (!(start= (uchar *)realloc(start, length)))
739 goto mem_error;
740 p= start + offset;
741 }
742
743 null_byte_offset= p - start;
744 memset(p, 0, null_count);
745 p += null_count;
746
747 int1store(p, stmt->send_types_to_server);
748 p++;
749
750 free_bytes= length - (p - start);
751
752 /* Store type information:
753 2 bytes per type
754 */
755 if (stmt->send_types_to_server)
756 {
757 if (free_bytes < stmt->param_count * 2 + 20)
758 {
759 size_t offset= p - start;
760 length= offset + stmt->param_count * 2 + 20;
761 if (!(start= (uchar *)realloc(start, length)))
762 goto mem_error;
763 p= start + offset;
764 }
765 for (i = 0; i < stmt->param_count; i++)
766 {
767 /* this differs from mysqlnd, c api supports unsigned !! */
768 uint buffer_type= stmt->params[i].buffer_type | (stmt->params[i].is_unsigned ? 32768 : 0);
769 /* check if parameter requires indicator variable */
770 int2store(p, buffer_type);
771 p+= 2;
772 }
773 }
774
775 /* calculate data size */
776 for (i=0; i < stmt->param_count; i++)
777 {
778 size_t size= 0;
779 my_bool has_data= TRUE;
780
781 if (stmt->params[i].long_data_used)
782 {
783 has_data= FALSE;
784 stmt->params[i].long_data_used= 0;
785 }
786
787 if (has_data)
788 {
789 switch (stmt->params[i].buffer_type) {
790 case MYSQL_TYPE_NULL:
791 has_data= FALSE;
792 break;
793 case MYSQL_TYPE_TINY_BLOB:
794 case MYSQL_TYPE_MEDIUM_BLOB:
795 case MYSQL_TYPE_LONG_BLOB:
796 case MYSQL_TYPE_BLOB:
797 case MYSQL_TYPE_VARCHAR:
798 case MYSQL_TYPE_VAR_STRING:
799 case MYSQL_TYPE_STRING:
800 case MYSQL_TYPE_JSON:
801 case MYSQL_TYPE_DECIMAL:
802 case MYSQL_TYPE_NEWDECIMAL:
803 case MYSQL_TYPE_GEOMETRY:
804 case MYSQL_TYPE_NEWDATE:
805 case MYSQL_TYPE_ENUM:
806 case MYSQL_TYPE_BIT:
807 case MYSQL_TYPE_SET:
808 size+= 9; /* max 8 bytes for size */
809 size+= (size_t)ma_get_length(stmt, i, 0);
810 break;
811 case MYSQL_TYPE_TIME:
812 size+= MAX_TIME_STR_LEN;
813 break;
814 case MYSQL_TYPE_DATE:
815 size+= MAX_DATE_STR_LEN;
816 break;
817 case MYSQL_TYPE_DATETIME:
818 case MYSQL_TYPE_TIMESTAMP:
819 size+= MAX_DATETIME_STR_LEN;
820 break;
821 default:
822 size+= mysql_ps_fetch_functions[stmt->params[i].buffer_type].pack_len;
823 break;
824 }
825 }
826 free_bytes= length - (p - start);
827 if (free_bytes < size + 20)
828 {
829 size_t offset= p - start;
830 length= MAX(2 * length, offset + size + 20);
831 if (!(start= (uchar *)realloc(start, length)))
832 goto mem_error;
833 p= start + offset;
834 }
835 if (((stmt->params[i].is_null && *stmt->params[i].is_null) ||
836 stmt->params[i].buffer_type == MYSQL_TYPE_NULL ||
837 !stmt->params[i].buffer))
838 {
839 has_data= FALSE;
840 (start + null_byte_offset)[i/8] |= (unsigned char) (1 << (i & 7));
841 }
842
843 if (has_data)
844 {
845 store_param(stmt, i, &p, 0);
846 }
847 }
848 }
849 stmt->send_types_to_server= 0;
850 *request_len = (size_t)(p - start);
851 return start;
852 mem_error:
853 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
854 free(start);
855 *request_len= 0;
856 return NULL;
857 }
858 /* }}} */
859
860 /* {{{ mysql_stmt_skip_paramset */
mysql_stmt_skip_paramset(MYSQL_STMT * stmt,uint row)861 my_bool mysql_stmt_skip_paramset(MYSQL_STMT *stmt, uint row)
862 {
863 uint i;
864 for (i=0; i < stmt->param_count; i++)
865 {
866 if (ma_get_indicator(stmt, i, row) == STMT_INDICATOR_IGNORE_ROW)
867 return '\1';
868 }
869
870 return '\0';
871 }
872 /* }}} */
873
874 /* {{{ mysql_stmt_execute_generate_bulk_request */
mysql_stmt_execute_generate_bulk_request(MYSQL_STMT * stmt,size_t * request_len)875 unsigned char* mysql_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *request_len)
876 {
877 /* execute packet has the following format:
878 Offset Length Description
879 -----------------------------------------
880 0 4 Statement id
881 4 2 Flags (cursor type):
882 STMT_BULK_FLAG_CLIENT_SEND_TYPES = 128
883 STMT_BULK_FLAG_INSERT_ID_REQUEST = 64
884 -----------------------------------------
885 if (stmt->send_types_to_server):
886 for (i=0; i < param_count; i++)
887 1st byte: parameter type
888 2nd byte flag:
889 unsigned flag (32768)
890 ------------------------------------------
891 for (i=0; i < param_count; i++)
892 1 indicator variable
893 STMT_INDICATOR_NONE 0
894 STMT_INDICATOR_NULL 1
895 STMT_INDICATOR_DEFAULT 2
896 STMT_INDICATOR_IGNORE 3
897 STMT_INDICATOR_SKIP_SET 4
898 n data from bind buffer
899
900 */
901
902 size_t length= 1024;
903 size_t free_bytes= 0;
904 ushort flags= 0;
905 uint i, j;
906
907 uchar *start= NULL, *p;
908
909 if (!MARIADB_STMT_BULK_SUPPORTED(stmt))
910 {
911 stmt_set_error(stmt, CR_FUNCTION_NOT_SUPPORTED, "IM001",
912 CER(CR_FUNCTION_NOT_SUPPORTED), "Bulk operation");
913 return NULL;
914 }
915
916 if (!stmt->param_count)
917 {
918 stmt_set_error(stmt, CR_BULK_WITHOUT_PARAMETERS, "IM001",
919 CER(CR_BULK_WITHOUT_PARAMETERS));
920 return NULL;
921 }
922
923 /* preallocate length bytes */
924 if (!(start= p= (uchar *)malloc(length)))
925 goto mem_error;
926
927 int4store(p, stmt->stmt_id);
928 p += STMT_ID_LENGTH;
929
930 /* todo: request to return auto generated ids */
931 if (stmt->send_types_to_server)
932 flags|= STMT_BULK_FLAG_CLIENT_SEND_TYPES;
933 int2store(p, flags);
934 p+=2;
935
936 /* When using mariadb_stmt_execute_direct stmt->paran_count is
937 not knowm, so we need to assign prebind_params, which was previously
938 set by mysql_stmt_attr_set
939 */
940 if (!stmt->param_count && stmt->prebind_params)
941 stmt->param_count= stmt->prebind_params;
942
943 if (stmt->param_count)
944 {
945 free_bytes= length - (p - start);
946
947 /* Store type information:
948 2 bytes per type
949 */
950 if (stmt->send_types_to_server)
951 {
952 if (free_bytes < stmt->param_count * 2 + 20)
953 {
954 size_t offset= p - start;
955 length= offset + stmt->param_count * 2 + 20;
956 if (!(start= (uchar *)realloc(start, length)))
957 goto mem_error;
958 p= start + offset;
959 }
960 for (i = 0; i < stmt->param_count; i++)
961 {
962 /* this differs from mysqlnd, c api supports unsigned !! */
963 uint buffer_type= stmt->params[i].buffer_type | (stmt->params[i].is_unsigned ? 32768 : 0);
964 int2store(p, buffer_type);
965 p+= 2;
966 }
967 }
968
969 /* calculate data size */
970 for (j=0; j < stmt->array_size; j++)
971 {
972 /* If callback for parameters was specified, we need to
973 update bind information for new row */
974 if (stmt->param_callback)
975 stmt->param_callback(stmt->user_data, stmt->params, j);
976
977 if (mysql_stmt_skip_paramset(stmt, j))
978 continue;
979
980 for (i=0; i < stmt->param_count; i++)
981 {
982 size_t size= 0;
983 my_bool has_data= TRUE;
984 signed char indicator= ma_get_indicator(stmt, i, j);
985 /* check if we need to send data */
986 if (indicator > 0)
987 has_data= FALSE;
988 size= 1;
989
990 /* Please note that mysql_stmt_send_long_data is not supported
991 current when performing bulk execute */
992
993 if (has_data)
994 {
995 switch (stmt->params[i].buffer_type) {
996 case MYSQL_TYPE_NULL:
997 has_data= FALSE;
998 indicator= STMT_INDICATOR_NULL;
999 break;
1000 case MYSQL_TYPE_TINY_BLOB:
1001 case MYSQL_TYPE_MEDIUM_BLOB:
1002 case MYSQL_TYPE_LONG_BLOB:
1003 case MYSQL_TYPE_BLOB:
1004 case MYSQL_TYPE_VARCHAR:
1005 case MYSQL_TYPE_VAR_STRING:
1006 case MYSQL_TYPE_STRING:
1007 case MYSQL_TYPE_JSON:
1008 case MYSQL_TYPE_DECIMAL:
1009 case MYSQL_TYPE_NEWDECIMAL:
1010 case MYSQL_TYPE_GEOMETRY:
1011 case MYSQL_TYPE_NEWDATE:
1012 case MYSQL_TYPE_ENUM:
1013 case MYSQL_TYPE_BIT:
1014 case MYSQL_TYPE_SET:
1015 size+= 5; /* max 8 bytes for size */
1016 if (!stmt->param_callback)
1017 {
1018 if (indicator == STMT_INDICATOR_NTS ||
1019 (!stmt->row_size && ma_get_length(stmt,i,j) == -1))
1020 {
1021 size+= strlen(ma_get_buffer_offset(stmt,
1022 stmt->params[i].buffer_type,
1023 stmt->params[i].buffer,j));
1024 }
1025 else
1026 size+= (size_t)ma_get_length(stmt, i, j);
1027 }
1028 else {
1029 size+= stmt->params[i].buffer_length;
1030 }
1031 break;
1032 default:
1033 size+= mysql_ps_fetch_functions[stmt->params[i].buffer_type].pack_len;
1034 break;
1035 }
1036 }
1037 free_bytes= length - (p - start);
1038 if (free_bytes < size + 20)
1039 {
1040 size_t offset= p - start;
1041 length= MAX(2 * length, offset + size + 20);
1042 if (!(start= (uchar *)realloc(start, length)))
1043 goto mem_error;
1044 p= start + offset;
1045 }
1046
1047 int1store(p, indicator > 0 ? indicator : 0);
1048 p++;
1049 if (has_data) {
1050 store_param(stmt, i, &p, (stmt->param_callback) ? 0 : j);
1051 }
1052 }
1053 }
1054
1055 }
1056 stmt->send_types_to_server= 0;
1057 *request_len = (size_t)(p - start);
1058 return start;
1059 mem_error:
1060 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1061 free(start);
1062 *request_len= 0;
1063 return NULL;
1064 }
1065 /* }}} */
1066 /*!
1067 *******************************************************************************
1068
1069 \fn unsigned long long mysql_stmt_affected_rows
1070 \brief returns the number of affected rows from last mysql_stmt_execute
1071 call
1072
1073 \param[in] stmt The statement handle
1074 *******************************************************************************
1075 */
mysql_stmt_affected_rows(MYSQL_STMT * stmt)1076 unsigned long long STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt)
1077 {
1078 return stmt->upsert_status.affected_rows;
1079 }
1080
mysql_stmt_attr_get(MYSQL_STMT * stmt,enum enum_stmt_attr_type attr_type,void * value)1081 my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *value)
1082 {
1083 switch (attr_type) {
1084 case STMT_ATTR_STATE:
1085 *(enum mysql_stmt_state *)value= stmt->state;
1086 break;
1087 case STMT_ATTR_UPDATE_MAX_LENGTH:
1088 *(my_bool *)value= stmt->update_max_length;
1089 break;
1090 case STMT_ATTR_CURSOR_TYPE:
1091 *(unsigned long *)value= stmt->flags;
1092 break;
1093 case STMT_ATTR_PREFETCH_ROWS:
1094 *(unsigned long *)value= stmt->prefetch_rows;
1095 break;
1096 case STMT_ATTR_PREBIND_PARAMS:
1097 *(unsigned int *)value= stmt->prebind_params;
1098 break;
1099 case STMT_ATTR_ARRAY_SIZE:
1100 *(unsigned int *)value= stmt->array_size;
1101 break;
1102 case STMT_ATTR_ROW_SIZE:
1103 *(size_t *)value= stmt->row_size;
1104 break;
1105 case STMT_ATTR_CB_USER_DATA:
1106 *((void **)value) = stmt->user_data;
1107 break;
1108 default:
1109 return(1);
1110 }
1111 return(0);
1112 }
1113
mysql_stmt_attr_set(MYSQL_STMT * stmt,enum enum_stmt_attr_type attr_type,const void * value)1114 my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *value)
1115 {
1116 switch (attr_type) {
1117 case STMT_ATTR_UPDATE_MAX_LENGTH:
1118 stmt->update_max_length= *(my_bool *)value;
1119 break;
1120 case STMT_ATTR_CURSOR_TYPE:
1121 if (*(ulong *)value > (unsigned long) CURSOR_TYPE_READ_ONLY)
1122 {
1123 SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
1124 return(1);
1125 }
1126 stmt->flags = *(ulong *)value;
1127 break;
1128 case STMT_ATTR_PREFETCH_ROWS:
1129 if (*(ulong *)value == 0)
1130 *(long *)value= MYSQL_DEFAULT_PREFETCH_ROWS;
1131 else
1132 stmt->prefetch_rows= *(long *)value;
1133 break;
1134 case STMT_ATTR_PREBIND_PARAMS:
1135 if (stmt->state > MYSQL_STMT_INITTED)
1136 {
1137 mysql_stmt_internal_reset(stmt, 1);
1138 net_stmt_close(stmt, 0);
1139 stmt->state= MYSQL_STMT_INITTED;
1140 stmt->params= 0;
1141 }
1142 stmt->prebind_params= *(unsigned int *)value;
1143 break;
1144 case STMT_ATTR_ARRAY_SIZE:
1145 stmt->array_size= *(unsigned int *)value;
1146 break;
1147 case STMT_ATTR_ROW_SIZE:
1148 stmt->row_size= *(size_t *)value;
1149 break;
1150 case STMT_ATTR_CB_RESULT:
1151 stmt->result_callback= (ps_result_callback)value;
1152 break;
1153 case STMT_ATTR_CB_PARAM:
1154 stmt->param_callback= (ps_param_callback)value;
1155 break;
1156 case STMT_ATTR_CB_USER_DATA:
1157 stmt->user_data= (void *)value;
1158 break;
1159 default:
1160 SET_CLIENT_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
1161 return(1);
1162 }
1163 return(0);
1164 }
1165
mysql_stmt_bind_param(MYSQL_STMT * stmt,MYSQL_BIND * bind)1166 my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
1167 {
1168 MYSQL *mysql= stmt->mysql;
1169
1170 if (!mysql)
1171 {
1172 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
1173 return(1);
1174 }
1175
1176 /* If number of parameters was specified via mysql_stmt_attr_set we need to realloc
1177 them, e.g. for mariadb_stmt_execute_direct()
1178 */
1179 if ((stmt->state < MYSQL_STMT_PREPARED || stmt->state >= MYSQL_STMT_EXECUTED) &&
1180 stmt->prebind_params > 0)
1181 {
1182 if (!stmt->params && stmt->prebind_params)
1183 {
1184 if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->prebind_params * sizeof(MYSQL_BIND))))
1185 {
1186 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1187 return(1);
1188 }
1189 memset(stmt->params, '\0', stmt->prebind_params * sizeof(MYSQL_BIND));
1190 }
1191 stmt->param_count= stmt->prebind_params;
1192 }
1193 else if (stmt->state < MYSQL_STMT_PREPARED) {
1194 SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
1195 return(1);
1196 }
1197
1198 if (stmt->param_count && bind)
1199 {
1200 uint i;
1201
1202 memcpy(stmt->params, bind, sizeof(MYSQL_BIND) * stmt->param_count);
1203 stmt->send_types_to_server= 1;
1204
1205 for (i=0; i < stmt->param_count; i++)
1206 {
1207 if (stmt->mysql->methods->db_supported_buffer_type &&
1208 !stmt->mysql->methods->db_supported_buffer_type(stmt->params[i].buffer_type))
1209 {
1210 SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
1211 return(1);
1212 }
1213 if (!stmt->params[i].is_null)
1214 stmt->params[i].is_null= &is_not_null;
1215
1216 if (stmt->params[i].long_data_used)
1217 stmt->params[i].long_data_used= 0;
1218
1219 if (!stmt->params[i].length)
1220 stmt->params[i].length= &stmt->params[i].buffer_length;
1221
1222 switch(stmt->params[i].buffer_type) {
1223 case MYSQL_TYPE_NULL:
1224 stmt->params[i].is_null= &is_null;
1225 break;
1226 case MYSQL_TYPE_TINY:
1227 stmt->params[i].buffer_length= 1;
1228 break;
1229 case MYSQL_TYPE_SHORT:
1230 case MYSQL_TYPE_YEAR:
1231 stmt->params[i].buffer_length= 2;
1232 break;
1233 case MYSQL_TYPE_LONG:
1234 case MYSQL_TYPE_FLOAT:
1235 stmt->params[i].buffer_length= 4;
1236 break;
1237 case MYSQL_TYPE_LONGLONG:
1238 case MYSQL_TYPE_DOUBLE:
1239 stmt->params[i].buffer_length= 8;
1240 break;
1241 case MYSQL_TYPE_DATETIME:
1242 case MYSQL_TYPE_TIMESTAMP:
1243 stmt->params[i].buffer_length= 12;
1244 break;
1245 case MYSQL_TYPE_TIME:
1246 stmt->params[i].buffer_length= 13;
1247 break;
1248 case MYSQL_TYPE_DATE:
1249 stmt->params[i].buffer_length= 5;
1250 break;
1251 case MYSQL_TYPE_STRING:
1252 case MYSQL_TYPE_JSON:
1253 case MYSQL_TYPE_VAR_STRING:
1254 case MYSQL_TYPE_BLOB:
1255 case MYSQL_TYPE_TINY_BLOB:
1256 case MYSQL_TYPE_MEDIUM_BLOB:
1257 case MYSQL_TYPE_LONG_BLOB:
1258 case MYSQL_TYPE_DECIMAL:
1259 case MYSQL_TYPE_NEWDECIMAL:
1260 break;
1261 default:
1262 SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
1263 return(1);
1264 break;
1265 }
1266 }
1267 }
1268 stmt->bind_param_done= stmt->send_types_to_server= 1;
1269
1270 CLEAR_CLIENT_STMT_ERROR(stmt);
1271 return(0);
1272 }
1273
mysql_stmt_bind_result(MYSQL_STMT * stmt,MYSQL_BIND * bind)1274 my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
1275 {
1276 uint i;
1277
1278 if (stmt->state < MYSQL_STMT_PREPARED)
1279 {
1280 SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
1281 return(1);
1282 }
1283
1284 if (!stmt->field_count)
1285 {
1286 SET_CLIENT_STMT_ERROR(stmt, CR_NO_STMT_METADATA, SQLSTATE_UNKNOWN, 0);
1287 return(1);
1288 }
1289
1290 if (!bind)
1291 return(1);
1292
1293 /* In case of a stored procedure we don't allocate memory for bind
1294 in mysql_stmt_prepare
1295 */
1296
1297 if (stmt->field_count && !stmt->bind)
1298 {
1299 MA_MEM_ROOT *fields_ma_alloc_root=
1300 &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
1301 if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
1302 {
1303 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1304 return(1);
1305 }
1306 }
1307
1308 memcpy(stmt->bind, bind, sizeof(MYSQL_BIND) * stmt->field_count);
1309
1310 for (i=0; i < stmt->field_count; i++)
1311 {
1312 if (stmt->mysql->methods->db_supported_buffer_type &&
1313 !stmt->mysql->methods->db_supported_buffer_type(bind[i].buffer_type))
1314 {
1315 SET_CLIENT_STMT_ERROR(stmt, CR_UNSUPPORTED_PARAM_TYPE, SQLSTATE_UNKNOWN, 0);
1316 return(1);
1317 }
1318
1319 if (!stmt->bind[i].is_null)
1320 stmt->bind[i].is_null= &stmt->bind[i].is_null_value;
1321 if (!stmt->bind[i].length)
1322 stmt->bind[i].length= &stmt->bind[i].length_value;
1323 if (!stmt->bind[i].error)
1324 stmt->bind[i].error= &stmt->bind[i].error_value;
1325
1326 /* set length values for numeric types */
1327 switch(bind[i].buffer_type) {
1328 case MYSQL_TYPE_NULL:
1329 *stmt->bind[i].length= stmt->bind[i].length_value= 0;
1330 break;
1331 case MYSQL_TYPE_TINY:
1332 *stmt->bind[i].length= stmt->bind[i].length_value= 1;
1333 break;
1334 case MYSQL_TYPE_SHORT:
1335 case MYSQL_TYPE_YEAR:
1336 *stmt->bind[i].length= stmt->bind[i].length_value= 2;
1337 break;
1338 case MYSQL_TYPE_INT24:
1339 case MYSQL_TYPE_LONG:
1340 case MYSQL_TYPE_FLOAT:
1341 *stmt->bind[i].length= stmt->bind[i].length_value= 4;
1342 break;
1343 case MYSQL_TYPE_LONGLONG:
1344 case MYSQL_TYPE_DOUBLE:
1345 *stmt->bind[i].length= stmt->bind[i].length_value= 8;
1346 break;
1347 case MYSQL_TYPE_TIME:
1348 case MYSQL_TYPE_DATE:
1349 case MYSQL_TYPE_DATETIME:
1350 case MYSQL_TYPE_TIMESTAMP:
1351 *stmt->bind[i].length= stmt->bind[i].length_value= sizeof(MYSQL_TIME);
1352 break;
1353 default:
1354 break;
1355 }
1356 }
1357 stmt->bind_result_done= 1;
1358 CLEAR_CLIENT_STMT_ERROR(stmt);
1359
1360 return(0);
1361 }
1362
net_stmt_close(MYSQL_STMT * stmt,my_bool remove)1363 static my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
1364 {
1365 char stmt_id[STMT_ID_LENGTH];
1366 MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
1367
1368 /* clear memory */
1369 ma_free_root(&stmt->result.alloc, MYF(0)); /* allocated in mysql_stmt_store_result */
1370 ma_free_root(&stmt->mem_root,MYF(0));
1371 ma_free_root(fields_ma_alloc_root, MYF(0));
1372
1373 if (stmt->mysql)
1374 {
1375 CLEAR_CLIENT_ERROR(stmt->mysql);
1376
1377 /* remove from stmt list */
1378 if (remove)
1379 stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list);
1380
1381 /* check if all data are fetched */
1382 if (stmt->mysql->status != MYSQL_STATUS_READY)
1383 {
1384 do {
1385 stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
1386 } while(mysql_stmt_more_results(stmt));
1387 stmt->mysql->status= MYSQL_STATUS_READY;
1388 }
1389 if (stmt->state > MYSQL_STMT_INITTED)
1390 {
1391 int4store(stmt_id, stmt->stmt_id);
1392 if (stmt->mysql->methods->db_command(stmt->mysql,COM_STMT_CLOSE, stmt_id,
1393 sizeof(stmt_id), 1, stmt))
1394 {
1395 UPDATE_STMT_ERROR(stmt);
1396 return 1;
1397 }
1398 }
1399 }
1400 return 0;
1401 }
1402
mysql_stmt_close(MYSQL_STMT * stmt)1403 my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
1404 {
1405 my_bool rc= 1;
1406
1407 if (stmt)
1408 {
1409 if (stmt->mysql && stmt->mysql->net.pvio)
1410 mysql_stmt_internal_reset(stmt, 1);
1411
1412 rc= net_stmt_close(stmt, 1);
1413
1414 free(stmt->extension);
1415 free(stmt);
1416 }
1417 return(rc);
1418 }
1419
mysql_stmt_data_seek(MYSQL_STMT * stmt,unsigned long long offset)1420 void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, unsigned long long offset)
1421 {
1422 unsigned long long i= offset;
1423 MYSQL_ROWS *ptr= stmt->result.data;
1424
1425 while(i-- && ptr)
1426 ptr= ptr->next;
1427
1428 stmt->result_cursor= ptr;
1429 stmt->state= MYSQL_STMT_USER_FETCHING;
1430
1431 return;
1432 }
1433
mysql_stmt_errno(MYSQL_STMT * stmt)1434 unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT *stmt)
1435 {
1436 return stmt->last_errno;
1437 }
1438
mysql_stmt_error(MYSQL_STMT * stmt)1439 const char * STDCALL mysql_stmt_error(MYSQL_STMT *stmt)
1440 {
1441 return (const char *)stmt->last_error;
1442 }
1443
mthd_stmt_fetch_row(MYSQL_STMT * stmt,unsigned char ** row)1444 int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row)
1445 {
1446 return stmt->fetch_row_func(stmt, row);
1447 }
1448
mysql_stmt_fetch(MYSQL_STMT * stmt)1449 int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
1450 {
1451 unsigned char *row;
1452 int rc;
1453
1454 if (stmt->state <= MYSQL_STMT_EXECUTED)
1455 {
1456 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
1457 return(1);
1458 }
1459
1460 if (stmt->state < MYSQL_STMT_WAITING_USE_OR_STORE || !stmt->field_count)
1461 {
1462 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
1463 return(1);
1464 } else if (stmt->state== MYSQL_STMT_WAITING_USE_OR_STORE)
1465 {
1466 stmt->default_rset_handler(stmt);
1467 }
1468
1469 if (stmt->state == MYSQL_STMT_FETCH_DONE)
1470 return(MYSQL_NO_DATA);
1471
1472 if ((rc= stmt->mysql->methods->db_stmt_fetch(stmt, &row)))
1473 {
1474 stmt->state= MYSQL_STMT_FETCH_DONE;
1475 stmt->mysql->status= MYSQL_STATUS_READY;
1476 /* to fetch data again, stmt must be executed again */
1477 return(rc);
1478 }
1479
1480 rc= stmt->mysql->methods->db_stmt_fetch_to_bind(stmt, row);
1481
1482 stmt->state= MYSQL_STMT_USER_FETCHING;
1483 CLEAR_CLIENT_ERROR(stmt->mysql);
1484 CLEAR_CLIENT_STMT_ERROR(stmt);
1485 return(rc);
1486 }
1487
mysql_stmt_fetch_column(MYSQL_STMT * stmt,MYSQL_BIND * bind,unsigned int column,unsigned long offset)1488 int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, unsigned int column, unsigned long offset)
1489 {
1490 if (stmt->state < MYSQL_STMT_USER_FETCHING || column >= stmt->field_count ||
1491 stmt->state == MYSQL_STMT_FETCH_DONE) {
1492 SET_CLIENT_STMT_ERROR(stmt, CR_NO_DATA, SQLSTATE_UNKNOWN, 0);
1493 return(1);
1494 }
1495
1496 if (!stmt->bind[column].u.row_ptr)
1497 {
1498 /* we set row_ptr only for columns which contain data, so this must be a NULL column */
1499 if (bind[0].is_null)
1500 *bind[0].is_null= 1;
1501 }
1502 else
1503 {
1504 unsigned char *save_ptr;
1505 if (bind[0].length)
1506 *bind[0].length= *stmt->bind[column].length;
1507 else
1508 bind[0].length= &stmt->bind[column].length_value;
1509 if (bind[0].is_null)
1510 *bind[0].is_null= 0;
1511 else
1512 bind[0].is_null= &bind[0].is_null_value;
1513 if (!bind[0].error)
1514 bind[0].error= &bind[0].error_value;
1515 *bind[0].error= 0;
1516 bind[0].offset= offset;
1517 save_ptr= stmt->bind[column].u.row_ptr;
1518 mysql_ps_fetch_functions[stmt->fields[column].type].func(&bind[0], &stmt->fields[column], &stmt->bind[column].u.row_ptr);
1519 stmt->bind[column].u.row_ptr= save_ptr;
1520 }
1521 return(0);
1522 }
1523
mysql_stmt_field_count(MYSQL_STMT * stmt)1524 unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt)
1525 {
1526 return stmt->field_count;
1527 }
1528
mysql_stmt_free_result(MYSQL_STMT * stmt)1529 my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
1530 {
1531 return madb_reset_stmt(stmt, MADB_RESET_LONGDATA | MADB_RESET_STORED |
1532 MADB_RESET_BUFFER | MADB_RESET_ERROR);
1533 }
1534
mysql_stmt_init(MYSQL * mysql)1535 MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql)
1536 {
1537
1538 MYSQL_STMT *stmt= NULL;
1539
1540 if (!(stmt= (MYSQL_STMT *)calloc(1, sizeof(MYSQL_STMT))) ||
1541 !(stmt->extension= (MADB_STMT_EXTENSION *)calloc(1, sizeof(MADB_STMT_EXTENSION))))
1542 {
1543 free(stmt);
1544 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1545 return(NULL);
1546 }
1547
1548
1549 /* fill mysql's stmt list */
1550 stmt->list.data= stmt;
1551 stmt->mysql= mysql;
1552 stmt->stmt_id= 0;
1553 mysql->stmts= list_add(mysql->stmts, &stmt->list);
1554
1555
1556 /* clear flags */
1557 strcpy(stmt->sqlstate, "00000");
1558
1559 stmt->state= MYSQL_STMT_INITTED;
1560
1561 /* set default */
1562 stmt->prefetch_rows= 1;
1563
1564 ma_init_alloc_root(&stmt->mem_root, 2048, 2048);
1565 ma_init_alloc_root(&stmt->result.alloc, 4096, 4096);
1566 ma_init_alloc_root(&((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root, 2048, 2048);
1567
1568 return(stmt);
1569 }
1570
mthd_stmt_read_prepare_response(MYSQL_STMT * stmt)1571 my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt)
1572 {
1573 ulong packet_length;
1574 uchar *p;
1575
1576 if ((packet_length= ma_net_safe_read(stmt->mysql)) == packet_error)
1577 return(1);
1578
1579 p= (uchar *)stmt->mysql->net.read_pos;
1580
1581 if (0xFF == p[0]) /* Error occurred */
1582 {
1583 return(1);
1584 }
1585
1586 p++;
1587 stmt->stmt_id= uint4korr(p);
1588 p+= 4;
1589 stmt->field_count= uint2korr(p);
1590 p+= 2;
1591 stmt->param_count= uint2korr(p);
1592 p+= 2;
1593
1594 /* filler */
1595 p++;
1596 /* for backward compatibility we also update mysql->warning_count */
1597 stmt->mysql->warning_count= stmt->upsert_status.warning_count= uint2korr(p);
1598 return(0);
1599 }
1600
mthd_stmt_get_param_metadata(MYSQL_STMT * stmt)1601 my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt)
1602 {
1603 MYSQL_DATA *result;
1604
1605 if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0,
1606 7 + ma_extended_type_info_rows(stmt->mysql))))
1607 return(1);
1608
1609 free_rows(result);
1610 return(0);
1611 }
1612
mthd_stmt_get_result_metadata(MYSQL_STMT * stmt)1613 my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt)
1614 {
1615 MYSQL_DATA *result;
1616 MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
1617
1618 if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0,
1619 7 + ma_extended_type_info_rows(stmt->mysql))))
1620 return(1);
1621 if (!(stmt->fields= unpack_fields(stmt->mysql, result, fields_ma_alloc_root,
1622 stmt->field_count, 0)))
1623 return(1);
1624 return(0);
1625 }
1626
mysql_stmt_warning_count(MYSQL_STMT * stmt)1627 int STDCALL mysql_stmt_warning_count(MYSQL_STMT *stmt)
1628 {
1629 return stmt->upsert_status.warning_count;
1630 }
1631
mysql_stmt_prepare(MYSQL_STMT * stmt,const char * query,unsigned long length)1632 int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)
1633 {
1634 MYSQL *mysql= stmt->mysql;
1635 int rc= 1;
1636 my_bool is_multi= 0;
1637
1638 if (!stmt->mysql)
1639 {
1640 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
1641 return(1);
1642 }
1643
1644 if (length == (unsigned long) -1)
1645 length= (unsigned long)strlen(query);
1646
1647 /* clear flags */
1648 CLEAR_CLIENT_STMT_ERROR(stmt);
1649 CLEAR_CLIENT_ERROR(stmt->mysql);
1650 stmt->upsert_status.affected_rows= mysql->affected_rows= (unsigned long long) ~0;
1651
1652 /* check if we have to clear results */
1653 if (stmt->state > MYSQL_STMT_INITTED)
1654 {
1655 char stmt_id[STMT_ID_LENGTH];
1656 is_multi= (mysql->net.extension->multi_status > COM_MULTI_OFF);
1657 /* We need to semi-close the prepared statement:
1658 reset stmt and free all buffers and close the statement
1659 on server side. Statement handle will get a new stmt_id */
1660
1661 if (!is_multi)
1662 ma_multi_command(mysql, COM_MULTI_ENABLED);
1663
1664 if (mysql_stmt_internal_reset(stmt, 1))
1665 goto fail;
1666
1667 ma_free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
1668 ma_free_root(&((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root, MYF(0));
1669
1670 stmt->param_count= 0;
1671 stmt->field_count= 0;
1672 stmt->params= 0;
1673
1674 int4store(stmt_id, stmt->stmt_id);
1675 if (mysql->methods->db_command(mysql, COM_STMT_CLOSE, stmt_id,
1676 sizeof(stmt_id), 1, stmt))
1677 goto fail;
1678 }
1679 if (mysql->methods->db_command(mysql, COM_STMT_PREPARE, query, length, 1, stmt))
1680 goto fail;
1681
1682 if (!is_multi && mysql->net.extension->multi_status == COM_MULTI_ENABLED)
1683 ma_multi_command(mysql, COM_MULTI_END);
1684
1685 if (mysql->net.extension->multi_status > COM_MULTI_OFF)
1686 return 0;
1687
1688 if (mysql->methods->db_read_prepare_response &&
1689 mysql->methods->db_read_prepare_response(stmt))
1690 goto fail;
1691
1692 /* metadata not supported yet */
1693
1694 if (stmt->param_count &&
1695 stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
1696 {
1697 goto fail;
1698 }
1699
1700 /* allocated bind buffer for parameters */
1701 if (stmt->field_count &&
1702 stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
1703 {
1704 goto fail;
1705 }
1706 if (stmt->param_count)
1707 {
1708 if (stmt->prebind_params)
1709 {
1710 if (stmt->prebind_params != stmt->param_count)
1711 {
1712 SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
1713 goto fail;
1714 }
1715 } else {
1716 if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
1717 {
1718 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1719 goto fail;
1720 }
1721 memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
1722 }
1723 }
1724 /* allocated bind buffer for result */
1725 if (stmt->field_count)
1726 {
1727 MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
1728 if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
1729 {
1730 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1731 goto fail;
1732 }
1733 memset(stmt->bind, 0, sizeof(MYSQL_BIND) * stmt->field_count);
1734 }
1735 stmt->state = MYSQL_STMT_PREPARED;
1736 return(0);
1737
1738 fail:
1739 stmt->state= MYSQL_STMT_INITTED;
1740 UPDATE_STMT_ERROR(stmt);
1741 return(rc);
1742 }
1743
mysql_stmt_store_result(MYSQL_STMT * stmt)1744 int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
1745 {
1746 unsigned int last_server_status;
1747
1748 if (!stmt->mysql)
1749 {
1750 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
1751 return(1);
1752 }
1753
1754 if (!stmt->field_count)
1755 return(0);
1756
1757 /* test_pure_coverage requires checking of error_no */
1758 if (stmt->last_errno)
1759 return(1);
1760
1761 if (stmt->state < MYSQL_STMT_EXECUTED)
1762 {
1763 SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
1764 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
1765 return(1);
1766 }
1767
1768 last_server_status= stmt->mysql->server_status;
1769
1770 /* if stmt is a cursor, we need to tell server to send all rows */
1771 if (stmt->cursor_exists && stmt->mysql->status == MYSQL_STATUS_READY)
1772 {
1773 char buff[STMT_ID_LENGTH + 4];
1774 int4store(buff, stmt->stmt_id);
1775 int4store(buff + STMT_ID_LENGTH, (int)~0);
1776
1777 if (stmt->mysql->methods->db_command(stmt->mysql, COM_STMT_FETCH,
1778 buff, sizeof(buff), 1, stmt))
1779 {
1780 UPDATE_STMT_ERROR(stmt);
1781 return(1);
1782 }
1783 }
1784 else if (stmt->mysql->status != MYSQL_STATUS_STMT_RESULT)
1785 {
1786 SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
1787 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
1788 return(1);
1789 }
1790
1791 if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
1792 {
1793 /* error during read - reset stmt->data */
1794 ma_free_root(&stmt->result.alloc, 0);
1795 stmt->result.data= NULL;
1796 stmt->result.rows= 0;
1797 stmt->mysql->status= MYSQL_STATUS_READY;
1798 return(1);
1799 }
1800
1801 /* workaround for MDEV 6304:
1802 more results not set if the resultset has
1803 SERVER_PS_OUT_PARAMS set
1804 */
1805 if (last_server_status & SERVER_PS_OUT_PARAMS &&
1806 !(stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST))
1807 stmt->mysql->server_status|= SERVER_MORE_RESULTS_EXIST;
1808
1809 stmt->result_cursor= stmt->result.data;
1810 stmt->fetch_row_func= stmt_buffered_fetch;
1811 stmt->mysql->status= MYSQL_STATUS_READY;
1812
1813 if (!stmt->result.rows)
1814 stmt->state= MYSQL_STMT_FETCH_DONE;
1815 else
1816 stmt->state= MYSQL_STMT_USE_OR_STORE_CALLED;
1817
1818 /* set affected rows: see bug 2247 */
1819 stmt->upsert_status.affected_rows= stmt->result.rows;
1820 stmt->mysql->affected_rows= stmt->result.rows;
1821
1822 return(0);
1823 }
1824
madb_alloc_stmt_fields(MYSQL_STMT * stmt)1825 static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
1826 {
1827 uint i;
1828 MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
1829
1830 if (stmt->mysql->field_count)
1831 {
1832 ma_free_root(fields_ma_alloc_root, MYF(0));
1833 if (!(stmt->fields= (MYSQL_FIELD *)ma_alloc_root(fields_ma_alloc_root,
1834 sizeof(MYSQL_FIELD) * stmt->mysql->field_count)))
1835 {
1836 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1837 return(1);
1838 }
1839 stmt->field_count= stmt->mysql->field_count;
1840
1841 for (i=0; i < stmt->field_count; i++)
1842 {
1843 if (stmt->mysql->fields[i].db)
1844 stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].db);
1845 if (stmt->mysql->fields[i].table)
1846 stmt->fields[i].table= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].table);
1847 if (stmt->mysql->fields[i].org_table)
1848 stmt->fields[i].org_table= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].org_table);
1849 if (stmt->mysql->fields[i].name)
1850 stmt->fields[i].name= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].name);
1851 if (stmt->mysql->fields[i].org_name)
1852 stmt->fields[i].org_name= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].org_name);
1853 if (stmt->mysql->fields[i].catalog)
1854 stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].catalog);
1855 stmt->fields[i].def= stmt->mysql->fields[i].def ? ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].def) : NULL;
1856 stmt->fields[i].type= stmt->mysql->fields[i].type;
1857 stmt->fields[i].length= stmt->mysql->fields[i].length;
1858 stmt->fields[i].flags= stmt->mysql->fields[i].flags;
1859 stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
1860 stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
1861 stmt->fields[i].max_length= stmt->mysql->fields[i].max_length;
1862 stmt->fields[i].extension=
1863 stmt->mysql->fields[i].extension ?
1864 ma_field_extension_deep_dup(fields_ma_alloc_root,
1865 stmt->mysql->fields[i].extension) :
1866 NULL;
1867 }
1868 if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
1869 {
1870 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1871 return(1);
1872 }
1873 memset(stmt->bind, 0, stmt->field_count * sizeof(MYSQL_BIND));
1874 stmt->bind_result_done= 0;
1875 }
1876 return(0);
1877 }
1878
stmt_read_execute_response(MYSQL_STMT * stmt)1879 int stmt_read_execute_response(MYSQL_STMT *stmt)
1880 {
1881 MYSQL *mysql= stmt->mysql;
1882 int ret;
1883
1884 if (!mysql)
1885 return(1);
1886
1887 ret= test((mysql->methods->db_read_stmt_result &&
1888 mysql->methods->db_read_stmt_result(mysql)));
1889 /* if a reconnect occurred, our connection handle is invalid */
1890 if (!stmt->mysql)
1891 return(1);
1892
1893 /* update affected rows, also if an error occurred */
1894 stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
1895
1896 if (ret)
1897 {
1898 SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate,
1899 mysql->net.last_error);
1900 /* if mariadb_stmt_execute_direct was used, we need to send the number
1901 of parameters to the specified prebinded value to prevent possible
1902 memory overrun */
1903 if (stmt->prebind_params)
1904 stmt->param_count= stmt->prebind_params;
1905 stmt->state= MYSQL_STMT_PREPARED;
1906 return(1);
1907 }
1908 stmt->upsert_status.last_insert_id= mysql->insert_id;
1909 stmt->upsert_status.server_status= mysql->server_status;
1910 stmt->upsert_status.warning_count= mysql->warning_count;
1911
1912 CLEAR_CLIENT_ERROR(mysql);
1913 CLEAR_CLIENT_STMT_ERROR(stmt);
1914
1915 stmt->execute_count++;
1916 stmt->send_types_to_server= 0;
1917
1918 stmt->state= MYSQL_STMT_EXECUTED;
1919
1920 if (mysql->field_count)
1921 {
1922 if (!stmt->field_count ||
1923 mysql->server_status & SERVER_MORE_RESULTS_EXIST) /* fix for ps_bug: test_misc */
1924 {
1925 MA_MEM_ROOT *fields_ma_alloc_root=
1926 &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
1927 uint i;
1928
1929 ma_free_root(fields_ma_alloc_root, MYF(0));
1930 if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root,
1931 sizeof(MYSQL_BIND) * mysql->field_count)) ||
1932 !(stmt->fields= (MYSQL_FIELD *)ma_alloc_root(fields_ma_alloc_root,
1933 sizeof(MYSQL_FIELD) * mysql->field_count)))
1934 {
1935 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1936 return(1);
1937 }
1938 memset(stmt->bind, 0, sizeof(MYSQL_BIND) * mysql->field_count);
1939 stmt->field_count= mysql->field_count;
1940
1941 for (i=0; i < stmt->field_count; i++)
1942 {
1943 memcpy(&stmt->fields[i], &mysql->fields[i], sizeof(MYSQL_FIELD));
1944
1945 /* since all pointers will be incorrect if another statement will
1946 be executed, so we need to allocate memory and copy the
1947 information */
1948 if (mysql->fields[i].db)
1949 stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].db);
1950 if (mysql->fields[i].table)
1951 stmt->fields[i].table= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].table);
1952 if (mysql->fields[i].org_table)
1953 stmt->fields[i].org_table= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].org_table);
1954 if (mysql->fields[i].name)
1955 stmt->fields[i].name= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].name);
1956 if (mysql->fields[i].org_name)
1957 stmt->fields[i].org_name= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].org_name);
1958 if (mysql->fields[i].catalog)
1959 stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].catalog);
1960 if (mysql->fields[i].def)
1961 stmt->fields[i].def= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def);
1962 stmt->fields[i].extension=
1963 mysql->fields[i].extension ?
1964 ma_field_extension_deep_dup(fields_ma_alloc_root,
1965 mysql->fields[i].extension) :
1966 NULL;
1967 }
1968 }
1969
1970 if ((stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) &&
1971 (stmt->flags & CURSOR_TYPE_READ_ONLY))
1972 {
1973 stmt->cursor_exists = TRUE;
1974 mysql->status = MYSQL_STATUS_READY;
1975
1976 /* Only cursor read */
1977 stmt->default_rset_handler = _mysql_stmt_use_result;
1978
1979 } else if (stmt->flags & CURSOR_TYPE_READ_ONLY &&
1980 !(stmt->upsert_status.server_status & SERVER_MORE_RESULTS_EXIST))
1981 {
1982 /*
1983 We have asked for CURSOR but got no cursor, because the condition
1984 above is not fulfilled. Then...
1985 This is a single-row result set, a result set with no rows, EXPLAIN,
1986 SHOW VARIABLES, or some other command which either a) bypasses the
1987 cursors framework in the server and writes rows directly to the
1988 network or b) is more efficient if all (few) result set rows are
1989 precached on client and server's resources are freed.
1990 */
1991
1992 /* preferred is buffered read */
1993 if (mysql_stmt_store_result(stmt))
1994 return 1;
1995 stmt->mysql->status= MYSQL_STATUS_STMT_RESULT;
1996 } else
1997 {
1998 /* preferred is unbuffered read */
1999 stmt->default_rset_handler = _mysql_stmt_use_result;
2000 stmt->mysql->status= MYSQL_STATUS_STMT_RESULT;
2001 }
2002 stmt->state= MYSQL_STMT_WAITING_USE_OR_STORE;
2003 /* in certain cases parameter types can change: For example see bug
2004 4026 (SELECT ?), so we need to update field information */
2005 if (mysql->field_count == stmt->field_count)
2006 {
2007 uint i;
2008 for (i=0; i < stmt->field_count; i++)
2009 {
2010 stmt->fields[i].type= mysql->fields[i].type;
2011 stmt->fields[i].length= mysql->fields[i].length;
2012 stmt->fields[i].flags= mysql->fields[i].flags;
2013 stmt->fields[i].decimals= mysql->fields[i].decimals;
2014 stmt->fields[i].charsetnr= mysql->fields[i].charsetnr;
2015 stmt->fields[i].max_length= mysql->fields[i].max_length;
2016 }
2017 } else
2018 {
2019 /* table was altered, see test_wl4166_2 */
2020 SET_CLIENT_STMT_ERROR(stmt, CR_NEW_STMT_METADATA, SQLSTATE_UNKNOWN, 0);
2021 return(1);
2022 }
2023 }
2024 return(0);
2025 }
2026
mysql_stmt_execute(MYSQL_STMT * stmt)2027 int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
2028 {
2029 MYSQL *mysql= stmt->mysql;
2030 char *request;
2031 int ret;
2032 size_t request_len= 0;
2033
2034 if (!stmt->mysql)
2035 {
2036 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
2037 return(1);
2038 }
2039
2040 if (stmt->state < MYSQL_STMT_PREPARED)
2041 {
2042 SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2043 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2044 return(1);
2045 }
2046
2047 if (stmt->param_count && !stmt->bind_param_done)
2048 {
2049 SET_CLIENT_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, SQLSTATE_UNKNOWN, 0);
2050 return(1);
2051 }
2052
2053 if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
2054 {
2055 stmt->default_rset_handler = _mysql_stmt_use_result;
2056 stmt->default_rset_handler(stmt);
2057 }
2058 if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
2059 {
2060 if (!stmt->cursor_exists)
2061 do {
2062 stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
2063 } while(mysql_stmt_more_results(stmt));
2064 stmt->state= MYSQL_STMT_PREPARED;
2065 stmt->mysql->status= MYSQL_STATUS_READY;
2066 }
2067
2068 /* clear data, in case mysql_stmt_store_result was called */
2069 if (stmt->result.data)
2070 {
2071 ma_free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
2072 stmt->result_cursor= stmt->result.data= 0;
2073 }
2074 /* CONC-344: set row count to zero */
2075 stmt->result.rows= 0;
2076 if (stmt->array_size > 0)
2077 request= (char *)mysql_stmt_execute_generate_bulk_request(stmt, &request_len);
2078 else
2079 request= (char *)mysql_stmt_execute_generate_simple_request(stmt, &request_len);
2080
2081 if (!request)
2082 return 1;
2083
2084 ret= stmt->mysql->methods->db_command(mysql,
2085 stmt->array_size > 0 ? COM_STMT_BULK_EXECUTE : COM_STMT_EXECUTE,
2086 request, request_len, 1, stmt);
2087 if (request)
2088 free(request);
2089
2090 if (ret)
2091 {
2092 UPDATE_STMT_ERROR(stmt);
2093 return(1);
2094 }
2095
2096 if (mysql->net.extension->multi_status > COM_MULTI_OFF)
2097 return(0);
2098
2099 return(stmt_read_execute_response(stmt));
2100 }
2101
madb_reset_stmt(MYSQL_STMT * stmt,unsigned int flags)2102 static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
2103 {
2104 MYSQL *mysql= stmt->mysql;
2105 my_bool ret= 0;
2106
2107 if (!stmt->mysql)
2108 {
2109 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
2110 return(1);
2111 }
2112
2113 /* clear error */
2114 if (flags & MADB_RESET_ERROR)
2115 {
2116 CLEAR_CLIENT_ERROR(stmt->mysql);
2117 CLEAR_CLIENT_STMT_ERROR(stmt);
2118 }
2119
2120 if (stmt->stmt_id)
2121 {
2122 /* free buffered resultset, previously allocated
2123 * by mysql_stmt_store_result
2124 */
2125 if (flags & MADB_RESET_STORED &&
2126 stmt->result_cursor)
2127 {
2128 ma_free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
2129 stmt->result.data= NULL;
2130 stmt->result.rows= 0;
2131 stmt->result_cursor= NULL;
2132 stmt->mysql->status= MYSQL_STATUS_READY;
2133 stmt->state= MYSQL_STMT_FETCH_DONE;
2134 }
2135
2136 /* if there is a pending result set, we will flush it */
2137 if (flags & MADB_RESET_BUFFER)
2138 {
2139 if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
2140 {
2141 stmt->default_rset_handler(stmt);
2142 stmt->state = MYSQL_STMT_USER_FETCHING;
2143 }
2144
2145 if (stmt->mysql->status!= MYSQL_STATUS_READY && stmt->field_count)
2146 {
2147 mysql->methods->db_stmt_flush_unbuffered(stmt);
2148 mysql->status= MYSQL_STATUS_READY;
2149 }
2150 }
2151
2152 if (flags & MADB_RESET_SERVER)
2153 {
2154 /* reset statement on server side */
2155 if (stmt->mysql && stmt->mysql->status == MYSQL_STATUS_READY &&
2156 stmt->mysql->net.pvio)
2157 {
2158 unsigned char cmd_buf[STMT_ID_LENGTH];
2159 int4store(cmd_buf, stmt->stmt_id);
2160 if ((ret= stmt->mysql->methods->db_command(mysql,COM_STMT_RESET, (char *)cmd_buf,
2161 sizeof(cmd_buf), 0, stmt)))
2162 {
2163 UPDATE_STMT_ERROR(stmt);
2164 return(ret);
2165 }
2166 }
2167 }
2168
2169 if (flags & MADB_RESET_LONGDATA)
2170 {
2171 if (stmt->params)
2172 {
2173 ulonglong i;
2174 for (i=0; i < stmt->param_count; i++)
2175 if (stmt->params[i].long_data_used)
2176 stmt->params[i].long_data_used= 0;
2177 }
2178 }
2179
2180 }
2181 return(ret);
2182 }
2183
mysql_stmt_internal_reset(MYSQL_STMT * stmt,my_bool is_close)2184 static my_bool mysql_stmt_internal_reset(MYSQL_STMT *stmt, my_bool is_close)
2185 {
2186 MYSQL *mysql= stmt->mysql;
2187 my_bool ret= 1;
2188 unsigned int flags= MADB_RESET_LONGDATA | MADB_RESET_BUFFER | MADB_RESET_ERROR;
2189
2190 if (!mysql)
2191 {
2192 /* connection could be invalid, e.g. after mysql_stmt_close or failed reconnect
2193 attempt (see bug CONC-97) */
2194 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
2195 return(1);
2196 }
2197
2198 if (stmt->state >= MYSQL_STMT_USER_FETCHING &&
2199 stmt->fetch_row_func == stmt_unbuffered_fetch)
2200 flags|= MADB_RESET_BUFFER;
2201
2202 ret= madb_reset_stmt(stmt, flags);
2203
2204 if (stmt->stmt_id)
2205 {
2206 if ((stmt->state > MYSQL_STMT_EXECUTED &&
2207 stmt->mysql->status != MYSQL_STATUS_READY) ||
2208 stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST)
2209 {
2210 /* flush any pending (multiple) result sets */
2211 if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
2212 {
2213 stmt->default_rset_handler(stmt);
2214 stmt->state = MYSQL_STMT_USER_FETCHING;
2215 }
2216
2217 if (stmt->field_count)
2218 {
2219 while (mysql_stmt_next_result(stmt) == 0);
2220 stmt->mysql->status= MYSQL_STATUS_READY;
2221 }
2222 }
2223 if (!is_close)
2224 ret= madb_reset_stmt(stmt, MADB_RESET_SERVER);
2225 stmt->state= MYSQL_STMT_PREPARED;
2226 }
2227 else
2228 stmt->state= MYSQL_STMT_INITTED;
2229
2230 stmt->upsert_status.affected_rows= mysql->affected_rows;
2231 stmt->upsert_status.last_insert_id= mysql->insert_id;
2232 stmt->upsert_status.server_status= mysql->server_status;
2233 stmt->upsert_status.warning_count= mysql->warning_count;
2234 mysql->status= MYSQL_STATUS_READY;
2235
2236 return(ret);
2237 }
2238
mysql_stmt_result_metadata(MYSQL_STMT * stmt)2239 MYSQL_RES * STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt)
2240 {
2241 MYSQL_RES *res;
2242
2243 if (!stmt->field_count)
2244 return(NULL);
2245
2246 /* aloocate result set structutr and copy stmt information */
2247 if (!(res= (MYSQL_RES *)calloc(1, sizeof(MYSQL_RES))))
2248 {
2249 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2250 return(NULL);
2251 }
2252
2253 res->eof= 1;
2254 res->fields= stmt->fields;
2255 res->field_count= stmt->field_count;
2256 return(res);
2257 }
2258
mysql_stmt_reset(MYSQL_STMT * stmt)2259 my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
2260 {
2261 if (stmt->stmt_id > 0 &&
2262 stmt->stmt_id != (unsigned long) -1)
2263 return mysql_stmt_internal_reset(stmt, 0);
2264 return 0;
2265 }
2266
mysql_stmt_sqlstate(MYSQL_STMT * stmt)2267 const char * STDCALL mysql_stmt_sqlstate(MYSQL_STMT *stmt)
2268 {
2269 return stmt->sqlstate;
2270 }
2271
mysql_stmt_row_tell(MYSQL_STMT * stmt)2272 MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt)
2273 {
2274 return(stmt->result_cursor);
2275 }
2276
mysql_stmt_param_count(MYSQL_STMT * stmt)2277 unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT *stmt)
2278 {
2279 return stmt->param_count;
2280 }
2281
mysql_stmt_row_seek(MYSQL_STMT * stmt,MYSQL_ROW_OFFSET new_row)2282 MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET new_row)
2283 {
2284 MYSQL_ROW_OFFSET old_row; /* for returning old position */
2285
2286 old_row= stmt->result_cursor;
2287 stmt->result_cursor= new_row;
2288
2289 return(old_row);
2290 }
2291
mysql_stmt_send_long_data(MYSQL_STMT * stmt,uint param_number,const char * data,unsigned long length)2292 my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
2293 const char *data, unsigned long length)
2294 {
2295 CLEAR_CLIENT_ERROR(stmt->mysql);
2296 CLEAR_CLIENT_STMT_ERROR(stmt);
2297
2298 if (stmt->state < MYSQL_STMT_PREPARED || !stmt->params)
2299 {
2300 SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
2301 return(1);
2302 }
2303
2304 if (param_number >= stmt->param_count)
2305 {
2306 SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
2307 return(1);
2308 }
2309
2310 if (length || !stmt->params[param_number].long_data_used)
2311 {
2312 int ret;
2313 size_t packet_len= STMT_ID_LENGTH + 2 + length;
2314 uchar *cmd_buff= (uchar *)calloc(1, packet_len);
2315 int4store(cmd_buff, stmt->stmt_id);
2316 int2store(cmd_buff + STMT_ID_LENGTH, param_number);
2317 memcpy(cmd_buff + STMT_ID_LENGTH + 2, data, length);
2318 stmt->params[param_number].long_data_used= 1;
2319 ret= stmt->mysql->methods->db_command(stmt->mysql, COM_STMT_SEND_LONG_DATA,
2320 (char *)cmd_buff, packet_len, 1, stmt);
2321 if (ret)
2322 UPDATE_STMT_ERROR(stmt);
2323 free(cmd_buff);
2324 return(ret);
2325 }
2326 return(0);
2327 }
2328
mysql_stmt_insert_id(MYSQL_STMT * stmt)2329 unsigned long long STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt)
2330 {
2331 return stmt->upsert_status.last_insert_id;
2332 }
2333
mysql_stmt_num_rows(MYSQL_STMT * stmt)2334 unsigned long long STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
2335 {
2336 return stmt->result.rows;
2337 }
2338
mysql_stmt_param_metadata(MYSQL_STMT * stmt)2339 MYSQL_RES* STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt __attribute__((unused)))
2340 {
2341 /* server doesn't deliver any information yet,
2342 so we just return NULL
2343 */
2344 return(NULL);
2345 }
2346
mysql_stmt_more_results(MYSQL_STMT * stmt)2347 my_bool STDCALL mysql_stmt_more_results(MYSQL_STMT *stmt)
2348 {
2349 /* MDEV 4604: Server doesn't set MORE_RESULT flag for
2350 OutParam result set, so we need to check
2351 for SERVER_MORE_RESULTS_EXIST and for
2352 SERVER_PS_OUT_PARAMS)
2353 */
2354 return (stmt &&
2355 stmt->mysql &&
2356 ((stmt->mysql->server_status & SERVER_MORE_RESULTS_EXIST) ||
2357 (stmt->mysql->server_status & SERVER_PS_OUT_PARAMS)));
2358 }
2359
mysql_stmt_next_result(MYSQL_STMT * stmt)2360 int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
2361 {
2362 int rc= 0;
2363
2364 if (!stmt->mysql)
2365 {
2366 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
2367 return(1);
2368 }
2369
2370 if (stmt->state < MYSQL_STMT_EXECUTED)
2371 {
2372 SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2373 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2374 return(1);
2375 }
2376
2377 if (!mysql_stmt_more_results(stmt))
2378 return(-1);
2379
2380 if (stmt->state > MYSQL_STMT_EXECUTED &&
2381 stmt->state < MYSQL_STMT_FETCH_DONE)
2382 madb_reset_stmt(stmt, MADB_RESET_ERROR | MADB_RESET_BUFFER | MADB_RESET_LONGDATA);
2383 stmt->state= MYSQL_STMT_WAITING_USE_OR_STORE;
2384
2385 if (mysql_next_result(stmt->mysql))
2386 {
2387 stmt->state= MYSQL_STMT_FETCH_DONE;
2388 SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate,
2389 stmt->mysql->net.last_error);
2390 return(1);
2391 }
2392
2393 if (stmt->mysql->status == MYSQL_STATUS_GET_RESULT)
2394 stmt->mysql->status= MYSQL_STATUS_STMT_RESULT;
2395
2396 if (stmt->mysql->field_count)
2397 rc= madb_alloc_stmt_fields(stmt);
2398 else
2399 {
2400 stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;
2401 stmt->upsert_status.last_insert_id= stmt->mysql->insert_id;
2402 stmt->upsert_status.server_status= stmt->mysql->server_status;
2403 stmt->upsert_status.warning_count= stmt->mysql->warning_count;
2404 }
2405
2406 stmt->field_count= stmt->mysql->field_count;
2407 stmt->result.rows= 0;
2408
2409 return(rc);
2410 }
2411
mariadb_stmt_execute_direct(MYSQL_STMT * stmt,const char * stmt_str,size_t length)2412 int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
2413 const char *stmt_str,
2414 size_t length)
2415 {
2416 MYSQL *mysql;
2417 my_bool emulate_cmd;
2418 my_bool clear_result= 0;
2419
2420 if (!stmt)
2421 return 1;
2422
2423 mysql= stmt->mysql;
2424 if (!mysql)
2425 {
2426 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
2427 return 1;
2428 }
2429
2430 emulate_cmd= !(!(stmt->mysql->server_capabilities & CLIENT_MYSQL) &&
2431 (stmt->mysql->extension->mariadb_server_capabilities &
2432 (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))) || mysql->net.compress;
2433
2434 /* Server versions < 10.2 don't support execute_direct, so we need to
2435 emulate it */
2436 if (emulate_cmd)
2437 {
2438 int rc;
2439
2440 /* avoid sending close + prepare in 2 packets */
2441 if ((rc= mysql_stmt_prepare(stmt, stmt_str, (unsigned long)length)))
2442 return rc;
2443 return mysql_stmt_execute(stmt);
2444 }
2445
2446 if (ma_multi_command(mysql, COM_MULTI_ENABLED))
2447 {
2448 SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2449 return 1;
2450 }
2451
2452 if (length == (size_t) -1)
2453 length= strlen(stmt_str);
2454
2455 /* clear flags */
2456 CLEAR_CLIENT_STMT_ERROR(stmt);
2457 CLEAR_CLIENT_ERROR(stmt->mysql);
2458 stmt->upsert_status.affected_rows= mysql->affected_rows= (unsigned long long) ~0;
2459
2460 /* check if we have to clear results */
2461 if (stmt->state > MYSQL_STMT_INITTED)
2462 {
2463 /* We need to semi-close the prepared statement:
2464 reset stmt and free all buffers and close the statement
2465 on server side. Statement handle will get a new stmt_id */
2466 char stmt_id[STMT_ID_LENGTH];
2467
2468 if (mysql_stmt_internal_reset(stmt, 1))
2469 goto fail;
2470
2471 ma_free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
2472 ma_free_root(&((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root, MYF(0));
2473 stmt->field_count= 0;
2474 stmt->param_count= 0;
2475 stmt->params= 0;
2476
2477 int4store(stmt_id, stmt->stmt_id);
2478 if (mysql->methods->db_command(mysql, COM_STMT_CLOSE, stmt_id,
2479 sizeof(stmt_id), 1, stmt))
2480 goto fail;
2481 }
2482 stmt->stmt_id= -1;
2483 if (mysql->methods->db_command(mysql, COM_STMT_PREPARE, stmt_str, length, 1, stmt))
2484 goto fail;
2485
2486 /* in case prepare fails, we need to clear the result package from execute, which
2487 is always an error packet (invalid statement id) */
2488 clear_result= 1;
2489
2490 stmt->state= MYSQL_STMT_PREPARED;
2491 /* Since we can't determine stmt_id here, we need to set it to -1, so server will know that the
2492 * execute command belongs to previous prepare */
2493 stmt->stmt_id= -1;
2494 if (mysql_stmt_execute(stmt))
2495 goto fail;
2496
2497 /* flush multi buffer */
2498 if (ma_multi_command(mysql, COM_MULTI_END))
2499 goto fail;
2500
2501 /* read prepare response */
2502 if (mysql->methods->db_read_prepare_response &&
2503 mysql->methods->db_read_prepare_response(stmt))
2504 goto fail;
2505
2506 clear_result= 0;
2507
2508 /* metadata not supported yet */
2509
2510 if (stmt->param_count &&
2511 stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
2512 {
2513 goto fail;
2514 }
2515
2516 /* allocated bind buffer for parameters */
2517 if (stmt->field_count &&
2518 stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
2519 {
2520 goto fail;
2521 }
2522
2523 /* allocated bind buffer for result */
2524 if (stmt->field_count)
2525 {
2526 MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
2527 if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
2528 {
2529 SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2530 goto fail;
2531 }
2532 memset(stmt->bind, 0, sizeof(MYSQL_BIND) * stmt->field_count);
2533 }
2534 stmt->state = MYSQL_STMT_PREPARED;
2535
2536 /* read execute response packet */
2537 return stmt_read_execute_response(stmt);
2538 fail:
2539 /* check if we need to set error message */
2540 if (!mysql_stmt_errno(stmt))
2541 UPDATE_STMT_ERROR(stmt);
2542 if (clear_result) {
2543 do {
2544 stmt->mysql->methods->db_stmt_flush_unbuffered(stmt);
2545 } while(mysql_stmt_more_results(stmt));
2546 }
2547 stmt->state= MYSQL_STMT_INITTED;
2548 return 1;
2549 }
2550
mariadb_stmt_fetch_fields(MYSQL_STMT * stmt)2551 MYSQL_FIELD * STDCALL mariadb_stmt_fetch_fields(MYSQL_STMT *stmt)
2552 {
2553 if (stmt)
2554 return stmt->fields;
2555 return NULL;
2556 }
2557