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

LTP GCOV extension - code coverage report
Current view: directory - mysqlnd - mysqlnd_ps.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 874
Code covered: 81.0 % Executed lines: 708
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:33 +0000 (35 hours ago)

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