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