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.c169
1 files changed, 73 insertions, 96 deletions
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index 4588165f05..c47da0262a 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -38,6 +38,7 @@ const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
/* 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);
+enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC);
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);
@@ -109,12 +110,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
DBG_RETURN(NULL);
}
/* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */
- set->data = mnd_emalloc((size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
+ set->data = mnd_emalloc((size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval)));
if (!set->data) {
SET_OOM_ERROR(*conn->error_info);
DBG_RETURN(NULL);
}
- memset(set->data, 0, (size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
+ memset(set->data, 0, (size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval)));;
}
/* Position at the first row */
set->data_cursor = set->data;
@@ -642,11 +643,13 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
fetch(); <-- no binding, but that's not a problem
bind_result();
execute(); <-- here we will leak because we separate without need
- */
+ */
unsigned int i;
for (i = 0; i < stmt->field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
- zval_copy_ctor(stmt->result_bind[i].zv);
+ zval *result = &stmt->result_bind[i].zv;
+ ZVAL_DEREF(result);
+ Z_TRY_ADDREF_P(result);
}
}
}
@@ -680,7 +683,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
DBG_RETURN(FAIL);
}
for (i = 0; i < stmt->param_count; i++) {
- if (stmt->param_bind[i].zv == NULL) {
+ if (Z_ISUNDEF(stmt->param_bind[i].zv)) {
not_bound++;
}
}
@@ -751,9 +754,9 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int
/* The user could have skipped binding - don't crash*/
if (stmt->result_bind) {
unsigned int i;
- zval **current_row = set->data_cursor;
+ zval *current_row = set->data_cursor;
- if (NULL == current_row[0]) {
+ if (Z_ISUNDEF(current_row[0])) {
uint64_t row_num = (set->data_cursor - set->data) / field_count;
enum_func_status rc = result->stored_data->m.row_decoder(result->stored_data->row_buffers[row_num],
current_row,
@@ -772,8 +775,8 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int
String of zero size, definitely can't be the next max_length.
Thus for NULL and zero-length we are quite efficient.
*/
- if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
- unsigned long len = Z_STRLEN_P(current_row[i]);
+ if (Z_TYPE(current_row[i]) == IS_STRING) {
+ php_uint_t len = Z_STRSIZE(current_row[i]);
if (meta->fields[i].max_length < len) {
meta->fields[i].max_length = len;
}
@@ -783,16 +786,17 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int
}
for (i = 0; i < result->field_count; i++) {
+ zval *result = &stmt->result_bind[i].zv;
+
+ ZVAL_DEREF(result);
/* Clean what we copied last time */
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- if (stmt->result_bind[i].zv) {
- zval_dtor(stmt->result_bind[i].zv);
- }
+ zval_dtor(result);
#endif
/* copy the type */
if (stmt->result_bind[i].bound == TRUE) {
- DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
- if (Z_TYPE_P(current_row[i]) != IS_NULL) {
+ DBG_INF_FMT("i=%u type=%u", i, Z_TYPE(current_row[i]));
+ if (Z_TYPE(current_row[i]) != IS_NULL) {
/*
Copy the value.
Pre-condition is that the zvals in the result_bind buffer
@@ -801,13 +805,12 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int
counting the user can't delete the strings the variables point to.
*/
- Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
- stmt->result_bind[i].zv->value = current_row[i]->value;
+ ZVAL_COPY_VALUE(result, &current_row[i]);
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_copy_ctor(stmt->result_bind[i].zv);
+ Z_TRY_ADDREF_P(result);
#endif
} else {
- ZVAL_NULL(stmt->result_bind[i].zv);
+ ZVAL_NULL(result);
}
}
}
@@ -889,19 +892,23 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned i
for (i = 0; i < field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
- zval *data = result->unbuf->last_row_data[i];
+ zval *data = &result->unbuf->last_row_data[i];
+ zval *result = &stmt->result_bind[i].zv;
+
+ ZVAL_DEREF(result);
/*
stmt->result_bind[i].zv has been already destructed
in result->unbuf->m.free_last_data()
*/
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_dtor(stmt->result_bind[i].zv);
+ zval_dtor(result);
#endif
- if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
- if ((Z_TYPE_P(data) == IS_STRING) && (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) {
- meta->fields[i].max_length = Z_STRLEN_P(data);
+ if (!Z_ISNULL_P(data)) {
+ if ((Z_TYPE_P(data) == IS_STRING) &&
+ (meta->fields[i].max_length < (unsigned long) Z_STRSIZE_P(data))) {
+ meta->fields[i].max_length = Z_STRSIZE_P(data);
}
- stmt->result_bind[i].zv->value = data->value;
+ ZVAL_COPY_VALUE(result, data);
/* copied data, thus also the ownership. Thus null data */
ZVAL_NULL(data);
}
@@ -1069,21 +1076,27 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f
/* If no result bind, do nothing. We consumed the data */
for (i = 0; i < field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
- zval *data = result->unbuf->last_row_data[i];
+ zval *data = &result->unbuf->last_row_data[i];
+ zval *result = &stmt->result_bind[i].zv;
+
+ ZVAL_DEREF(result);
/*
stmt->result_bind[i].zv has been already destructed
in result->unbuf->m.free_last_data()
*/
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_dtor(stmt->result_bind[i].zv);
+ zval_dtor(result);
#endif
- 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) && (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) {
- meta->fields[i].max_length = Z_STRLEN_P(data);
+ DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, &stmt->result_bind[i].zv,
+ Z_TYPE_P(data), Z_REFCOUNTED(stmt->result_bind[i].zv)?
+ Z_REFCOUNT(stmt->result_bind[i].zv) : 0);
+
+ if (!Z_ISNULL_P(data)) {
+ if ((Z_TYPE_P(data) == IS_STRING) &&
+ (meta->fields[i].max_length < (unsigned long) Z_STRSIZE_P(data))) {
+ meta->fields[i].max_length = Z_STRSIZE_P(data);
}
- stmt->result_bind[i].zv->value = data->value;
+ ZVAL_COPY_VALUE(result, data);
/* copied data, thus also the ownership. Thus null data */
ZVAL_NULL(data);
}
@@ -1167,7 +1180,7 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fe
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);
+ 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.
@@ -1180,8 +1193,10 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fe
*/
for (i = 0; i < stmt->result->field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
- zval_dtor(stmt->result_bind[i].zv);
- ZVAL_NULL(stmt->result_bind[i].zv);
+ zval *result = &stmt->result_bind[i].zv;
+ ZVAL_DEREF(result);
+ zval_dtor(result);
+ ZVAL_NULL(result);
}
}
stmt->result_zvals_separated_once = TRUE;
@@ -1287,7 +1302,7 @@ MYSQLND_METHOD(mysqlnd_stmt, flush)(MYSQLND_STMT * const s TSRMLS_DC)
/* {{{ mysqlnd_stmt::send_long_data */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
- const char * const data, unsigned long length TSRMLS_DC)
+ const char * const data, php_uint_t length TSRMLS_DC)
{
MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
enum_func_status ret = FAIL;
@@ -1437,9 +1452,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PA
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) {
- zval_ptr_dtor(&stmt->param_bind[i].zv);
- }
+ zval_ptr_dtor(&stmt->param_bind[i].zv);
}
if (stmt->param_bind != param_bind) {
s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
@@ -1452,7 +1465,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PA
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);
+ Z_TRY_ADDREF(stmt->param_bind[i].zv);
stmt->param_bind[i].flags = 0;
if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
@@ -1502,17 +1515,15 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigne
/* Prevent from freeing */
/* Don't update is_ref, or we will leak during conversion */
- Z_ADDREF_P(zv);
+ Z_TRY_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);
- }
+ 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;
+ ZVAL_COPY_VALUE(&stmt->param_bind[param_no].zv, zv);
stmt->param_bind[param_no].type = type;
stmt->send_types_to_server = 1;
@@ -1588,8 +1599,10 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
stmt->result_bind = result_bind;
for (i = 0; i < stmt->field_count; i++) {
/* Prevent from freeing */
- Z_ADDREF_P(stmt->result_bind[i].zv);
- DBG_INF_FMT("ref of %p = %u", stmt->result_bind[i].zv, Z_REFCOUNT_P(stmt->result_bind[i].zv));
+ Z_TRY_ADDREF(stmt->result_bind[i].zv);
+
+ DBG_INF_FMT("ref of %p = %u", &stmt->result_bind[i].zv,
+ Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0);
/*
Don't update is_ref !!! it's not our job
Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
@@ -1643,7 +1656,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned i
if (!stmt->result_bind) {
DBG_RETURN(FAIL);
}
- ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
+ ZVAL_NULL(&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
@@ -1866,7 +1879,7 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
}
case STMT_ATTR_CURSOR_TYPE: {
unsigned int ival = *(unsigned int *) value;
- if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) {
+ if (ival > (php_uint_t) CURSOR_TYPE_READ_ONLY) {
SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
DBG_INF("FAIL");
DBG_RETURN(FAIL);
@@ -1914,10 +1927,10 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
*(zend_bool *) value= stmt->update_max_length;
break;
case STMT_ATTR_CURSOR_TYPE:
- *(unsigned long *) value= stmt->flags;
+ *(php_uint_t *) value= stmt->flags;
break;
case STMT_ATTR_PREFETCH_ROWS:
- *(unsigned long *) value= stmt->prefetch_rows;
+ *(php_uint_t *) value= stmt->prefetch_rows;
break;
default:
DBG_RETURN(FAIL);
@@ -2008,29 +2021,12 @@ mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s 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("%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
- */
- if (Z_REFCOUNT_P(stmt->result_bind[i].zv) > 1) {
-#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_copy_ctor(stmt->result_bind[i].zv);
-#endif
- zval_ptr_dtor(&stmt->result_bind[i].zv);
- } else {
- /*
- If it is a string, what is pointed will be freed
- later in free_result(). We need to remove the variable to
- which the user has lost reference.
- */
-#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- ZVAL_NULL(stmt->result_bind[i].zv);
-#endif
- zval_ptr_dtor(&stmt->result_bind[i].zv);
- }
+ DBG_INF_FMT("%u has refcount=%u", i,
+ Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0);
+ zval_ptr_dtor(&stmt->result_bind[i].zv);
}
}
+
s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC);
stmt->result_bind = NULL;
@@ -2061,27 +2057,10 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param
*/
/* Let's try with no cache */
if (stmt->result_bind[param_no].bound == TRUE) {
- 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
- */
- if (Z_REFCOUNT_P(stmt->result_bind[param_no].zv) > 1) {
-#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_copy_ctor(stmt->result_bind[param_no].zv);
-#endif
- zval_ptr_dtor(&stmt->result_bind[param_no].zv);
- } else {
- /*
- If it is a string, what is pointed will be freed
- later in free_result(). We need to remove the variable to
- which the user has lost reference.
- */
-#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- ZVAL_NULL(stmt->result_bind[param_no].zv);
-#endif
- zval_ptr_dtor(&stmt->result_bind[param_no].zv);
- }
+ DBG_INF_FMT("%u has refcount=%u", param_no,
+ Z_REFCOUNTED(stmt->result_bind[param_no].zv)?
+ Z_REFCOUNT(stmt->result_bind[param_no].zv) : 0);
+ zval_ptr_dtor(&stmt->result_bind[param_no].zv);
}
DBG_VOID_RETURN;
@@ -2144,9 +2123,7 @@ MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC
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);
- }
+ zval_ptr_dtor(&stmt->param_bind[i].zv);
}
s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
stmt->param_bind = NULL;