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= ¤t->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