PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd_ps.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 859 1069 80.4 %
Date: 2014-04-18 Functions: 45 52 86.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 5                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2013 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Georg Richter <georg@mysql.com>                             |
      16             :   |          Andrey Hristov <andrey@mysql.com>                           |
      17             :   |          Ulf Wendel <uwendel@mysql.com>                              |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : #include "php.h"
      23             : #include "mysqlnd.h"
      24             : #include "mysqlnd_wireprotocol.h"
      25             : #include "mysqlnd_priv.h"
      26             : #include "mysqlnd_result.h"
      27             : #include "mysqlnd_result_meta.h"
      28             : #include "mysqlnd_statistics.h"
      29             : #include "mysqlnd_debug.h"
      30             : #include "mysqlnd_block_alloc.h"
      31             : 
      32             : 
      33             : #define MYSQLND_SILENT
      34             : 
      35             : 
      36             : const char * const mysqlnd_not_bound_as_blob = "Can't send long data for non-string/non-binary data types";
      37             : const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
      38             : 
      39             : static struct st_mysqlnd_stmt_methods *mysqlnd_stmt_methods;
      40             : 
      41             : /* Exported by mysqlnd_ps_codec.c */
      42             : enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC);
      43             : 
      44             : enum_func_status mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param,
      45             :                                                                                                 unsigned int flags,
      46             :                                                                                                 zend_bool *fetched_anything TSRMLS_DC);
      47             : 
      48             : enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param,
      49             :                                                                                            unsigned int flags,
      50             :                                                                                            zend_bool *fetched_anything TSRMLS_DC);
      51             : 
      52             : static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
      53             : static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC);
      54             : 
      55             : /* {{{ mysqlnd_stmt::store_result */
      56             : static MYSQLND_RES *
      57         475 : MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
      58             : {
      59         475 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
      60             :         enum_func_status ret;
      61             :         MYSQLND * conn;
      62             :         MYSQLND_RES * result;
      63         475 :         zend_bool to_cache = FALSE;
      64             : 
      65         475 :         DBG_ENTER("mysqlnd_stmt::store_result");
      66         475 :         if (!stmt || !stmt->conn || !stmt->result) {
      67           0 :                 DBG_RETURN(NULL);
      68             :         }
      69         475 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
      70             : 
      71         475 :         conn = stmt->conn;
      72             : 
      73             :         /* be compliant with libmysql - NULL will turn */
      74         475 :         if (!stmt->field_count) {
      75           0 :                 DBG_RETURN(NULL);
      76             :         }
      77             : 
      78         475 :         if (stmt->cursor_exists) {
      79             :                 /* Silently convert buffered to unbuffered, for now */
      80           0 :                 DBG_RETURN(s->m->use_result(s TSRMLS_CC));
      81             :         }
      82             : 
      83             :         /* Nothing to store for UPSERT/LOAD DATA*/
      84         947 :         if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA ||
      85         472 :                 stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
      86             :         {
      87           3 :                 SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
      88             :                                                  UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
      89           3 :                 DBG_RETURN(NULL);
      90             :         }
      91             : 
      92         472 :         stmt->default_rset_handler = s->m->store_result;
      93             : 
      94         472 :         SET_EMPTY_ERROR(stmt->error_info);
      95         472 :         SET_EMPTY_ERROR(stmt->conn->error_info);
      96         472 :         MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
      97             : 
      98         472 :         result = stmt->result;
      99         472 :         result->type                 = MYSQLND_RES_PS_BUF;
     100         472 :         result->m.fetch_row          = mysqlnd_stmt_fetch_row_buffered;
     101         472 :         result->m.fetch_lengths      = NULL;/* makes no sense */
     102             : 
     103         472 :         result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
     104             : 
     105         472 :         ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE, to_cache TSRMLS_CC);
     106             : 
     107         472 :         if (PASS == ret) {
     108             :                 /* libmysql API docs say it should be so for SELECT statements */
     109         472 :                 stmt->upsert_status.affected_rows = stmt->result->stored_data->row_count;
     110             : 
     111         472 :                 stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
     112             :         } else {
     113           0 :                 conn->error_info = result->stored_data->error_info;
     114           0 :                 stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
     115           0 :                 mnd_efree(stmt->result);
     116           0 :                 stmt->result = NULL;
     117           0 :                 stmt->state = MYSQLND_STMT_PREPARED;
     118             :         }
     119             : 
     120         472 :         DBG_RETURN(result);
     121             : }
     122             : /* }}} */
     123             : 
     124             : 
     125             : /* {{{ mysqlnd_stmt::get_result */
     126             : static MYSQLND_RES *
     127         584 : MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
     128             : {
     129         584 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     130             :         MYSQLND * conn;
     131             :         MYSQLND_RES *result;
     132             : 
     133         584 :         DBG_ENTER("mysqlnd_stmt::get_result");
     134         584 :         if (!stmt || !stmt->conn || !stmt->result) {
     135           0 :                 DBG_RETURN(NULL);
     136             :         }
     137         584 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     138             : 
     139         584 :         conn = stmt->conn;
     140             : 
     141             :         /* be compliant with libmysql - NULL will turn */
     142         584 :         if (!stmt->field_count) {
     143           0 :                 DBG_RETURN(NULL);
     144             :         }
     145             : 
     146         584 :         if (stmt->cursor_exists) {
     147             :                 /* Silently convert buffered to unbuffered, for now */
     148           0 :                 DBG_RETURN(s->m->use_result(s TSRMLS_CC));
     149             :         }
     150             : 
     151             :         /* Nothing to store for UPSERT/LOAD DATA*/
     152         584 :         if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
     153           6 :                 SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
     154             :                                                  UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
     155           6 :                 DBG_RETURN(NULL);
     156             :         }
     157             : 
     158         578 :         SET_EMPTY_ERROR(stmt->error_info);
     159         578 :         SET_EMPTY_ERROR(stmt->conn->error_info);
     160         578 :         MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
     161             : 
     162             :         do {
     163         578 :                 result = conn->m->result_init(stmt->result->field_count, stmt->persistent TSRMLS_CC);
     164         578 :                 if (!result) {
     165           0 :                         SET_OOM_ERROR(stmt->conn->error_info);
     166           0 :                         break;
     167             :                 }
     168             : 
     169         578 :                 result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
     170         578 :                 if (!result->meta) {
     171           0 :                         SET_OOM_ERROR(stmt->conn->error_info);
     172           0 :                         break;
     173             :                 }
     174             : 
     175         578 :                 if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) {
     176         578 :                         stmt->upsert_status.affected_rows = result->stored_data->row_count;
     177         578 :                         stmt->state = MYSQLND_STMT_PREPARED;
     178         578 :                         result->type = MYSQLND_RES_PS_BUF;
     179             :                 } else {
     180           0 :                         stmt->error_info = conn->error_info;
     181           0 :                         stmt->state = MYSQLND_STMT_PREPARED;
     182           0 :                         break;
     183             :                 }
     184         578 :                 DBG_RETURN(result);
     185             :         } while (0);
     186             : 
     187           0 :         if (result) {
     188           0 :                 result->m.free_result(result, TRUE TSRMLS_CC);
     189             :         }
     190           0 :         DBG_RETURN(NULL);
     191             : }
     192             : /* }}} */
     193             : 
     194             : 
     195             : /* {{{ mysqlnd_stmt::more_results */
     196             : static zend_bool
     197        4279 : MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * s TSRMLS_DC)
     198             : {
     199        4279 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     200        4279 :         DBG_ENTER("mysqlnd_stmt::more_results");
     201             :         /* (conn->state == CONN_NEXT_RESULT_PENDING) too */
     202        4279 :         DBG_RETURN((stmt && stmt->conn && (stmt->conn->upsert_status.server_status &
     203             :                                                            SERVER_MORE_RESULTS_EXISTS))?
     204             :                                                                         TRUE:
     205             :                                                                         FALSE);
     206             : }
     207             : /* }}} */
     208             : 
     209             : 
     210             : /* {{{ mysqlnd_stmt::next_result */
     211             : static enum_func_status
     212          19 : MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC)
     213             : {
     214          19 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     215             :         MYSQLND * conn;
     216             : 
     217          19 :         DBG_ENTER("mysqlnd_stmt::next_result");
     218          19 :         if (!stmt || !stmt->conn || !stmt->result) {
     219           1 :                 DBG_RETURN(FAIL);
     220             :         }
     221          18 :         conn = stmt->conn;
     222          18 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     223             : 
     224          18 :         if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS)) {
     225           1 :                 DBG_RETURN(FAIL);
     226             :         }
     227             : 
     228          17 :         DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
     229          17 :         DBG_INF_FMT("server_status=%u cursor=%u", conn->upsert_status.server_status, conn->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
     230             : 
     231             :         /* Free space for next result */
     232          17 :         s->m->free_stmt_content(s TSRMLS_CC);
     233             :         {
     234          17 :                 enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC);
     235          17 :                 DBG_RETURN(ret);
     236             :         }
     237             : }
     238             : /* }}} */
     239             : 
     240             : 
     241             : /* {{{ mysqlnd_stmt_skip_metadata */
     242             : static enum_func_status
     243         822 : mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC)
     244             : {
     245         822 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     246             :         /* Follows parameter metadata, we have just to skip it, as libmysql does */
     247         822 :         unsigned int i = 0;
     248         822 :         enum_func_status ret = FAIL;
     249             :         MYSQLND_PACKET_RES_FIELD * field_packet;
     250             : 
     251         822 :         DBG_ENTER("mysqlnd_stmt_skip_metadata");
     252         822 :         if (!stmt || !stmt->conn || !stmt->conn->protocol) {
     253           0 :                 DBG_RETURN(FAIL);
     254             :         }
     255         822 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     256             : 
     257         822 :         field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
     258         822 :         if (!field_packet) {
     259           0 :                 SET_OOM_ERROR(stmt->error_info);
     260           0 :                 SET_OOM_ERROR(stmt->conn->error_info);
     261             :         } else {
     262         822 :                 ret = PASS;
     263         822 :                 field_packet->skip_parsing = TRUE;
     264      133226 :                 for (;i < stmt->param_count; i++) {
     265      132404 :                         if (FAIL == PACKET_READ(field_packet, stmt->conn)) {
     266           0 :                                 ret = FAIL;
     267           0 :                                 break;
     268             :                         }
     269             :                 }
     270         822 :                 PACKET_FREE(field_packet);
     271             :         }
     272             : 
     273         822 :         DBG_RETURN(ret);
     274             : }
     275             : /* }}} */
     276             : 
     277             : 
     278             : /* {{{ mysqlnd_stmt_read_prepare_response */
     279             : static enum_func_status
     280        4234 : mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
     281             : {
     282        4234 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     283             :         MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp;
     284        4234 :         enum_func_status ret = FAIL;
     285             : 
     286        4234 :         DBG_ENTER("mysqlnd_stmt_read_prepare_response");
     287        4234 :         if (!stmt || !stmt->conn || !stmt->conn->protocol) {
     288           0 :                 DBG_RETURN(FAIL);
     289             :         }
     290        4234 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     291             : 
     292        4234 :         prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
     293        4234 :         if (!prepare_resp) {
     294           0 :                 SET_OOM_ERROR(stmt->error_info);
     295           0 :                 SET_OOM_ERROR(stmt->conn->error_info);
     296           0 :                 goto done;
     297             :         }
     298             : 
     299        4234 :         if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) {
     300           1 :                 goto done;
     301             :         }
     302             : 
     303        4233 :         if (0xFF == prepare_resp->error_code) {
     304          26 :                 stmt->error_info = stmt->conn->error_info = prepare_resp->error_info;
     305          26 :                 goto done;
     306             :         }
     307        4207 :         ret = PASS;
     308        4207 :         stmt->stmt_id = prepare_resp->stmt_id;
     309        4207 :         stmt->warning_count = stmt->conn->upsert_status.warning_count = prepare_resp->warning_count;
     310        4207 :         stmt->field_count = stmt->conn->field_count = prepare_resp->field_count;
     311        4207 :         stmt->param_count = prepare_resp->param_count;
     312             : done:
     313        4234 :         PACKET_FREE(prepare_resp);
     314             : 
     315        4234 :         DBG_RETURN(ret);
     316             : }
     317             : /* }}} */
     318             : 
     319             : 
     320             : /* {{{ mysqlnd_stmt_prepare_read_eof */
     321             : static enum_func_status
     322        3248 : mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC)
     323             : {
     324        3248 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     325             :         MYSQLND_PACKET_EOF * fields_eof;
     326        3248 :         enum_func_status ret = FAIL;
     327             : 
     328        3248 :         DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
     329        3248 :         if (!stmt || !stmt->conn || !stmt->conn->protocol) {
     330           0 :                 DBG_RETURN(FAIL);
     331             :         }
     332        3248 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     333             : 
     334        3248 :         fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
     335        3248 :         if (!fields_eof) {
     336           0 :                 SET_OOM_ERROR(stmt->error_info);
     337           0 :                 SET_OOM_ERROR(stmt->conn->error_info);
     338             :         } else {
     339        3248 :                 if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
     340           0 :                         if (stmt->result) {
     341           0 :                                 stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
     342           0 :                                 mnd_efree(stmt->result);
     343           0 :                                 memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
     344           0 :                                 stmt->state = MYSQLND_STMT_INITTED;
     345             :                         }
     346             :                 } else {
     347        3248 :                         stmt->upsert_status.server_status = fields_eof->server_status;
     348        3248 :                         stmt->upsert_status.warning_count = fields_eof->warning_count;
     349        3248 :                         stmt->state = MYSQLND_STMT_PREPARED;
     350             :                 }
     351        3248 :                 PACKET_FREE(fields_eof);
     352             :         }
     353             : 
     354        3248 :         DBG_RETURN(ret);
     355             : }
     356             : /* }}} */
     357             : 
     358             : 
     359             : /* {{{ mysqlnd_stmt::prepare */
     360             : static enum_func_status
     361        4238 : MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const query, unsigned int query_len TSRMLS_DC)
     362             : {
     363        4238 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     364        4238 :         MYSQLND_STMT * s_to_prepare = s;
     365        4238 :         MYSQLND_STMT_DATA * stmt_to_prepare = stmt;
     366             : 
     367        4238 :         DBG_ENTER("mysqlnd_stmt::prepare");
     368        4238 :         if (!stmt || !stmt->conn) {
     369           0 :                 DBG_RETURN(FAIL);
     370             :         }
     371        4238 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     372             : 
     373        4238 :         SET_ERROR_AFF_ROWS(stmt);
     374        4238 :         SET_ERROR_AFF_ROWS(stmt->conn);
     375             : 
     376        4238 :         SET_EMPTY_ERROR(stmt->error_info);
     377        4238 :         SET_EMPTY_ERROR(stmt->conn->error_info);
     378             : 
     379        4238 :         if (stmt->state > MYSQLND_STMT_INITTED) {
     380             :                 /* See if we have to clean the wire */
     381        2421 :                 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
     382             :                         /* Do implicit use_result and then flush the result */
     383           1 :                         stmt->default_rset_handler = s->m->use_result;
     384           1 :                         stmt->default_rset_handler(s TSRMLS_CC);
     385             :                 }
     386             :                 /* No 'else' here please :) */
     387        2421 :                 if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE && stmt->result) {
     388         954 :                         stmt->result->m.skip_result(stmt->result TSRMLS_CC);
     389             :                 }
     390             :                 /*
     391             :                   Create a new test statement, which we will prepare, but if anything
     392             :                   fails, we will scrap it.
     393             :                 */
     394        2421 :                 s_to_prepare = stmt->conn->m->stmt_init(stmt->conn TSRMLS_CC);
     395        2421 :                 if (!s_to_prepare) {
     396           0 :                         goto fail;
     397             :                 }
     398        2421 :                 stmt_to_prepare = s_to_prepare->data;
     399             :         }
     400             : 
     401        8472 :         if (FAIL == stmt_to_prepare->conn->m->simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, query, query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) ||
     402        4234 :                 FAIL == mysqlnd_stmt_read_prepare_response(s_to_prepare TSRMLS_CC))
     403             :         {
     404             :                 goto fail;
     405             :         }
     406             : 
     407        4207 :         if (stmt_to_prepare->param_count) {
     408        1644 :                 if (FAIL == mysqlnd_stmt_skip_metadata(s_to_prepare TSRMLS_CC) ||
     409         822 :                         FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
     410             :                 {
     411             :                         goto fail;
     412             :                 }
     413             :         }
     414             : 
     415             :         /*
     416             :           Read metadata only if there is actual result set.
     417             :           Beware that SHOW statements bypass the PS framework and thus they send
     418             :           no metadata at prepare.
     419             :         */
     420        4207 :         if (stmt_to_prepare->field_count) {
     421        2426 :                 MYSQLND_RES * result = stmt->conn->m->result_init(stmt_to_prepare->field_count, stmt_to_prepare->persistent TSRMLS_CC);
     422        2426 :                 if (!result) {
     423           0 :                         SET_OOM_ERROR(stmt->conn->error_info);
     424           0 :                         goto fail;
     425             :                 }
     426             :                 /* Allocate the result now as it is needed for the reading of metadata */
     427        2426 :                 stmt_to_prepare->result = result; 
     428             : 
     429        2426 :                 result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn TSRMLS_CC);
     430             : 
     431        2426 :                 result->type = MYSQLND_RES_PS_BUF;
     432             : 
     433        4852 :                 if (FAIL == result->m.read_result_metadata(result, stmt_to_prepare->conn TSRMLS_CC) ||
     434        2426 :                         FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
     435             :                 {
     436             :                         goto fail;
     437             :                 }
     438             :         }
     439             : 
     440        4207 :         if (stmt_to_prepare != stmt) {
     441             :                 /* swap */
     442        2418 :                 size_t real_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
     443        2418 :                 char * tmp_swap = mnd_malloc(real_size);
     444        2418 :                 memcpy(tmp_swap, s, real_size);
     445        2418 :                 memcpy(s, s_to_prepare, real_size);
     446        2418 :                 memcpy(s_to_prepare, tmp_swap, real_size);
     447        2418 :                 mnd_free(tmp_swap);
     448             :                 {
     449        2418 :                         MYSQLND_STMT_DATA * tmp_swap_data = stmt_to_prepare;
     450        2418 :                         stmt_to_prepare = stmt;
     451        2418 :                         stmt = tmp_swap_data;
     452             :                 }
     453        2418 :                 s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
     454             :         }
     455        4207 :         stmt->state = MYSQLND_STMT_PREPARED;
     456        4207 :         DBG_INF("PASS");
     457        4207 :         DBG_RETURN(PASS);
     458             : 
     459             : fail:
     460          31 :         if (stmt_to_prepare != stmt && s_to_prepare) {
     461           3 :                 s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
     462             :         }
     463          31 :         stmt->state = MYSQLND_STMT_INITTED;
     464             : 
     465          31 :         DBG_INF("FAIL");
     466          31 :         DBG_RETURN(FAIL);
     467             : }
     468             : /* }}} */
     469             : 
     470             : 
     471             : /* {{{ mysqlnd_stmt_execute_parse_response */
     472             : static enum_func_status
     473        4899 : mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC)
     474             : {
     475        4899 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     476             :         enum_func_status ret;
     477             :         MYSQLND * conn;
     478             : 
     479        4899 :         DBG_ENTER("mysqlnd_stmt_execute_parse_response");
     480        4899 :         if (!stmt || !stmt->conn) {
     481           0 :                 DBG_RETURN(FAIL);
     482             :         }
     483        4899 :         conn = stmt->conn;
     484        4899 :         CONN_SET_STATE(conn, CONN_QUERY_SENT);
     485             : 
     486        4899 :         ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC);
     487        4899 :         if (ret == FAIL) {
     488           8 :                 stmt->error_info = conn->error_info;
     489           8 :                 stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
     490           8 :                 if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
     491             :                         /* close the statement here, the connection has been closed */
     492             :                 }
     493           8 :                 stmt->state = MYSQLND_STMT_PREPARED;
     494           8 :                 stmt->send_types_to_server = 1;
     495             :         } else {
     496             :                 /*
     497             :                   stmt->send_types_to_server has already been set to 0 in
     498             :                   mysqlnd_stmt_execute_generate_request / mysqlnd_stmt_execute_store_params
     499             :                   In case there is a situation in which binding was done for integer and the
     500             :                   value is > LONG_MAX or < LONG_MIN, there is string conversion and we have
     501             :                   to resend the types. Next execution will also need to resend the type.
     502             :                 */
     503        4891 :                 SET_EMPTY_ERROR(stmt->error_info);
     504        4891 :                 SET_EMPTY_ERROR(stmt->conn->error_info);
     505        4891 :                 stmt->upsert_status = conn->upsert_status;
     506        4891 :                 stmt->state = MYSQLND_STMT_EXECUTED;
     507        4891 :                 if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type == QUERY_LOAD_LOCAL) {
     508        2579 :                         DBG_INF("PASS");
     509        2579 :                         DBG_RETURN(PASS);
     510             :                 }
     511             : 
     512        2312 :                 stmt->result->type = MYSQLND_RES_PS_BUF;
     513        2312 :                 if (!stmt->result->conn) {
     514             :                         /*
     515             :                           For SHOW we don't create (bypasses PS in server)
     516             :                           a result set at prepare and thus a connection was missing
     517             :                         */
     518          24 :                         stmt->result->conn = stmt->conn->m->get_reference(stmt->conn TSRMLS_CC);
     519             :                 }
     520             : 
     521             :                 /* Update stmt->field_count as SHOW sets it to 0 at prepare */
     522        2312 :                 stmt->field_count = stmt->result->field_count = conn->field_count;
     523        2312 :                 stmt->result->lengths = NULL;
     524        2312 :                 if (stmt->field_count) {
     525        2312 :                         stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
     526             :                         /*
     527             :                           We need to set this because the user might not call
     528             :                           use_result() or store_result() and we should be able to scrap the
     529             :                           data on the line, if he just decides to close the statement.
     530             :                         */
     531        2312 :                         DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status,
     532             :                                                 stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
     533             : 
     534        2312 :                         if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
     535           4 :                                 DBG_INF("cursor exists");
     536           4 :                                 stmt->cursor_exists = TRUE;
     537           4 :                                 CONN_SET_STATE(conn, CONN_READY);
     538             :                                 /* Only cursor read */
     539           4 :                                 stmt->default_rset_handler = s->m->use_result;
     540           4 :                                 DBG_INF("use_result");
     541        2308 :                         } else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
     542           0 :                                 DBG_INF("asked for cursor but got none");
     543             :                                 /*
     544             :                                   We have asked for CURSOR but got no cursor, because the condition
     545             :                                   above is not fulfilled. Then...
     546             : 
     547             :                                   This is a single-row result set, a result set with no rows, EXPLAIN,
     548             :                                   SHOW VARIABLES, or some other command which either a) bypasses the
     549             :                                   cursors framework in the server and writes rows directly to the
     550             :                                   network or b) is more efficient if all (few) result set rows are
     551             :                                   precached on client and server's resources are freed.
     552             :                                 */
     553             :                                 /* preferred is buffered read */
     554           0 :                                 stmt->default_rset_handler = s->m->store_result;
     555           0 :                                 DBG_INF("store_result");
     556             :                         } else {
     557        2308 :                                 DBG_INF("no cursor");
     558             :                                 /* preferred is unbuffered read */
     559        2308 :                                 stmt->default_rset_handler = s->m->use_result;
     560        2308 :                                 DBG_INF("use_result");
     561             :                         }
     562             :                 }
     563             :         }
     564             : #ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET
     565        2320 :         if (stmt->upsert_status.server_status & SERVER_PS_OUT_PARAMS) {
     566           0 :                 s->m->free_stmt_content(s TSRMLS_CC);
     567           0 :                 DBG_INF("PS OUT Variable RSet, skipping");
     568             :                 /* OUT params result set. Skip for now to retain compatibility */
     569           0 :                 ret = mysqlnd_stmt_execute_parse_response(s TSRMLS_CC);
     570             :         }
     571             : #endif
     572             : 
     573        2320 :         DBG_INF(ret == PASS? "PASS":"FAIL");
     574        2320 :         DBG_RETURN(ret);
     575             : }
     576             : /* }}} */
     577             : 
     578             : 
     579             : /* {{{ mysqlnd_stmt::execute */
     580             : static enum_func_status
     581        4889 : MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
     582             : {
     583        4889 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     584             :         enum_func_status ret;
     585             :         MYSQLND *       conn;
     586        4889 :         zend_uchar *request = NULL;
     587             :         size_t          request_len;
     588             :         zend_bool       free_request;
     589             : 
     590        4889 :         DBG_ENTER("mysqlnd_stmt::execute");
     591        4889 :         if (!stmt || !stmt->conn) {
     592           0 :                 DBG_RETURN(FAIL);
     593             :         }
     594        4889 :         conn = stmt->conn;
     595        4889 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     596             : 
     597        4889 :         SET_ERROR_AFF_ROWS(stmt);
     598        4889 :         SET_ERROR_AFF_ROWS(stmt->conn);
     599             : 
     600        7185 :         if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) {
     601             :                 /*
     602             :                   We don need to copy the data from the buffers which we will clean.
     603             :                   Because it has already been copied. See
     604             :                   #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
     605             :                 */
     606             : #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
     607             :                 if (stmt->result_bind &&
     608             :                         stmt->result_zvals_separated_once == TRUE && 
     609             :                         stmt->state >= MYSQLND_STMT_USER_FETCHING)
     610             :                 {
     611             :                         /*
     612             :                           We need to copy the data from the buffers which we will clean.
     613             :                           The bound variables point to them only if the user has started
     614             :                           to fetch data (MYSQLND_STMT_USER_FETCHING).
     615             :                           We need to check 'result_zvals_separated_once' or we will leak
     616             :                           in the following scenario
     617             :                           prepare("select 1 from dual");
     618             :                           execute();
     619             :                           fetch(); <-- no binding, but that's not a problem
     620             :                           bind_result();
     621             :                           execute(); <-- here we will leak because we separate without need
     622             :                         */
     623             :                         unsigned int i;
     624             :                         for (i = 0; i < stmt->field_count; i++) {
     625             :                                 if (stmt->result_bind[i].bound == TRUE) {
     626             :                                         zval_copy_ctor(stmt->result_bind[i].zv);
     627             :                                 }
     628             :                         }
     629             :                 }
     630             : #endif
     631             : 
     632             :                 /*
     633             :                   If right after execute() we have to call the appropriate
     634             :                   use_result() or store_result() and clean.
     635             :                 */
     636        2296 :                 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
     637           0 :                         DBG_INF("fetching result set header");
     638             :                         /* Do implicit use_result and then flush the result */
     639           0 :                         stmt->default_rset_handler = s->m->use_result;
     640           0 :                         stmt->default_rset_handler(s TSRMLS_CC);
     641             :                 }
     642             : 
     643        2296 :                 if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
     644          24 :                         DBG_INF("skipping result");
     645             :                         /* Flush if anything is left and unbuffered set */
     646          24 :                         stmt->result->m.skip_result(stmt->result TSRMLS_CC);
     647             :                 }
     648             : 
     649        2296 :                 if (stmt->state > MYSQLND_STMT_PREPARED) {
     650             :                         /* As the buffers have been freed, we should go back to PREPARED */
     651          24 :                         stmt->state = MYSQLND_STMT_PREPARED;
     652             :                 }
     653             : 
     654             :                 /*
     655             :                   Executed, but the user hasn't started to fetch
     656             :                   This will clean also the metadata, but after the EXECUTE call we will
     657             :                   have it again.
     658             :                 */
     659        2296 :                 stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
     660        2593 :         } else if (stmt->state < MYSQLND_STMT_PREPARED) {
     661             :                 /* Only initted - error */
     662           2 :                 SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
     663             :                                                  mysqlnd_out_of_sync);
     664           2 :                 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
     665           2 :                 DBG_INF("FAIL");
     666           2 :                 DBG_RETURN(FAIL);
     667             :         }
     668             : 
     669        4887 :         if (stmt->param_count) {
     670        1440 :                 unsigned int i, not_bound = 0;
     671        1440 :                 if (!stmt->param_bind) {
     672           1 :                         SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
     673             :                                                          "No data supplied for parameters in prepared statement");
     674           1 :                         DBG_INF("FAIL");
     675           1 :                         DBG_RETURN(FAIL);
     676             :                 }
     677      135254 :                 for (i = 0; i < stmt->param_count; i++) {
     678      133815 :                         if (stmt->param_bind[i].zv == NULL) {
     679           0 :                                 not_bound++;
     680             :                         }
     681             :                 }
     682        1439 :                 if (not_bound) {
     683             :                         char * msg;
     684           0 :                         spprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement",
     685             :                                          not_bound, not_bound>1 ?"s":"");
     686           0 :                         SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, msg);
     687           0 :                         if (msg) {
     688           0 :                                 efree(msg); /* allocated by spprintf */
     689             :                         }
     690           0 :                         DBG_INF("FAIL");
     691           0 :                         DBG_RETURN(FAIL);
     692             :                 }
     693             :         }
     694        4886 :         ret = s->m->generate_execute_request(s, &request, &request_len, &free_request TSRMLS_CC);
     695        4886 :         if (ret == PASS) {
     696             :                 /* support for buffer types should be added here ! */
     697        4886 :                 ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len,
     698             :                                                                                         PROT_LAST /* we will handle the response packet*/,
     699             :                                                                                         FALSE, FALSE TSRMLS_CC);
     700             :         } else {
     701           0 :                 SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM.");
     702             :         }
     703             : 
     704        4886 :         if (free_request) {
     705          17 :                 mnd_efree(request);
     706             :         }
     707             : 
     708        4886 :         if (ret == FAIL) {
     709           4 :                 stmt->error_info = conn->error_info;
     710           4 :                 DBG_INF("FAIL");
     711           4 :                 DBG_RETURN(FAIL);
     712             :         }
     713        4882 :         stmt->execute_count++;
     714             : 
     715        4882 :         ret = s->m->parse_execute_response(s TSRMLS_CC);
     716             : 
     717        4882 :         DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
     718             : 
     719        4882 :         if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status.affected_rows) {
     720        2422 :                 MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status.affected_rows);
     721             :         }
     722        4882 :         DBG_RETURN(ret);
     723             : }
     724             : /* }}} */
     725             : 
     726             : 
     727             : /* {{{ mysqlnd_stmt_fetch_row_buffered */
     728             : enum_func_status
     729        1734 : mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
     730             : {
     731        1734 :         MYSQLND_STMT * s = (MYSQLND_STMT *) param;
     732        1734 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     733        1734 :         MYSQLND_RES_BUFFERED *set = result->stored_data;
     734        1734 :         unsigned int field_count = result->meta->field_count;
     735             : 
     736        1734 :         DBG_ENTER("mysqlnd_stmt_fetch_row_buffered");
     737        1734 :         *fetched_anything = FALSE;
     738        1734 :         DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L);
     739             : 
     740             :         /* If we haven't read everything */
     741        5120 :         if (set->data_cursor &&
     742        1722 :                 (set->data_cursor - set->data) < (set->row_count * field_count))
     743             :         {
     744             :                 /* The user could have skipped binding - don't crash*/
     745        1664 :                 if (stmt->result_bind) {
     746             :                         unsigned int i;
     747        1664 :                         MYSQLND_RES_METADATA * meta = result->meta;
     748        1664 :                         zval **current_row = set->data_cursor;
     749             : 
     750        1664 :                         if (NULL == current_row[0]) {
     751        1664 :                                 uint64_t row_num = (set->data_cursor - set->data) / field_count;
     752        8320 :                                 enum_func_status rc = result->m.row_decoder(set->row_buffers[row_num],
     753             :                                                                                                 current_row,
     754             :                                                                                                 meta->field_count,
     755             :                                                                                                 meta->fields,
     756        1664 :                                                                                                 result->stored_data->persistent,
     757        1664 :                                                                                                 result->conn->options.numeric_and_datetime_as_unicode,
     758        1664 :                                                                                                 result->conn->options.int_and_float_native,
     759        3328 :                                                                                                 result->conn->stats TSRMLS_CC);
     760        1664 :                                 if (PASS != rc) {
     761           0 :                                         DBG_RETURN(FAIL);
     762             :                                 }
     763        1664 :                                 set->initialized_rows++;
     764        1664 :                                 if (stmt->update_max_length) {
     765           0 :                                         for (i = 0; i < result->field_count; i++) {
     766             :                                                 /*
     767             :                                                   NULL fields are 0 length, 0 is not more than 0
     768             :                                                   String of zero size, definitely can't be the next max_length.
     769             :                                                   Thus for NULL and zero-length we are quite efficient.
     770             :                                                 */
     771           0 :                                                 if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
     772           0 :                                                         unsigned long len = Z_STRLEN_P(current_row[i]);
     773           0 :                                                         if (meta->fields[i].max_length < len) {
     774           0 :                                                                 meta->fields[i].max_length = len;
     775             :                                                         }
     776             :                                                 }
     777             :                                         }
     778             :                                 }
     779             :                         }
     780             : 
     781        6067 :                         for (i = 0; i < result->field_count; i++) {
     782             :                                 /* Clean what we copied last time */
     783             : #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
     784        4403 :                                 if (stmt->result_bind[i].zv) {
     785        4403 :                                         zval_dtor(stmt->result_bind[i].zv);
     786             :                                 }
     787             : #endif
     788             :                                 /* copy the type */
     789        4403 :                                 if (stmt->result_bind[i].bound == TRUE) {
     790        4403 :                                         DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
     791        4403 :                                         if (Z_TYPE_P(current_row[i]) != IS_NULL) {
     792             :                                                 /*
     793             :                                                   Copy the value.
     794             :                                                   Pre-condition is that the zvals in the result_bind buffer
     795             :                                                   have been  ZVAL_NULL()-ed or to another simple type
     796             :                                                   (int, double, bool but not string). Because of the reference
     797             :                                                   counting the user can't delete the strings the variables point to.
     798             :                                                 */
     799             : 
     800        4395 :                                                 Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
     801        4395 :                                                 stmt->result_bind[i].zv->value = current_row[i]->value;
     802             : #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
     803        4395 :                                                 zval_copy_ctor(stmt->result_bind[i].zv);
     804             : #endif
     805             :                                         } else {
     806           8 :                                                 ZVAL_NULL(stmt->result_bind[i].zv);
     807             :                                         }
     808             :                                 }
     809             :                         }
     810             :                 }
     811        1664 :                 set->data_cursor += field_count;
     812        1664 :                 *fetched_anything = TRUE;
     813             :                 /* buffered result sets don't have a connection */
     814        1664 :                 MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
     815        1664 :                 DBG_INF("row fetched");
     816             :         } else {
     817          70 :                 set->data_cursor = NULL;
     818          70 :                 DBG_INF("no more data");
     819             :         }
     820        1734 :         DBG_INF("PASS");
     821        1734 :         DBG_RETURN(PASS);
     822             : }
     823             : /* }}} */
     824             : 
     825             : 
     826             : /* {{{ mysqlnd_stmt_fetch_row_unbuffered */
     827             : static enum_func_status
     828       19029 : mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
     829             : {
     830             :         enum_func_status ret;
     831       19029 :         MYSQLND_STMT * s = (MYSQLND_STMT *) param;
     832       19029 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     833             :         MYSQLND_PACKET_ROW * row_packet;
     834             : 
     835       19029 :         DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
     836             : 
     837       19029 :         *fetched_anything = FALSE;
     838             : 
     839       19029 :         if (result->unbuf->eof_reached) {
     840             :                 /* No more rows obviously */
     841           0 :                 DBG_INF("eof reached");
     842           0 :                 DBG_RETURN(PASS);
     843             :         }
     844       19029 :         if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) {
     845           4 :                 SET_CLIENT_ERROR(result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
     846             :                                                  UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
     847           4 :                 DBG_ERR("command out of sync");
     848           4 :                 DBG_RETURN(FAIL);
     849             :         }
     850       19025 :         if (!(row_packet = result->row_packet)) {
     851           0 :                 DBG_RETURN(FAIL);
     852             :         }
     853             : 
     854             :         /* Let the row packet fill our buffer and skip additional malloc + memcpy */
     855       19025 :         row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
     856             : 
     857             :         /*
     858             :           If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to
     859             :           result->m.unbuffered_free_last_data() before it. The function returns always true.
     860             :         */
     861       36799 :         if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
     862       17774 :                 unsigned int i, field_count = result->field_count;
     863             : 
     864       17774 :                 if (!row_packet->skip_extraction) {
     865       17584 :                         result->m.unbuffered_free_last_data(result TSRMLS_CC);
     866             : 
     867       17584 :                         DBG_INF("extracting data");
     868       17584 :                         result->unbuf->last_row_data = row_packet->fields;
     869       17584 :                         result->unbuf->last_row_buffer = row_packet->row_buffer;
     870       17584 :                         row_packet->fields = NULL;
     871       17584 :                         row_packet->row_buffer = NULL;
     872             : 
     873       87920 :                         if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
     874       17584 :                                                                         result->unbuf->last_row_data,
     875             :                                                                         row_packet->field_count,
     876             :                                                                         row_packet->fields_metadata,
     877             :                                                                         FALSE,
     878       17584 :                                                                         result->conn->options.numeric_and_datetime_as_unicode,
     879       17584 :                                                                         result->conn->options.int_and_float_native,
     880       17584 :                                                                         result->conn->stats TSRMLS_CC))
     881             :                         {
     882           0 :                                 DBG_RETURN(FAIL);
     883             :                         }
     884             : 
     885       54713 :                         for (i = 0; i < field_count; i++) {
     886       37129 :                                 if (stmt->result_bind[i].bound == TRUE) {
     887       37129 :                                         zval *data = result->unbuf->last_row_data[i];
     888             :                                         /*
     889             :                                           stmt->result_bind[i].zv has been already destructed
     890             :                                           in result->m.unbuffered_free_last_data()
     891             :                                         */
     892             : #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
     893       37129 :                                         zval_dtor(stmt->result_bind[i].zv);
     894             : #endif
     895       37129 :                                         if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
     896       53386 :                                                 if (
     897       36547 :                                                         (Z_TYPE_P(data) == IS_STRING
     898             : #if MYSQLND_UNICODE
     899             :                                                         || Z_TYPE_P(data) == IS_UNICODE
     900             : #endif
     901             :                                                         )
     902       16839 :                                                          && (result->meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data)))
     903             :                                                 {
     904         623 :                                                         result->meta->fields[i].max_length = Z_STRLEN_P(data);
     905             :                                                 }
     906       36547 :                                                 stmt->result_bind[i].zv->value = data->value;
     907             :                                                 /* copied data, thus also the ownership. Thus null data */
     908       36547 :                                                 ZVAL_NULL(data);
     909             :                                         }
     910             :                                 }
     911             :                         }
     912       17584 :                         MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF);
     913             :                 } else {
     914         190 :                         DBG_INF("skipping extraction");
     915             :                         /*
     916             :                           Data has been allocated and usually result->m.unbuffered_free_last_data()
     917             :                           frees it but we can't call this function as it will cause problems with
     918             :                           the bound variables. Thus we need to do part of what it does or Zend will
     919             :                           report leaks.
     920             :                         */
     921         190 :                         row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
     922         190 :                         row_packet->row_buffer = NULL;
     923             :                 }
     924             : 
     925       17774 :                 result->unbuf->row_count++;
     926       17774 :                 *fetched_anything = TRUE;
     927        1251 :         } else if (ret == FAIL) {
     928           0 :                 if (row_packet->error_info.error_no) {
     929           0 :                         stmt->conn->error_info = row_packet->error_info; 
     930           0 :                         stmt->error_info = row_packet->error_info; 
     931             :                 }
     932           0 :                 CONN_SET_STATE(result->conn, CONN_READY);
     933           0 :                 result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
     934        1251 :         } else if (row_packet->eof) {
     935        1251 :                 DBG_INF("EOF");
     936             :                 /* Mark the connection as usable again */
     937        1251 :                 result->unbuf->eof_reached = TRUE;
     938        1251 :                 result->conn->upsert_status.warning_count = row_packet->warning_count;
     939        1251 :                 result->conn->upsert_status.server_status = row_packet->server_status;
     940             :                 /*
     941             :                   result->row_packet will be cleaned when
     942             :                   destroying the result object
     943             :                 */
     944        1251 :                 if (result->conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {
     945           5 :                         CONN_SET_STATE(result->conn, CONN_NEXT_RESULT_PENDING);
     946             :                 } else {
     947        1246 :                         CONN_SET_STATE(result->conn, CONN_READY);
     948             :                 }
     949             :         }
     950             : 
     951       19025 :         DBG_INF_FMT("ret=%s fetched_anything=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
     952       19025 :         DBG_RETURN(ret);
     953             : }
     954             : /* }}} */
     955             : 
     956             : 
     957             : /* {{{ mysqlnd_stmt::use_result */
     958             : static MYSQLND_RES *
     959        1262 : MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC)
     960             : {
     961        1262 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
     962             :         MYSQLND_RES *result;
     963             :         MYSQLND * conn;
     964             : 
     965        1262 :         DBG_ENTER("mysqlnd_stmt::use_result");
     966        1262 :         if (!stmt || !stmt->conn || !stmt->result) {
     967           0 :                 DBG_RETURN(NULL);
     968             :         }
     969        1262 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
     970             : 
     971        1262 :         conn = stmt->conn;
     972             : 
     973        6304 :         if (!stmt->field_count ||
     974        2520 :                 (!stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_FETCHING_DATA) ||
     975        1263 :                 (stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) ||
     976        1259 :                 (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
     977             :         {
     978           3 :                 SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
     979             :                                                  UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
     980           3 :                 DBG_ERR("command out of sync");
     981           3 :                 DBG_RETURN(NULL);
     982             :         }
     983             : 
     984        1259 :         SET_EMPTY_ERROR(stmt->error_info);
     985             : 
     986        1259 :         MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);
     987        1259 :         result = stmt->result;
     988             : 
     989        1259 :         DBG_INF_FMT("%scursor exists", stmt->cursor_exists? "":"no ");
     990        1259 :         result->m.use_result(stmt->result, TRUE TSRMLS_CC);
     991        1259 :         result->m.fetch_row  = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
     992             :                                                                                            mysqlnd_stmt_fetch_row_unbuffered;
     993        1259 :         stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
     994             : 
     995        1259 :         DBG_INF_FMT("%p", result);
     996        1259 :         DBG_RETURN(result);
     997             : }
     998             : /* }}} */
     999             : 
    1000             : 
    1001             : #define STMT_ID_LENGTH 4
    1002             : 
    1003             : /* {{{ mysqlnd_fetch_row_cursor */
    1004             : enum_func_status
    1005          28 : mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
    1006             : {
    1007             :         enum_func_status ret;
    1008          28 :         MYSQLND_STMT * s = (MYSQLND_STMT *) param;
    1009          28 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1010             :         zend_uchar buf[STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
    1011             :         MYSQLND_PACKET_ROW * row_packet;
    1012             : 
    1013          28 :         DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
    1014             : 
    1015          28 :         if (!stmt || !stmt->conn || !result || !result->conn || !result->unbuf) {
    1016           2 :                 DBG_ERR("no statement");
    1017           2 :                 DBG_RETURN(FAIL);
    1018             :         }
    1019             : 
    1020          26 :         DBG_INF_FMT("stmt=%lu flags=%u", stmt->stmt_id, flags);
    1021             : 
    1022          26 :         if (stmt->state < MYSQLND_STMT_USER_FETCHING) {
    1023             :                 /* Only initted - error */
    1024           0 :                 SET_CLIENT_ERROR(stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
    1025             :                                                 mysqlnd_out_of_sync);
    1026           0 :                 DBG_ERR("command out of sync");
    1027           0 :                 DBG_RETURN(FAIL);
    1028             :         }
    1029          26 :         if (!(row_packet = result->row_packet)) {
    1030           0 :                 DBG_RETURN(FAIL);
    1031             :         }
    1032             : 
    1033          26 :         SET_EMPTY_ERROR(stmt->error_info);
    1034          26 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1035             : 
    1036          26 :         int4store(buf, stmt->stmt_id);
    1037          26 :         int4store(buf + STMT_ID_LENGTH, 1); /* for now fetch only one row */
    1038             : 
    1039          26 :         if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, (char *)buf, sizeof(buf),
    1040             :                                                                                           PROT_LAST /* we will handle the response packet*/,
    1041             :                                                                                           FALSE, TRUE TSRMLS_CC)) {
    1042           0 :                 stmt->error_info = stmt->conn->error_info;
    1043           0 :                 DBG_RETURN(FAIL);
    1044             :         }
    1045             : 
    1046          26 :         row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
    1047             : 
    1048          50 :         if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
    1049          24 :                 unsigned int i, field_count = result->field_count;
    1050             : 
    1051          24 :                 DBG_INF_FMT("skip_extraction=%u", row_packet->skip_extraction); 
    1052          24 :                 if (!row_packet->skip_extraction) {
    1053          24 :                         result->m.unbuffered_free_last_data(result TSRMLS_CC);
    1054             : 
    1055          24 :                         DBG_INF("extracting data");
    1056          24 :                         result->unbuf->last_row_data = row_packet->fields;
    1057          24 :                         result->unbuf->last_row_buffer = row_packet->row_buffer;
    1058          24 :                         row_packet->fields = NULL;
    1059          24 :                         row_packet->row_buffer = NULL;
    1060             : 
    1061         120 :                         if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
    1062          24 :                                                                           result->unbuf->last_row_data,
    1063             :                                                                           row_packet->field_count,
    1064             :                                                                           row_packet->fields_metadata,
    1065             :                                                                           FALSE,
    1066          24 :                                                                           result->conn->options.numeric_and_datetime_as_unicode,
    1067          24 :                                                                           result->conn->options.int_and_float_native,
    1068          24 :                                                                           result->conn->stats TSRMLS_CC))
    1069             :                         {
    1070           0 :                                 DBG_RETURN(FAIL);                                                 
    1071             :                         }
    1072             : 
    1073             :                         /* If no result bind, do nothing. We consumed the data */
    1074          54 :                         for (i = 0; i < field_count; i++) {
    1075          30 :                                 if (stmt->result_bind[i].bound == TRUE) {
    1076          30 :                                         zval *data = result->unbuf->last_row_data[i];
    1077             :                                         /*
    1078             :                                           stmt->result_bind[i].zv has been already destructed
    1079             :                                           in result->m.unbuffered_free_last_data()
    1080             :                                         */
    1081             : #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
    1082          30 :                                         zval_dtor(stmt->result_bind[i].zv);
    1083             : #endif
    1084          60 :                                         DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, stmt->result_bind[i].zv,
    1085          60 :                                                                 Z_TYPE_P(data), Z_REFCOUNT_P(stmt->result_bind[i].zv));
    1086          30 :                                         if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data))) {
    1087          36 :                                                 if ((Z_TYPE_P(data) == IS_STRING
    1088             : #if MYSQLND_UNICODE
    1089             :                                                         || Z_TYPE_P(data) == IS_UNICODE
    1090             : #endif
    1091             :                                                         )
    1092           6 :                                                          && (result->meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data)))
    1093             :                                                 {
    1094           1 :                                                         result->meta->fields[i].max_length = Z_STRLEN_P(data);
    1095             :                                                 }
    1096          30 :                                                 stmt->result_bind[i].zv->value = data->value;
    1097             :                                                 /* copied data, thus also the ownership. Thus null data */
    1098          30 :                                                 ZVAL_NULL(data);
    1099             :                                         }
    1100             :                                 }
    1101             :                         }
    1102             :                 } else {
    1103           0 :                         DBG_INF("skipping extraction");
    1104             :                         /*
    1105             :                           Data has been allocated and usually result->m.unbuffered_free_last_data()
    1106             :                           frees it but we can't call this function as it will cause problems with
    1107             :                           the bound variables. Thus we need to do part of what it does or Zend will
    1108             :                           report leaks.
    1109             :                         */
    1110           0 :                         row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
    1111           0 :                         row_packet->row_buffer = NULL;
    1112             :                 }
    1113             :                 /* We asked for one row, the next one should be EOF, eat it */
    1114          24 :                 ret = PACKET_READ(row_packet, result->conn);
    1115          24 :                 if (row_packet->row_buffer) {
    1116          24 :                         row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
    1117          24 :                         row_packet->row_buffer = NULL;
    1118             :                 }
    1119          24 :                 MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
    1120             : 
    1121          24 :                 result->unbuf->row_count++;
    1122          24 :                 *fetched_anything = TRUE;
    1123             :         } else {
    1124           2 :                 *fetched_anything = FALSE;
    1125             : 
    1126           4 :                 stmt->upsert_status.warning_count =
    1127           6 :                         stmt->conn->upsert_status.warning_count =
    1128           2 :                                 row_packet->warning_count;
    1129             : 
    1130           4 :                 stmt->upsert_status.server_status = 
    1131           6 :                         stmt->conn->upsert_status.server_status =
    1132           2 :                                 row_packet->server_status;
    1133             : 
    1134           2 :                 result->unbuf->eof_reached = row_packet->eof;
    1135             :         }
    1136          52 :         stmt->upsert_status.warning_count =
    1137          78 :                 stmt->conn->upsert_status.warning_count =
    1138          26 :                         row_packet->warning_count;
    1139          52 :         stmt->upsert_status.server_status = 
    1140          78 :                 stmt->conn->upsert_status.server_status =
    1141          26 :                         row_packet->server_status;
    1142             : 
    1143         104 :         DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u",
    1144          26 :                                 ret == PASS? "PASS":"FAIL", *fetched_anything,
    1145          52 :                                 row_packet->server_status, row_packet->warning_count,
    1146          26 :                                 result->unbuf->eof_reached);
    1147          26 :         DBG_RETURN(ret);
    1148             : }
    1149             : /* }}} */
    1150             : 
    1151             : 
    1152             : /* {{{ mysqlnd_stmt::fetch */
    1153             : static enum_func_status
    1154       19514 : MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fetched_anything TSRMLS_DC)
    1155             : {
    1156       19514 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1157             :         enum_func_status ret;
    1158       19514 :         DBG_ENTER("mysqlnd_stmt::fetch");
    1159       19514 :         if (!stmt || !stmt->conn) {
    1160           0 :                 DBG_RETURN(FAIL);
    1161             :         }
    1162       19514 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
    1163             : 
    1164       39028 :         if (!stmt->result ||
    1165       19514 :                 stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
    1166           8 :                 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
    1167             : 
    1168           8 :                 DBG_ERR("command out of sync");
    1169           8 :                 DBG_RETURN(FAIL);
    1170       19506 :         } else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
    1171             :                 /* Execute only once. We have to free the previous contents of user's bound vars */
    1172             : 
    1173        1241 :                 stmt->default_rset_handler(s TSRMLS_CC);
    1174             :         }
    1175       19506 :         stmt->state = MYSQLND_STMT_USER_FETCHING;
    1176             : 
    1177       19506 :         SET_EMPTY_ERROR(stmt->error_info);
    1178       19506 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1179             : 
    1180       19506 :         DBG_INF_FMT("result_bind=%p separated_once=%u", stmt->result_bind, stmt->result_zvals_separated_once);
    1181             :         /*
    1182             :           The user might have not bound any variables for result.
    1183             :           Do the binding once she does it.
    1184             :         */
    1185       19506 :         if (stmt->result_bind && !stmt->result_zvals_separated_once) {
    1186             :                 unsigned int i;
    1187             :                 /*
    1188             :                   mysqlnd_stmt_store_result() has been called free the bind
    1189             :                   variables to prevent leaking of their previous content.
    1190             :                 */
    1191        7777 :                 for (i = 0; i < stmt->result->field_count; i++) {
    1192        6179 :                         if (stmt->result_bind[i].bound == TRUE) {
    1193        6179 :                                 zval_dtor(stmt->result_bind[i].zv);
    1194        6179 :                                 ZVAL_NULL(stmt->result_bind[i].zv);
    1195             :                         }
    1196             :                 }
    1197        1598 :                 stmt->result_zvals_separated_once = TRUE;
    1198             :         }
    1199             : 
    1200       19506 :         ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything TSRMLS_CC);
    1201       19506 :         DBG_RETURN(ret);
    1202             : }
    1203             : /* }}} */
    1204             : 
    1205             : 
    1206             : /* {{{ mysqlnd_stmt::reset */
    1207             : static enum_func_status
    1208           6 : MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s TSRMLS_DC)
    1209             : {
    1210           6 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1211           6 :         enum_func_status ret = PASS;
    1212             :         zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
    1213             : 
    1214           6 :         DBG_ENTER("mysqlnd_stmt::reset");
    1215           6 :         if (!stmt || !stmt->conn) {
    1216           0 :                 DBG_RETURN(FAIL);
    1217             :         }
    1218           6 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
    1219             : 
    1220           6 :         SET_EMPTY_ERROR(stmt->error_info);
    1221           6 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1222             : 
    1223           6 :         if (stmt->stmt_id) {
    1224           6 :                 MYSQLND * conn = stmt->conn;
    1225           6 :                 if (stmt->param_bind) {
    1226             :                         unsigned int i;
    1227           2 :                         DBG_INF("resetting long data");
    1228             :                         /* Reset Long Data */
    1229           4 :                         for (i = 0; i < stmt->param_count; i++) {
    1230           2 :                                 if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
    1231           1 :                                         stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
    1232             :                                 }
    1233             :                         }
    1234             :                 }
    1235             : 
    1236             :                 /*
    1237             :                   If the user decided to close the statement right after execute()
    1238             :                   We have to call the appropriate use_result() or store_result() and
    1239             :                   clean.
    1240             :                 */
    1241             :                 do {
    1242           6 :                         if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
    1243           2 :                                 DBG_INF("fetching result set header");
    1244           2 :                                 stmt->default_rset_handler(s TSRMLS_CC);
    1245           2 :                                 stmt->state = MYSQLND_STMT_USER_FETCHING;
    1246             :                         }
    1247             : 
    1248           6 :                         if (stmt->result) {
    1249           5 :                                 DBG_INF("skipping result");
    1250           5 :                                 stmt->result->m.skip_result(stmt->result TSRMLS_CC);
    1251             :                         }
    1252           6 :                 } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
    1253             : 
    1254             :                 /*
    1255             :                   Don't free now, let the result be usable. When the stmt will again be
    1256             :                   executed then the result set will be cleaned, the bound variables will
    1257             :                   be separated before that.
    1258             :                 */
    1259             : 
    1260           6 :                 int4store(cmd_buf, stmt->stmt_id);
    1261          12 :                 if (CONN_GET_STATE(conn) == CONN_READY &&
    1262           6 :                         FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, (char *)cmd_buf,
    1263             :                                                                                                   sizeof(cmd_buf), PROT_OK_PACKET,
    1264             :                                                                                                   FALSE, TRUE TSRMLS_CC))) {
    1265           0 :                         stmt->error_info = conn->error_info;
    1266             :                 }
    1267           6 :                 stmt->upsert_status = conn->upsert_status;
    1268             :         }
    1269           6 :         DBG_INF(ret == PASS? "PASS":"FAIL");
    1270           6 :         DBG_RETURN(ret);
    1271             : }
    1272             : /* }}} */
    1273             : 
    1274             : 
    1275             : /* {{{ mysqlnd_stmt::send_long_data */
    1276             : static enum_func_status
    1277          16 : MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
    1278             :                                                                                          const char * const data, unsigned long length TSRMLS_DC)
    1279             : {
    1280          16 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1281          16 :         enum_func_status ret = FAIL;
    1282             :         MYSQLND * conn;
    1283             :         zend_uchar *cmd_buf;
    1284          16 :         enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
    1285             : 
    1286          16 :         DBG_ENTER("mysqlnd_stmt::send_long_data");
    1287          16 :         if (!stmt || !stmt->conn) {
    1288           0 :                 DBG_RETURN(FAIL);
    1289             :         }
    1290          16 :         DBG_INF_FMT("stmt=%lu param_no=%u data_len=%lu", stmt->stmt_id, param_no, length);
    1291             : 
    1292          16 :         conn = stmt->conn;
    1293             : 
    1294          16 :         SET_EMPTY_ERROR(stmt->error_info);
    1295          16 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1296             : 
    1297          16 :         if (stmt->state < MYSQLND_STMT_PREPARED) {
    1298           0 :                 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
    1299           0 :                 DBG_ERR("not prepared");
    1300           0 :                 DBG_RETURN(FAIL);
    1301             :         }
    1302          16 :         if (!stmt->param_bind) {
    1303           0 :                 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
    1304           0 :                 DBG_ERR("command out of sync");
    1305           0 :                 DBG_RETURN(FAIL);
    1306             :         }
    1307             : 
    1308          16 :         if (param_no >= stmt->param_count) {
    1309           1 :                 SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
    1310           1 :                 DBG_ERR("invalid param_no");
    1311           1 :                 DBG_RETURN(FAIL);
    1312             :         }
    1313          15 :         if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {
    1314           0 :                 SET_STMT_ERROR(stmt, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, mysqlnd_not_bound_as_blob);
    1315           0 :                 DBG_ERR("param_no is not of a blob type");
    1316           0 :                 DBG_RETURN(FAIL);
    1317             :         }
    1318             : 
    1319             :         /*
    1320             :           XXX:  Unfortunately we have to allocate additional buffer to be able the
    1321             :                         additional data, which is like a header inside the payload.
    1322             :                         This should be optimised, but it will be a pervasive change, so
    1323             :                         conn->m->simple_command() will accept not a buffer, but actually MYSQLND_STRING*
    1324             :                         terminated by NULL, to send. If the strings are not big, we can collapse them
    1325             :                         on the buffer every connection has, but otherwise we will just send them
    1326             :                         one by one to the wire.
    1327             :         */
    1328             : 
    1329          15 :         if (CONN_GET_STATE(conn) == CONN_READY) {
    1330             :                 size_t packet_len;
    1331          15 :                 cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
    1332          15 :                 if (cmd_buf) {
    1333          15 :                         stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
    1334             : 
    1335          15 :                         int4store(cmd_buf, stmt->stmt_id);
    1336          15 :                         int2store(cmd_buf + STMT_ID_LENGTH, param_no);
    1337          15 :                         memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length);
    1338             : 
    1339             :                         /* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/
    1340          15 :                         ret = conn->m->simple_command(conn, cmd, (char *)cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC);
    1341          15 :                         mnd_efree(cmd_buf);
    1342          15 :                         if (FAIL == ret) {
    1343           0 :                                 stmt->error_info = conn->error_info;
    1344             :                         }
    1345             :                 } else {
    1346           0 :                         ret = FAIL;
    1347           0 :                         SET_OOM_ERROR(stmt->error_info);
    1348           0 :                         SET_OOM_ERROR(conn->error_info);
    1349             :                 }
    1350             :                 /*
    1351             :                   Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not
    1352             :                   sent response packets. According to documentation the only way to get an error
    1353             :                   is to have out-of-memory on the server-side. However, that's not true, as if
    1354             :                   max_allowed_packet_size is smaller than the chunk being sent to the server, the
    1355             :                   latter will complain with an error message. However, normally we don't expect
    1356             :                   an error message, thus we continue. When sending the next command, which expects
    1357             :                   response we will read the unexpected data and error message will look weird.
    1358             :                   Therefore we do non-blocking read to clean the line, if there is a need.
    1359             :                   Nevertheless, there is a built-in protection when sending a command packet, that
    1360             :                   checks if the line is clear - useful for debug purposes and to be switched off
    1361             :                   in release builds.
    1362             : 
    1363             :                   Maybe we can make it automatic by checking what's the value of
    1364             :                   max_allowed_packet_size on the server and resending the data.
    1365             :                 */
    1366             : #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
    1367             : #if HAVE_USLEEP && !defined(PHP_WIN32)
    1368             :                 usleep(120000);
    1369             : #endif
    1370             :                 if ((packet_len = conn->net->m.consume_uneaten_data(conn->net, cmd TSRMLS_CC))) {
    1371             :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error "
    1372             :                                                          "while sending long data. Probably max_allowed_packet_size "
    1373             :                                                          "is smaller than the data. You have to increase it or send "
    1374             :                                                          "smaller chunks of data. Answer was "MYSQLND_SZ_T_SPEC" bytes long.", packet_len);
    1375             :                         SET_STMT_ERROR(stmt, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE,
    1376             :                                                         "Server responded to COM_STMT_SEND_LONG_DATA.");
    1377             :                         ret = FAIL;
    1378             :                 }
    1379             : #endif
    1380             :         }
    1381             : 
    1382          15 :         DBG_INF(ret == PASS? "PASS":"FAIL");
    1383          15 :         DBG_RETURN(ret);
    1384             : }
    1385             : /* }}} */
    1386             : 
    1387             : 
    1388             : /* {{{ mysqlnd_stmt::bind_parameters */
    1389             : static enum_func_status
    1390       20874 : MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
    1391             : {
    1392       20874 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1393       20874 :         DBG_ENTER("mysqlnd_stmt::bind_param");
    1394       20874 :         if (!stmt || !stmt->conn) {
    1395           0 :                 DBG_RETURN(FAIL);
    1396             :         }
    1397       20874 :         DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
    1398             : 
    1399       20874 :         if (stmt->state < MYSQLND_STMT_PREPARED) {
    1400           0 :                 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
    1401           0 :                 DBG_ERR("not prepared");
    1402           0 :                 if (param_bind) {
    1403           0 :                         s->m->free_parameter_bind(s, param_bind TSRMLS_CC);
    1404             :                 }
    1405           0 :                 DBG_RETURN(FAIL);
    1406             :         }
    1407             : 
    1408       20874 :         SET_EMPTY_ERROR(stmt->error_info);
    1409       20874 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1410             : 
    1411       20874 :         if (stmt->param_count) {
    1412       20874 :                 unsigned int i = 0;
    1413             : 
    1414       20874 :                 if (!param_bind) {
    1415           0 :                         SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported");
    1416           0 :                         DBG_ERR("Re-binding (still) not supported");
    1417           0 :                         DBG_RETURN(FAIL);
    1418       20874 :                 } else if (stmt->param_bind) {
    1419       20435 :                         DBG_INF("Binding");
    1420             :                         /*
    1421             :                           There is already result bound.
    1422             :                           Forbid for now re-binding!!
    1423             :                         */
    1424       61305 :                         for (i = 0; i < stmt->param_count; i++) {
    1425             :                                 /*
    1426             :                                   We may have the last reference, then call zval_ptr_dtor()
    1427             :                                   or we may leak memory.
    1428             :                                   Switching from bind_one_parameter to bind_parameters may result in zv being NULL
    1429             :                                 */
    1430       40870 :                                 if (stmt->param_bind[i].zv) {
    1431       40870 :                                         zval_ptr_dtor(&stmt->param_bind[i].zv);
    1432             :                                 }
    1433             :                         }
    1434       20435 :                         if (stmt->param_bind != param_bind) {
    1435       20435 :                                 s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
    1436             :                         }
    1437             :                 }
    1438             : 
    1439       20874 :                 stmt->param_bind = param_bind;
    1440      193664 :                 for (i = 0; i < stmt->param_count; i++) {
    1441             :                         /* The client will use stmt_send_long_data */
    1442      172790 :                         DBG_INF_FMT("%u is of type %u", i, stmt->param_bind[i].type);
    1443             :                         /* Prevent from freeing */
    1444             :                         /* Don't update is_ref, or we will leak during conversion */
    1445      172790 :                         Z_ADDREF_P(stmt->param_bind[i].zv);
    1446      172790 :                         stmt->param_bind[i].flags = 0;
    1447      172790 :                         if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
    1448          24 :                                 stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
    1449             :                         }
    1450             :                 }
    1451       20874 :                 stmt->send_types_to_server = 1;
    1452             :         }
    1453       20874 :         DBG_INF("PASS");
    1454       20874 :         DBG_RETURN(PASS);
    1455             : }
    1456             : /* }}} */
    1457             : 
    1458             : 
    1459             : /* {{{ mysqlnd_stmt::bind_one_parameter */
    1460             : static enum_func_status
    1461         285 : MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigned int param_no,
    1462             :                                                                                                  zval * const zv, zend_uchar type TSRMLS_DC)
    1463             : {
    1464         285 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1465         285 :         DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
    1466         285 :         if (!stmt || !stmt->conn) {
    1467           0 :                 DBG_RETURN(FAIL);
    1468             :         }
    1469         285 :         DBG_INF_FMT("stmt=%lu param_no=%u param_count=%u type=%u",
    1470             :                                 stmt->stmt_id, param_no, stmt->param_count, type);
    1471             : 
    1472         285 :         if (stmt->state < MYSQLND_STMT_PREPARED) {
    1473           0 :                 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
    1474           0 :                 DBG_ERR("not prepared");
    1475           0 :                 DBG_RETURN(FAIL);
    1476             :         }
    1477             : 
    1478         285 :         if (param_no >= stmt->param_count) {
    1479           0 :                 SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
    1480           0 :                 DBG_ERR("invalid param_no");
    1481           0 :                 DBG_RETURN(FAIL);
    1482             :         }
    1483         285 :         SET_EMPTY_ERROR(stmt->error_info);
    1484         285 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1485             : 
    1486         285 :         if (stmt->param_count) {
    1487         285 :                 if (!stmt->param_bind) {
    1488         184 :                         stmt->param_bind = mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent);
    1489         184 :                         if (!stmt->param_bind) {
    1490           0 :                                 DBG_RETURN(FAIL);
    1491             :                         }
    1492             :                 }
    1493             : 
    1494             :                 /* Prevent from freeing */
    1495             :                 /* Don't update is_ref, or we will leak during conversion */
    1496             :                 Z_ADDREF_P(zv);
    1497         285 :                 DBG_INF("Binding");
    1498             :                 /* Release what we had, if we had */
    1499         285 :                 if (stmt->param_bind[param_no].zv) {
    1500           8 :                         zval_ptr_dtor(&stmt->param_bind[param_no].zv);
    1501             :                 }
    1502         285 :                 if (type == MYSQL_TYPE_LONG_BLOB) {
    1503             :                         /* The client will use stmt_send_long_data */
    1504           0 :                         stmt->param_bind[param_no].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
    1505             :                 }
    1506         285 :                 stmt->param_bind[param_no].zv = zv;
    1507         285 :                 stmt->param_bind[param_no].type = type;
    1508             : 
    1509         285 :                 stmt->send_types_to_server = 1;
    1510             :         }
    1511         285 :         DBG_INF("PASS");
    1512         285 :         DBG_RETURN(PASS);
    1513             : }
    1514             : /* }}} */
    1515             : 
    1516             : 
    1517             : /* {{{ mysqlnd_stmt::refresh_bind_param */
    1518             : static enum_func_status
    1519           0 : MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const s TSRMLS_DC)
    1520             : {
    1521           0 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1522           0 :         DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
    1523           0 :         if (!stmt || !stmt->conn) {
    1524           0 :                 DBG_RETURN(FAIL);
    1525             :         }
    1526           0 :         DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
    1527             : 
    1528           0 :         if (stmt->state < MYSQLND_STMT_PREPARED) {
    1529           0 :                 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
    1530           0 :                 DBG_ERR("not prepared");
    1531           0 :                 DBG_RETURN(FAIL);
    1532             :         }
    1533             : 
    1534           0 :         SET_EMPTY_ERROR(stmt->error_info);
    1535           0 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1536             : 
    1537           0 :         if (stmt->param_count) {
    1538           0 :                 stmt->send_types_to_server = 1;
    1539             :         }
    1540           0 :         DBG_INF("PASS");
    1541           0 :         DBG_RETURN(PASS);
    1542             : }
    1543             : /* }}} */
    1544             : 
    1545             : 
    1546             : /* {{{ mysqlnd_stmt::bind_result */
    1547             : static enum_func_status
    1548        1265 : MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
    1549             :                                                                                   MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC)
    1550             : {
    1551        1265 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1552        1265 :         DBG_ENTER("mysqlnd_stmt::bind_result");
    1553        1265 :         if (!stmt || !stmt->conn) {
    1554           0 :                 DBG_RETURN(FAIL);
    1555             :         }
    1556        1265 :         DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
    1557             : 
    1558        1265 :         if (stmt->state < MYSQLND_STMT_PREPARED) {
    1559           0 :                 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
    1560           0 :                 if (result_bind) {
    1561           0 :                         s->m->free_result_bind(s, result_bind TSRMLS_CC);
    1562             :                 }
    1563           0 :                 DBG_ERR("not prepared");
    1564           0 :                 DBG_RETURN(FAIL);
    1565             :         }
    1566             : 
    1567        1265 :         SET_EMPTY_ERROR(stmt->error_info);
    1568        1265 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1569             : 
    1570        1265 :         if (stmt->field_count) {
    1571        1265 :                 unsigned int i = 0;
    1572             : 
    1573        1265 :                 if (!result_bind) {
    1574           0 :                         DBG_ERR("no result bind passed");
    1575           0 :                         DBG_RETURN(FAIL);
    1576             :                 }
    1577             : 
    1578        1265 :                 mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
    1579        1265 :                 stmt->result_zvals_separated_once = FALSE;
    1580        1265 :                 stmt->result_bind = result_bind;
    1581        6781 :                 for (i = 0; i < stmt->field_count; i++) {
    1582             :                         /* Prevent from freeing */
    1583        5516 :                         Z_ADDREF_P(stmt->result_bind[i].zv);
    1584       11032 :                         DBG_INF_FMT("ref of %p = %u", stmt->result_bind[i].zv, Z_REFCOUNT_P(stmt->result_bind[i].zv));
    1585             :                         /*
    1586             :                           Don't update is_ref !!! it's not our job
    1587             :                           Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
    1588             :                           will fail.
    1589             :                         */
    1590        5516 :                         stmt->result_bind[i].bound = TRUE;
    1591             :                 }
    1592           0 :         } else if (result_bind) {
    1593           0 :                 s->m->free_result_bind(s, result_bind TSRMLS_CC);
    1594             :         }
    1595        1265 :         DBG_INF("PASS");
    1596        1265 :         DBG_RETURN(PASS);
    1597             : }
    1598             : /* }}} */
    1599             : 
    1600             : 
    1601             : /* {{{ mysqlnd_stmt::bind_result */
    1602             : static enum_func_status
    1603         891 : MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
    1604             : {
    1605         891 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1606         891 :         DBG_ENTER("mysqlnd_stmt::bind_result");
    1607         891 :         if (!stmt || !stmt->conn) {
    1608           0 :                 DBG_RETURN(FAIL);
    1609             :         }
    1610         891 :         DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
    1611             : 
    1612         891 :         if (stmt->state < MYSQLND_STMT_PREPARED) {
    1613           0 :                 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
    1614           0 :                 DBG_ERR("not prepared");
    1615           0 :                 DBG_RETURN(FAIL);
    1616             :         }
    1617             : 
    1618         891 :         if (param_no >= stmt->field_count) {
    1619           0 :                 SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
    1620           0 :                 DBG_ERR("invalid param_no");
    1621           0 :                 DBG_RETURN(FAIL);
    1622             :         }
    1623             : 
    1624         891 :         SET_EMPTY_ERROR(stmt->error_info);
    1625         891 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    1626             : 
    1627         891 :         if (stmt->field_count) {
    1628         891 :                 mysqlnd_stmt_separate_one_result_bind(s, param_no TSRMLS_CC);
    1629             :                 /* Guaranteed is that stmt->result_bind is NULL */
    1630         891 :                 if (!stmt->result_bind) {
    1631         429 :                         stmt->result_bind = mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent);
    1632             :                 } else {
    1633         462 :                         stmt->result_bind = mnd_perealloc(stmt->result_bind, stmt->field_count * sizeof(MYSQLND_RESULT_BIND), stmt->persistent);
    1634             :                 }
    1635         891 :                 if (!stmt->result_bind) {
    1636           0 :                         DBG_RETURN(FAIL);
    1637             :                 }
    1638         891 :                 ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
    1639             :                 /*
    1640             :                   Don't update is_ref !!! it's not our job
    1641             :                   Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
    1642             :                   will fail.
    1643             :                 */
    1644         891 :                 stmt->result_bind[param_no].bound = TRUE;
    1645             :         }
    1646         891 :         DBG_INF("PASS");
    1647         891 :         DBG_RETURN(PASS);
    1648             : }
    1649             : /* }}} */
    1650             : 
    1651             : 
    1652             : /* {{{ mysqlnd_stmt::insert_id */
    1653             : static uint64_t
    1654           9 : MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s TSRMLS_DC)
    1655             : {
    1656           9 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1657           9 :         return stmt? stmt->upsert_status.last_insert_id : 0;
    1658             : }
    1659             : /* }}} */
    1660             : 
    1661             : 
    1662             : /* {{{ mysqlnd_stmt::affected_rows */
    1663             : static uint64_t
    1664         754 : MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
    1665             : {
    1666         754 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1667         754 :         return stmt? stmt->upsert_status.affected_rows : 0;
    1668             : }
    1669             : /* }}} */
    1670             : 
    1671             : 
    1672             : /* {{{ mysqlnd_stmt::num_rows */
    1673             : static uint64_t
    1674          24 : MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
    1675             : {
    1676          24 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1677          24 :         return stmt && stmt->result? mysqlnd_num_rows(stmt->result):0;
    1678             : }
    1679             : /* }}} */
    1680             : 
    1681             : 
    1682             : /* {{{ mysqlnd_stmt::warning_count */
    1683             : static unsigned int
    1684           0 : MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s TSRMLS_DC)
    1685             : {
    1686           0 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1687           0 :         return stmt? stmt->upsert_status.warning_count : 0;
    1688             : }
    1689             : /* }}} */
    1690             : 
    1691             : 
    1692             : /* {{{ mysqlnd_stmt::server_status */
    1693             : static unsigned int
    1694           0 : MYSQLND_METHOD(mysqlnd_stmt, server_status)(const MYSQLND_STMT * const s TSRMLS_DC)
    1695             : {
    1696           0 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1697           0 :         return stmt? stmt->upsert_status.server_status : 0;
    1698             : }
    1699             : /* }}} */
    1700             : 
    1701             : 
    1702             : /* {{{ mysqlnd_stmt::field_count */
    1703             : static unsigned int
    1704        2493 : MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const s TSRMLS_DC)
    1705             : {
    1706        2493 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1707        2493 :         return stmt? stmt->field_count : 0;
    1708             : }
    1709             : /* }}} */
    1710             : 
    1711             : 
    1712             : /* {{{ mysqlnd_stmt::param_count */
    1713             : static unsigned int
    1714       21748 : MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const s TSRMLS_DC)
    1715             : {
    1716       21748 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1717       21748 :         return stmt? stmt->param_count : 0;
    1718             : }
    1719             : /* }}} */
    1720             : 
    1721             : 
    1722             : /* {{{ mysqlnd_stmt::errno */
    1723             : static unsigned int
    1724          21 : MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s TSRMLS_DC)
    1725             : {
    1726          21 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1727          21 :         return stmt? stmt->error_info.error_no : 0;
    1728             : }
    1729             : /* }}} */
    1730             : 
    1731             : 
    1732             : /* {{{ mysqlnd_stmt::error */
    1733             : static const char *
    1734          11 : MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s TSRMLS_DC)
    1735             : {
    1736          11 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1737          11 :         return stmt? stmt->error_info.error : 0;
    1738             : }
    1739             : /* }}} */
    1740             : 
    1741             : 
    1742             : /* {{{ mysqlnd_stmt::sqlstate */
    1743             : static const char *
    1744          12 : MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s TSRMLS_DC)
    1745             : {
    1746          12 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1747          12 :         return stmt && stmt->error_info.sqlstate[0] ? stmt->error_info.sqlstate:MYSQLND_SQLSTATE_NULL;
    1748             : }
    1749             : /* }}} */
    1750             : 
    1751             : 
    1752             : /* {{{ mysqlnd_stmt::data_seek */
    1753             : static enum_func_status
    1754           3 : MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const s, uint64_t row TSRMLS_DC)
    1755             : {
    1756           3 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1757           3 :         return stmt && stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
    1758             : }
    1759             : /* }}} */
    1760             : 
    1761             : 
    1762             : /* {{{ mysqlnd_stmt::param_metadata */
    1763             : static MYSQLND_RES *
    1764           0 : MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
    1765             : {
    1766           0 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1767           0 :         if (!stmt || !stmt->param_count) {
    1768           0 :                 return NULL;
    1769             :         }
    1770           0 :         return NULL;
    1771             : }
    1772             : /* }}} */
    1773             : 
    1774             : 
    1775             : /* {{{ mysqlnd_stmt::result_metadata */
    1776             : static MYSQLND_RES *
    1777         945 : MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
    1778             : {
    1779         945 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1780             :         MYSQLND_RES *result;
    1781             : 
    1782         945 :         DBG_ENTER("mysqlnd_stmt::result_metadata");
    1783         945 :         if (!stmt) {
    1784           0 :                 DBG_RETURN(NULL);
    1785             :         }
    1786         945 :         DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
    1787             : 
    1788         945 :         if (!stmt->field_count || !stmt->conn || !stmt->result || !stmt->result->meta) {
    1789         292 :                 DBG_INF("NULL");
    1790         292 :                 DBG_RETURN(NULL);
    1791             :         }
    1792             : 
    1793         653 :         if (stmt->update_max_length && stmt->result->stored_data) {
    1794             :                 /* stored result, we have to update the max_length before we clone the meta data :( */
    1795           1 :                 stmt->result->m.initialize_result_set_rest(stmt->result TSRMLS_CC);
    1796             :         }
    1797             :         /*
    1798             :           TODO: This implementation is kind of a hack,
    1799             :                         find a better way to do it. In different functions I have put
    1800             :                         fuses to check for result->m.fetch_row() being NULL. This should
    1801             :                         be handled in a better way.
    1802             : 
    1803             :           In the meantime we don't need a zval cache reference for this fake
    1804             :           result set, so we don't get one.
    1805             :         */
    1806             :         do {
    1807         653 :                 result = stmt->conn->m->result_init(stmt->field_count, stmt->persistent TSRMLS_CC);
    1808         653 :                 if (!result) {
    1809           0 :                         break;
    1810             :                 }
    1811         653 :                 result->type = MYSQLND_RES_NORMAL;
    1812         653 :                 result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
    1813         653 :                 result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
    1814         653 :                 if (!result->unbuf) {
    1815           0 :                         break;
    1816             :                 }
    1817         653 :                 result->unbuf->eof_reached = TRUE;
    1818         653 :                 result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
    1819         653 :                 if (!result->meta) {
    1820           0 :                         break;
    1821             :                 }
    1822             : 
    1823         653 :                 DBG_INF_FMT("result=%p", result);
    1824         653 :                 DBG_RETURN(result);
    1825             :         } while (0);
    1826             : 
    1827           0 :         SET_OOM_ERROR(stmt->conn->error_info);
    1828           0 :         if (result) {
    1829           0 :                 result->m.free_result(result, TRUE TSRMLS_CC);
    1830             :         }
    1831           0 :         DBG_RETURN(NULL);
    1832             : }
    1833             : /* }}} */
    1834             : 
    1835             : 
    1836             : /* {{{ mysqlnd_stmt::attr_set */
    1837             : static enum_func_status
    1838        1110 : MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
    1839             :                                                                            enum mysqlnd_stmt_attr attr_type,
    1840             :                                                                            const void * const value TSRMLS_DC)
    1841             : {
    1842        1110 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1843        1110 :         DBG_ENTER("mysqlnd_stmt::attr_set");
    1844        1110 :         if (!stmt) {
    1845           0 :                 DBG_RETURN(FAIL);
    1846             :         }
    1847        1110 :         DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
    1848             : 
    1849        1110 :         switch (attr_type) {
    1850             :                 case STMT_ATTR_UPDATE_MAX_LENGTH:{
    1851           2 :                         zend_uchar bval = *(zend_uchar *) value;
    1852             :                         /*
    1853             :                           XXX : libmysql uses my_bool, but mysqli uses ulong as storage on the stack
    1854             :                           and mysqlnd won't be used out of the scope of PHP -> use ulong.
    1855             :                         */
    1856           2 :                         stmt->update_max_length = bval? TRUE:FALSE;
    1857           2 :                         break;
    1858             :                 }
    1859             :                 case STMT_ATTR_CURSOR_TYPE: {
    1860           9 :                         unsigned int ival = *(unsigned int *) value;
    1861           9 :                         if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) {
    1862           2 :                                 SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
    1863           2 :                                 DBG_INF("FAIL");
    1864           2 :                                 DBG_RETURN(FAIL);
    1865             :                         }
    1866           7 :                         stmt->flags = ival;
    1867           7 :                         break;
    1868             :                 }
    1869             :                 case STMT_ATTR_PREFETCH_ROWS: {
    1870           1 :                         unsigned int ival = *(unsigned int *) value;
    1871           1 :                         if (ival == 0) {
    1872           0 :                                 ival = MYSQLND_DEFAULT_PREFETCH_ROWS;
    1873           1 :                         } else if (ival > 1) {
    1874           0 :                                 SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
    1875           0 :                                 DBG_INF("FAIL");
    1876           0 :                                 DBG_RETURN(FAIL);
    1877             :                         }
    1878           1 :                         stmt->prefetch_rows = ival;
    1879           1 :                         break;
    1880             :                 }
    1881             :                 default:
    1882        1098 :                         SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
    1883        1098 :                         DBG_RETURN(FAIL);
    1884             :         }
    1885          10 :         DBG_INF("PASS");
    1886          10 :         DBG_RETURN(PASS);
    1887             : }
    1888             : /* }}} */
    1889             : 
    1890             : 
    1891             : /* {{{ mysqlnd_stmt::attr_get */
    1892             : static enum_func_status
    1893           6 : MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
    1894             :                                                                            enum mysqlnd_stmt_attr attr_type,
    1895             :                                                                            void * const value TSRMLS_DC)
    1896             : {
    1897           6 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1898           6 :         DBG_ENTER("mysqlnd_stmt::attr_set");
    1899           6 :         if (!stmt) {
    1900           0 :                 DBG_RETURN(FAIL);
    1901             :         }
    1902           6 :         DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
    1903             : 
    1904           6 :         switch (attr_type) {
    1905             :                 case STMT_ATTR_UPDATE_MAX_LENGTH:
    1906           3 :                         *(zend_bool *) value= stmt->update_max_length;
    1907           3 :                         break;
    1908             :                 case STMT_ATTR_CURSOR_TYPE:
    1909           1 :                         *(unsigned long *) value= stmt->flags;
    1910           1 :                         break;
    1911             :                 case STMT_ATTR_PREFETCH_ROWS:
    1912           1 :                         *(unsigned long *) value= stmt->prefetch_rows;
    1913           1 :                         break;
    1914             :                 default:
    1915           1 :                         DBG_RETURN(FAIL);
    1916             :         }
    1917           5 :         DBG_INF_FMT("value=%lu", value);
    1918           5 :         DBG_RETURN(PASS);
    1919             : }
    1920             : /* }}} */
    1921             : 
    1922             : /* free_result() doesn't actually free stmt->result but only the buffers */
    1923             : /* {{{ mysqlnd_stmt::free_result */
    1924             : static enum_func_status
    1925         260 : MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s TSRMLS_DC)
    1926             : {
    1927         260 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1928         260 :         DBG_ENTER("mysqlnd_stmt::free_result");
    1929         260 :         if (!stmt || !stmt->conn) {
    1930           0 :                 DBG_RETURN(FAIL);
    1931             :         }
    1932         260 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
    1933             : 
    1934         260 :         if (!stmt->result) {
    1935           6 :                 DBG_INF("no result");
    1936           6 :                 DBG_RETURN(PASS);
    1937             :         }
    1938             : 
    1939             :         /*
    1940             :           If right after execute() we have to call the appropriate
    1941             :           use_result() or store_result() and clean.
    1942             :         */
    1943         254 :         if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
    1944           3 :                 DBG_INF("fetching result set header");
    1945             :                 /* Do implicit use_result and then flush the result */
    1946           3 :                 stmt->default_rset_handler = s->m->use_result;
    1947           3 :                 stmt->default_rset_handler(s TSRMLS_CC);
    1948             :         }
    1949             : 
    1950         254 :         if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
    1951         253 :                 DBG_INF("skipping result");
    1952             :                 /* Flush if anything is left and unbuffered set */
    1953         253 :                 stmt->result->m.skip_result(stmt->result TSRMLS_CC);
    1954             :                 /*
    1955             :                   Separate the bound variables, which point to the result set, then
    1956             :                   destroy the set.
    1957             :                 */
    1958         253 :                 mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
    1959             : 
    1960             :                 /* Now we can destroy the result set */
    1961         253 :                 stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
    1962             :         }
    1963             : 
    1964         254 :         if (stmt->state > MYSQLND_STMT_PREPARED) {
    1965             :                 /* As the buffers have been freed, we should go back to PREPARED */
    1966         253 :                 stmt->state = MYSQLND_STMT_PREPARED;
    1967             :         }
    1968             : 
    1969             :         /* Line is free! */
    1970         254 :         CONN_SET_STATE(stmt->conn, CONN_READY);
    1971             : 
    1972         254 :         DBG_RETURN(PASS);
    1973             : }
    1974             : /* }}} */
    1975             : 
    1976             : 
    1977             : /* {{{ mysqlnd_stmt_separate_result_bind */
    1978             : static void
    1979        5771 : mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC)
    1980             : {
    1981        5771 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    1982             :         unsigned int i;
    1983             : 
    1984        5771 :         DBG_ENTER("mysqlnd_stmt_separate_result_bind");
    1985        5771 :         if (!stmt) {
    1986           0 :                 DBG_VOID_RETURN;
    1987             :         }
    1988        5771 :         DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u",
    1989             :                                 stmt->stmt_id, stmt->result_bind, stmt->field_count);
    1990             : 
    1991        5771 :         if (!stmt->result_bind) {
    1992        4077 :                 DBG_VOID_RETURN;
    1993             :         }
    1994             : 
    1995             :         /*
    1996             :           Because only the bound variables can point to our internal buffers, then
    1997             :           separate or free only them. Free is possible because the user could have
    1998             :           lost reference.
    1999             :         */
    2000        8062 :         for (i = 0; i < stmt->field_count; i++) {
    2001             :                 /* Let's try with no cache */
    2002        6368 :                 if (stmt->result_bind[i].bound == TRUE) {
    2003       12736 :                         DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNT_P(stmt->result_bind[i].zv));
    2004             :                         /*
    2005             :                           We have to separate the actual zval value of the bound
    2006             :                           variable from our allocated zvals or we will face double-free
    2007             :                         */
    2008       12736 :                         if (Z_REFCOUNT_P(stmt->result_bind[i].zv) > 1) {
    2009             : #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
    2010             :                                 zval_copy_ctor(stmt->result_bind[i].zv);
    2011             : #endif
    2012        5506 :                                 zval_ptr_dtor(&stmt->result_bind[i].zv);
    2013             :                         } else {
    2014             :                                 /*
    2015             :                                   If it is a string, what is pointed will be freed
    2016             :                                   later in free_result(). We need to remove the variable to
    2017             :                                   which the user has lost reference.
    2018             :                                 */
    2019             : #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
    2020             :                                 ZVAL_NULL(stmt->result_bind[i].zv);
    2021             : #endif
    2022         862 :                                 zval_ptr_dtor(&stmt->result_bind[i].zv);
    2023             :                         }
    2024             :                 }
    2025             :         }
    2026        1694 :         s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC);
    2027        1694 :         stmt->result_bind = NULL;
    2028             : 
    2029        1694 :         DBG_VOID_RETURN;
    2030             : }
    2031             : /* }}} */
    2032             : 
    2033             : 
    2034             : /* {{{ mysqlnd_stmt_separate_one_result_bind */
    2035             : static void
    2036         891 : mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
    2037             : {
    2038         891 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2039         891 :         DBG_ENTER("mysqlnd_stmt_separate_one_result_bind");
    2040         891 :         if (!stmt) {
    2041           0 :                 DBG_VOID_RETURN;
    2042             :         }
    2043         891 :         DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%u",
    2044             :                                 stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no);
    2045             : 
    2046         891 :         if (!stmt->result_bind) {
    2047         429 :                 DBG_VOID_RETURN;
    2048             :         }
    2049             : 
    2050             :         /*
    2051             :           Because only the bound variables can point to our internal buffers, then
    2052             :           separate or free only them. Free is possible because the user could have
    2053             :           lost reference.
    2054             :         */
    2055             :         /* Let's try with no cache */
    2056         462 :         if (stmt->result_bind[param_no].bound == TRUE) {
    2057          78 :                 DBG_INF_FMT("%u has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
    2058             :                 /*
    2059             :                   We have to separate the actual zval value of the bound
    2060             :                   variable from our allocated zvals or we will face double-free
    2061             :                 */
    2062          78 :                 if (Z_REFCOUNT_P(stmt->result_bind[param_no].zv) > 1) {
    2063             : #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
    2064             :                         zval_copy_ctor(stmt->result_bind[param_no].zv);
    2065             : #endif
    2066           0 :                         zval_ptr_dtor(&stmt->result_bind[param_no].zv);
    2067             :                 } else {
    2068             :                         /*
    2069             :                           If it is a string, what is pointed will be freed
    2070             :                           later in free_result(). We need to remove the variable to
    2071             :                           which the user has lost reference.
    2072             :                         */
    2073             : #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
    2074             :                         ZVAL_NULL(stmt->result_bind[param_no].zv);
    2075             : #endif
    2076          39 :                         zval_ptr_dtor(&stmt->result_bind[param_no].zv);
    2077             :                 }
    2078             :         }
    2079             : 
    2080         462 :         DBG_VOID_RETURN;
    2081             : }
    2082             : /* }}} */
    2083             : 
    2084             : 
    2085             : /* {{{ mysqlnd_stmt::free_stmt_content */
    2086             : static void
    2087        4253 : MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC)
    2088             : {
    2089        4253 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2090        4253 :         DBG_ENTER("mysqlnd_stmt::free_stmt_content");
    2091        4253 :         if (!stmt) {
    2092           0 :                 DBG_VOID_RETURN;
    2093             :         }
    2094        4253 :         DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u",
    2095             :                                 stmt->stmt_id, stmt->param_bind, stmt->param_count);
    2096             : 
    2097             :         /* Destroy the input bind */
    2098        4253 :         if (stmt->param_bind) {
    2099             :                 unsigned int i;
    2100             :                 /*
    2101             :                   Because only the bound variables can point to our internal buffers, then
    2102             :                   separate or free only them. Free is possible because the user could have
    2103             :                   lost reference.
    2104             :                 */
    2105      132821 :                 for (i = 0; i < stmt->param_count; i++) {
    2106             :                         /*
    2107             :                           If bind_one_parameter was used, but not everything was
    2108             :                           bound and nothing was fetched, then some `zv` could be NULL
    2109             :                         */
    2110      132198 :                         if (stmt->param_bind[i].zv) {
    2111      132197 :                                 zval_ptr_dtor(&stmt->param_bind[i].zv);
    2112             :                         }
    2113             :                 }
    2114         623 :                 s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
    2115         623 :                 stmt->param_bind = NULL;
    2116             :         }
    2117             : 
    2118             :         /*
    2119             :           First separate the bound variables, which point to the result set, then
    2120             :           destroy the set.
    2121             :         */
    2122        4253 :         mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
    2123             :         /* Not every statement has a result set attached */
    2124        4253 :         if (stmt->result) {
    2125        2450 :                 stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
    2126        2450 :                 stmt->result = NULL;
    2127             :         }
    2128             : 
    2129        4253 :         DBG_VOID_RETURN;
    2130             : }
    2131             : /* }}} */
    2132             : 
    2133             : 
    2134             : /* {{{ mysqlnd_stmt::net_close */
    2135             : static enum_func_status
    2136        4236 : MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
    2137             : {
    2138        4236 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2139             :         MYSQLND * conn;
    2140             :         zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
    2141        4236 :         enum_mysqlnd_collected_stats statistic = STAT_LAST;
    2142             : 
    2143        4236 :         DBG_ENTER("mysqlnd_stmt::net_close");
    2144        4236 :         if (!stmt || !stmt->conn) {
    2145           0 :                 DBG_RETURN(FAIL);
    2146             :         }
    2147        4236 :         DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
    2148             : 
    2149        4236 :         conn = stmt->conn;
    2150             : 
    2151        4236 :         SET_EMPTY_ERROR(stmt->error_info);
    2152        4236 :         SET_EMPTY_ERROR(stmt->conn->error_info);
    2153             : 
    2154             :         /*
    2155             :           If the user decided to close the statement right after execute()
    2156             :           We have to call the appropriate use_result() or store_result() and
    2157             :           clean.
    2158             :         */
    2159             :         do {
    2160        4237 :                 DBG_INF_FMT("stmt->state=%u", stmt->state);
    2161        4237 :                 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
    2162          15 :                         DBG_INF("fetching result set header");
    2163          15 :                         stmt->default_rset_handler(s TSRMLS_CC);
    2164          15 :                         stmt->state = MYSQLND_STMT_USER_FETCHING;
    2165             :                 }
    2166             : 
    2167             :                 /* unbuffered set not fetched to the end ? Clean the line */
    2168        4237 :                 if (stmt->result) {
    2169        2434 :                         DBG_INF("skipping result");
    2170        2434 :                         stmt->result->m.skip_result(stmt->result TSRMLS_CC);
    2171             :                 }
    2172        4237 :         } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
    2173             :         /*
    2174             :           After this point we are allowed to free the result set,
    2175             :           as we have cleaned the line
    2176             :         */
    2177        4236 :         if (stmt->stmt_id) {
    2178        4207 :                 MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE?  STAT_FREE_RESULT_IMPLICIT:
    2179             :                                                                                                                 STAT_FREE_RESULT_EXPLICIT);
    2180             : 
    2181        4207 :                 int4store(cmd_buf, stmt->stmt_id);
    2182        8391 :                 if (CONN_GET_STATE(conn) == CONN_READY &&
    2183        4184 :                         FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, (char *)cmd_buf, sizeof(cmd_buf),
    2184             :                                                                                    PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
    2185             :                                                                                    FALSE, TRUE TSRMLS_CC)) {
    2186           0 :                         stmt->error_info = conn->error_info;
    2187           0 :                         DBG_RETURN(FAIL);
    2188             :                 }
    2189             :         }
    2190        4236 :         switch (stmt->execute_count) {
    2191             :                 case 0:
    2192         260 :                         statistic = STAT_PS_PREPARED_NEVER_EXECUTED;
    2193         260 :                         break;
    2194             :                 case 1:
    2195        3656 :                         statistic = STAT_PS_PREPARED_ONCE_USED;
    2196             :                         break;
    2197             :                 default:
    2198             :                         break;
    2199             :         }
    2200        4236 :         if (statistic != STAT_LAST) {
    2201        3916 :                 MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
    2202             :         }
    2203             : 
    2204        4236 :         if (stmt->execute_cmd_buffer.buffer) {
    2205        4236 :                 mnd_pefree(stmt->execute_cmd_buffer.buffer, stmt->persistent);
    2206        4236 :                 stmt->execute_cmd_buffer.buffer = NULL;
    2207             :         }
    2208             : 
    2209        4236 :         s->m->free_stmt_content(s TSRMLS_CC);
    2210             : 
    2211        4236 :         if (stmt->conn) {
    2212        4236 :                 stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
    2213        4236 :                 stmt->conn = NULL;
    2214             :         }
    2215             : 
    2216        4236 :         DBG_RETURN(PASS);
    2217             : }
    2218             : /* }}} */
    2219             : 
    2220             : /* {{{ mysqlnd_stmt::dtor */
    2221             : static enum_func_status
    2222        4236 : MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
    2223             : {
    2224        4236 :         MYSQLND_STMT_DATA * stmt = (s != NULL) ? s->data:NULL;
    2225        4236 :         enum_func_status ret = FAIL;
    2226        4236 :         zend_bool persistent = (s != NULL) ? s->persistent : 0;
    2227             : 
    2228        4236 :         DBG_ENTER("mysqlnd_stmt::dtor");
    2229        4236 :         if (stmt) {
    2230             : 
    2231        4236 :                 DBG_INF_FMT("stmt=%p", stmt);
    2232             : 
    2233        4236 :                 MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE?  STAT_STMT_CLOSE_IMPLICIT:
    2234             :                                                                                                                 STAT_STMT_CLOSE_EXPLICIT);
    2235             : 
    2236        4236 :                 ret = s->m->net_close(s, implicit TSRMLS_CC);
    2237        4236 :                 mnd_pefree(stmt, persistent);
    2238             :         }
    2239        4236 :         mnd_pefree(s, persistent);
    2240             : 
    2241        4236 :         DBG_INF(ret == PASS? "PASS":"FAIL");
    2242        4236 :         DBG_RETURN(ret);
    2243             : }
    2244             : /* }}} */
    2245             : 
    2246             : 
    2247             : /* {{{ mysqlnd_stmt::alloc_param_bind */
    2248             : static MYSQLND_PARAM_BIND *
    2249       20876 : MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind)(MYSQLND_STMT * const s TSRMLS_DC)
    2250             : {
    2251       20876 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2252       20876 :         DBG_ENTER("mysqlnd_stmt::alloc_param_bind");
    2253       20876 :         if (!stmt) {
    2254           0 :                 DBG_RETURN(NULL);
    2255             :         }
    2256       20876 :         DBG_RETURN(mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent));
    2257             : }
    2258             : /* }}} */
    2259             : 
    2260             : 
    2261             : /* {{{ mysqlnd_stmt::alloc_result_bind */
    2262             : static MYSQLND_RESULT_BIND *
    2263        1265 : MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind)(MYSQLND_STMT * const s TSRMLS_DC)
    2264             : {
    2265        1265 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2266        1265 :         DBG_ENTER("mysqlnd_stmt::alloc_result_bind");
    2267        1265 :         if (!stmt) {
    2268           0 :                 DBG_RETURN(NULL);
    2269             :         }
    2270        1265 :         DBG_RETURN(mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent));
    2271             : }
    2272             : /* }}} */
    2273             : 
    2274             : 
    2275             : /* {{{ param_bind::free_parameter_bind */
    2276             : PHPAPI void
    2277       21060 : MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * param_bind TSRMLS_DC)
    2278             : {
    2279       21060 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2280       21060 :         if (stmt) {
    2281       21060 :                 mnd_pefree(param_bind, stmt->persistent);
    2282             :         }
    2283       21060 : }
    2284             : /* }}} */
    2285             : 
    2286             : 
    2287             : /* {{{ mysqlnd_stmt::free_result_bind */
    2288             : PHPAPI void
    2289        1694 : MYSQLND_METHOD(mysqlnd_stmt, free_result_bind)(MYSQLND_STMT * const s, MYSQLND_RESULT_BIND * result_bind TSRMLS_DC)
    2290             : {
    2291        1694 :         MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
    2292        1694 :         if (stmt) {
    2293        1694 :                 mnd_pefree(result_bind, stmt->persistent);
    2294             :         }
    2295        1694 : }
    2296             : /* }}} */
    2297             : 
    2298             : 
    2299             : 
    2300             : MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
    2301             :         MYSQLND_METHOD(mysqlnd_stmt, prepare),
    2302             :         MYSQLND_METHOD(mysqlnd_stmt, execute),
    2303             :         MYSQLND_METHOD(mysqlnd_stmt, use_result),
    2304             :         MYSQLND_METHOD(mysqlnd_stmt, store_result),
    2305             :         MYSQLND_METHOD(mysqlnd_stmt, get_result),
    2306             :         MYSQLND_METHOD(mysqlnd_stmt, more_results),
    2307             :         MYSQLND_METHOD(mysqlnd_stmt, next_result),
    2308             :         MYSQLND_METHOD(mysqlnd_stmt, free_result),
    2309             :         MYSQLND_METHOD(mysqlnd_stmt, data_seek),
    2310             :         MYSQLND_METHOD(mysqlnd_stmt, reset),
    2311             :         MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close),
    2312             :         MYSQLND_METHOD(mysqlnd_stmt, dtor),
    2313             : 
    2314             :         MYSQLND_METHOD(mysqlnd_stmt, fetch),
    2315             : 
    2316             :         MYSQLND_METHOD(mysqlnd_stmt, bind_parameters),
    2317             :         MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter),
    2318             :         MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
    2319             :         MYSQLND_METHOD(mysqlnd_stmt, bind_result),
    2320             :         MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
    2321             :         MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
    2322             :         MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
    2323             :         MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
    2324             : 
    2325             :         MYSQLND_METHOD(mysqlnd_stmt, insert_id),
    2326             :         MYSQLND_METHOD(mysqlnd_stmt, affected_rows),
    2327             :         MYSQLND_METHOD(mysqlnd_stmt, num_rows),
    2328             : 
    2329             :         MYSQLND_METHOD(mysqlnd_stmt, param_count),
    2330             :         MYSQLND_METHOD(mysqlnd_stmt, field_count),
    2331             :         MYSQLND_METHOD(mysqlnd_stmt, warning_count),
    2332             : 
    2333             :         MYSQLND_METHOD(mysqlnd_stmt, errno),
    2334             :         MYSQLND_METHOD(mysqlnd_stmt, error),
    2335             :         MYSQLND_METHOD(mysqlnd_stmt, sqlstate),
    2336             : 
    2337             :         MYSQLND_METHOD(mysqlnd_stmt, attr_get),
    2338             :         MYSQLND_METHOD(mysqlnd_stmt, attr_set),
    2339             : 
    2340             : 
    2341             :         MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind),
    2342             :         MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind),
    2343             :         MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind),
    2344             :         MYSQLND_METHOD(mysqlnd_stmt, free_result_bind),
    2345             :         MYSQLND_METHOD(mysqlnd_stmt, server_status),
    2346             :         mysqlnd_stmt_execute_generate_request,
    2347             :         mysqlnd_stmt_execute_parse_response,
    2348             :         MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)
    2349             : MYSQLND_CLASS_METHODS_END;
    2350             : 
    2351             : 
    2352             : /* {{{ _mysqlnd_stmt_init */
    2353        4236 : MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
    2354             : {
    2355        4236 :         size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
    2356        4236 :         MYSQLND_STMT * ret = mnd_pecalloc(1, alloc_size, conn->persistent);
    2357        4236 :         MYSQLND_STMT_DATA * stmt = NULL;
    2358             : 
    2359        4236 :         DBG_ENTER("_mysqlnd_stmt_init");
    2360             :         do {
    2361        4236 :                 if (!ret) {
    2362           0 :                         break;
    2363             :                 }
    2364        4236 :                 ret->m = mysqlnd_stmt_methods;
    2365        4236 :                 ret->persistent = conn->persistent;
    2366             : 
    2367        4236 :                 stmt = ret->data = mnd_pecalloc(1, sizeof(MYSQLND_STMT_DATA), conn->persistent);
    2368        4236 :                 DBG_INF_FMT("stmt=%p", stmt);
    2369        4236 :                 if (!stmt) {
    2370           0 :                         break;
    2371             :                 }
    2372        4236 :                 stmt->persistent = conn->persistent;
    2373        4236 :                 stmt->state = MYSQLND_STMT_INITTED;
    2374        4236 :                 stmt->execute_cmd_buffer.length = 4096;
    2375        4236 :                 stmt->execute_cmd_buffer.buffer = mnd_pemalloc(stmt->execute_cmd_buffer.length, stmt->persistent);
    2376        4236 :                 if (!stmt->execute_cmd_buffer.buffer) {
    2377           0 :                         break;
    2378             :                 }
    2379             : 
    2380        4236 :                 stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
    2381             :                 /*
    2382             :                   Mark that we reference the connection, thus it won't be
    2383             :                   be destructed till there is open statements. The last statement
    2384             :                   or normal query result will close it then.
    2385             :                 */
    2386        4236 :                 stmt->conn = conn->m->get_reference(conn TSRMLS_CC);
    2387             : 
    2388        4236 :                 DBG_RETURN(ret);
    2389             :         } while (0);
    2390             : 
    2391           0 :         SET_OOM_ERROR(conn->error_info);
    2392           0 :         if (ret) {
    2393           0 :                 ret->m->dtor(ret, TRUE TSRMLS_CC);
    2394           0 :                 ret = NULL;
    2395             :         }
    2396           0 :         DBG_RETURN(NULL);
    2397             : }
    2398             : /* }}} */
    2399             : 
    2400             : 
    2401             : /* {{{ _mysqlnd_plugin_get_plugin_stmt_data */
    2402           0 : PHPAPI void ** _mysqlnd_plugin_get_plugin_stmt_data(const MYSQLND_STMT * stmt, unsigned int plugin_id TSRMLS_DC)
    2403             : {
    2404           0 :         DBG_ENTER("_mysqlnd_plugin_get_plugin_stmt_data");
    2405           0 :         DBG_INF_FMT("plugin_id=%u", plugin_id);
    2406           0 :         if (!stmt || plugin_id >= mysqlnd_plugin_count()) {
    2407           0 :                 return NULL;
    2408             :         }
    2409           0 :         DBG_RETURN((void *)((char *)stmt + sizeof(MYSQLND_STMT) + plugin_id * sizeof(void *)));
    2410             : }
    2411             : /* }}} */
    2412             : 
    2413             : 
    2414             : /* {{{ _mysqlnd_init_ps_subsystem */
    2415       19341 : void _mysqlnd_init_ps_subsystem()
    2416             : {
    2417       19341 :         mysqlnd_stmt_methods = &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt);
    2418       19341 :         _mysqlnd_init_ps_fetch_subsystem();
    2419       19341 : }
    2420             : /* }}} */
    2421             : 
    2422             : 
    2423             : /* {{{ mysqlnd_conn_get_methods */
    2424           0 : PHPAPI struct st_mysqlnd_stmt_methods * mysqlnd_stmt_get_methods()
    2425             : {
    2426           0 :         return mysqlnd_stmt_methods;
    2427             : }
    2428             : /* }}} */
    2429             : 
    2430             : 
    2431             : /* {{{ mysqlnd_conn_set_methods */
    2432           0 : PHPAPI void mysqlnd_stmt_set_methods(struct st_mysqlnd_stmt_methods *methods)
    2433             : {
    2434           0 :         mysqlnd_stmt_methods = methods;
    2435           0 : }
    2436             : /* }}} */
    2437             : 
    2438             : 
    2439             : /*
    2440             :  * Local variables:
    2441             :  * tab-width: 4
    2442             :  * c-basic-offset: 4
    2443             :  * End:
    2444             :  * vim600: noet sw=4 ts=4 fdm=marker
    2445             :  * vim<600: noet sw=4 ts=4
    2446             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:30 +0000 (36 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.