summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/mysqlnd/mysqlnd_palloc.c7
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c62
-rw-r--r--ext/mysqlnd/mysqlnd_ps_codec.c2
-rw-r--r--ext/mysqlnd/mysqlnd_result.c5
4 files changed, 53 insertions, 23 deletions
diff --git a/ext/mysqlnd/mysqlnd_palloc.c b/ext/mysqlnd/mysqlnd_palloc.c
index ca945c1901..1b035ed365 100644
--- a/ext/mysqlnd/mysqlnd_palloc.c
+++ b/ext/mysqlnd/mysqlnd_palloc.c
@@ -497,9 +497,14 @@ void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd
*(thd_cache->gc_list.last_added++) = (mysqlnd_zval *)*zv;
UNLOCK_PCACHE(cache);
} else {
+ DBG_INF("No user reference");
/* No user reference */
if (((mysqlnd_zval *)*zv)->point_type == MYSQLND_POINTS_EXT_BUFFER) {
- /* PS are here and also in Unicode mode, for non-binary */
+ DBG_INF("Points to external buffer. Calling zval_dtor");
+ /*
+ PS are here
+ Unicode mode goes also here if the column is not binary but a text
+ */
zval_dtor(*zv);
}
LOCK_PCACHE(cache);
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index f406fb8068..3427157617 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -536,12 +536,14 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
+ DBG_INF("cursor exists");
stmt->cursor_exists = TRUE;
CONN_SET_STATE(conn, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = stmt->m->use_result;
DBG_INF("use_result");
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
+ DBG_INF("asked for cursor but got none");
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
@@ -556,6 +558,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
stmt->default_rset_handler = stmt->m->store_result;
DBG_INF("store_result");
} else {
+ DBG_INF("no cursor");
/* preferred is unbuffered read */
stmt->default_rset_handler = stmt->m->use_result;
DBG_INF("use_result");
@@ -853,15 +856,10 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
stmt->result_bind[i].zv has been already destructed
in mysqlnd_unbuffered_free_last_data()
*/
-
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
zval_dtor(stmt->result_bind[i].zv);
#endif
if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
- stmt->result_bind[i].zv->value = data->value;
-#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_copy_ctor(stmt->result_bind[i].zv);
-#endif
if (
(Z_TYPE_P(data) == IS_STRING
#if PHP_MAJOR_VERSION >= 6
@@ -872,6 +870,9 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
{
result->meta->fields[i].max_length = Z_STRLEN_P(data);
}
+ stmt->result_bind[i].zv->value = data->value;
+ // copied data, thus also the ownership. Thus null data
+ ZVAL_NULL(data);
}
}
}
@@ -888,14 +889,15 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
row_packet->row_buffer = NULL;
}
} 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;
}
- *fetched_anything = FALSE;
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;
@@ -910,7 +912,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
} else {
CONN_SET_STATE(result->conn, CONN_READY);
}
- *fetched_anything = FALSE;
}
DBG_INF_FMT("ret=%s fetched_anything=%d", ret == PASS? "PASS":"FAIL", *fetched_anything);
@@ -944,7 +945,8 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT *stmt TSRMLS_DC)
MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);
result = stmt->result;
-
+
+ DBG_INF_FMT("%scursor exists", stmt->cursor_exists? "":"no ");
result->m.use_result(stmt->result, TRUE TSRMLS_CC);
result->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
mysqlnd_stmt_fetch_row_unbuffered;
@@ -1002,15 +1004,19 @@ 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;
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->unbuf->row_count++;
+ *fetched_anything = TRUE;
- result->unbuf->last_row_data = row_packet->fields;
- result->unbuf->last_row_buffer = row_packet->row_buffer;
+ DBG_INF_FMT("skip_extraction=%d", row_packet->skip_extraction);
+ if (!row_packet->skip_extraction) {
+ mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ DBG_INF("extracting data");
+ result->unbuf->last_row_data = row_packet->fields;
+ result->unbuf->last_row_buffer = row_packet->row_buffer;
+ row_packet->fields = NULL;
+ row_packet->row_buffer = NULL;
- row_packet->fields = NULL;
- row_packet->row_buffer = NULL;
- if (!row_packet->skip_extraction) {
result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
row_packet->field_count,
@@ -1025,12 +1031,12 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
stmt->result_bind[i].zv has been already destructed
in mysqlnd_unbuffered_free_last_data()
*/
- DBG_INF_FMT("i=%d type=%d", i, Z_TYPE_P(stmt->result_bind[i].zv));
- if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
- stmt->result_bind[i].zv->value = data->value;
-#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- zval_copy_ctor(stmt->result_bind[i].zv);
+#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,
+ 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
#if PHP_MAJOR_VERSION >= 6
|| Z_TYPE_P(data) == IS_UNICODE
@@ -1040,12 +1046,23 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
{
result->meta->fields[i].max_length = Z_STRLEN_P(data);
}
+ stmt->result_bind[i].zv->value = data->value;
+ // copied data, thus also the ownership. Thus null data
+ ZVAL_NULL(data);
}
}
}
+ } else {
+ DBG_INF("skipping extraction");
+ /*
+ Data has been allocated and usually mysqlnd_unbuffered_free_last_data()
+ frees it but we can't call this function as it will cause problems with
+ 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 = NULL;
}
- result->unbuf->row_count++;
- *fetched_anything = TRUE;
/* 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) {
@@ -1491,7 +1508,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
stmt->result_bind = result_bind;
for (i = 0; i < stmt->field_count; i++) {
/* Prevent from freeing */
- Z_ADDREF_P(stmt->result_bind[i].zv);
+ 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));
/*
Don't update is_ref !!! it's not our job
Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c
index 673523c77c..6fd2e053b2 100644
--- a/ext/mysqlnd/mysqlnd_ps_codec.c
+++ b/ext/mysqlnd/mysqlnd_ps_codec.c
@@ -405,12 +405,14 @@ void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field,
DBG_ENTER("ps_fetch_string");
DBG_INF_FMT("len = %lu", length);
#if PHP_MAJOR_VERSION < 6
+ DBG_INF("copying from the row buffer");
ZVAL_STRINGL(zv, (char *)*row, length, 1);
#else
if (field->charsetnr == MYSQLND_BINARY_CHARSET_NR) {
DBG_INF("Binary charset");
ZVAL_STRINGL(zv, (char *)*row, length, 1);
} else {
+ DBG_INF_FMT("copying from the row buffer");
ZVAL_UTF8_STRINGL(zv, (char*)*row, length, ZSTR_DUPLICATE);
}
#endif
diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
index f791fd0fb5..e161f28854 100644
--- a/ext/mysqlnd/mysqlnd_result.c
+++ b/ext/mysqlnd/mysqlnd_result.c
@@ -143,10 +143,13 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
DBG_VOID_RETURN;
}
+ DBG_INF_FMT("last_row_data=%p", unbuf->last_row_data);
if (unbuf->last_row_data) {
unsigned int i, ctor_called_count = 0;
zend_bool copy_ctor_called;
MYSQLND_STATS *global_stats = result->conn? &result->conn->stats:NULL;
+
+ DBG_INF_FMT("%u columns to free", result->field_count);
for (i = 0; i < result->field_count; i++) {
mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]),
result->zval_cache, result->type,
@@ -155,6 +158,7 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
ctor_called_count++;
}
}
+ DBG_INF_FMT("copy_ctor_called_count=%u", ctor_called_count);
/* By using value3 macros we hold a mutex only once, there is no value2 */
MYSQLND_INC_CONN_STATISTIC_W_VALUE3(global_stats,
STAT_COPY_ON_WRITE_PERFORMED,
@@ -168,6 +172,7 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
unbuf->last_row_data = NULL;
}
if (unbuf->last_row_buffer) {
+ DBG_INF("Freeing last row buffer");
/* Nothing points to this buffer now, free it */
unbuf->last_row_buffer->free_chunk(unbuf->last_row_buffer, TRUE TSRMLS_CC);
unbuf->last_row_buffer = NULL;