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