--- embedaddon/php/ext/mysqlnd/mysqlnd_ps.c 2012/02/21 23:47:58 1.1.1.1 +++ embedaddon/php/ext/mysqlnd/mysqlnd_ps.c 2012/05/29 12:34:41 1.1.1.2 @@ -12,13 +12,13 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Authors: Georg Richter | - | Andrey Hristov | + | Authors: Andrey Hristov | | Ulf Wendel | + | Georg Richter | +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_ps.c,v 1.1.1.1 2012/02/21 23:47:58 misho Exp $ */ +/* $Id: mysqlnd_ps.c,v 1.1.1.2 2012/05/29 12:34:41 misho Exp $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_wireprotocol.h" @@ -28,16 +28,14 @@ #include "mysqlnd_statistics.h" #include "mysqlnd_debug.h" #include "mysqlnd_block_alloc.h" +#include "mysqlnd_ext_plugin.h" - #define MYSQLND_SILENT const char * const mysqlnd_not_bound_as_blob = "Can't send long data for non-string/non-binary data types"; const char * const mysqlnd_stmt_not_prepared = "Statement not prepared"; -static struct st_mysqlnd_stmt_methods *mysqlnd_stmt_methods; - /* Exported by mysqlnd_ps_codec.c */ enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC); @@ -52,15 +50,15 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC); static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC); + /* {{{ mysqlnd_stmt::store_result */ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; enum_func_status ret; - MYSQLND * conn; + MYSQLND_CONN_DATA * conn; MYSQLND_RES * result; - zend_bool to_cache = FALSE; DBG_ENTER("mysqlnd_stmt::store_result"); if (!stmt || !stmt->conn || !stmt->result) { @@ -84,33 +82,34 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STM if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) { - SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, + SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); DBG_RETURN(NULL); } stmt->default_rset_handler = s->m->store_result; - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*conn->error_info); MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS); result = stmt->result; result->type = MYSQLND_RES_PS_BUF; result->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; result->m.fetch_lengths = NULL;/* makes no sense */ + result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC); - ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE, to_cache TSRMLS_CC); + ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC); if (PASS == ret) { /* libmysql API docs say it should be so for SELECT statements */ - stmt->upsert_status.affected_rows = stmt->result->stored_data->row_count; + stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count; stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED; } else { - conn->error_info = result->stored_data->error_info; + COPY_CLIENT_ERROR(*conn->error_info, result->stored_data->error_info); stmt->result->m.free_result_contents(stmt->result TSRMLS_CC); mnd_efree(stmt->result); stmt->result = NULL; @@ -127,7 +126,7 @@ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - MYSQLND * conn; + MYSQLND_CONN_DATA * conn; MYSQLND_RES *result; DBG_ENTER("mysqlnd_stmt::get_result"); @@ -150,34 +149,34 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT /* Nothing to store for UPSERT/LOAD DATA*/ if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) { - SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, + SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); DBG_RETURN(NULL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*conn->error_info); MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS); do { result = conn->m->result_init(stmt->result->field_count, stmt->persistent TSRMLS_CC); if (!result) { - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*conn->error_info); break; } result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC); if (!result->meta) { - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*conn->error_info); break; } if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) { - stmt->upsert_status.affected_rows = result->stored_data->row_count; + stmt->upsert_status->affected_rows = result->stored_data->row_count; stmt->state = MYSQLND_STMT_PREPARED; result->type = MYSQLND_RES_PS_BUF; } else { - stmt->error_info = conn->error_info; + COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); stmt->state = MYSQLND_STMT_PREPARED; break; } @@ -199,8 +198,7 @@ MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQL MYSQLND_STMT_DATA * stmt = s? s->data:NULL; DBG_ENTER("mysqlnd_stmt::more_results"); /* (conn->state == CONN_NEXT_RESULT_PENDING) too */ - DBG_RETURN((stmt && stmt->conn && (stmt->conn->upsert_status.server_status & - SERVER_MORE_RESULTS_EXISTS))? + DBG_RETURN((stmt && stmt->conn && (stmt->conn->m->get_server_status(stmt->conn TSRMLS_CC) & SERVER_MORE_RESULTS_EXISTS))? TRUE: FALSE); } @@ -212,7 +210,7 @@ static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - MYSQLND * conn; + MYSQLND_CONN_DATA * conn; DBG_ENTER("mysqlnd_stmt::next_result"); if (!stmt || !stmt->conn || !stmt->result) { @@ -221,12 +219,11 @@ MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT conn = stmt->conn; DBG_INF_FMT("stmt=%lu", stmt->stmt_id); - if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS)) { + if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS)) { DBG_RETURN(FAIL); } - DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); - DBG_INF_FMT("server_status=%u cursor=%u", conn->upsert_status.server_status, conn->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); + DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS); /* Free space for next result */ s->m->free_stmt_content(s TSRMLS_CC); @@ -256,8 +253,8 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC) field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC); if (!field_packet) { - SET_OOM_ERROR(stmt->error_info); - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*stmt->error_info); + SET_OOM_ERROR(*stmt->conn->error_info); } else { ret = PASS; field_packet->skip_parsing = TRUE; @@ -291,8 +288,8 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TS prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC); if (!prepare_resp) { - SET_OOM_ERROR(stmt->error_info); - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*stmt->error_info); + SET_OOM_ERROR(*stmt->conn->error_info); goto done; } @@ -301,12 +298,13 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TS } if (0xFF == prepare_resp->error_code) { - stmt->error_info = stmt->conn->error_info = prepare_resp->error_info; + COPY_CLIENT_ERROR(*stmt->error_info, prepare_resp->error_info); + COPY_CLIENT_ERROR(*stmt->conn->error_info, prepare_resp->error_info); goto done; } ret = PASS; stmt->stmt_id = prepare_resp->stmt_id; - stmt->warning_count = stmt->conn->upsert_status.warning_count = prepare_resp->warning_count; + stmt->warning_count = stmt->conn->upsert_status->warning_count = prepare_resp->warning_count; stmt->field_count = stmt->conn->field_count = prepare_resp->field_count; stmt->param_count = prepare_resp->param_count; done: @@ -333,8 +331,8 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_ fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC); if (!fields_eof) { - SET_OOM_ERROR(stmt->error_info); - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*stmt->error_info); + SET_OOM_ERROR(*stmt->conn->error_info); } else { if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) { if (stmt->result) { @@ -344,8 +342,8 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_ stmt->state = MYSQLND_STMT_INITTED; } } else { - stmt->upsert_status.server_status = fields_eof->server_status; - stmt->upsert_status.warning_count = fields_eof->warning_count; + stmt->upsert_status->server_status = fields_eof->server_status; + stmt->upsert_status->warning_count = fields_eof->warning_count; stmt->state = MYSQLND_STMT_PREPARED; } PACKET_FREE(fields_eof); @@ -369,12 +367,13 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * c DBG_RETURN(FAIL); } DBG_INF_FMT("stmt=%lu", stmt->stmt_id); + DBG_INF_FMT("query=%s", query); SET_ERROR_AFF_ROWS(stmt); SET_ERROR_AFF_ROWS(stmt->conn); - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->state > MYSQLND_STMT_INITTED) { /* See if we have to clean the wire */ @@ -398,7 +397,7 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * c stmt_to_prepare = s_to_prepare->data; } - if (FAIL == stmt_to_prepare->conn->m->simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, query, query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) || + if (FAIL == stmt_to_prepare->conn->m->simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, (const zend_uchar *) query, query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) || FAIL == mysqlnd_stmt_read_prepare_response(s_to_prepare TSRMLS_CC)) { goto fail; @@ -420,7 +419,7 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * c if (stmt_to_prepare->field_count) { MYSQLND_RES * result = stmt->conn->m->result_init(stmt_to_prepare->field_count, stmt_to_prepare->persistent TSRMLS_CC); if (!result) { - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*stmt->conn->error_info); goto fail; } /* Allocate the result now as it is needed for the reading of metadata */ @@ -474,7 +473,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * con { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; enum_func_status ret; - MYSQLND * conn; + MYSQLND_CONN_DATA * conn; DBG_ENTER("mysqlnd_stmt_execute_parse_response"); if (!stmt || !stmt->conn) { @@ -485,8 +484,8 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * con ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC); if (ret == FAIL) { - stmt->error_info = conn->error_info; - stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows; + COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); + stmt->upsert_status->affected_rows = conn->upsert_status->affected_rows; if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) { /* close the statement here, the connection has been closed */ } @@ -500,9 +499,9 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * con value is > LONG_MAX or < LONG_MIN, there is string conversion and we have to resend the types. Next execution will also need to resend the type. */ - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); - stmt->upsert_status = conn->upsert_status; + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); + *stmt->upsert_status = *conn->upsert_status; /* copy status */ stmt->state = MYSQLND_STMT_EXECUTED; if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type == QUERY_LOAD_LOCAL) { DBG_INF("PASS"); @@ -528,10 +527,10 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * con use_result() or store_result() and we should be able to scrap the data on the line, if he just decides to close the statement. */ - DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, - stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); + DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, + stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS); - if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) { + if (stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS) { DBG_INF("cursor exists"); stmt->cursor_exists = TRUE; CONN_SET_STATE(conn, CONN_READY); @@ -562,7 +561,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * con } } #ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET - if (stmt->upsert_status.server_status & SERVER_PS_OUT_PARAMS) { + if (stmt->upsert_status->server_status & SERVER_PS_OUT_PARAMS) { s->m->free_stmt_content(s TSRMLS_CC); DBG_INF("PS OUT Variable RSet, skipping"); /* OUT params result set. Skip for now to retain compatibility */ @@ -582,7 +581,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; enum_func_status ret; - MYSQLND * conn; + MYSQLND_CONN_DATA * conn; zend_uchar *request = NULL; size_t request_len; zend_bool free_request; @@ -629,28 +628,8 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c } #endif - /* - If right after execute() we have to call the appropriate - use_result() or store_result() and clean. - */ - if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) { - DBG_INF("fetching result set header"); - /* Do implicit use_result and then flush the result */ - stmt->default_rset_handler = s->m->use_result; - stmt->default_rset_handler(s TSRMLS_CC); - } + s->m->flush(s TSRMLS_CC); - if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) { - DBG_INF("skipping result"); - /* Flush if anything is left and unbuffered set */ - stmt->result->m.skip_result(stmt->result TSRMLS_CC); - } - - if (stmt->state > MYSQLND_STMT_PREPARED) { - /* As the buffers have been freed, we should go back to PREPARED */ - stmt->state = MYSQLND_STMT_PREPARED; - } - /* Executed, but the user hasn't started to fetch This will clean also the metadata, but after the EXECUTE call we will @@ -659,7 +638,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC); } else if (stmt->state < MYSQLND_STMT_PREPARED) { /* Only initted - error */ - SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, + SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); DBG_INF("FAIL"); @@ -681,11 +660,11 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c } if (not_bound) { char * msg; - spprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement", - not_bound, not_bound>1 ?"s":""); + mnd_sprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement", + not_bound, not_bound>1 ?"s":""); SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, msg); if (msg) { - efree(msg); /* allocated by spprintf */ + mnd_sprintf_free(msg); } DBG_INF("FAIL"); DBG_RETURN(FAIL); @@ -694,7 +673,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c ret = s->m->generate_execute_request(s, &request, &request_len, &free_request TSRMLS_CC); if (ret == PASS) { /* support for buffer types should be added here ! */ - ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len, + ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, request, request_len, PROT_LAST /* we will handle the response packet*/, FALSE, FALSE TSRMLS_CC); } else { @@ -706,7 +685,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c } if (ret == FAIL) { - stmt->error_info = conn->error_info; + COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); DBG_INF("FAIL"); DBG_RETURN(FAIL); } @@ -714,10 +693,10 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * c ret = s->m->parse_execute_response(s TSRMLS_CC); - DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); + DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS); - if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status.affected_rows) { - MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status.affected_rows); + if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status->affected_rows) { + MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status->affected_rows); } DBG_RETURN(ret); } @@ -753,9 +732,8 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, v current_row, meta->field_count, meta->fields, - result->stored_data->persistent, - result->conn->options.numeric_and_datetime_as_unicode, - result->conn->options.int_and_float_native, + result->conn->options->numeric_and_datetime_as_unicode, + result->conn->options->int_and_float_native, result->conn->stats TSRMLS_CC); if (PASS != rc) { DBG_RETURN(FAIL); @@ -838,11 +816,11 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, if (result->unbuf->eof_reached) { /* No more rows obviously */ - DBG_INF("eof reached"); + DBG_INF("EOF already reached"); DBG_RETURN(PASS); } if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) { - SET_CLIENT_ERROR(result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, + SET_CLIENT_ERROR(*result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); DBG_ERR("command out of sync"); DBG_RETURN(FAIL); @@ -864,7 +842,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, if (!row_packet->skip_extraction) { result->m.unbuffered_free_last_data(result TSRMLS_CC); - DBG_INF("extracting data"); result->unbuf->last_row_data = row_packet->fields; result->unbuf->last_row_buffer = row_packet->row_buffer; row_packet->fields = NULL; @@ -874,9 +851,8 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, result->unbuf->last_row_data, row_packet->field_count, row_packet->fields_metadata, - FALSE, - result->conn->options.numeric_and_datetime_as_unicode, - result->conn->options.int_and_float_native, + result->conn->options->numeric_and_datetime_as_unicode, + result->conn->options->int_and_float_native, result->conn->stats TSRMLS_CC)) { DBG_RETURN(FAIL); @@ -926,8 +902,8 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, *fetched_anything = TRUE; } else if (ret == FAIL) { if (row_packet->error_info.error_no) { - stmt->conn->error_info = row_packet->error_info; - stmt->error_info = row_packet->error_info; + COPY_CLIENT_ERROR(*stmt->conn->error_info, row_packet->error_info); + COPY_CLIENT_ERROR(*stmt->error_info, row_packet->error_info); } CONN_SET_STATE(result->conn, CONN_READY); result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ @@ -935,13 +911,13 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, DBG_INF("EOF"); /* Mark the connection as usable again */ result->unbuf->eof_reached = TRUE; - result->conn->upsert_status.warning_count = row_packet->warning_count; - result->conn->upsert_status.server_status = row_packet->server_status; + result->conn->upsert_status->warning_count = row_packet->warning_count; + result->conn->upsert_status->server_status = row_packet->server_status; /* result->row_packet will be cleaned when destroying the result object */ - if (result->conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) { + if (result->conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS) { CONN_SET_STATE(result->conn, CONN_NEXT_RESULT_PENDING); } else { CONN_SET_STATE(result->conn, CONN_READY); @@ -959,8 +935,8 @@ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - MYSQLND_RES *result; - MYSQLND * conn; + MYSQLND_RES * result; + MYSQLND_CONN_DATA * conn; DBG_ENTER("mysqlnd_stmt::use_result"); if (!stmt || !stmt->conn || !stmt->result) { @@ -975,18 +951,17 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT (stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) || (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)) { - SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, + SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); DBG_ERR("command out of sync"); DBG_RETURN(NULL); } - SET_EMPTY_ERROR(stmt->error_info); + SET_EMPTY_ERROR(*stmt->error_info); MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_PS_UNBUFFERED_SETS); result = stmt->result; - DBG_INF_FMT("%scursor exists", stmt->cursor_exists? "":"no "); result->m.use_result(stmt->result, TRUE TSRMLS_CC); result->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor: mysqlnd_stmt_fetch_row_unbuffered; @@ -1021,7 +996,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, voi if (stmt->state < MYSQLND_STMT_USER_FETCHING) { /* Only initted - error */ - SET_CLIENT_ERROR(stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, + SET_CLIENT_ERROR(*stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); DBG_ERR("command out of sync"); DBG_RETURN(FAIL); @@ -1030,16 +1005,16 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, voi DBG_RETURN(FAIL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); int4store(buf, stmt->stmt_id); int4store(buf + STMT_ID_LENGTH, 1); /* for now fetch only one row */ - if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, (char *)buf, sizeof(buf), + if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, buf, sizeof(buf), PROT_LAST /* we will handle the response packet*/, FALSE, TRUE TSRMLS_CC)) { - stmt->error_info = stmt->conn->error_info; + COPY_CLIENT_ERROR(*stmt->error_info, *stmt->conn->error_info); DBG_RETURN(FAIL); } @@ -1048,11 +1023,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, voi if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) { unsigned int i, field_count = result->field_count; - DBG_INF_FMT("skip_extraction=%u", row_packet->skip_extraction); if (!row_packet->skip_extraction) { result->m.unbuffered_free_last_data(result TSRMLS_CC); - DBG_INF("extracting data"); result->unbuf->last_row_data = row_packet->fields; result->unbuf->last_row_buffer = row_packet->row_buffer; row_packet->fields = NULL; @@ -1062,9 +1035,8 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, voi result->unbuf->last_row_data, row_packet->field_count, row_packet->fields_metadata, - FALSE, - result->conn->options.numeric_and_datetime_as_unicode, - result->conn->options.int_and_float_native, + result->conn->options->numeric_and_datetime_as_unicode, + result->conn->options->int_and_float_native, result->conn->stats TSRMLS_CC)) { DBG_RETURN(FAIL); @@ -1123,21 +1095,21 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, voi } else { *fetched_anything = FALSE; - stmt->upsert_status.warning_count = - stmt->conn->upsert_status.warning_count = + stmt->upsert_status->warning_count = + stmt->conn->upsert_status->warning_count = row_packet->warning_count; - stmt->upsert_status.server_status = - stmt->conn->upsert_status.server_status = + stmt->upsert_status->server_status = + stmt->conn->upsert_status->server_status = row_packet->server_status; result->unbuf->eof_reached = row_packet->eof; } - stmt->upsert_status.warning_count = - stmt->conn->upsert_status.warning_count = + stmt->upsert_status->warning_count = + stmt->conn->upsert_status->warning_count = row_packet->warning_count; - stmt->upsert_status.server_status = - stmt->conn->upsert_status.server_status = + stmt->upsert_status->server_status = + stmt->conn->upsert_status->server_status = row_packet->server_status; DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u", @@ -1174,8 +1146,8 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * con } stmt->state = MYSQLND_STMT_USER_FETCHING; - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); DBG_INF_FMT("result_bind=%p separated_once=%u", stmt->result_bind, stmt->result_zvals_separated_once); /* @@ -1217,11 +1189,11 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * con } DBG_INF_FMT("stmt=%lu", stmt->stmt_id); - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->stmt_id) { - MYSQLND * conn = stmt->conn; + MYSQLND_CONN_DATA * conn = stmt->conn; if (stmt->param_bind) { unsigned int i; DBG_INF("resetting long data"); @@ -1233,7 +1205,46 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * con } } + s->m->flush(s TSRMLS_CC); + /* + Don't free now, let the result be usable. When the stmt will again be + executed then the result set will be cleaned, the bound variables will + be separated before that. + */ + + int4store(cmd_buf, stmt->stmt_id); + if (CONN_GET_STATE(conn) == CONN_READY && + FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, cmd_buf, + sizeof(cmd_buf), PROT_OK_PACKET, + FALSE, TRUE TSRMLS_CC))) { + COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); + } + *stmt->upsert_status = *conn->upsert_status; + + stmt->state = MYSQLND_STMT_PREPARED; + } + DBG_INF(ret == PASS? "PASS":"FAIL"); + DBG_RETURN(ret); +} +/* }}} */ + + +/* {{{ mysqlnd_stmt::flush */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_stmt, flush)(MYSQLND_STMT * const s TSRMLS_DC) +{ + MYSQLND_STMT_DATA * stmt = s? s->data:NULL; + enum_func_status ret = PASS; + + DBG_ENTER("mysqlnd_stmt::flush"); + if (!stmt || !stmt->conn) { + DBG_RETURN(FAIL); + } + DBG_INF_FMT("stmt=%lu", stmt->stmt_id); + + if (stmt->stmt_id) { + /* If the user decided to close the statement right after execute() We have to call the appropriate use_result() or store_result() and clean. @@ -1251,21 +1262,6 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * con } } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS); - /* - Don't free now, let the result be usable. When the stmt will again be - executed then the result set will be cleaned, the bound variables will - be separated before that. - */ - - int4store(cmd_buf, stmt->stmt_id); - if (CONN_GET_STATE(conn) == CONN_READY && - FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, (char *)cmd_buf, - sizeof(cmd_buf), PROT_OK_PACKET, - FALSE, TRUE TSRMLS_CC))) { - stmt->error_info = conn->error_info; - } - stmt->upsert_status = conn->upsert_status; - stmt->state = MYSQLND_STMT_PREPARED; } DBG_INF(ret == PASS? "PASS":"FAIL"); @@ -1281,8 +1277,8 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_S { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; enum_func_status ret = FAIL; - MYSQLND * conn; - zend_uchar *cmd_buf; + MYSQLND_CONN_DATA * conn; + zend_uchar * cmd_buf; enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA; DBG_ENTER("mysqlnd_stmt::send_long_data"); @@ -1293,8 +1289,8 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_S conn = stmt->conn; - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->state < MYSQLND_STMT_PREPARED) { SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared); @@ -1306,7 +1302,6 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_S DBG_ERR("command out of sync"); DBG_RETURN(FAIL); } - if (param_no >= stmt->param_count) { SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number"); DBG_ERR("invalid param_no"); @@ -1339,15 +1334,15 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_S memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length); /* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/ - ret = conn->m->simple_command(conn, cmd, (char *)cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC); + ret = conn->m->simple_command(conn, cmd, cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC); mnd_efree(cmd_buf); if (FAIL == ret) { - stmt->error_info = conn->error_info; + COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); } } else { ret = FAIL; - SET_OOM_ERROR(stmt->error_info); - SET_OOM_ERROR(conn->error_info); + SET_OOM_ERROR(*stmt->error_info); + SET_OOM_ERROR(*conn->error_info); } /* Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not @@ -1407,8 +1402,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_ DBG_RETURN(FAIL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->param_count) { unsigned int i = 0; @@ -1425,8 +1420,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_ */ for (i = 0; i < stmt->param_count; i++) { /* - We may have the last reference, then call zval_ptr_dtor() - or we may leak memory. + We may have the last reference, then call zval_ptr_dtor() or we may leak memory. Switching from bind_one_parameter to bind_parameters may result in zv being NULL */ if (stmt->param_bind[i].zv) { @@ -1468,8 +1462,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQL if (!stmt || !stmt->conn) { DBG_RETURN(FAIL); } - DBG_INF_FMT("stmt=%lu param_no=%u param_count=%u type=%u", - stmt->stmt_id, param_no, stmt->param_count, type); + DBG_INF_FMT("stmt=%lu param_no=%u param_count=%u type=%u", stmt->stmt_id, param_no, stmt->param_count, type); if (stmt->state < MYSQLND_STMT_PREPARED) { SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared); @@ -1482,8 +1475,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQL DBG_ERR("invalid param_no"); DBG_RETURN(FAIL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->param_count) { if (!stmt->param_bind) { @@ -1533,13 +1526,12 @@ MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQL DBG_RETURN(FAIL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->param_count) { stmt->send_types_to_server = 1; } - DBG_INF("PASS"); DBG_RETURN(PASS); } /* }}} */ @@ -1566,8 +1558,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT DBG_RETURN(FAIL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->field_count) { unsigned int i = 0; @@ -1623,8 +1615,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_ DBG_RETURN(FAIL); } - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); if (stmt->field_count) { mysqlnd_stmt_separate_one_result_bind(s, param_no TSRMLS_CC); @@ -1656,7 +1648,7 @@ static uint64_t MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt? stmt->upsert_status.last_insert_id : 0; + return stmt? stmt->upsert_status->last_insert_id : 0; } /* }}} */ @@ -1666,7 +1658,7 @@ static uint64_t MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt? stmt->upsert_status.affected_rows : 0; + return stmt? stmt->upsert_status->affected_rows : 0; } /* }}} */ @@ -1686,7 +1678,7 @@ static unsigned int MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt? stmt->upsert_status.warning_count : 0; + return stmt? stmt->upsert_status->warning_count : 0; } /* }}} */ @@ -1696,7 +1688,7 @@ static unsigned int MYSQLND_METHOD(mysqlnd_stmt, server_status)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt? stmt->upsert_status.server_status : 0; + return stmt? stmt->upsert_status->server_status : 0; } /* }}} */ @@ -1726,7 +1718,7 @@ static unsigned int MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt? stmt->error_info.error_no : 0; + return stmt? stmt->error_info->error_no : 0; } /* }}} */ @@ -1736,7 +1728,7 @@ static const char * MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt? stmt->error_info.error : 0; + return stmt? stmt->error_info->error : 0; } /* }}} */ @@ -1746,7 +1738,7 @@ static const char * MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - return stmt && stmt->error_info.sqlstate[0] ? stmt->error_info.sqlstate:MYSQLND_SQLSTATE_NULL; + return stmt && stmt->error_info->sqlstate[0] ? stmt->error_info->sqlstate:MYSQLND_SQLSTATE_NULL; } /* }}} */ @@ -1826,7 +1818,7 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_ DBG_RETURN(result); } while (0); - SET_OOM_ERROR(stmt->conn->error_info); + SET_OOM_ERROR(*stmt->conn->error_info); if (result) { result->m.free_result(result, TRUE TSRMLS_CC); } @@ -1921,6 +1913,7 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_S } /* }}} */ + /* free_result() doesn't actually free stmt->result but only the buffers */ /* {{{ mysqlnd_stmt::free_result */ static enum_func_status @@ -1987,8 +1980,7 @@ mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const if (!stmt) { DBG_VOID_RETURN; } - DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u", - stmt->stmt_id, stmt->result_bind, stmt->field_count); + DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count); if (!stmt->result_bind) { DBG_VOID_RETURN; @@ -2042,8 +2034,7 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * c if (!stmt) { DBG_VOID_RETURN; } - DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%u", - stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no); + DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no); if (!stmt->result_bind) { DBG_VOID_RETURN; @@ -2093,8 +2084,7 @@ MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLN if (!stmt) { DBG_VOID_RETURN; } - DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u", - stmt->stmt_id, stmt->param_bind, stmt->param_count); + DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u", stmt->stmt_id, stmt->param_bind, stmt->param_count); /* Destroy the input bind */ if (stmt->param_bind) { @@ -2127,6 +2117,11 @@ MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLN stmt->result->m.free_result_internal(stmt->result TSRMLS_CC); stmt->result = NULL; } + if (stmt->error_info->error_list) { + zend_llist_clean(stmt->error_info->error_list); + mnd_pefree(stmt->error_info->error_list, s->persistent); + stmt->error_info->error_list = NULL; + } DBG_VOID_RETURN; } @@ -2138,7 +2133,7 @@ static enum_func_status MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - MYSQLND * conn; + MYSQLND_CONN_DATA * conn; zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */]; enum_mysqlnd_collected_stats statistic = STAT_LAST; @@ -2150,8 +2145,8 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLN conn = stmt->conn; - SET_EMPTY_ERROR(stmt->error_info); - SET_EMPTY_ERROR(stmt->conn->error_info); + SET_EMPTY_ERROR(*stmt->error_info); + SET_EMPTY_ERROR(*stmt->conn->error_info); /* If the user decided to close the statement right after execute() @@ -2159,7 +2154,6 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLN clean. */ do { - DBG_INF_FMT("stmt->state=%u", stmt->state); if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) { DBG_INF("fetching result set header"); stmt->default_rset_handler(s TSRMLS_CC); @@ -2182,10 +2176,10 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLN int4store(cmd_buf, stmt->stmt_id); if (CONN_GET_STATE(conn) == CONN_READY && - FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, (char *)cmd_buf, sizeof(cmd_buf), + FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf), PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/, FALSE, TRUE TSRMLS_CC)) { - stmt->error_info = conn->error_info; + COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); DBG_RETURN(FAIL); } } @@ -2229,7 +2223,6 @@ MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * cons DBG_ENTER("mysqlnd_stmt::dtor"); if (stmt) { - DBG_INF_FMT("stmt=%p", stmt); MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT: @@ -2347,93 +2340,28 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_stmt) MYSQLND_METHOD(mysqlnd_stmt, server_status), mysqlnd_stmt_execute_generate_request, mysqlnd_stmt_execute_parse_response, - MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content) + MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content), + MYSQLND_METHOD(mysqlnd_stmt, flush) MYSQLND_CLASS_METHODS_END; /* {{{ _mysqlnd_stmt_init */ -MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC) +MYSQLND_STMT * +_mysqlnd_stmt_init(MYSQLND_CONN_DATA * const conn TSRMLS_DC) { - size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *); - MYSQLND_STMT * ret = mnd_pecalloc(1, alloc_size, conn->persistent); - MYSQLND_STMT_DATA * stmt = NULL; - + MYSQLND_STMT * ret; DBG_ENTER("_mysqlnd_stmt_init"); - do { - if (!ret) { - break; - } - ret->m = mysqlnd_stmt_methods; - ret->persistent = conn->persistent; - - stmt = ret->data = mnd_pecalloc(1, sizeof(MYSQLND_STMT_DATA), conn->persistent); - DBG_INF_FMT("stmt=%p", stmt); - if (!stmt) { - break; - } - stmt->persistent = conn->persistent; - stmt->state = MYSQLND_STMT_INITTED; - stmt->execute_cmd_buffer.length = 4096; - stmt->execute_cmd_buffer.buffer = mnd_pemalloc(stmt->execute_cmd_buffer.length, stmt->persistent); - if (!stmt->execute_cmd_buffer.buffer) { - break; - } - - stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS; - /* - Mark that we reference the connection, thus it won't be - be destructed till there is open statements. The last statement - or normal query result will close it then. - */ - stmt->conn = conn->m->get_reference(conn TSRMLS_CC); - - DBG_RETURN(ret); - } while (0); - - SET_OOM_ERROR(conn->error_info); - if (ret) { - ret->m->dtor(ret, TRUE TSRMLS_CC); - ret = NULL; - } - DBG_RETURN(NULL); + ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_prepared_statement(conn TSRMLS_CC); + DBG_RETURN(ret); } /* }}} */ -/* {{{ _mysqlnd_plugin_get_plugin_stmt_data */ -PHPAPI void ** _mysqlnd_plugin_get_plugin_stmt_data(const MYSQLND_STMT * stmt, unsigned int plugin_id TSRMLS_DC) -{ - DBG_ENTER("_mysqlnd_plugin_get_plugin_stmt_data"); - DBG_INF_FMT("plugin_id=%u", plugin_id); - if (!stmt || plugin_id >= mysqlnd_plugin_count()) { - return NULL; - } - DBG_RETURN((void *)((char *)stmt + sizeof(MYSQLND_STMT) + plugin_id * sizeof(void *))); -} -/* }}} */ - - /* {{{ _mysqlnd_init_ps_subsystem */ void _mysqlnd_init_ps_subsystem() { - mysqlnd_stmt_methods = &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt); + mysqlnd_stmt_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt)); _mysqlnd_init_ps_fetch_subsystem(); -} -/* }}} */ - - -/* {{{ mysqlnd_conn_get_methods */ -PHPAPI struct st_mysqlnd_stmt_methods * mysqlnd_stmt_get_methods() -{ - return mysqlnd_stmt_methods; -} -/* }}} */ - - -/* {{{ mysqlnd_conn_set_methods */ -PHPAPI void mysqlnd_stmt_set_methods(struct st_mysqlnd_stmt_methods *methods) -{ - mysqlnd_stmt_methods = methods; } /* }}} */