From 74ba88e186a0f70caa6e8e5a440a3a204afabf50 Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Tue, 26 Nov 2013 19:01:49 +0200 Subject: Fix for Bug #66141 (mysqlnd quote function is wrong with NO_BACKSLASH_ESCAPES after failed query) --- ext/mysqlnd/mysqlnd_ps.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index cd5b302275..3a1f6a0521 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -485,6 +485,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC) ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC); if (ret == FAIL) { COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); + memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status)); stmt->upsert_status->affected_rows = conn->upsert_status->affected_rows; if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) { /* close the statement here, the connection has been closed */ @@ -913,6 +914,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int DBG_INF("EOF"); /* Mark the connection as usable again */ result->unbuf->eof_reached = TRUE; + memset(result->conn->upsert_status, 0, sizeof(*result->conn->upsert_status)); result->conn->upsert_status->warning_count = row_packet->warning_count; result->conn->upsert_status->server_status = row_packet->server_status; /* @@ -1022,6 +1024,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE; + memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status)); if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) { unsigned int i, field_count = result->field_count; -- cgit v1.2.1 From c0d060f5c02db168f1de895b41afffbc6e3cacfb Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 3 Jan 2014 11:04:26 +0800 Subject: Bump year --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 3a1f6a0521..23a0f8a687 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 2006-2013 The PHP Group | + | Copyright (c) 2006-2014 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 | -- cgit v1.2.1 From 47c902777297ce895aa915c13efdb00881af3669 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 3 Jan 2014 11:06:16 +0800 Subject: Bump year --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 1eca92776f..8096cbbbd9 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 2006-2013 The PHP Group | + | Copyright (c) 2006-2014 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 | -- cgit v1.2.1 From c081ce628f0d76d44784d7bb8e06428b06142ac0 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 3 Jan 2014 11:08:10 +0800 Subject: Bump year --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 1eca92776f..8096cbbbd9 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 2006-2013 The PHP Group | + | Copyright (c) 2006-2014 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 | -- cgit v1.2.1 From 7072db5a6bffedef619d7458d6aca8b469d72c70 Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Thu, 23 Jan 2014 18:20:13 +0200 Subject: FIx failing tests because of operator precedence --- ext/mysqlnd/mysqlnd_ps.c | 1 + 1 file changed, 1 insertion(+) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 8096cbbbd9..2d270c9b2f 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); enum_func_status mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, -- cgit v1.2.1 From b2cd56c3cb9e752e3d0e4accb99d0f2e1ac71632 Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Mon, 17 Feb 2014 18:37:08 +0200 Subject: Move code out, that handles the actual structure to be used for the decoded data. Will make it easier to add different structures --- ext/mysqlnd/mysqlnd_ps.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 8096cbbbd9..fa2abc71d7 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -104,6 +104,26 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC); if (PASS == ret) { + /* Overflow ? */ + MYSQLND_RES_BUFFERED * set = result->stored_data; + if (set->row_count) { + /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ + if (set->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) { + SET_OOM_ERROR(*conn->error_info); + 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)(set->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)(set->row_count * result->meta->field_count * sizeof(zval *))); + } + /* Position at the first row */ + set->data_cursor = set->data; + + /* libmysql API docs say it should be so for SELECT statements */ stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count; -- cgit v1.2.1 From 6b804b96b8c454954d30ed8f0cf1a05d91801c4f Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Wed, 5 Mar 2014 16:22:23 +0200 Subject: Refactor the result set data structures. Move more to the buffered and unbuffered substructures. Add methods to these too. Preparing for pluggable interface for returning data to the engine (zvals, c-style, something else) --- ext/mysqlnd/mysqlnd_ps.c | 76 +++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 40 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index fa2abc71d7..dc97d2d36f 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -39,14 +39,6 @@ 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_fetch_row_buffered(MYSQLND_RES *result, void *param, - unsigned int flags, - zend_bool *fetched_anything TSRMLS_DC); - -enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, - unsigned int flags, - zend_bool *fetched_anything 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); @@ -95,14 +87,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) result = stmt->result; result->type = MYSQLND_RES_PS_BUF; - result->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; - result->m.fetch_lengths = NULL;/* makes no sense */ - result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; - - result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC); +/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */ ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC); + result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; + if (PASS == ret) { /* Overflow ? */ MYSQLND_RES_BUFFERED * set = result->stored_data; @@ -541,7 +531,11 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC) /* Update stmt->field_count as SHOW sets it to 0 at prepare */ stmt->field_count = stmt->result->field_count = conn->field_count; - stmt->result->lengths = NULL; + if (stmt->result->stored_data) { + stmt->result->stored_data->lengths = NULL; + } else if (stmt->result->unbuf) { + stmt->result->unbuf->lengths = NULL; + } if (stmt->field_count) { stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE; /* @@ -729,12 +723,13 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC) /* {{{ mysqlnd_stmt_fetch_row_buffered */ enum_func_status -mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC) +mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC) { 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; + const MYSQLND_RES_METADATA * const meta = result->meta; + unsigned int field_count = meta->field_count; DBG_ENTER("mysqlnd_stmt_fetch_row_buffered"); *fetched_anything = FALSE; @@ -747,12 +742,11 @@ mysqlnd_stmt_fetch_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]) { uint64_t row_num = (set->data_cursor - set->data) / field_count; - enum_func_status rc = result->m.row_decoder(set->row_buffers[row_num], + enum_func_status rc = result->stored_data->m.row_decoder(set->row_buffers[row_num], current_row, meta->field_count, meta->fields, @@ -825,13 +819,14 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int f /* {{{ mysqlnd_stmt_fetch_row_unbuffered */ -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 +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 * s = (MYSQLND_STMT *) param; MYSQLND_STMT_DATA * stmt = s? s->data:NULL; MYSQLND_PACKET_ROW * row_packet; + const MYSQLND_RES_METADATA * const meta = result->meta; DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered"); @@ -848,7 +843,7 @@ 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)) { + if (!(row_packet = result->unbuf->row_packet)) { DBG_RETURN(FAIL); } @@ -857,20 +852,20 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int /* If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to - result->m.unbuffered_free_last_data() before it. The function returns always true. + result->unbuf->m.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; if (!row_packet->skip_extraction) { - result->m.unbuffered_free_last_data(result TSRMLS_CC); + result->unbuf->m.free_last_data(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC); 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; - if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer, + if (PASS != result->unbuf->m.row_decoder(result->unbuf->last_row_buffer, result->unbuf->last_row_data, row_packet->field_count, row_packet->fields_metadata, @@ -885,14 +880,14 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int zval *data = result->unbuf->last_row_data[i]; /* stmt->result_bind[i].zv has been already destructed - in result->m.unbuffered_free_last_data() + 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); #endif if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) { - if ((Z_TYPE_P(data) == IS_STRING) && (result->meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) { - result->meta->fields[i].max_length = Z_STRLEN_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); } stmt->result_bind[i].zv->value = data->value; /* copied data, thus also the ownership. Thus null data */ @@ -904,7 +899,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int } else { DBG_INF("skipping extraction"); /* - Data has been allocated and usually result->m.unbuffered_free_last_data() + Data has been allocated and usually result->unbuf->m.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. @@ -979,7 +974,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC) result = stmt->result; result->m.use_result(stmt->result, TRUE TSRMLS_CC); - result->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor: + result->unbuf->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor: mysqlnd_stmt_fetch_row_unbuffered; stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED; @@ -993,7 +988,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC) /* {{{ mysqlnd_fetch_row_cursor */ enum_func_status -mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC) +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 * s = (MYSQLND_STMT *) param; @@ -1017,7 +1012,7 @@ 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)) { + if (!(row_packet = result->unbuf->row_packet)) { DBG_RETURN(FAIL); } @@ -1038,17 +1033,18 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status)); if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) { + const MYSQLND_RES_METADATA * const meta = result->meta; unsigned int i, field_count = result->field_count; if (!row_packet->skip_extraction) { - result->m.unbuffered_free_last_data(result TSRMLS_CC); + result->unbuf->m.free_last_data(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC); 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; - if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer, + if (PASS != result->unbuf->m.row_decoder(result->unbuf->last_row_buffer, result->unbuf->last_row_data, row_packet->field_count, row_packet->fields_metadata, @@ -1064,7 +1060,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla zval *data = result->unbuf->last_row_data[i]; /* stmt->result_bind[i].zv has been already destructed - in result->m.unbuffered_free_last_data() + 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); @@ -1072,8 +1068,8 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla 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) && (result->meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) { - result->meta->fields[i].max_length = Z_STRLEN_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); } stmt->result_bind[i].zv->value = data->value; /* copied data, thus also the ownership. Thus null data */ @@ -1084,7 +1080,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla } else { DBG_INF("skipping extraction"); /* - Data has been allocated and usually result->m.unbuffered_free_last_data() + Data has been allocated and usually result->unbuf->m.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. @@ -1792,7 +1788,8 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC) if (stmt->update_max_length && stmt->result->stored_data) { /* stored result, we have to update the max_length before we clone the meta data :( */ - stmt->result->m.initialize_result_set_rest(stmt->result TSRMLS_CC); + stmt->result->stored_data->m.initialize_result_set_rest(stmt->result->stored_data, stmt->result->meta, stmt->conn->stats, + stmt->conn->options->int_and_float_native TSRMLS_CC); } /* TODO: This implementation is kind of a hack, @@ -1809,8 +1806,7 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC) 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)); + result->unbuf = mysqlnd_result_unbuffered_init(stmt->field_count, TRUE, result->persistent TSRMLS_CC); if (!result->unbuf) { break; } -- cgit v1.2.1 From 73f03a47d0cd97a3c55a79b897ba55ea1ed2e90e Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Mon, 10 Mar 2014 18:18:56 +0200 Subject: DI --- ext/mysqlnd/mysqlnd_ps.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index dc97d2d36f..fc30bddcb5 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -89,6 +89,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) result->type = MYSQLND_RES_PS_BUF; /* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */ + result->stored_data = mysqlnd_result_buffered_init(result->field_count, TRUE, result->persistent TSRMLS_CC); + if (!result->stored_data) { + SET_OOM_ERROR(*conn->error_info); + DBG_RETURN(NULL); + } + ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC); result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; -- cgit v1.2.1 From d2a291393ad899e0ea6fcb11c45095a51ddabb7a Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Mon, 10 Mar 2014 19:15:30 +0200 Subject: inject it directly. This is not C++ and I don't want to use hacks with similar structures that are binary compatible. Better be explicit. --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index fc30bddcb5..669cc3365f 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -95,7 +95,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) DBG_RETURN(NULL); } - ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC); + ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE TSRMLS_CC); result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; -- cgit v1.2.1 From 63791d055ad64762c3f63e08ca7ad8ba1f44e0ab Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Thu, 10 Apr 2014 16:44:54 +0300 Subject: New result fetching mode for mysqlnd, which should use less memory but implies more memory copy. The old method is still available and can be used. It stays as default. Choosing the method is through a flag to mysqli_query()/mysqli_real_query() New mode can be forced with an INI setting, for all extensions that support this mode (ext/mysql and mysqli, because PDO due to it's architecture can't support it) The setting is mysqlnd.fetch_data_copy=[0|1] --- ext/mysqlnd/mysqlnd_ps.c | 171 ++++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 82 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index fc30bddcb5..bee8e1d0ee 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -89,36 +89,39 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) result->type = MYSQLND_RES_PS_BUF; /* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */ - result->stored_data = mysqlnd_result_buffered_init(result->field_count, TRUE, result->persistent TSRMLS_CC); + result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, TRUE, result->persistent TSRMLS_CC); if (!result->stored_data) { SET_OOM_ERROR(*conn->error_info); DBG_RETURN(NULL); } - ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE TSRMLS_CC); + ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE TSRMLS_CC); result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered; if (PASS == ret) { /* Overflow ? */ - MYSQLND_RES_BUFFERED * set = result->stored_data; - if (set->row_count) { - /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ - if (set->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) { - SET_OOM_ERROR(*conn->error_info); - 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)(set->row_count * result->meta->field_count * sizeof(zval *))); - if (!set->data) { - SET_OOM_ERROR(*conn->error_info); - DBG_RETURN(NULL); + if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) { + MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; + if (result->stored_data->row_count) { + /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ + if (result->stored_data->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) { + SET_OOM_ERROR(*conn->error_info); + 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 *))); + 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)(set->row_count * result->meta->field_count * sizeof(zval *))); + /* Position at the first row */ + set->data_cursor = set->data; + } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) { + /*TODO*/ } - /* Position at the first row */ - set->data_cursor = set->data; - /* libmysql API docs say it should be so for SELECT statements */ stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count; @@ -187,7 +190,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC) break; } - if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) { + if ((result = result->m.store_result(result, conn, MYSQLND_STORE_PS | MYSQLND_STORE_NO_COPY TSRMLS_CC))) { stmt->upsert_status->affected_rows = result->stored_data->row_count; stmt->state = MYSQLND_STMT_PREPARED; result->type = MYSQLND_RES_PS_BUF; @@ -733,7 +736,6 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int { MYSQLND_STMT * s = (MYSQLND_STMT *) param; MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - MYSQLND_RES_BUFFERED *set = result->stored_data; const MYSQLND_RES_METADATA * const meta = result->meta; unsigned int field_count = meta->field_count; @@ -742,81 +744,86 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L); /* If we haven't read everything */ - if (set->data_cursor && - (set->data_cursor - set->data) < (set->row_count * field_count)) - { - /* The user could have skipped binding - don't crash*/ - if (stmt->result_bind) { - unsigned int i; - zval **current_row = set->data_cursor; - - if (NULL == current_row[0]) { - uint64_t row_num = (set->data_cursor - set->data) / field_count; - enum_func_status rc = result->stored_data->m.row_decoder(set->row_buffers[row_num], - current_row, - meta->field_count, - meta->fields, - result->conn->options->int_and_float_native, - result->conn->stats TSRMLS_CC); - if (PASS != rc) { - DBG_RETURN(FAIL); - } - set->initialized_rows++; - if (stmt->update_max_length) { - for (i = 0; i < result->field_count; i++) { - /* - NULL fields are 0 length, 0 is not more than 0 - 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 (meta->fields[i].max_length < len) { - meta->fields[i].max_length = len; + if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) { + MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data; + if (set->data_cursor && + (set->data_cursor - set->data) < (result->stored_data->row_count * field_count)) + { + /* The user could have skipped binding - don't crash*/ + if (stmt->result_bind) { + unsigned int i; + zval **current_row = set->data_cursor; + + if (NULL == 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, + meta->field_count, + meta->fields, + result->conn->options->int_and_float_native, + result->conn->stats TSRMLS_CC); + if (PASS != rc) { + DBG_RETURN(FAIL); + } + result->stored_data->initialized_rows++; + if (stmt->update_max_length) { + for (i = 0; i < result->field_count; i++) { + /* + NULL fields are 0 length, 0 is not more than 0 + 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 (meta->fields[i].max_length < len) { + meta->fields[i].max_length = len; + } } } } } - } - for (i = 0; i < result->field_count; i++) { - /* Clean what we copied last time */ + for (i = 0; i < result->field_count; i++) { + /* 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); - } + if (stmt->result_bind[i].zv) { + zval_dtor(stmt->result_bind[i].zv); + } #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) { - /* - Copy the value. - Pre-condition is that the zvals in the result_bind buffer - have been ZVAL_NULL()-ed or to another simple type - (int, double, bool but not string). Because of the reference - 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; + /* 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) { + /* + Copy the value. + Pre-condition is that the zvals in the result_bind buffer + have been ZVAL_NULL()-ed or to another simple type + (int, double, bool but not string). Because of the reference + 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; #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - zval_copy_ctor(stmt->result_bind[i].zv); + zval_copy_ctor(stmt->result_bind[i].zv); #endif - } else { - ZVAL_NULL(stmt->result_bind[i].zv); + } else { + ZVAL_NULL(stmt->result_bind[i].zv); + } } } } + set->data_cursor += field_count; + *fetched_anything = TRUE; + /* buffered result sets don't have a connection */ + MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF); + DBG_INF("row fetched"); + } else { + set->data_cursor = NULL; + DBG_INF("no more data"); } - set->data_cursor += field_count; - *fetched_anything = TRUE; - /* buffered result sets don't have a connection */ - MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF); - DBG_INF("row fetched"); - } else { - set->data_cursor = NULL; - DBG_INF("no more data"); + } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) { + /*TODO*/ } DBG_INF("PASS"); DBG_RETURN(PASS); -- cgit v1.2.1 From 6288bb8ffefe9cf9648b8d2190729c087b5c2586 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 17 Jun 2014 17:50:54 +0800 Subject: Refactoring mysqlnd (incompleted, only mysqlnd ext compilable) --- ext/mysqlnd/mysqlnd_ps.c | 101 +++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 51 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 539d1c8f83..a074bf403d 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -648,7 +648,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC) 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_copy_ctor(&stmt->result_bind[i].zv); } } } @@ -682,7 +682,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++; } } @@ -753,9 +753,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, @@ -774,8 +774,9 @@ 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) { + if (Z_TYPE(current_row[i]) == IS_STRING) { + unsigned long len = Z_STRLEN(current_row[i]); if (meta->fields[i].max_length < len) { meta->fields[i].max_length = len; } @@ -787,14 +788,12 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int for (i = 0; i < result->field_count; i++) { /* 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(&stmt->result_bind[i].zv); #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 @@ -803,13 +802,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(&stmt->result_bind[i].zv, ¤t_row[i]); #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - zval_copy_ctor(stmt->result_bind[i].zv); + zval_copy_ctor(&stmt->result_bind[i].zv); #endif } else { - ZVAL_NULL(stmt->result_bind[i].zv); + ZVAL_NULL(&stmt->result_bind[i].zv); } } } @@ -891,19 +889,20 @@ 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]; /* 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(&stmt->result_bind[i].zv); #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))) { + if (!Z_ISNULL_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); } - stmt->result_bind[i].zv->value = data->value; + ZVAL_COPY_VALUE(&stmt->result_bind[i].zv, data); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1071,21 +1070,23 @@ 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]; /* 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(&stmt->result_bind[i].zv); #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))) { + 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_STRLEN_P(data))) { meta->fields[i].max_length = Z_STRLEN_P(data); } - stmt->result_bind[i].zv->value = data->value; + ZVAL_COPY_VALUE(&stmt->result_bind[i].zv, data); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1169,7 +1170,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. @@ -1182,8 +1183,8 @@ 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_dtor(&stmt->result_bind[i].zv); + ZVAL_NULL(&stmt->result_bind[i].zv); } } stmt->result_zvals_separated_once = TRUE; @@ -1439,9 +1440,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); @@ -1454,7 +1453,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; @@ -1507,14 +1506,12 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigne 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); - } + 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; @@ -1590,8 +1587,9 @@ 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 @@ -1645,7 +1643,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 @@ -2010,14 +2008,15 @@ 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)); + DBG_INF_FMT("%u has refcount=%u", i, + Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0); /* 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) { + if (Z_REFCOUNTED(stmt->result_bind[i].zv) && Z_REFCOUNT(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); + zval_copy_ctor(&stmt->result_bind[i].zv); #endif zval_ptr_dtor(&stmt->result_bind[i].zv); } else { @@ -2063,14 +2062,16 @@ 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)); + 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); /* 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) { + if (Z_REFCOUNTED(stmt->result_bind[param_no].zv) && Z_REFCOUNT(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); + zval_copy_ctor(&stmt->result_bind[param_no].zv); #endif zval_ptr_dtor(&stmt->result_bind[param_no].zv); } else { @@ -2080,7 +2081,7 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param 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); + ZVAL_NULL(&stmt->result_bind[param_no].zv); #endif zval_ptr_dtor(&stmt->result_bind[param_no].zv); } @@ -2115,9 +2116,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; -- cgit v1.2.1 From 049e52f19b5854d6b9bce8ada3c3cb1a1bd01d56 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Thu, 19 Jun 2014 14:24:49 +0800 Subject: Fixed various bugs --- ext/mysqlnd/mysqlnd_ps.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index a074bf403d..a72da6e5e9 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -644,13 +644,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); } } + */ } #endif @@ -788,7 +788,7 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int for (i = 0; i < result->field_count; i++) { /* Clean what we copied last time */ #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - zval_dtor(&stmt->result_bind[i].zv); + zval_dtor(Z_REFVAL(stmt->result_bind[i].zv)); #endif /* copy the type */ if (stmt->result_bind[i].bound == TRUE) { @@ -802,12 +802,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. */ - ZVAL_COPY_VALUE(&stmt->result_bind[i].zv, ¤t_row[i]); + ZVAL_COPY_VALUE(Z_REFVAL(stmt->result_bind[i].zv), ¤t_row[i]); #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - zval_copy_ctor(&stmt->result_bind[i].zv); + zval_copy_ctor(Z_REFVAL(stmt->result_bind[i].zv)); #endif } else { - ZVAL_NULL(&stmt->result_bind[i].zv); + ZVAL_NULL(Z_REFVAL(stmt->result_bind[i].zv)); } } } @@ -895,14 +895,14 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned i 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(Z_REFVAL(stmt->result_bind[i].zv)); #endif if (!Z_ISNULL_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); } - ZVAL_COPY_VALUE(&stmt->result_bind[i].zv, data); + ZVAL_COPY_VALUE(Z_REFVAL(stmt->result_bind[i].zv), data); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1076,7 +1076,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f 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(Z_REFVAL(stmt->result_bind[i].zv)); #endif 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)? @@ -1086,7 +1086,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) { meta->fields[i].max_length = Z_STRLEN_P(data); } - ZVAL_COPY_VALUE(&stmt->result_bind[i].zv, data); + ZVAL_COPY_VALUE(Z_REFVAL(stmt->result_bind[i].zv), data); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } -- cgit v1.2.1 From f81498c8c868ef88a652649c1bd608f8898a3cac Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Thu, 19 Jun 2014 15:49:56 +0800 Subject: Fixed invalid read --- ext/mysqlnd/mysqlnd_ps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index a72da6e5e9..4019aabec0 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -111,12 +111,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; -- cgit v1.2.1 From e0680cb170ba022ee0b54b33ea36bbb67e79618d Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Thu, 19 Jun 2014 16:08:45 +0800 Subject: Fixed reference handling of bind_result --- ext/mysqlnd/mysqlnd_ps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 4019aabec0..b114296130 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -1183,8 +1183,8 @@ 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_dtor(Z_REFVAL(stmt->result_bind[i].zv)); + ZVAL_NULL(Z_REFVAL(stmt->result_bind[i].zv)); } } stmt->result_zvals_separated_once = TRUE; -- cgit v1.2.1 From e091a91f4337f79c4314b18706dfd277ce1c01fc Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 20 Jun 2014 13:08:40 +0800 Subject: Fixed bugs in binding result --- ext/mysqlnd/mysqlnd_ps.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index b114296130..b638863621 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -644,13 +644,15 @@ 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); + zval_copy_ctor(result); } } - */ } #endif @@ -786,9 +788,12 @@ 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 - zval_dtor(Z_REFVAL(stmt->result_bind[i].zv)); + zval_dtor(result); #endif /* copy the type */ if (stmt->result_bind[i].bound == TRUE) { @@ -802,12 +807,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. */ - ZVAL_COPY_VALUE(Z_REFVAL(stmt->result_bind[i].zv), ¤t_row[i]); + ZVAL_COPY_VALUE(result, ¤t_row[i]); #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - zval_copy_ctor(Z_REFVAL(stmt->result_bind[i].zv)); + zval_copy_ctor(result); #endif } else { - ZVAL_NULL(Z_REFVAL(stmt->result_bind[i].zv)); + ZVAL_NULL(result); } } } @@ -890,19 +895,22 @@ 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 *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(Z_REFVAL(stmt->result_bind[i].zv)); + zval_dtor(result); #endif if (!Z_ISNULL_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); } - ZVAL_COPY_VALUE(Z_REFVAL(stmt->result_bind[i].zv), data); + ZVAL_COPY_VALUE(result, data); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1071,22 +1079,26 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f for (i = 0; i < field_count; i++) { if (stmt->result_bind[i].bound == TRUE) { 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(Z_REFVAL(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_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_STRLEN_P(data))) { meta->fields[i].max_length = Z_STRLEN_P(data); } - ZVAL_COPY_VALUE(Z_REFVAL(stmt->result_bind[i].zv), data); + ZVAL_COPY_VALUE(result, data); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1183,8 +1195,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(Z_REFVAL(stmt->result_bind[i].zv)); - ZVAL_NULL(Z_REFVAL(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; @@ -1503,7 +1517,7 @@ 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 */ zval_ptr_dtor(&stmt->param_bind[param_no].zv); @@ -1588,6 +1602,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s, for (i = 0; i < stmt->field_count; i++) { /* Prevent from freeing */ 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); /* @@ -2026,7 +2041,7 @@ mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC) which the user has lost reference. */ #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - ZVAL_NULL(stmt->result_bind[i].zv); + ZVAL_NULL(&stmt->result_bind[i].zv); #endif zval_ptr_dtor(&stmt->result_bind[i].zv); } -- cgit v1.2.1 From d632870e4dfe506e21ddd4275351e7244060c942 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 20 Jun 2014 13:27:56 +0800 Subject: Fixed memory leak --- ext/mysqlnd/mysqlnd_ps.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index b638863621..3885733fa2 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -650,7 +650,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC) if (stmt->result_bind[i].bound == TRUE) { zval *result = &stmt->result_bind[i].zv; ZVAL_DEREF(result); - zval_copy_ctor(result); + Z_TRY_ADDREF_P(result); } } } @@ -809,7 +809,7 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int ZVAL_COPY_VALUE(result, ¤t_row[i]); #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - zval_copy_ctor(result); + Z_TRY_ADDREF_P(result); #endif } else { ZVAL_NULL(result); @@ -2031,7 +2031,7 @@ mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC) */ if (Z_REFCOUNTED(stmt->result_bind[i].zv) && Z_REFCOUNT(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); + Z_TRY_ADDREF_P(&stmt->result_bind[i].zv); #endif zval_ptr_dtor(&stmt->result_bind[i].zv); } else { @@ -2041,7 +2041,7 @@ mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC) which the user has lost reference. */ #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - ZVAL_NULL(&stmt->result_bind[i].zv); + //??? ZVAL_NULL(&stmt->result_bind[i].zv); #endif zval_ptr_dtor(&stmt->result_bind[i].zv); } @@ -2086,7 +2086,7 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param */ if (Z_REFCOUNTED(stmt->result_bind[param_no].zv) && Z_REFCOUNT(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); + Z_TRY_ADDREF_P(&stmt->result_bind[param_no].zv); #endif zval_ptr_dtor(&stmt->result_bind[param_no].zv); } else { @@ -2096,7 +2096,7 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param 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); + //???ZVAL_NULL(&stmt->result_bind[param_no].zv); #endif zval_ptr_dtor(&stmt->result_bind[param_no].zv); } -- cgit v1.2.1 From 587923ccc837fc22901f3114631bcc3b1b384fcd Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Mon, 23 Jun 2014 23:01:35 +0800 Subject: Cleanup (refactoring is finish) --- ext/mysqlnd/mysqlnd_ps.c | 44 +++----------------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 3885733fa2..adb9578fc8 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -776,7 +776,6 @@ 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(current_row[i]) >= IS_STRING) { if (Z_TYPE(current_row[i]) == IS_STRING) { unsigned long len = Z_STRLEN(current_row[i]); if (meta->fields[i].max_length < len) { @@ -2025,28 +2024,10 @@ mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC) if (stmt->result_bind[i].bound == TRUE) { DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0); - /* - We have to separate the actual zval value of the bound - variable from our allocated zvals or we will face double-free - */ - if (Z_REFCOUNTED(stmt->result_bind[i].zv) && Z_REFCOUNT(stmt->result_bind[i].zv) > 1) { -#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - Z_TRY_ADDREF_P(&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); - } + zval_ptr_dtor(&stmt->result_bind[i].zv); } } + s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC); stmt->result_bind = NULL; @@ -2080,26 +2061,7 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param 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); - /* - We have to separate the actual zval value of the bound - variable from our allocated zvals or we will face double-free - */ - if (Z_REFCOUNTED(stmt->result_bind[param_no].zv) && Z_REFCOUNT(stmt->result_bind[param_no].zv) > 1) { -#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF - Z_TRY_ADDREF_P(&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); - } + zval_ptr_dtor(&stmt->result_bind[param_no].zv); } DBG_VOID_RETURN; -- cgit v1.2.1 From 547451796cbd59c236a08429c93a48f184421bac Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Wed, 6 Aug 2014 14:52:12 +0300 Subject: Fix handling of multi-result sets with PS...used to clean not only the result set but the whole PS. --- ext/mysqlnd/mysqlnd_ps.c | 51 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 17 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 23a0f8a687..bdc46bdb06 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -50,6 +50,7 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, 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); +static void MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(MYSQLND_STMT * const s TSRMLS_DC); /* {{{ mysqlnd_stmt::store_result */ static MYSQLND_RES * @@ -226,7 +227,7 @@ MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC) DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS); /* Free space for next result */ - s->m->free_stmt_content(s TSRMLS_CC); + MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(s TSRMLS_CC); { enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC); DBG_RETURN(ret); @@ -2076,6 +2077,37 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param /* }}} */ +/* {{{ mysqlnd_stmt::free_stmt_result */ +static void +MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(MYSQLND_STMT * const s TSRMLS_DC) +{ + MYSQLND_STMT_DATA * stmt = s? s->data:NULL; + DBG_ENTER("mysqlnd_stmt::free_stmt_result"); + if (!stmt) { + DBG_VOID_RETURN; + } + + /* + First separate the bound variables, which point to the result set, then + destroy the set. + */ + 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); + stmt->result = NULL; + } + if (stmt->error_info->error_list) { + zend_llist_clean(stmt->error_info->error_list); + mnd_pefree(stmt->error_info->error_list, s->persistent); + stmt->error_info->error_list = NULL; + } + + DBG_VOID_RETURN; +} +/* }}} */ + + /* {{{ mysqlnd_stmt::free_stmt_content */ static void MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC) @@ -2108,22 +2140,7 @@ MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC stmt->param_bind = NULL; } - /* - First separate the bound variables, which point to the result set, then - destroy the set. - */ - 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); - stmt->result = NULL; - } - if (stmt->error_info->error_list) { - zend_llist_clean(stmt->error_info->error_list); - mnd_pefree(stmt->error_info->error_list, s->persistent); - stmt->error_info->error_list = NULL; - } - + MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(s TSRMLS_CC); DBG_VOID_RETURN; } /* }}} */ -- cgit v1.2.1 From 9959ead30942e7b1d016b7ce1e428e7f5dc167ee Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Wed, 6 Aug 2014 16:50:27 +0300 Subject: Use callback structure --- ext/mysqlnd/mysqlnd_ps.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 1fc5e33a8c..4588165f05 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -42,8 +42,6 @@ enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, z 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); -static void MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(MYSQLND_STMT * const s TSRMLS_DC); - /* {{{ mysqlnd_stmt::store_result */ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) @@ -246,7 +244,7 @@ MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC) DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS); /* Free space for next result */ - MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(s TSRMLS_CC); + s->m->free_stmt_result(s TSRMLS_CC); { enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC); DBG_RETURN(ret); @@ -2154,7 +2152,7 @@ MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC stmt->param_bind = NULL; } - MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(s TSRMLS_CC); + s->m->free_stmt_result(s TSRMLS_CC); DBG_VOID_RETURN; } /* }}} */ @@ -2373,7 +2371,8 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_stmt) mysqlnd_stmt_execute_generate_request, mysqlnd_stmt_execute_parse_response, MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content), - MYSQLND_METHOD(mysqlnd_stmt, flush) + MYSQLND_METHOD(mysqlnd_stmt, flush), + MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result) MYSQLND_CLASS_METHODS_END; -- cgit v1.2.1 From 63d3f0b844b3a5f1c94be3c97bca29235dc2b3fc Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 19 Aug 2014 08:07:31 +0200 Subject: basic macro replacements, all at once --- ext/mysqlnd/mysqlnd_ps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 986a664410..33c78f1bbe 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -776,7 +776,7 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int Thus for NULL and zero-length we are quite efficient. */ if (Z_TYPE(current_row[i]) == IS_STRING) { - unsigned long len = Z_STRLEN(current_row[i]); + unsigned long len = Z_STRSIZE(current_row[i]); if (meta->fields[i].max_length < len) { meta->fields[i].max_length = len; } @@ -905,8 +905,8 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned i #endif if (!Z_ISNULL_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); + (meta->fields[i].max_length < (unsigned long) Z_STRSIZE_P(data))) { + meta->fields[i].max_length = Z_STRSIZE_P(data); } ZVAL_COPY_VALUE(result, data); /* copied data, thus also the ownership. Thus null data */ @@ -1093,8 +1093,8 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f if (!Z_ISNULL_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); + (meta->fields[i].max_length < (unsigned long) Z_STRSIZE_P(data))) { + meta->fields[i].max_length = Z_STRSIZE_P(data); } ZVAL_COPY_VALUE(result, data); /* copied data, thus also the ownership. Thus null data */ -- cgit v1.2.1 From bdbf47df181bdafc1b2bc2df1d23815f01510b88 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 19 Aug 2014 16:51:06 +0200 Subject: ported mysql and mysqlnd --- ext/mysqlnd/mysqlnd_ps.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 33c78f1bbe..6edaa20c60 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -776,7 +776,7 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int Thus for NULL and zero-length we are quite efficient. */ if (Z_TYPE(current_row[i]) == IS_STRING) { - unsigned long len = Z_STRSIZE(current_row[i]); + php_uint_t len = Z_STRSIZE(current_row[i]); if (meta->fields[i].max_length < len) { meta->fields[i].max_length = len; } @@ -1302,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; @@ -1927,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); -- cgit v1.2.1 From eb1871b3fb63f48216f20663f0cc479d322e3970 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 21 Aug 2014 09:54:40 +0200 Subject: yet trivial fixes to mysql exts --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 6edaa20c60..c47da0262a 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -1879,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); -- cgit v1.2.1 From c3e3c98ec666812daaaca896cf5ef758a8a6df14 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 25 Aug 2014 19:24:55 +0200 Subject: master renames phase 1 --- ext/mysqlnd/mysqlnd_ps.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index c47da0262a..e2745d8729 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -776,7 +776,7 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int Thus for NULL and zero-length we are quite efficient. */ if (Z_TYPE(current_row[i]) == IS_STRING) { - php_uint_t len = Z_STRSIZE(current_row[i]); + zend_ulong len = Z_STRLEN(current_row[i]); if (meta->fields[i].max_length < len) { meta->fields[i].max_length = len; } @@ -905,8 +905,8 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned i #endif 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); + (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) { + meta->fields[i].max_length = Z_STRLEN_P(data); } ZVAL_COPY_VALUE(result, data); /* copied data, thus also the ownership. Thus null data */ @@ -1093,8 +1093,8 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f 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); + (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) { + meta->fields[i].max_length = Z_STRLEN_P(data); } ZVAL_COPY_VALUE(result, data); /* copied data, thus also the ownership. Thus null data */ @@ -1302,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, php_uint_t length TSRMLS_DC) + const char * const data, zend_ulong length TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; enum_func_status ret = FAIL; @@ -1879,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 > (php_uint_t) CURSOR_TYPE_READ_ONLY) { + if (ival > (zend_ulong) CURSOR_TYPE_READ_ONLY) { SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented"); DBG_INF("FAIL"); DBG_RETURN(FAIL); @@ -1927,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: - *(php_uint_t *) value= stmt->flags; + *(zend_ulong *) value= stmt->flags; break; case STMT_ATTR_PREFETCH_ROWS: - *(php_uint_t *) value= stmt->prefetch_rows; + *(zend_ulong *) value= stmt->prefetch_rows; break; default: DBG_RETURN(FAIL); -- cgit v1.2.1 From fee39d0868e416d80b4cf3f3c206d3c43c02ef6a Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 2 Sep 2014 15:54:16 +0200 Subject: fix type --- ext/mysqlnd/mysqlnd_ps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index e2745d8729..458ce47ff6 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -905,7 +905,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned i #endif if (!Z_ISNULL_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 < (zend_ulong) Z_STRLEN_P(data))) { meta->fields[i].max_length = Z_STRLEN_P(data); } ZVAL_COPY_VALUE(result, data); @@ -1093,7 +1093,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f if (!Z_ISNULL_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 < (zend_ulong) Z_STRLEN_P(data))) { meta->fields[i].max_length = Z_STRLEN_P(data); } ZVAL_COPY_VALUE(result, data); -- cgit v1.2.1 From 99fb5d0ea87866f9ef13a2e8840007004332c936 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 11 Sep 2014 13:12:54 +0200 Subject: remove extra semicolon --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 458ce47ff6..d87bbc9793 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -115,7 +115,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) 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; -- cgit v1.2.1 From d0cb715373c3fbe9dc095378ec5ed8c71f799f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Schl=C3=BCter?= Date: Fri, 19 Sep 2014 18:33:14 +0200 Subject: s/PHP 5/PHP 7/ --- ext/mysqlnd/mysqlnd_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mysqlnd/mysqlnd_ps.c') diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index d87bbc9793..1b2602e6b6 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 2006-2014 The PHP Group | +----------------------------------------------------------------------+ -- cgit v1.2.1