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.c260
1 files changed, 197 insertions, 63 deletions
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index 7679b72169..59e9a96f63 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -56,7 +56,7 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param,
unsigned int flags,
zend_bool *fetched_anything TSRMLS_DC);
-void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
+static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
/* {{{ mysqlnd_stmt::store_result */
@@ -78,8 +78,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
- MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC);
- DBG_RETURN(res);
+ DBG_RETURN(stmt->m->use_result(stmt TSRMLS_CC));
}
/* Nothing to store for UPSERT/LOAD DATA*/
@@ -135,7 +134,7 @@ MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt
MYSQLND_RES *result;
zend_bool to_cache = FALSE;
- DBG_ENTER("mysqlnd_stmt::store_result");
+ DBG_ENTER("mysqlnd_stmt::background_store_result");
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
/* be compliant with libmysql - NULL will turn */
@@ -198,6 +197,7 @@ MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt
}
/* }}} */
+
/* {{{ mysqlnd_stmt::get_result */
static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
@@ -215,8 +215,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
- MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC);
- DBG_RETURN(res);
+ DBG_RETURN(stmt->m->use_result(stmt TSRMLS_CC));
}
/* Nothing to store for UPSERT/LOAD DATA*/
@@ -255,6 +254,7 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
{
/* Follows parameter metadata, we have just to skip it, as libmysql does */
unsigned int i = 0;
+ enum_func_status ret = PASS;
php_mysql_packet_res_field field_packet;
DBG_ENTER("mysqlnd_stmt_skip_metadata");
@@ -264,13 +264,13 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
field_packet.skip_parsing = TRUE;
for (;i < stmt->param_count; i++) {
if (FAIL == PACKET_READ_ALLOCA(field_packet, stmt->conn)) {
- PACKET_FREE_ALLOCA(field_packet);
- DBG_RETURN(FAIL);
+ ret = FAIL;
+ break;
}
}
PACKET_FREE_ALLOCA(field_packet);
- DBG_RETURN(PASS);
+ DBG_RETURN(ret);
}
/* }}} */
@@ -280,19 +280,21 @@ static enum_func_status
mysqlnd_stmt_read_prepare_response(MYSQLND_STMT *stmt TSRMLS_DC)
{
php_mysql_packet_prepare_response prepare_resp;
+ enum_func_status ret = PASS;
DBG_ENTER("mysqlnd_stmt_read_prepare_response");
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
PACKET_INIT_ALLOCA(prepare_resp, PROT_PREPARE_RESP_PACKET);
if (FAIL == PACKET_READ_ALLOCA(prepare_resp, stmt->conn)) {
- PACKET_FREE_ALLOCA(prepare_resp);
- return FAIL;
+ ret = FAIL;
+ goto done;
}
if (0xFF == prepare_resp.error_code) {
stmt->error_info = stmt->conn->error_info = prepare_resp.error_info;
- return FAIL;
+ ret = FAIL;
+ goto done;
}
stmt->stmt_id = prepare_resp.stmt_id;
@@ -301,7 +303,8 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT *stmt TSRMLS_DC)
stmt->param_count = prepare_resp.param_count;
PACKET_FREE_ALLOCA(prepare_resp);
- DBG_RETURN(PASS);
+done:
+ DBG_RETURN(ret);
}
/* }}} */
@@ -487,13 +490,31 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
DBG_RETURN(FAIL);
}
- if (stmt->param_count && !stmt->param_bind) {
- SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
- "No data supplied for parameters in prepared statement");
- DBG_INF("FAIL");
- DBG_RETURN(FAIL);
+ if (stmt->param_count) {
+ uint i, not_bound = 0;
+ if (!stmt->param_bind) {
+ SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
+ "No data supplied for parameters in prepared statement");
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
+ }
+ for (i = 0; i < stmt->param_count; i++) {
+ if (stmt->param_bind[i].zv == NULL) {
+ not_bound++;
+ }
+ }
+ if (not_bound) {
+ char * msg;
+ spprintf(&msg, 0, "No data supplied for %d 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);
+ }
+ 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 ! */
@@ -553,7 +574,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(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\n", stmt->upsert_status.server_status,
+ DBG_INF_FMT("server_status=%d cursor=%d", stmt->upsert_status.server_status,
stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
@@ -595,10 +616,9 @@ enum_func_status
mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags,
zend_bool *fetched_anything TSRMLS_DC)
{
- unsigned int i;
MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
- uint field_count = result->meta->field_count;
MYSQLND_RES_BUFFERED *set = result->stored_data;
+ uint field_count = result->meta->field_count;
DBG_ENTER("mysqlnd_fetch_stmt_row_buffered");
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
@@ -609,6 +629,8 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
{
/* The user could have skipped binding - don't crash*/
if (stmt->result_bind) {
+ unsigned int i;
+ MYSQLND_RES_METADATA * meta = result->meta;
zval **current_row = set->data_cursor;
if (NULL == current_row[0]) {
@@ -616,8 +638,8 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
set->initialized_rows++;
result->m.row_decoder(set->row_buffers[row_num],
current_row,
- result->meta->field_count,
- result->meta->fields,
+ meta->field_count,
+ meta->fields,
result->conn TSRMLS_CC);
if (stmt->update_max_length) {
for (i = 0; i < result->field_count; i++) {
@@ -628,8 +650,8 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
*/
if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
unsigned long len = Z_STRLEN_P(current_row[i]);
- if (result->meta->fields[i].max_length < len) {
- result->meta->fields[i].max_length = len;
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
}
}
}
@@ -687,7 +709,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
{
enum_func_status ret;
MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
- unsigned int i, field_count = result->field_count;
php_mysql_packet_row *row_packet = result->row_packet;
DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
@@ -712,6 +733,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
mysqlnd_unbuffered_free_last_data() before it. The function returns always true.
*/
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;
@@ -966,7 +988,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
/* {{{ mysqlnd_stmt::fetch */
-PHPAPI enum_func_status
+static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt,
zend_bool * const fetched_anything TSRMLS_DC)
{
@@ -1021,7 +1043,6 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
{
enum_func_status ret = PASS;
- MYSQLND * conn = stmt->conn;
zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
DBG_ENTER("mysqlnd_stmt::reset");
@@ -1031,6 +1052,7 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->stmt_id) {
+ MYSQLND * conn = stmt->conn;
if (stmt->param_bind) {
unsigned int i;
DBG_INF("resetting long data");
@@ -1084,7 +1106,6 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned
enum_func_status ret = FAIL;
MYSQLND * conn = stmt->conn;
zend_uchar *cmd_buf;
- size_t packet_len;
enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
DBG_ENTER("mysqlnd_stmt::send_long_data");
@@ -1126,6 +1147,7 @@ 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);
@@ -1178,19 +1200,20 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned
/* }}} */
-/* {{{ _mysqlnd_stmt_bind_param */
+/* {{{ mysqlnd_stmt::bind_parameters */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt,
- MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const stmt,
+ MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
{
- unsigned int i = 0;
-
DBG_ENTER("mysqlnd_stmt::bind_param");
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);
+ }
DBG_RETURN(FAIL);
}
@@ -1198,6 +1221,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt,
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->param_count) {
+ unsigned int i = 0;
+
if (!param_bind) {
SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
"Re-binding (still) not supported");
@@ -1210,29 +1235,28 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt,
Forbid for now re-binding!!
*/
for (i = 0; i < stmt->param_count; i++) {
- /* For BLOBS zv is NULL */
+ /*
+ 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) {
- /*
- We may have the last reference, then call zval_ptr_dtor()
- or we may leak memory.
- */
zval_ptr_dtor(&stmt->param_bind[i].zv);
- stmt->param_bind[i].zv = NULL;
}
}
- mnd_efree(stmt->param_bind);
+ if (stmt->param_bind != param_bind && stmt->param_bind_dtor) {
+ stmt->param_bind_dtor(stmt->param_bind);
+ }
}
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);
- if (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB) {
- /* Prevent from freeing */
- Z_ADDREF_P(stmt->param_bind[i].zv);
- /* Don't update is_ref, or we will leak during conversion */
- } else {
- stmt->param_bind[i].zv = NULL;
+ /* Prevent from freeing */
+ /* Don't update is_ref, or we will leak during conversion */
+ Z_ADDREF_P(stmt->param_bind[i].zv);
+ if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
}
}
@@ -1244,7 +1268,58 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt,
/* }}} */
-/* {{{ _mysqlnd_stmt_refresh_bind_param */
+/* {{{ mysqlnd_stmt::bind_one_parameter */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const stmt, unsigned int param_no,
+ zval * const zv, zend_uchar type TSRMLS_DC)
+{
+ DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
+ DBG_INF_FMT("stmt=%lu param_no=%d param_count=%u type=%d",
+ 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);
+ DBG_ERR("not prepared");
+ DBG_RETURN(FAIL);
+ }
+
+ if (param_no < 0 || param_no >= stmt->param_count) {
+ SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
+ DBG_ERR("invalid param_no");
+ DBG_RETURN(FAIL);
+ }
+ SET_EMPTY_ERROR(stmt->error_info);
+ SET_EMPTY_ERROR(stmt->conn->error_info);
+
+ if (stmt->param_count) {
+ if (!stmt->param_bind) {
+ stmt->param_bind = ecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND));
+ }
+
+ /* Prevent from freeing */
+ /* Don't update is_ref, or we will leak during conversion */
+ Z_ADDREF_P(zv);
+ DBG_INF("Binding");
+ /* Release what we had, if we had */
+ if (stmt->param_bind[param_no].zv) {
+ zval_ptr_dtor(&stmt->param_bind[param_no].zv);
+ }
+ if (type == MYSQL_TYPE_LONG_BLOB) {
+ /* The client will use stmt_send_long_data */
+ stmt->param_bind[param_no].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
+ }
+ stmt->param_bind[param_no].zv = zv;
+ stmt->param_bind[param_no].type = type;
+
+ stmt->send_types_to_server = 1;
+ }
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt::refresh_bind_param */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const stmt TSRMLS_DC)
{
@@ -1269,13 +1344,24 @@ 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)
+{
+ 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_RESULT_BIND * const result_bind TSRMLS_DC)
{
- uint i = 0;
-
DBG_ENTER("mysqlnd_stmt::bind_result");
DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
@@ -1284,14 +1370,16 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
- if (result_bind) {
- mnd_efree(result_bind);
+ if (result_bind && stmt->result_bind_dtor) {
+ stmt->result_bind_dtor(result_bind);
}
DBG_ERR("not prepared");
DBG_RETURN(FAIL);
}
if (stmt->field_count) {
+ uint i = 0;
+
if (!result_bind) {
DBG_ERR("no result bind passed");
DBG_RETURN(FAIL);
@@ -1310,8 +1398,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
*/
stmt->result_bind[i].bound = TRUE;
}
- } else if (result_bind) {
- mnd_efree(result_bind);
+ } else if (result_bind && stmt->result_bind_dtor) {
+ stmt->result_bind_dtor(result_bind);
}
DBG_INF("PASS");
DBG_RETURN(PASS);
@@ -1319,6 +1407,19 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
/* }}} */
+/* {{{ 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)
+{
+ 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
MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const stmt)
@@ -1483,7 +1584,8 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
case STMT_ATTR_CURSOR_TYPE: {
if (val > (unsigned long) CURSOR_TYPE_READ_ONLY) {
SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
- return FAIL;
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
}
stmt->flags = val;
break;
@@ -1493,7 +1595,8 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
val = MYSQLND_DEFAULT_PREFETCH_ROWS;
} else if (val > 1) {
SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
- return FAIL;
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
}
stmt->prefetch_rows = val;
break;
@@ -1508,7 +1611,7 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
/* }}} */
-/* {{{ _mysqlnd_stmt_attr_get */
+/* {{{ mysqlnd_stmt::attr_get */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, attr_get)(MYSQLND_STMT * const stmt,
enum mysqlnd_stmt_attr attr_type,
@@ -1624,7 +1727,9 @@ void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
}
}
}
- mnd_efree(stmt->result_bind);
+ if (stmt->result_bind_dtor) {
+ stmt->result_bind_dtor(stmt->result_bind);
+ }
stmt->result_bind = NULL;
DBG_VOID_RETURN;
@@ -1649,13 +1754,17 @@ void mysqlnd_internal_free_stmt_content(MYSQLND_STMT *stmt TSRMLS_DC)
lost reference.
*/
for (i = 0; i < stmt->param_count; i++) {
- /* For BLOBs zv is NULL */
+ /*
+ If bind_one_parameter was used, but not everything was
+ bound and nothing was fetched, then some `zv` could be NULL
+ */
if (stmt->param_bind[i].zv) {
zval_ptr_dtor(&stmt->param_bind[i].zv);
}
}
-
- mnd_efree(stmt->param_bind);
+ if (stmt->param_bind_dtor) {
+ stmt->param_bind_dtor(stmt->param_bind);
+ }
stmt->param_bind = NULL;
}
@@ -1790,9 +1899,12 @@ struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = {
MYSQLND_METHOD(mysqlnd_stmt, fetch),
- MYSQLND_METHOD(mysqlnd_stmt, bind_param),
+ 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, set_result_bind_dtor),
MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
@@ -1835,10 +1947,32 @@ MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
*/
stmt->conn = conn->m->get_reference(conn);
+ 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);
+
DBG_RETURN(stmt);
}
/* }}} */
+
+/* {{{ mysqlnd_efree_param_bind_dtor */
+PHPAPI void
+mysqlnd_efree_param_bind_dtor(MYSQLND_PARAM_BIND * param_bind)
+{
+ efree(param_bind);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_efree_result_bind_dtor */
+PHPAPI void
+mysqlnd_efree_result_bind_dtor(MYSQLND_RESULT_BIND * result_bind)
+{
+ efree(result_bind);
+}
+/* }}} */
+
+
/*
* Local variables:
* tab-width: 4