summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_ps.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mysqlnd/mysqlnd_ps.c')
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c929
1 files changed, 595 insertions, 334 deletions
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index 06ec510f5..fa8be3ec2 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -1,8 +1,8 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 6 |
+ | PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 2006-2009 The PHP Group |
+ | Copyright (c) 2006-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -18,7 +18,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: mysqlnd_ps.c 294543 2010-02-04 20:28:55Z johannes $ */
+/* $Id: mysqlnd_ps.c 300735 2010-06-24 19:52:13Z andrey $ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
@@ -39,11 +39,7 @@ 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 */
-zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
- zend_bool *free_buffer TSRMLS_DC);
-
-
-MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC);
+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);
enum_func_status mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param,
unsigned int flags,
@@ -57,20 +53,25 @@ static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_D
static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC);
static void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC);
-static enum_func_status mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC);
/* {{{ mysqlnd_stmt::store_result */
static MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
+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 = stmt->conn;
- MYSQLND_RES *result;
+ MYSQLND * conn;
+ MYSQLND_RES * result;
zend_bool to_cache = FALSE;
DBG_ENTER("mysqlnd_stmt::store_result");
+ if (!stmt || !stmt->conn || !stmt->result) {
+ DBG_RETURN(NULL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+ conn = stmt->conn;
+
/* be compliant with libmysql - NULL will turn */
if (!stmt->field_count) {
DBG_RETURN(NULL);
@@ -78,7 +79,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
- DBG_RETURN(stmt->m->use_result(stmt TSRMLS_CC));
+ DBG_RETURN(s->m->use_result(s TSRMLS_CC));
}
/* Nothing to store for UPSERT/LOAD DATA*/
@@ -90,7 +91,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
DBG_RETURN(NULL);
}
- stmt->default_rset_handler = stmt->m->store_result;
+ stmt->default_rset_handler = s->m->store_result;
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
@@ -101,7 +102,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
result->m.fetch_lengths = NULL;/* makes no sense */
- result->result_set_memory_pool = mysqlnd_mempool_create(16000 TSRMLS_CC);
+ 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);
@@ -125,14 +126,20 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt::get_result */
static MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
{
- MYSQLND *conn = stmt->conn;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ MYSQLND * conn;
MYSQLND_RES *result;
DBG_ENTER("mysqlnd_stmt::get_result");
+ if (!stmt || !stmt->conn || !stmt->result) {
+ DBG_RETURN(NULL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+ conn = stmt->conn;
+
/* be compliant with libmysql - NULL will turn */
if (!stmt->field_count) {
DBG_RETURN(NULL);
@@ -140,7 +147,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
- DBG_RETURN(stmt->m->use_result(stmt TSRMLS_CC));
+ DBG_RETURN(s->m->use_result(s TSRMLS_CC));
}
/* Nothing to store for UPSERT/LOAD DATA*/
@@ -154,31 +161,47 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
SET_EMPTY_ERROR(stmt->conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
- result = mysqlnd_result_init(stmt->result->field_count TSRMLS_CC);
+ do {
+ result = conn->m->result_init(stmt->result->field_count, stmt->persistent TSRMLS_CC);
+ if (!result) {
+ SET_OOM_ERROR(stmt->conn->error_info);
+ break;
+ }
- result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
+ result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
+ if (!result->meta) {
+ SET_OOM_ERROR(stmt->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->state = MYSQLND_STMT_PREPARED;
- result->type = MYSQLND_RES_PS_BUF;
- } else {
- stmt->error_info = conn->error_info;
- stmt->state = MYSQLND_STMT_PREPARED;
- }
+ if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) {
+ 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;
+ stmt->state = MYSQLND_STMT_PREPARED;
+ break;
+ }
+ DBG_RETURN(result);
+ } while (0);
- DBG_RETURN(result);
+ if (result) {
+ result->m.free_result(result, TRUE TSRMLS_CC);
+ }
+ DBG_RETURN(NULL);
}
/* }}} */
/* {{{ mysqlnd_stmt::more_results */
static zend_bool
-MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::more_results");
/* (conn->state == CONN_NEXT_RESULT_PENDING) too */
- DBG_RETURN((stmt->conn && (stmt->conn->upsert_status.server_status &
+ DBG_RETURN((stmt && stmt->conn && (stmt->conn->upsert_status.server_status &
SERVER_MORE_RESULTS_EXISTS))?
TRUE:
FALSE);
@@ -188,50 +211,61 @@ MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt::next_result */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC)
{
- MYSQLND *conn = stmt->conn;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ MYSQLND * conn;
DBG_ENTER("mysqlnd_stmt::next_result");
+ if (!stmt || !stmt->conn || !stmt->result) {
+ DBG_RETURN(FAIL);
+ }
+ conn = stmt->conn;
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
- if (!conn ||
- CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING ||
- !(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) ||
- !stmt->result)
- {
+ if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS)) {
DBG_RETURN(FAIL);
}
/* Free space for next result */
- mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
+ mysqlnd_internal_free_stmt_content(s TSRMLS_CC);
- DBG_RETURN(mysqlnd_stmt_execute_parse_response(stmt TSRMLS_CC));
+ DBG_RETURN(s->m->parse_execute_response(s TSRMLS_CC));
}
/* }}} */
/* {{{ mysqlnd_stmt_skip_metadata */
static enum_func_status
-mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
+mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
/* Follows parameter metadata, we have just to skip it, as libmysql does */
unsigned int i = 0;
- enum_func_status ret = PASS;
+ enum_func_status ret = FAIL;
MYSQLND_PACKET_RES_FIELD * field_packet;
DBG_ENTER("mysqlnd_stmt_skip_metadata");
+ if (!stmt || !stmt->conn || !stmt->conn->protocol) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
- field_packet->skip_parsing = TRUE;
- for (;i < stmt->param_count; i++) {
- if (FAIL == PACKET_READ(field_packet, stmt->conn)) {
- ret = FAIL;
- break;
+ if (!field_packet) {
+ SET_OOM_ERROR(stmt->error_info);
+ SET_OOM_ERROR(stmt->conn->error_info);
+ } else {
+ ret = PASS;
+ field_packet->skip_parsing = TRUE;
+ for (;i < stmt->param_count; i++) {
+ if (FAIL == PACKET_READ(field_packet, stmt->conn)) {
+ ret = FAIL;
+ break;
+ }
}
+ PACKET_FREE(field_packet);
}
- PACKET_FREE(field_packet);
DBG_RETURN(ret);
}
@@ -240,26 +274,34 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt_read_prepare_response */
static enum_func_status
-mysqlnd_stmt_read_prepare_response(MYSQLND_STMT *stmt TSRMLS_DC)
+mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp;
- enum_func_status ret = PASS;
+ enum_func_status ret = FAIL;
DBG_ENTER("mysqlnd_stmt_read_prepare_response");
+ if (!stmt || !stmt->conn || !stmt->conn->protocol) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
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);
+ goto done;
+ }
+
if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) {
- ret = FAIL;
goto done;
}
if (0xFF == prepare_resp->error_code) {
stmt->error_info = stmt->conn->error_info = prepare_resp->error_info;
- ret = FAIL;
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->field_count = stmt->conn->field_count = prepare_resp->field_count;
@@ -274,28 +316,37 @@ done:
/* {{{ mysqlnd_stmt_prepare_read_eof */
static enum_func_status
-mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT *stmt TSRMLS_DC)
+mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
MYSQLND_PACKET_EOF * fields_eof;
- enum_func_status ret;
+ enum_func_status ret = FAIL;
DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
+ if (!stmt || !stmt->conn || !stmt->conn->protocol) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
- if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
- if (stmt->result) {
- stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
- mnd_efree(stmt->result);
- memset(stmt, 0, sizeof(MYSQLND_STMT));
- stmt->state = MYSQLND_STMT_INITTED;
- }
+ if (!fields_eof) {
+ SET_OOM_ERROR(stmt->error_info);
+ SET_OOM_ERROR(stmt->conn->error_info);
} else {
- stmt->upsert_status.server_status = fields_eof->server_status;
- stmt->upsert_status.warning_count = fields_eof->warning_count;
- stmt->state = MYSQLND_STMT_PREPARED;
+ if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
+ if (stmt->result) {
+ stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
+ mnd_efree(stmt->result);
+ memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
+ 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->state = MYSQLND_STMT_PREPARED;
+ }
+ PACKET_FREE(fields_eof);
}
- PACKET_FREE(fields_eof);
DBG_RETURN(ret);
}
@@ -304,11 +355,16 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT *stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt::prepare */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * const query, unsigned int query_len TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const query, unsigned int query_len TSRMLS_DC)
{
- MYSQLND_STMT *stmt_to_prepare = stmt;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ MYSQLND_STMT * s_to_prepare = s;
+ MYSQLND_STMT_DATA * stmt_to_prepare = stmt;
DBG_ENTER("mysqlnd_stmt::prepare");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
SET_ERROR_AFF_ROWS(stmt);
@@ -321,29 +377,33 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * co
/* See if we have to clean the wire */
if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
/* Do implicit use_result and then flush the result */
- stmt->default_rset_handler = stmt->m->use_result;
- stmt->default_rset_handler(stmt TSRMLS_CC);
+ stmt->default_rset_handler = s->m->use_result;
+ stmt->default_rset_handler(s TSRMLS_CC);
}
/* No 'else' here please :) */
- if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
+ if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE && stmt->result) {
stmt->result->m.skip_result(stmt->result TSRMLS_CC);
}
/*
Create a new test statement, which we will prepare, but if anything
fails, we will scrap it.
*/
- stmt_to_prepare = mysqlnd_stmt_init(stmt->conn);
+ s_to_prepare = stmt->conn->m->stmt_init(stmt->conn TSRMLS_CC);
+ if (!s_to_prepare) {
+ goto fail;
+ }
+ 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) ||
- FAIL == mysqlnd_stmt_read_prepare_response(stmt_to_prepare TSRMLS_CC)) {
+ 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) ||
+ FAIL == mysqlnd_stmt_read_prepare_response(s_to_prepare TSRMLS_CC))
+ {
goto fail;
}
if (stmt_to_prepare->param_count) {
- if (FAIL == mysqlnd_stmt_skip_metadata(stmt_to_prepare TSRMLS_CC) ||
- FAIL == mysqlnd_stmt_prepare_read_eof(stmt_to_prepare TSRMLS_CC))
+ if (FAIL == mysqlnd_stmt_skip_metadata(s_to_prepare TSRMLS_CC) ||
+ FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
{
goto fail;
}
@@ -355,7 +415,11 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * co
no metadata at prepare.
*/
if (stmt_to_prepare->field_count) {
- MYSQLND_RES *result = mysqlnd_result_init(stmt_to_prepare->field_count TSRMLS_CC);
+ 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);
+ goto fail;
+ }
/* Allocate the result now as it is needed for the reading of metadata */
stmt_to_prepare->result = result;
@@ -364,27 +428,28 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * co
result->type = MYSQLND_RES_PS_BUF;
if (FAIL == result->m.read_result_metadata(result, stmt_to_prepare->conn TSRMLS_CC) ||
- FAIL == mysqlnd_stmt_prepare_read_eof(stmt_to_prepare TSRMLS_CC)) {
+ FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
+ {
goto fail;
}
}
if (stmt_to_prepare != stmt) {
/* Free old buffers, binding and resources on server */
- stmt->m->net_close(stmt, TRUE TSRMLS_CC);
+ s->m->net_close(s, TRUE TSRMLS_CC);
- memcpy(stmt, stmt_to_prepare, sizeof(MYSQLND_STMT));
+ memcpy(stmt, stmt_to_prepare, sizeof(MYSQLND_STMT_DATA));
/* Now we will have a clean new statement object */
- mnd_efree(stmt_to_prepare);
+ mnd_pefree(stmt_to_prepare, stmt_to_prepare->persistent);
}
stmt->state = MYSQLND_STMT_PREPARED;
DBG_INF("PASS");
DBG_RETURN(PASS);
fail:
- if (stmt_to_prepare != stmt) {
- stmt_to_prepare->m->dtor(stmt_to_prepare, TRUE TSRMLS_CC);
+ if (stmt_to_prepare != stmt && s_to_prepare) {
+ s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
}
stmt->state = MYSQLND_STMT_INITTED;
@@ -396,16 +461,20 @@ fail:
/* {{{ mysqlnd_stmt_execute_parse_response */
static enum_func_status
-mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
+mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret;
- MYSQLND *conn = stmt->conn;
+ MYSQLND * conn;
DBG_ENTER("mysqlnd_stmt_execute_parse_response");
-
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
+ conn = stmt->conn;
CONN_SET_STATE(conn, CONN_QUERY_SENT);
- ret = mysqlnd_query_read_result_set_header(stmt->conn, stmt TSRMLS_CC);
+ 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;
@@ -443,7 +512,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
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=%d cursor=%d", stmt->upsert_status.server_status,
+ 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) {
@@ -451,7 +520,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
stmt->cursor_exists = TRUE;
CONN_SET_STATE(conn, CONN_READY);
/* Only cursor read */
- stmt->default_rset_handler = stmt->m->use_result;
+ stmt->default_rset_handler = s->m->use_result;
DBG_INF("use_result");
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
DBG_INF("asked for cursor but got none");
@@ -466,12 +535,12 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
- stmt->default_rset_handler = stmt->m->store_result;
+ stmt->default_rset_handler = s->m->store_result;
DBG_INF("store_result");
} else {
DBG_INF("no cursor");
/* preferred is unbuffered read */
- stmt->default_rset_handler = stmt->m->use_result;
+ stmt->default_rset_handler = s->m->use_result;
DBG_INF("use_result");
}
}
@@ -485,15 +554,20 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt::execute */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret;
- MYSQLND *conn = stmt->conn;
- zend_uchar *request;
+ MYSQLND * conn;
+ zend_uchar *request = NULL;
size_t request_len;
zend_bool free_request;
DBG_ENTER("mysqlnd_stmt::execute");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
+ conn = stmt->conn;
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
SET_ERROR_AFF_ROWS(stmt);
@@ -538,8 +612,8 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
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 = stmt->m->use_result;
- stmt->default_rset_handler(stmt TSRMLS_CC);
+ stmt->default_rset_handler = s->m->use_result;
+ stmt->default_rset_handler(s TSRMLS_CC);
}
if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
@@ -583,23 +657,25 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
}
if (not_bound) {
char * msg;
- spprintf(&msg, 0, "No data supplied for %d parameter%s in prepared statement",
+ spprintf(&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);
+ efree(msg); /* allocated by spprintf */
}
DBG_INF("FAIL");
DBG_RETURN(FAIL);
}
}
- request = mysqlnd_stmt_execute_generate_request(stmt, &request_len, &free_request TSRMLS_CC);
-
- /* support for buffer types should be added here ! */
-
- ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len,
- PROT_LAST /* we will handle the response packet*/,
- FALSE, FALSE TSRMLS_CC);
+ 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,
+ PROT_LAST /* we will handle the response packet*/,
+ FALSE, FALSE TSRMLS_CC);
+ } else {
+ SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM.");
+ }
if (free_request) {
mnd_efree(request);
@@ -612,7 +688,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
}
stmt->execute_count++;
- ret = mysqlnd_stmt_execute_parse_response(stmt TSRMLS_CC);
+ ret = s->m->parse_execute_response(s TSRMLS_CC);
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);
@@ -626,11 +702,13 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
enum_func_status
mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
{
- MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
+ MYSQLND_STMT * s = (MYSQLND_STMT *) param;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
MYSQLND_RES_BUFFERED *set = result->stored_data;
unsigned int field_count = result->meta->field_count;
DBG_ENTER("mysqlnd_fetch_stmt_row_buffered");
+ *fetched_anything = FALSE;
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
/* If we haven't read everything */
@@ -645,15 +723,18 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
if (NULL == current_row[0]) {
uint64_t row_num = (set->data_cursor - set->data) / field_count;
+ enum_func_status rc = result->m.row_decoder(set->row_buffers[row_num],
+ 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->stats TSRMLS_CC);
+ if (PASS != rc) {
+ DBG_RETURN(FAIL);
+ }
set->initialized_rows++;
- result->m.row_decoder(set->row_buffers[row_num],
- 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->stats TSRMLS_CC);
if (stmt->update_max_length) {
for (i = 0; i < result->field_count; i++) {
/*
@@ -680,7 +761,7 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
#endif
/* copy the type */
if (stmt->result_bind[i].bound == TRUE) {
- DBG_INF_FMT("i=%d type=%d", i, Z_TYPE_P(current_row[i]));
+ DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
if (Z_TYPE_P(current_row[i]) != IS_NULL) {
/*
Copy the value.
@@ -708,7 +789,6 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
DBG_INF("row fetched");
} else {
set->data_cursor = NULL;
- *fetched_anything = FALSE;
DBG_INF("no more data");
}
DBG_INF("PASS");
@@ -722,14 +802,16 @@ static enum_func_status
mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
{
enum_func_status ret;
- MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
- MYSQLND_PACKET_ROW *row_packet = result->row_packet;
+ MYSQLND_STMT * s = (MYSQLND_STMT *) param;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ MYSQLND_PACKET_ROW * row_packet;
DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
+ *fetched_anything = FALSE;
+
if (result->unbuf->eof_reached) {
/* No more rows obviously */
- *fetched_anything = FALSE;
DBG_INF("eof reached");
DBG_RETURN(PASS);
}
@@ -739,6 +821,10 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
DBG_ERR("command out of sync");
DBG_RETURN(FAIL);
}
+ if (!(row_packet = result->row_packet)) {
+ DBG_RETURN(FAIL);
+ }
+
/* Let the row packet fill our buffer and skip additional malloc + memcpy */
row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
@@ -748,8 +834,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
unsigned int i, field_count = result->field_count;
- result->unbuf->row_count++;
- *fetched_anything = TRUE;
if (!row_packet->skip_extraction) {
result->m.unbuffered_free_last_data(result TSRMLS_CC);
@@ -760,14 +844,17 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
- result->m.row_decoder(result->unbuf->last_row_buffer,
- 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->stats TSRMLS_CC);
+ if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
+ 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->stats TSRMLS_CC))
+ {
+ DBG_RETURN(FAIL);
+ }
for (i = 0; i < field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
@@ -805,11 +892,13 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
the bound variables. Thus we need to do part of what it does or Zend will
report leaks.
*/
- row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC);
+ row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
row_packet->row_buffer = NULL;
}
+
+ result->unbuf->row_count++;
+ *fetched_anything = TRUE;
} else if (ret == FAIL) {
- *fetched_anything = FALSE;
if (row_packet->error_info.error_no) {
stmt->conn->error_info = row_packet->error_info;
stmt->error_info = row_packet->error_info;
@@ -817,7 +906,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
CONN_SET_STATE(result->conn, CONN_READY);
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
} else if (row_packet->eof) {
- *fetched_anything = FALSE;
DBG_INF("EOF");
/* Mark the connection as usable again */
result->unbuf->eof_reached = TRUE;
@@ -834,7 +922,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
}
}
- DBG_INF_FMT("ret=%s fetched_anything=%d", ret == PASS? "PASS":"FAIL", *fetched_anything);
+ DBG_INF_FMT("ret=%s fetched_anything=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
DBG_RETURN(ret);
}
/* }}} */
@@ -842,14 +930,20 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
/* {{{ mysqlnd_stmt::use_result */
static MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT *stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
MYSQLND_RES *result;
- MYSQLND *conn = stmt->conn;
+ MYSQLND * conn;
DBG_ENTER("mysqlnd_stmt::use_result");
+ if (!stmt || !stmt->conn || !stmt->result) {
+ DBG_RETURN(NULL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+ conn = stmt->conn;
+
if (!stmt->field_count ||
(!stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_FETCHING_DATA) ||
(stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) ||
@@ -885,13 +979,14 @@ enum_func_status
mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
{
enum_func_status ret;
- MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
+ MYSQLND_STMT * s = (MYSQLND_STMT *) param;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
zend_uchar buf[STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
- MYSQLND_PACKET_ROW *row_packet = result->row_packet;
+ MYSQLND_PACKET_ROW * row_packet;
DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
- if (!stmt) {
+ if (!stmt || !stmt->conn || !result || !result->conn || !result->unbuf) {
DBG_ERR("no statement");
DBG_RETURN(FAIL);
}
@@ -905,6 +1000,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
DBG_ERR("command out of sync");
DBG_RETURN(FAIL);
}
+ if (!(row_packet = result->row_packet)) {
+ DBG_RETURN(FAIL);
+ }
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
@@ -923,10 +1021,8 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
unsigned int i, field_count = result->field_count;
- result->unbuf->row_count++;
- *fetched_anything = TRUE;
- DBG_INF_FMT("skip_extraction=%d", row_packet->skip_extraction);
+ DBG_INF_FMT("skip_extraction=%u", row_packet->skip_extraction);
if (!row_packet->skip_extraction) {
result->m.unbuffered_free_last_data(result TSRMLS_CC);
@@ -936,14 +1032,17 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
- result->m.row_decoder(result->unbuf->last_row_buffer,
- 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->stats TSRMLS_CC);
+ if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
+ 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->stats TSRMLS_CC))
+ {
+ DBG_RETURN(FAIL);
+ }
/* If no result bind, do nothing. We consumed the data */
for (i = 0; i < field_count; i++) {
@@ -956,7 +1055,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
zval_dtor(stmt->result_bind[i].zv);
#endif
- DBG_INF_FMT("i=%d bound_var=%p type=%d refc=%u", i, stmt->result_bind[i].zv,
+ DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, stmt->result_bind[i].zv,
Z_TYPE_P(data), Z_REFCOUNT_P(stmt->result_bind[i].zv));
if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data))) {
if ((Z_TYPE_P(data) == IS_STRING
@@ -982,16 +1081,19 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
the bound variables. Thus we need to do part of what it does or Zend will
report leaks.
*/
- row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC);
+ row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
row_packet->row_buffer = NULL;
}
/* We asked for one row, the next one should be EOF, eat it */
ret = PACKET_READ(row_packet, result->conn);
if (row_packet->row_buffer) {
- row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC);
+ row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
row_packet->row_buffer = NULL;
}
MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
+
+ result->unbuf->row_count++;
+ *fetched_anything = TRUE;
} else {
*fetched_anything = FALSE;
@@ -1012,7 +1114,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
stmt->conn->upsert_status.server_status =
row_packet->server_status;
- DBG_INF_FMT("ret=%s fetched=%d server_status=%d warnings=%d eof=%d",
+ DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u",
ret == PASS? "PASS":"FAIL", *fetched_anything,
row_packet->server_status, row_packet->warning_count,
result->unbuf->eof_reached);
@@ -1023,10 +1125,14 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
/* {{{ mysqlnd_stmt::fetch */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fetched_anything TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret;
DBG_ENTER("mysqlnd_stmt::fetch");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
if (!stmt->result ||
@@ -1038,14 +1144,14 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt, zend_bool * const
} else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
/* Execute only once. We have to free the previous contents of user's bound vars */
- stmt->default_rset_handler(stmt TSRMLS_CC);
+ stmt->default_rset_handler(s TSRMLS_CC);
}
stmt->state = MYSQLND_STMT_USER_FETCHING;
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
- DBG_INF_FMT("result_bind=%p separated_once=%d", stmt->result_bind, stmt->result_zvals_separated_once);
+ DBG_INF_FMT("result_bind=%p separated_once=%u", stmt->result_bind, stmt->result_zvals_separated_once);
/*
The user might have not bound any variables for result.
Do the binding once she does it.
@@ -1065,7 +1171,7 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt, zend_bool * const
stmt->result_zvals_separated_once = TRUE;
}
- ret = stmt->result->m.fetch_row(stmt->result, (void*)stmt, 0, fetched_anything TSRMLS_CC);
+ ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything TSRMLS_CC);
DBG_RETURN(ret);
}
/* }}} */
@@ -1073,12 +1179,16 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt, zend_bool * const
/* {{{ mysqlnd_stmt::reset */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret = PASS;
zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
DBG_ENTER("mysqlnd_stmt::reset");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
SET_EMPTY_ERROR(stmt->error_info);
@@ -1102,16 +1212,18 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
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");
- stmt->default_rset_handler(stmt TSRMLS_CC);
- stmt->state = MYSQLND_STMT_USER_FETCHING;
- }
+ do {
+ if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
+ DBG_INF("fetching result set header");
+ stmt->default_rset_handler(s TSRMLS_CC);
+ stmt->state = MYSQLND_STMT_USER_FETCHING;
+ }
- if (stmt->result) {
- DBG_INF("skipping result");
- stmt->result->m.skip_result(stmt->result TSRMLS_CC);
- }
+ if (stmt->result) {
+ DBG_INF("skipping result");
+ stmt->result->m.skip_result(stmt->result TSRMLS_CC);
+ }
+ } 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
@@ -1138,16 +1250,22 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt::send_long_data */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned int param_no,
+MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
const char * const data, unsigned long length TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret = FAIL;
- MYSQLND * conn = stmt->conn;
+ MYSQLND * conn;
zend_uchar *cmd_buf;
enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
DBG_ENTER("mysqlnd_stmt::send_long_data");
- DBG_INF_FMT("stmt=%lu param_no=%d data_len=%lu", stmt->stmt_id, param_no, length);
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
+ DBG_INF_FMT("stmt=%lu param_no=%u data_len=%lu", stmt->stmt_id, param_no, length);
+
+ conn = stmt->conn;
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
@@ -1186,19 +1304,25 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned
if (CONN_GET_STATE(conn) == CONN_READY) {
size_t packet_len;
- stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
-
- int4store(cmd_buf, stmt->stmt_id);
- int2store(cmd_buf + STMT_ID_LENGTH, param_no);
- 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);
- mnd_efree(cmd_buf);
- if (FAIL == ret) {
- stmt->error_info = conn->error_info;
+ if (cmd_buf) {
+ stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
+
+ int4store(cmd_buf, stmt->stmt_id);
+ int2store(cmd_buf + STMT_ID_LENGTH, param_no);
+ 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);
+ mnd_efree(cmd_buf);
+ if (FAIL == ret) {
+ stmt->error_info = conn->error_info;
+ }
+ } else {
+ ret = FAIL;
+ 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
@@ -1240,16 +1364,20 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned
/* {{{ mysqlnd_stmt::bind_parameters */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::bind_param");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
DBG_ERR("not prepared");
- if (param_bind && stmt->param_bind_dtor) {
- stmt->param_bind_dtor(param_bind TSRMLS_CC);
+ if (param_bind) {
+ s->m->free_parameter_bind(s, param_bind TSRMLS_CC);
}
DBG_RETURN(FAIL);
}
@@ -1261,8 +1389,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const stmt, MYSQLND
unsigned int i = 0;
if (!param_bind) {
- SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
- "Re-binding (still) not supported");
+ SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported");
DBG_ERR("Re-binding (still) not supported");
DBG_RETURN(FAIL);
} else if (stmt->param_bind) {
@@ -1281,15 +1408,15 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const stmt, MYSQLND
zval_ptr_dtor(&stmt->param_bind[i].zv);
}
}
- if (stmt->param_bind != param_bind && stmt->param_bind_dtor) {
- stmt->param_bind_dtor(stmt->param_bind TSRMLS_CC);
+ if (stmt->param_bind != param_bind) {
+ s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
}
}
stmt->param_bind = param_bind;
for (i = 0; i < stmt->param_count; i++) {
/* The client will use stmt_send_long_data */
- DBG_INF_FMT("%d is of type %d", i, stmt->param_bind[i].type);
+ DBG_INF_FMT("%u is of type %u", i, stmt->param_bind[i].type);
/* Prevent from freeing */
/* Don't update is_ref, or we will leak during conversion */
Z_ADDREF_P(stmt->param_bind[i].zv);
@@ -1308,11 +1435,15 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const stmt, MYSQLND
/* {{{ mysqlnd_stmt::bind_one_parameter */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const stmt, unsigned int param_no,
+MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigned int param_no,
zval * const zv, zend_uchar type TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
- DBG_INF_FMT("stmt=%lu param_no=%d param_count=%u type=%d",
+ 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);
if (stmt->state < MYSQLND_STMT_PREPARED) {
@@ -1332,6 +1463,9 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const stmt, unsi
if (stmt->param_count) {
if (!stmt->param_bind) {
stmt->param_bind = mnd_ecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND));
+ if (!stmt->param_bind) {
+ DBG_RETURN(FAIL);
+ }
}
/* Prevent from freeing */
@@ -1359,9 +1493,13 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const stmt, unsi
/* {{{ mysqlnd_stmt::refresh_bind_param */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
if (stmt->state < MYSQLND_STMT_PREPARED) {
@@ -1382,32 +1520,22 @@ MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const stmt TSRML
/* }}} */
-/* {{{ mysqlnd_stmt::set_bind_param_dtor */
-static void
-MYSQLND_METHOD(mysqlnd_stmt, set_param_bind_dtor)(MYSQLND_STMT * const stmt,
- void (*param_bind_dtor)(MYSQLND_PARAM_BIND * dtor TSRMLS_DC) TSRMLS_DC)
-{
- DBG_ENTER("mysqlnd_stmt::set_bind_param_dtor");
- DBG_INF_FMT("stmt=%p", param_bind_dtor);
- stmt->param_bind_dtor = param_bind_dtor;
- DBG_VOID_RETURN;
-}
-/* }}} */
-
-
/* {{{ mysqlnd_stmt::bind_result */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
+MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::bind_result");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
-
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
- if (result_bind && stmt->result_bind_dtor) {
- stmt->result_bind_dtor(result_bind TSRMLS_CC);
+ if (result_bind) {
+ s->m->free_result_bind(s, result_bind TSRMLS_CC);
}
DBG_ERR("not prepared");
DBG_RETURN(FAIL);
@@ -1424,7 +1552,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
DBG_RETURN(FAIL);
}
- mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
+ mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
stmt->result_zvals_separated_once = FALSE;
stmt->result_bind = result_bind;
for (i = 0; i < stmt->field_count; i++) {
@@ -1438,8 +1566,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
*/
stmt->result_bind[i].bound = TRUE;
}
- } else if (result_bind && stmt->result_bind_dtor) {
- stmt->result_bind_dtor(result_bind TSRMLS_CC);
+ } else if (result_bind) {
+ s->m->free_result_bind(s, result_bind TSRMLS_CC);
}
DBG_INF("PASS");
DBG_RETURN(PASS);
@@ -1449,9 +1577,13 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
/* {{{ mysqlnd_stmt::bind_result */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::bind_result");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
if (stmt->state < MYSQLND_STMT_PREPARED) {
@@ -1470,19 +1602,22 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const stmt, unsigne
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->field_count) {
- mysqlnd_stmt_separate_one_result_bind(stmt, param_no TSRMLS_CC);
+ mysqlnd_stmt_separate_one_result_bind(s, param_no TSRMLS_CC);
/* Guaranteed is that stmt->result_bind is NULL */
if (!stmt->result_bind) {
stmt->result_bind = mnd_ecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND));
} else {
stmt->result_bind = mnd_erealloc(stmt->result_bind, stmt->field_count * sizeof(MYSQLND_RESULT_BIND));
}
+ if (!stmt->result_bind) {
+ DBG_RETURN(FAIL);
+ }
ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
/*
Don't update is_ref !!! it's not our job
Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
will fail.
- */
+ */
stmt->result_bind[param_no].bound = TRUE;
}
DBG_INF("PASS");
@@ -1491,117 +1626,124 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const stmt, unsigne
/* }}} */
-/* {{{ mysqlnd_stmt::set_bind_result_dtor */
-static void
-MYSQLND_METHOD(mysqlnd_stmt, set_result_bind_dtor)(MYSQLND_STMT * const stmt,
- void (*result_bind_dtor)(MYSQLND_RESULT_BIND * dtor TSRMLS_DC) TSRMLS_DC)
-{
- DBG_ENTER("mysqlnd_stmt::set_bind_param_dtor");
- DBG_INF_FMT("stmt=%p", result_bind_dtor);
- stmt->result_bind_dtor = result_bind_dtor;
- DBG_VOID_RETURN;
-}
-/* }}} */
-
-
/* {{{ mysqlnd_stmt::insert_id */
static uint64_t
-MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->upsert_status.last_insert_id;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->upsert_status.last_insert_id : 0;
}
/* }}} */
/* {{{ mysqlnd_stmt::affected_rows */
static uint64_t
-MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->upsert_status.affected_rows;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->upsert_status.affected_rows : 0;
}
/* }}} */
/* {{{ mysqlnd_stmt::num_rows */
static uint64_t
-MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->result? mysqlnd_num_rows(stmt->result):0;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt && stmt->result? mysqlnd_num_rows(stmt->result):0;
}
/* }}} */
/* {{{ mysqlnd_stmt::warning_count */
static unsigned int
-MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->upsert_status.warning_count;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->upsert_status.warning_count : 0;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt::server_status */
+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;
}
/* }}} */
/* {{{ mysqlnd_stmt::field_count */
static unsigned int
-MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->field_count;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->field_count : 0;
}
/* }}} */
/* {{{ mysqlnd_stmt::param_count */
static unsigned int
-MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->param_count;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->param_count : 0;
}
/* }}} */
/* {{{ mysqlnd_stmt::errno */
static unsigned int
-MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->error_info.error_no;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->error_info.error_no : 0;
}
/* }}} */
/* {{{ mysqlnd_stmt::error */
static const char *
-MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->error_info.error;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt? stmt->error_info.error : 0;
}
/* }}} */
/* {{{ mysqlnd_stmt::sqlstate */
static const char *
-MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s TSRMLS_DC)
{
- return stmt->error_info.sqlstate[0] ? stmt->error_info.sqlstate:MYSQLND_SQLSTATE_NULL;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt && stmt->error_info.sqlstate[0] ? stmt->error_info.sqlstate:MYSQLND_SQLSTATE_NULL;
}
/* }}} */
/* {{{ mysqlnd_stmt::data_seek */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const stmt, uint64_t row TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const s, uint64_t row TSRMLS_DC)
{
- return stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ return stmt && stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
}
/* }}} */
/* {{{ mysqlnd_stmt::param_metadata */
static MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
{
- if (!stmt->param_count) {
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ if (!stmt || !stmt->param_count) {
return NULL;
}
-
return NULL;
}
/* }}} */
@@ -1609,11 +1751,15 @@ MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC
/* {{{ mysqlnd_stmt::result_metadata */
static MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
MYSQLND_RES *result;
DBG_ENTER("mysqlnd_stmt::result_metadata");
+ if (!stmt) {
+ DBG_RETURN(NULL);
+ }
DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
if (!stmt->field_count || !stmt->conn || !stmt->result || !stmt->result->meta) {
@@ -1634,27 +1780,48 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const stmt TSRMLS_D
In the meantime we don't need a zval cache reference for this fake
result set, so we don't get one.
*/
- result = mysqlnd_result_init(stmt->field_count TSRMLS_CC);
- result->type = MYSQLND_RES_NORMAL;
- result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
- result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
- result->unbuf->eof_reached = TRUE;
- result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
-
- DBG_INF_FMT("result=%p", result);
- DBG_RETURN(result);
+ do {
+ result = stmt->conn->m->result_init(stmt->field_count, stmt->persistent TSRMLS_CC);
+ if (!result) {
+ break;
+ }
+ result->type = MYSQLND_RES_NORMAL;
+ result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
+ result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ if (!result->unbuf) {
+ break;
+ }
+ result->unbuf->eof_reached = TRUE;
+ result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
+ if (!result->meta) {
+ break;
+ }
+
+ DBG_INF_FMT("result=%p", result);
+ DBG_RETURN(result);
+ } while (0);
+
+ SET_OOM_ERROR(stmt->conn->error_info);
+ if (result) {
+ result->m.free_result(result, TRUE TSRMLS_CC);
+ }
+ DBG_RETURN(NULL);
}
/* }}} */
/* {{{ mysqlnd_stmt::attr_set */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
+MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
enum mysqlnd_stmt_attr attr_type,
const void * const value TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
unsigned long val = *(unsigned long *) value;
DBG_ENTER("mysqlnd_stmt::attr_set");
+ if (!stmt) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu attr_type=%u value=%lu", stmt->stmt_id, attr_type, val);
switch (attr_type) {
@@ -1697,11 +1864,15 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
/* {{{ mysqlnd_stmt::attr_get */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const stmt,
+MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
enum mysqlnd_stmt_attr attr_type,
void * const value TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::attr_set");
+ if (!stmt) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
switch (attr_type) {
@@ -1725,9 +1896,13 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const stmt,
/* free_result() doesn't actually free stmt->result but only the buffers */
/* {{{ mysqlnd_stmt::free_result */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt::free_result");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
if (!stmt->result) {
@@ -1742,8 +1917,8 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
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 = stmt->m->use_result;
- stmt->default_rset_handler(stmt TSRMLS_CC);
+ stmt->default_rset_handler = s->m->use_result;
+ stmt->default_rset_handler(s TSRMLS_CC);
}
if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
@@ -1754,7 +1929,7 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
Separate the bound variables, which point to the result set, then
destroy the set.
*/
- mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
+ mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
/* Now we can destroy the result set */
stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
@@ -1774,11 +1949,16 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt_separate_result_bind */
-void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
+static void
+mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
unsigned int i;
DBG_ENTER("mysqlnd_stmt_separate_result_bind");
+ 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);
@@ -1794,7 +1974,7 @@ void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
for (i = 0; i < stmt->field_count; i++) {
/* Let's try with no cache */
if (stmt->result_bind[i].bound == TRUE) {
- DBG_INF_FMT("%d has refcount=%u", i, Z_REFCOUNT_P(stmt->result_bind[i].zv));
+ DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNT_P(stmt->result_bind[i].zv));
/*
We have to separate the actual zval value of the bound
variable from our allocated zvals or we will face double-free
@@ -1817,9 +1997,7 @@ void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
}
}
}
- if (stmt->result_bind_dtor) {
- stmt->result_bind_dtor(stmt->result_bind TSRMLS_CC);
- }
+ s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC);
stmt->result_bind = NULL;
DBG_VOID_RETURN;
@@ -1828,10 +2006,15 @@ void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt_separate_one_result_bind */
-void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC)
+static void
+mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_stmt_separate_one_result_bind");
- DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%d",
+ 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);
if (!stmt->result_bind) {
@@ -1845,7 +2028,7 @@ void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned i
*/
/* Let's try with no cache */
if (stmt->result_bind[param_no].bound == TRUE) {
- DBG_INF_FMT("%d has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
+ DBG_INF_FMT("%u has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
/*
We have to separate the actual zval value of the bound
variable from our allocated zvals or we will face double-free
@@ -1874,10 +2057,14 @@ void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned i
/* {{{ mysqlnd_internal_free_stmt_content */
-static
-void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC)
+static void
+mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const s TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
DBG_ENTER("mysqlnd_internal_free_stmt_content");
+ 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);
@@ -1898,9 +2085,7 @@ void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC)
zval_ptr_dtor(&stmt->param_bind[i].zv);
}
}
- if (stmt->param_bind_dtor) {
- stmt->param_bind_dtor(stmt->param_bind TSRMLS_CC);
- }
+ s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
stmt->param_bind = NULL;
}
@@ -1908,7 +2093,7 @@ void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC)
First separate the bound variables, which point to the result set, then
destroy the set.
*/
- mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
+ mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
/* Not every statement has a result set attached */
if (stmt->result) {
stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
@@ -1922,15 +2107,21 @@ void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC)
/* {{{ mysqlnd_stmt::net_close */
static enum_func_status
-MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC)
+MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
{
- MYSQLND * conn = stmt->conn;
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ MYSQLND * conn;
zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
enum_mysqlnd_collected_stats stat = STAT_LAST;
DBG_ENTER("mysqlnd_stmt::net_close");
+ if (!stmt || !stmt->conn) {
+ DBG_RETURN(FAIL);
+ }
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+ conn = stmt->conn;
+
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
@@ -1940,10 +2131,10 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_
clean.
*/
do {
- DBG_INF_FMT("stmt->state=%d", stmt->state);
+ 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(stmt TSRMLS_CC);
+ stmt->default_rset_handler(s TSRMLS_CC);
stmt->state = MYSQLND_STMT_USER_FETCHING;
}
@@ -1952,7 +2143,7 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_
DBG_INF("skipping result");
stmt->result->m.skip_result(stmt->result TSRMLS_CC);
}
- } while (mysqlnd_stmt_more_results(stmt) && mysqlnd_stmt_next_result(stmt) == PASS);
+ } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
/*
After this point we are allowed to free the result set,
as we have cleaned the line
@@ -1985,11 +2176,11 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_
}
if (stmt->execute_cmd_buffer.buffer) {
- mnd_efree(stmt->execute_cmd_buffer.buffer);
+ mnd_pefree(stmt->execute_cmd_buffer.buffer, stmt->persistent);
stmt->execute_cmd_buffer.buffer = NULL;
}
- mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
+ mysqlnd_internal_free_stmt_content(s TSRMLS_CC);
if (stmt->conn) {
stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
@@ -2002,18 +2193,24 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_
/* {{{ mysqlnd_stmt::dtor */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret;
+ zend_bool persistent = s->persistent;
DBG_ENTER("mysqlnd_stmt::dtor");
- DBG_INF_FMT("stmt=%p", stmt);
+ if (stmt) {
- MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
- STAT_STMT_CLOSE_EXPLICIT);
+ DBG_INF_FMT("stmt=%p", stmt);
- ret = stmt->m->net_close(stmt, implicit TSRMLS_CC);
- mnd_efree(stmt);
+ MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
+ STAT_STMT_CLOSE_EXPLICIT);
+
+ ret = s->m->net_close(s, implicit TSRMLS_CC);
+ mnd_pefree(stmt, persistent);
+ }
+ mnd_pefree(s, persistent);
DBG_INF(ret == PASS? "PASS":"FAIL");
DBG_RETURN(ret);
@@ -2021,6 +2218,59 @@ MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const stmt, zend_bool implicit
/* }}} */
+/* {{{ mysqlnd_stmt::alloc_param_bind */
+static MYSQLND_PARAM_BIND *
+MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind)(MYSQLND_STMT * const s TSRMLS_DC)
+{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ DBG_ENTER("mysqlnd_stmt::alloc_param_bind");
+ if (!stmt) {
+ DBG_RETURN(NULL);
+ }
+ DBG_RETURN(mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent));
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt::alloc_result_bind */
+static MYSQLND_RESULT_BIND *
+MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind)(MYSQLND_STMT * const s TSRMLS_DC)
+{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ DBG_ENTER("mysqlnd_stmt::alloc_result_bind");
+ if (!stmt) {
+ DBG_RETURN(NULL);
+ }
+ DBG_RETURN(mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent));
+}
+/* }}} */
+
+
+/* {{{ param_bind::free_parameter_bind */
+PHPAPI void
+MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * param_bind TSRMLS_DC)
+{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ if (stmt) {
+ mnd_pefree(param_bind, stmt->persistent);
+ }
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt::free_result_bind */
+PHPAPI void
+MYSQLND_METHOD(mysqlnd_stmt, free_result_bind)(MYSQLND_STMT * const s, MYSQLND_RESULT_BIND * result_bind TSRMLS_DC)
+{
+ MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
+ if (stmt) {
+ mnd_pefree(result_bind, stmt->persistent);
+ }
+}
+/* }}} */
+
+
+
MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
MYSQLND_METHOD(mysqlnd_stmt, prepare),
MYSQLND_METHOD(mysqlnd_stmt, execute),
@@ -2040,10 +2290,8 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
MYSQLND_METHOD(mysqlnd_stmt, bind_parameters),
MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter),
MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
- MYSQLND_METHOD(mysqlnd_stmt, set_param_bind_dtor),
MYSQLND_METHOD(mysqlnd_stmt, bind_result),
MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
- MYSQLND_METHOD(mysqlnd_stmt, set_result_bind_dtor),
MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
@@ -2061,7 +2309,16 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
MYSQLND_METHOD(mysqlnd_stmt, sqlstate),
MYSQLND_METHOD(mysqlnd_stmt, attr_get),
- MYSQLND_METHOD(mysqlnd_stmt, attr_set),
+ MYSQLND_METHOD(mysqlnd_stmt, attr_set),
+
+
+ MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind),
+ MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind),
+ MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind),
+ MYSQLND_METHOD(mysqlnd_stmt, free_result_bind),
+ MYSQLND_METHOD(mysqlnd_stmt, server_status),
+ mysqlnd_stmt_execute_generate_request,
+ mysqlnd_stmt_execute_parse_response
MYSQLND_CLASS_METHODS_END;
@@ -2069,28 +2326,47 @@ MYSQLND_CLASS_METHODS_END;
MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
{
size_t alloc_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
- MYSQLND_STMT *stmt = mnd_ecalloc(1, alloc_size);
+ MYSQLND_STMT * ret = mnd_pecalloc(1, alloc_size, conn->persistent);
+ MYSQLND_STMT_DATA * stmt = NULL;
DBG_ENTER("_mysqlnd_stmt_init");
- DBG_INF_FMT("stmt=%p", stmt);
-
- stmt->m = mysqlnd_stmt_methods;
- stmt->state = MYSQLND_STMT_INITTED;
- stmt->execute_cmd_buffer.length = 4096;
- stmt->execute_cmd_buffer.buffer = mnd_emalloc(stmt->execute_cmd_buffer.length);
+ do {
+ if (!ret) {
+ break;
+ }
+ ret->m = mysqlnd_stmt_methods;
+ ret->persistent = conn->persistent;
- 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);
+ 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->m->set_param_bind_dtor(stmt, mysqlnd_efree_param_bind_dtor TSRMLS_CC);
- stmt->m->set_result_bind_dtor(stmt, mysqlnd_efree_result_bind_dtor TSRMLS_CC);
+ 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(stmt);
+ 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);
}
/* }}} */
@@ -2108,23 +2384,6 @@ PHPAPI void ** _mysqlnd_plugin_get_plugin_stmt_data(const MYSQLND_STMT * stmt, u
/* }}} */
-/* {{{ mysqlnd_efree_param_bind_dtor */
-PHPAPI void
-mysqlnd_efree_param_bind_dtor(MYSQLND_PARAM_BIND * param_bind TSRMLS_DC)
-{
- mnd_efree(param_bind);
-}
-/* }}} */
-
-
-/* {{{ mysqlnd_efree_result_bind_dtor */
-PHPAPI void
-mysqlnd_efree_result_bind_dtor(MYSQLND_RESULT_BIND * result_bind TSRMLS_DC)
-{
- mnd_efree(result_bind);
-}
-/* }}} */
-
/* {{{ _mysqlnd_init_ps_subsystem */
void _mysqlnd_init_ps_subsystem()
{
@@ -2133,6 +2392,7 @@ void _mysqlnd_init_ps_subsystem()
}
/* }}} */
+
/* {{{ mysqlnd_conn_get_methods */
PHPAPI struct st_mysqlnd_stmt_methods * mysqlnd_stmt_get_methods()
{
@@ -2140,6 +2400,7 @@ PHPAPI struct st_mysqlnd_stmt_methods * mysqlnd_stmt_get_methods()
}
/* }}} */
+
/* {{{ mysqlnd_conn_set_methods */
PHPAPI void mysqlnd_stmt_set_methods(struct st_mysqlnd_stmt_methods *methods)
{