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