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