summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_result.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2014-04-17 11:11:51 +0200
committerOndřej Surý <ondrej@sury.org>2014-04-17 11:11:51 +0200
commit9566c3fcaf4cfaa866ea395ee5d1a480785fef0d (patch)
treed053b8b66afe080ea2250d5fbcdfc21c243d54ab /ext/mysqlnd/mysqlnd_result.c
parent30bdcf2392ef8cc7b8b4a07b49367571ae1db286 (diff)
downloadphp-9566c3fcaf4cfaa866ea395ee5d1a480785fef0d.tar.gz
New upstream version 5.6.0~beta1+dfsgupstream/5.6.0_beta1+dfsg
Diffstat (limited to 'ext/mysqlnd/mysqlnd_result.c')
-rw-r--r--ext/mysqlnd/mysqlnd_result.c770
1 files changed, 464 insertions, 306 deletions
diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
index a4fb9f6cf..fc6f48581 100644
--- a/ext/mysqlnd/mysqlnd_result.c
+++ b/ext/mysqlnd/mysqlnd_result.c
@@ -33,36 +33,37 @@
#define MYSQLND_SILENT
-/* {{{ mysqlnd_res::initialize_result_set_rest */
+/* {{{ mysqlnd_result_buffered::initialize_result_set_rest */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered, initialize_result_set_rest)(MYSQLND_RES_BUFFERED * const result, MYSQLND_RES_METADATA * const meta,
+ MYSQLND_STATS * stats, zend_bool int_and_float_native TSRMLS_DC)
{
unsigned int i;
- zval **data_cursor = result->stored_data? result->stored_data->data:NULL;
- zval **data_begin = result->stored_data? result->stored_data->data:NULL;
- unsigned int field_count = result->meta? result->meta->field_count : 0;
- uint64_t row_count = result->stored_data? result->stored_data->row_count:0;
+ zval **data_cursor = result->data;
+ zval **data_begin = result->data;
+ unsigned int field_count = meta->field_count;
+ uint64_t row_count = result->row_count;
enum_func_status ret = PASS;
- DBG_ENTER("mysqlnd_res::initialize_result_set_rest");
+ DBG_ENTER("mysqlnd_result_buffered::initialize_result_set_rest");
- if (!data_cursor || row_count == result->stored_data->initialized_rows) {
+ if (!data_cursor || row_count == result->initialized_rows) {
DBG_RETURN(ret);
}
while ((data_cursor - data_begin) < (int)(row_count * field_count)) {
if (NULL == data_cursor[0]) {
enum_func_status rc = result->m.row_decoder(
- result->stored_data->row_buffers[(data_cursor - data_begin) / field_count],
+ result->row_buffers[(data_cursor - data_begin) / field_count],
data_cursor,
- result->meta->field_count,
- result->meta->fields,
- result->conn->options->int_and_float_native,
- result->conn->stats TSRMLS_CC);
+ meta->field_count,
+ meta->fields,
+ int_and_float_native,
+ stats TSRMLS_CC);
if (rc != PASS) {
ret = FAIL;
break;
}
- result->stored_data->initialized_rows++;
- for (i = 0; i < result->field_count; i++) {
+ result->initialized_rows++;
+ for (i = 0; i < meta->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.
@@ -70,8 +71,8 @@ MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const resu
*/
if (Z_TYPE_P(data_cursor[i]) >= IS_STRING) {
unsigned long len = Z_STRLEN_P(data_cursor[i]);
- if (result->meta->fields[i].max_length < len) {
- result->meta->fields[i].max_length = len;
+ if (meta->fields[i].max_length < len) {
+ meta->fields[i].max_length = len;
}
}
}
@@ -88,6 +89,7 @@ static void
mysqlnd_rset_zval_ptr_dtor(zval **zv, enum_mysqlnd_res_type type, zend_bool * copy_ctor_called TSRMLS_DC)
{
DBG_ENTER("mysqlnd_rset_zval_ptr_dtor");
+ DBG_INF_FMT("type=%u", type);
if (!zv || !*zv) {
*copy_ctor_called = FALSE;
DBG_ERR_FMT("zv was NULL");
@@ -121,42 +123,42 @@ mysqlnd_rset_zval_ptr_dtor(zval **zv, enum_mysqlnd_res_type type, zend_bool * co
ZVAL_NULL(*zv);
}
}
+ DBG_INF_FMT("call the dtor on zval with refc %u", Z_REFCOUNT_PP(zv));
zval_ptr_dtor(zv);
DBG_VOID_RETURN;
}
/* }}} */
-/* {{{ mysqlnd_res::unbuffered_free_last_data */
+/* {{{ mysqlnd_result_unbuffered::free_last_data */
static void
-MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data)(MYSQLND_RES * result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_unbuffered, free_last_data)(MYSQLND_RES_UNBUFFERED * unbuf, MYSQLND_STATS * const global_stats TSRMLS_DC)
{
- MYSQLND_RES_UNBUFFERED *unbuf = result->unbuf;
-
DBG_ENTER("mysqlnd_res::unbuffered_free_last_data");
if (!unbuf) {
DBG_VOID_RETURN;
}
+ DBG_INF_FMT("field_count=%u", unbuf->field_count);
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;
- for (i = 0; i < result->field_count; i++) {
- mysqlnd_rset_zval_ptr_dtor(&(unbuf->last_row_data[i]), result->type, &copy_ctor_called TSRMLS_CC);
+ for (i = 0; i < unbuf->field_count; i++) {
+ mysqlnd_rset_zval_ptr_dtor(&(unbuf->last_row_data[i]), unbuf->ps ? MYSQLND_RES_PS_UNBUF : MYSQLND_RES_NORMAL, &copy_ctor_called TSRMLS_CC);
if (copy_ctor_called) {
++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_VALUE2(global_stats,
STAT_COPY_ON_WRITE_PERFORMED,
ctor_called_count,
STAT_COPY_ON_WRITE_SAVED,
- result->field_count - ctor_called_count);
+ unbuf->field_count - ctor_called_count);
/* Free last row's zvals */
mnd_efree(unbuf->last_row_data);
unbuf->last_row_data = NULL;
@@ -173,12 +175,41 @@ MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data)(MYSQLND_RES * result TSRM
/* }}} */
-/* {{{ mysqlnd_res::free_buffered_data */
+/* {{{ mysqlnd_result_unbuffered::free_result */
static void
-MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)(MYSQLND_RES_UNBUFFERED * const result, MYSQLND_STATS * const global_stats TSRMLS_DC)
{
- MYSQLND_RES_BUFFERED *set = result->stored_data;
- unsigned int field_count = result->field_count;
+ DBG_ENTER("mysqlnd_result_unbuffered, free_result");
+ result->m.free_last_data(result, global_stats TSRMLS_CC);
+
+ if (result->lengths) {
+ mnd_pefree(result->lengths, result->persistent);
+ result->lengths = NULL;
+ }
+
+ /* must be free before because references the memory pool */
+ if (result->row_packet) {
+ PACKET_FREE(result->row_packet);
+ result->row_packet = NULL;
+ }
+
+ if (result->result_set_memory_pool) {
+ mysqlnd_mempool_destroy(result->result_set_memory_pool TSRMLS_CC);
+ result->result_set_memory_pool = NULL;
+ }
+
+
+ mnd_pefree(result, result->persistent);
+ DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered::free_result */
+static void
+MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * const set TSRMLS_DC)
+{
+ unsigned int field_count = set->field_count;
int64_t row;
DBG_ENTER("mysqlnd_res::free_buffered_data");
@@ -199,7 +230,7 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC)
for (col = field_count - 1; col >= 0; --col) {
if (current_row[col]) {
zend_bool copy_ctor_called;
- mysqlnd_rset_zval_ptr_dtor(&(current_row[col]), result->type, &copy_ctor_called TSRMLS_CC);
+ mysqlnd_rset_zval_ptr_dtor(&(current_row[col]), set->ps? MYSQLND_RES_PS_BUF : MYSQLND_RES_NORMAL, &copy_ctor_called TSRMLS_CC);
if (copy_ctor_called) {
++copy_on_write_performed;
} else {
@@ -216,14 +247,26 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC)
mnd_efree(data);
}
+ if (set->lengths) {
+ mnd_pefree(set->lengths, set->persistent);
+ set->lengths = NULL;
+ }
+
if (set->row_buffers) {
mnd_efree(set->row_buffers);
set->row_buffers = NULL;
}
+
+ if (set->result_set_memory_pool) {
+ mysqlnd_mempool_destroy(set->result_set_memory_pool TSRMLS_CC);
+ set->result_set_memory_pool = NULL;
+ }
+
+
set->data_cursor = NULL;
set->row_count = 0;
- mnd_efree(set);
+ mnd_pefree(set, set->persistent);
DBG_VOID_RETURN;
}
@@ -238,39 +281,24 @@ MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES * result TSRMLS_DC)
DBG_INF_FMT("%s", result->unbuf? "unbuffered":(result->stored_data? "buffered":"unknown"));
if (result->unbuf) {
- result->m.unbuffered_free_last_data(result TSRMLS_CC);
- mnd_efree(result->unbuf);
+ result->unbuf->m.free_result(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC);
result->unbuf = NULL;
} else if (result->stored_data) {
- result->m.free_buffered_data(result TSRMLS_CC);
+ result->stored_data->m.free_result(result->stored_data TSRMLS_CC);
result->stored_data = NULL;
}
- if (result->lengths) {
- mnd_efree(result->lengths);
- result->lengths = NULL;
- }
-
- if (result->row_packet) {
- PACKET_FREE(result->row_packet);
- result->row_packet = NULL;
- }
-
- if (result->result_set_memory_pool) {
- mysqlnd_mempool_destroy(result->result_set_memory_pool TSRMLS_CC);
- result->result_set_memory_pool = NULL;
- }
DBG_VOID_RETURN;
}
/* }}} */
-/* {{{ mysqlnd_internal_free_result_contents */
+/* {{{ mysqlnd_res::free_result_contents_internal */
static
-void mysqlnd_internal_free_result_contents(MYSQLND_RES * result TSRMLS_DC)
+void MYSQLND_METHOD(mysqlnd_res, free_result_contents_internal)(MYSQLND_RES * result TSRMLS_DC)
{
- DBG_ENTER("mysqlnd_internal_free_result_contents");
+ DBG_ENTER("mysqlnd_res::free_result_contents_internal");
result->m.free_result_buffers(result TSRMLS_CC);
@@ -284,11 +312,13 @@ void mysqlnd_internal_free_result_contents(MYSQLND_RES * result TSRMLS_DC)
/* }}} */
-/* {{{ mysqlnd_internal_free_result */
+/* {{{ mysqlnd_res::free_result_internal */
static
-void mysqlnd_internal_free_result(MYSQLND_RES * result TSRMLS_DC)
+void MYSQLND_METHOD(mysqlnd_res, free_result_internal)(MYSQLND_RES * result TSRMLS_DC)
{
- DBG_ENTER("mysqlnd_internal_free_result");
+ DBG_ENTER("mysqlnd_res::free_result_internal");
+ result->m.skip_result(result TSRMLS_CC);
+
result->m.free_result_contents(result TSRMLS_CC);
if (result->conn) {
@@ -552,7 +582,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s
/* }}} */
-/* {{{ mysqlnd_fetch_lengths_buffered */
+/* {{{ mysqlnd_result_buffered::fetch_lengths */
/*
Do lazy initialization for buffered results. As PHP strings have
length inside, this function makes not much sense in the context
@@ -560,11 +590,11 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s
completeness.
*/
static unsigned long *
-mysqlnd_fetch_lengths_buffered(MYSQLND_RES * const result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered, fetch_lengths)(MYSQLND_RES_BUFFERED * const result TSRMLS_DC)
{
unsigned int i;
zval **previous_row;
- MYSQLND_RES_BUFFERED *set = result->stored_data;
+ MYSQLND_RES_BUFFERED *set = result;
/*
If:
@@ -574,13 +604,13 @@ mysqlnd_fetch_lengths_buffered(MYSQLND_RES * const result TSRMLS_DC)
*/
if (set->data_cursor == NULL ||
set->data_cursor == set->data ||
- ((set->data_cursor - set->data) > (set->row_count * result->meta->field_count) ))
+ ((set->data_cursor - set->data) > (set->row_count * result->field_count) ))
{
return NULL;/* No rows or no more rows */
}
- previous_row = set->data_cursor - result->meta->field_count;
- for (i = 0; i < result->meta->field_count; i++) {
+ previous_row = set->data_cursor - result->field_count;
+ for (i = 0; i < result->field_count; i++) {
result->lengths[i] = (Z_TYPE_P(previous_row[i]) == IS_NULL)? 0:Z_STRLEN_P(previous_row[i]);
}
@@ -589,49 +619,56 @@ mysqlnd_fetch_lengths_buffered(MYSQLND_RES * const result TSRMLS_DC)
/* }}} */
-/* {{{ mysqlnd_fetch_lengths_unbuffered */
+/* {{{ mysqlnd_result_unbuffered::fetch_lengths */
static unsigned long *
-mysqlnd_fetch_lengths_unbuffered(MYSQLND_RES * const result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_lengths)(MYSQLND_RES_UNBUFFERED * const result TSRMLS_DC)
{
/* simulate output of libmysql */
- return (!result->unbuf || result->unbuf->last_row_data || result->unbuf->eof_reached)? result->lengths:NULL;
+ return (result->last_row_data || result->eof_reached)? result->lengths : NULL;
}
/* }}} */
/* {{{ mysqlnd_res::fetch_lengths */
-PHPAPI unsigned long * _mysqlnd_fetch_lengths(MYSQLND_RES * const result TSRMLS_DC)
+static unsigned long *
+MYSQLND_METHOD(mysqlnd_res, fetch_lengths)(MYSQLND_RES * const result TSRMLS_DC)
{
- return result->m.fetch_lengths? result->m.fetch_lengths(result TSRMLS_CC) : NULL;
+ unsigned long * ret;
+ DBG_ENTER("mysqlnd_res::fetch_lengths");
+ ret = result->stored_data && result->stored_data->m.fetch_lengths ?
+ result->stored_data->m.fetch_lengths(result->stored_data TSRMLS_CC) :
+ (result->unbuf && result->unbuf->m.fetch_lengths ?
+ result->unbuf->m.fetch_lengths(result->unbuf TSRMLS_CC) :
+ NULL
+ );
+ DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_fetch_row_unbuffered_c */
-static MYSQLND_ROW_C
-mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
+/* {{{ mysqlnd_result_unbuffered::fetch_row_c */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
enum_func_status ret;
- MYSQLND_ROW_C retrow = NULL;
- unsigned int i,
- field_count = result->field_count;
- MYSQLND_PACKET_ROW *row_packet = result->row_packet;
- unsigned long *lengths = result->lengths;
+ MYSQLND_ROW_C *row = (MYSQLND_ROW_C *) param;
+ MYSQLND_PACKET_ROW *row_packet = result->unbuf->row_packet;
+ const MYSQLND_RES_METADATA * const meta = result->meta;
- DBG_ENTER("mysqlnd_fetch_row_unbuffered_c");
+ DBG_ENTER("mysqlnd_result_unbuffered::fetch_row_c");
+ *fetched_anything = FALSE;
if (result->unbuf->eof_reached) {
/* No more rows obviously */
- DBG_RETURN(retrow);
+ DBG_RETURN(PASS);
}
if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) {
- SET_CLIENT_ERROR(*result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
- UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- DBG_RETURN(retrow);
+ SET_CLIENT_ERROR(*result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
+ DBG_RETURN(FAIL);
}
if (!row_packet) {
/* Not fully initialized object that is being cleaned up */
- DBG_RETURN(retrow);
+ DBG_RETURN(FAIL);
}
/* Let the row packet fill our buffer and skip additional mnd_malloc + memcpy */
row_packet->skip_extraction = FALSE;
@@ -641,9 +678,7 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
result->m.unbuffered_free_last_data() before it. The function returns always true.
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
- result->unbuf->row_count++;
-
- 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;
@@ -653,46 +688,51 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
MYSQLND_INC_CONN_STATISTIC(result->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF);
if (!row_packet->skip_extraction) {
- MYSQLND_FIELD *field = result->meta->fields;
- struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys;
-
- enum_func_status rc = result->m.row_decoder(result->unbuf->last_row_buffer,
- result->unbuf->last_row_data,
- row_packet->field_count,
- row_packet->fields_metadata,
- result->conn->options->int_and_float_native,
- result->conn->stats TSRMLS_CC);
+ unsigned int i, field_count = meta->field_count;
+
+ enum_func_status rc = result->unbuf->m.row_decoder(result->unbuf->last_row_buffer,
+ result->unbuf->last_row_data,
+ field_count,
+ row_packet->fields_metadata,
+ result->conn->options->int_and_float_native,
+ result->conn->stats TSRMLS_CC);
if (PASS != rc) {
- DBG_RETURN(retrow);
+ DBG_RETURN(FAIL);
}
+ {
+ *row = mnd_malloc(field_count * sizeof(char *));
+ if (*row) {
+ MYSQLND_FIELD * field = meta->fields;
+ unsigned long * lengths = result->unbuf->lengths;
+
+ for (i = 0; i < field_count; i++, field++) {
+ zval * data = result->unbuf->last_row_data[i];
+ unsigned int len = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
+
+/* BEGIN difference between normal normal fetch and _c */
+ if (Z_TYPE_P(data) != IS_NULL) {
+ convert_to_string(data);
+ (*row)[i] = Z_STRVAL_P(data);
+ } else {
+ (*row)[i] = NULL;
+ }
+/* END difference between normal normal fetch and _c */
- retrow = mnd_malloc(result->field_count * sizeof(char *));
- if (retrow) {
- for (i = 0; i < field_count; i++, field++, hash_key++) {
- zval *data = result->unbuf->last_row_data[i];
- unsigned int len;
-
- if (Z_TYPE_P(data) != IS_NULL) {
- convert_to_string(data);
- retrow[i] = Z_STRVAL_P(data);
- len = Z_STRLEN_P(data);
- } else {
- retrow[i] = NULL;
- len = 0;
- }
-
- if (lengths) {
- lengths[i] = len;
- }
+ if (lengths) {
+ lengths[i] = len;
+ }
- if (field->max_length < len) {
- field->max_length = len;
+ if (field->max_length < len) {
+ field->max_length = len;
+ }
}
+ } else {
+ SET_OOM_ERROR(*result->conn->error_info);
}
- } else {
- SET_OOM_ERROR(*result->conn->error_info);
}
}
+ result->unbuf->row_count++;
+ *fetched_anything = TRUE;
} else if (ret == FAIL) {
if (row_packet->error_info.error_no) {
COPY_CLIENT_ERROR(*result->conn->error_info, row_packet->error_info);
@@ -716,23 +756,25 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
} else {
CONN_SET_STATE(result->conn, CONN_READY);
}
- 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);
}
- DBG_RETURN(retrow);
+ DBG_INF_FMT("ret=%s fetched=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
+ DBG_RETURN(PASS);
}
/* }}} */
-/* {{{ mysqlnd_fetch_row_unbuffered */
+/* {{{ mysqlnd_result_unbuffered::fetch_row */
static enum_func_status
-mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
enum_func_status ret;
zval *row = (zval *) param;
- MYSQLND_PACKET_ROW *row_packet = result->row_packet;
+ MYSQLND_PACKET_ROW *row_packet = result->unbuf->row_packet;
+ const MYSQLND_RES_METADATA * const meta = result->meta;
- DBG_ENTER("mysqlnd_fetch_row_unbuffered");
+ DBG_ENTER("mysqlnd_result_unbuffered::fetch_row");
*fetched_anything = FALSE;
if (result->unbuf->eof_reached) {
@@ -755,7 +797,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
result->m.unbuffered_free_last_data() before it. The function returns always true.
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
- 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;
@@ -765,13 +807,9 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
MYSQLND_INC_CONN_STATISTIC(result->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF);
if (!row_packet->skip_extraction) {
- HashTable *row_ht = Z_ARRVAL_P(row);
- MYSQLND_FIELD *field = result->meta->fields;
- struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys;
- unsigned int i, field_count = result->field_count;
- unsigned long *lengths = result->lengths;
+ unsigned int i, field_count = meta->field_count;
- enum_func_status rc = result->m.row_decoder(result->unbuf->last_row_buffer,
+ enum_func_status rc = result->unbuf->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
field_count,
row_packet->fields_metadata,
@@ -780,46 +818,51 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
if (PASS != rc) {
DBG_RETURN(FAIL);
}
- for (i = 0; i < field_count; i++, field++, hash_key++) {
- zval *data = result->unbuf->last_row_data[i];
- unsigned int len = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
+ {
+ HashTable * row_ht = Z_ARRVAL_P(row);
+ MYSQLND_FIELD * field = meta->fields;
+ unsigned long * lengths = result->unbuf->lengths;
+
+ for (i = 0; i < field_count; i++, field++) {
+ zval * data = result->unbuf->last_row_data[i];
+ unsigned int len = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
+
+ if (flags & MYSQLND_FETCH_NUM) {
+ Z_ADDREF_P(data);
+ zend_hash_next_index_insert(row_ht, &data, sizeof(zval *), NULL);
+ }
+ if (flags & MYSQLND_FETCH_ASSOC) {
+ /* zend_hash_quick_update needs length + trailing zero */
+ /* QQ: Error handling ? */
+ /*
+ zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether
+ the index is a numeric and convert it to it. This however means constant
+ hashing of the column name, which is not needed as it can be precomputed.
+ */
+ Z_ADDREF_P(data);
+ if (meta->zend_hash_keys[i].is_numeric == FALSE) {
+ zend_hash_quick_update(Z_ARRVAL_P(row),
+ field->name,
+ field->name_length + 1,
+ meta->zend_hash_keys[i].key,
+ (void *) &data, sizeof(zval *), NULL);
+ } else {
+ zend_hash_index_update(Z_ARRVAL_P(row), meta->zend_hash_keys[i].key, (void *) &data, sizeof(zval *), NULL);
+ }
+ }
- if (lengths) {
- lengths[i] = len;
- }
+ if (lengths) {
+ lengths[i] = len;
+ }
- if (flags & MYSQLND_FETCH_NUM) {
- Z_ADDREF_P(data);
- zend_hash_next_index_insert(row_ht, &data, sizeof(zval *), NULL);
- }
- if (flags & MYSQLND_FETCH_ASSOC) {
- /* zend_hash_quick_update needs length + trailing zero */
- /* QQ: Error handling ? */
- /*
- zend_hash_quick_update does not check, as add_assoc_zval_ex do, whether
- the index is a numeric and convert it to it. This however means constant
- hashing of the column name, which is not needed as it can be precomputed.
- */
- Z_ADDREF_P(data);
- if (hash_key->is_numeric == FALSE) {
- zend_hash_quick_update(Z_ARRVAL_P(row),
- field->name,
- field->name_length + 1,
- hash_key->key,
- (void *) &data, sizeof(zval *), NULL);
- } else {
- zend_hash_index_update(Z_ARRVAL_P(row),
- hash_key->key,
- (void *) &data, sizeof(zval *), NULL);
+ if (field->max_length < len) {
+ field->max_length = len;
}
}
- if (field->max_length < len) {
- field->max_length = len;
- }
}
}
- *fetched_anything = TRUE;
result->unbuf->row_count++;
+ *fetched_anything = TRUE;
} else if (ret == FAIL) {
if (row_packet->error_info.error_no) {
COPY_CLIENT_ERROR(*result->conn->error_info, row_packet->error_info);
@@ -843,7 +886,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
} else {
CONN_SET_STATE(result->conn, CONN_READY);
}
- 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);
}
DBG_INF_FMT("ret=%s fetched=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
@@ -862,44 +905,31 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
if (ps == FALSE) {
result->type = MYSQLND_RES_NORMAL;
- result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
- result->m.fetch_lengths = mysqlnd_fetch_lengths_unbuffered;
- result->m.row_decoder = php_mysqlnd_rowp_read_text_protocol;
- result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
- if (!result->lengths) {
- goto oom;
- }
} else {
result->type = MYSQLND_RES_PS_UNBUF;
- result->m.fetch_row = NULL;
- /* result->m.fetch_row() will be set in mysqlnd_ps.c */
- result->m.fetch_lengths = NULL; /* makes no sense */
- result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
- result->lengths = NULL;
}
- result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
- result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
- if (!result->result_set_memory_pool || !result->unbuf) {
+ result->unbuf = mysqlnd_result_unbuffered_init(result->field_count, ps, result->persistent TSRMLS_CC);
+ if (!result->unbuf) {
goto oom;
}
/*
Will be freed in the mysqlnd_internal_free_result_contents() called
- by the resource destructor. mysqlnd_fetch_row_unbuffered() expects
+ by the resource destructor. mysqlnd_result_unbuffered::fetch_row() expects
this to be not NULL.
*/
/* FALSE = non-persistent */
- result->row_packet = result->conn->protocol->m.get_row_packet(result->conn->protocol, FALSE TSRMLS_CC);
- if (!result->row_packet) {
+ result->unbuf->row_packet = result->conn->protocol->m.get_row_packet(result->conn->protocol, FALSE TSRMLS_CC);
+ if (!result->unbuf->row_packet) {
goto oom;
}
- result->row_packet->result_set_memory_pool = result->result_set_memory_pool;
- result->row_packet->field_count = result->field_count;
- result->row_packet->binary_protocol = ps;
- result->row_packet->fields_metadata = result->meta->fields;
- result->row_packet->bit_fields_count = result->meta->bit_fields_count;
- result->row_packet->bit_fields_total_len = result->meta->bit_fields_total_len;
+ result->unbuf->row_packet->result_set_memory_pool = result->unbuf->result_set_memory_pool;
+ result->unbuf->row_packet->field_count = result->field_count;
+ result->unbuf->row_packet->binary_protocol = ps;
+ result->unbuf->row_packet->fields_metadata = result->meta->fields;
+ result->unbuf->row_packet->bit_fields_count = result->meta->bit_fields_count;
+ result->unbuf->row_packet->bit_fields_total_len = result->meta->bit_fields_total_len;
DBG_RETURN(result);
oom:
@@ -909,37 +939,39 @@ oom:
/* }}} */
-/* {{{ mysqlnd_fetch_row_buffered_c */
-static MYSQLND_ROW_C
-mysqlnd_fetch_row_buffered_c(MYSQLND_RES * result TSRMLS_DC)
+/* {{{ mysqlnd_result_buffered::fetch_row_c */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
- MYSQLND_ROW_C ret = NULL;
- MYSQLND_RES_BUFFERED *set = result->stored_data;
+ MYSQLND_ROW_C * row = (MYSQLND_ROW_C *) param;
+ MYSQLND_RES_BUFFERED * set = result->stored_data;
+ const MYSQLND_RES_METADATA * const meta = result->meta;
+ unsigned int field_count = meta->field_count;
+ enum_func_status ret = FAIL;
- DBG_ENTER("mysqlnd_fetch_row_buffered_c");
+ DBG_ENTER("mysqlnd_result_buffered::fetch_row_c");
/* If we haven't read everything */
if (set->data_cursor &&
- (set->data_cursor - set->data) < (set->row_count * result->meta->field_count))
+ (set->data_cursor - set->data) < (set->row_count * field_count))
{
zval **current_row = set->data_cursor;
- MYSQLND_FIELD *field = result->meta->fields;
- struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys;
+ MYSQLND_FIELD * field = meta->fields;
unsigned int i;
if (NULL == current_row[0]) {
- uint64_t row_num = (set->data_cursor - set->data) / result->meta->field_count;
- enum_func_status rc = result->m.row_decoder(set->row_buffers[row_num],
+ uint64_t row_num = (set->data_cursor - set->data) / field_count;
+ enum_func_status rc = set->m.row_decoder(set->row_buffers[row_num],
current_row,
- result->meta->field_count,
- result->meta->fields,
+ field_count,
+ meta->fields,
result->conn->options->int_and_float_native,
result->conn->stats TSRMLS_CC);
if (rc != PASS) {
- DBG_RETURN(ret);
+ DBG_RETURN(FAIL);
}
set->initialized_rows++;
- for (i = 0; i < result->field_count; i++) {
+ for (i = 0; i < 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.
@@ -954,64 +986,72 @@ mysqlnd_fetch_row_buffered_c(MYSQLND_RES * result TSRMLS_DC)
}
}
- set->data_cursor += result->meta->field_count;
- MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
-
- ret = mnd_malloc(result->field_count * sizeof(char *));
+/* BEGIN difference between normal normal fetch and _c */
+ /* there is no conn handle in this function thus we can't set OOM in error_info */
+ *row = mnd_malloc(field_count * sizeof(char *));
if (ret) {
- for (i = 0; i < result->field_count; i++, field++, hash_key++) {
- zval *data = current_row[i];
+ for (i = 0; i < field_count; i++) {
+ zval * data = current_row[i];
if (Z_TYPE_P(data) != IS_NULL) {
convert_to_string(data);
- ret[i] = Z_STRVAL_P(data);
+ (*row)[i] = Z_STRVAL_P(data);
} else {
- ret[i] = NULL;
+ (*row)[i] = NULL;
}
}
}
- /* there is no conn handle in this function thus we can't set OOM in error_info */
+/* END difference between normal normal fetch and _c */
+
+ set->data_cursor += field_count;
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
+ *fetched_anything = TRUE;
+ ret = PASS;
} else {
set->data_cursor = NULL;
DBG_INF("EOF reached");
+ *fetched_anything = FALSE;
+ ret = PASS;
}
+ DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything);
DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_fetch_row_buffered */
+/* {{{ mysqlnd_result_buffered::fetch_row */
static enum_func_status
-mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
{
- unsigned int i;
- zval *row = (zval *) param;
- MYSQLND_RES_BUFFERED *set = result->stored_data;
+ zval * row = (zval *) param;
+ MYSQLND_RES_BUFFERED * set = result->stored_data;
+ const MYSQLND_RES_METADATA * const meta = result->meta;
+ unsigned int field_count = meta->field_count;
enum_func_status ret = FAIL;
- DBG_ENTER("mysqlnd_fetch_row_buffered");
+ DBG_ENTER("mysqlnd_result_buffered::fetch_row");
/* If we haven't read everything */
if (set->data_cursor &&
- (set->data_cursor - set->data) < (set->row_count * result->meta->field_count))
+ (set->data_cursor - set->data) < (set->row_count * field_count))
{
zval **current_row = set->data_cursor;
- MYSQLND_FIELD *field = result->meta->fields;
- struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys;
+ MYSQLND_FIELD * field = meta->fields;
+ unsigned int i;
if (NULL == current_row[0]) {
- uint64_t row_num = (set->data_cursor - set->data) / result->meta->field_count;
- enum_func_status rc = result->m.row_decoder(set->row_buffers[row_num],
+ uint64_t row_num = (set->data_cursor - set->data) / field_count;
+ enum_func_status rc = set->m.row_decoder(set->row_buffers[row_num],
current_row,
- result->meta->field_count,
- result->meta->fields,
+ field_count,
+ meta->fields,
result->conn->options->int_and_float_native,
result->conn->stats TSRMLS_CC);
if (rc != PASS) {
DBG_RETURN(FAIL);
}
set->initialized_rows++;
- for (i = 0; i < result->field_count; i++) {
+ for (i = 0; i < 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.
@@ -1026,8 +1066,8 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags
}
}
- for (i = 0; i < result->field_count; i++, field++, hash_key++) {
- zval *data = current_row[i];
+ for (i = 0; i < field_count; i++, field++) {
+ zval * data = current_row[i];
if (flags & MYSQLND_FETCH_NUM) {
Z_ADDREF_P(data);
@@ -1042,28 +1082,28 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags
hashing of the column name, which is not needed as it can be precomputed.
*/
Z_ADDREF_P(data);
- if (hash_key->is_numeric == FALSE) {
+ if (meta->zend_hash_keys[i].is_numeric == FALSE) {
zend_hash_quick_update(Z_ARRVAL_P(row),
field->name,
field->name_length + 1,
- hash_key->key,
+ meta->zend_hash_keys[i].key,
(void *) &data, sizeof(zval *), NULL);
} else {
zend_hash_index_update(Z_ARRVAL_P(row),
- hash_key->key,
+ meta->zend_hash_keys[i].key,
(void *) &data, sizeof(zval *), NULL);
}
}
}
- set->data_cursor += result->meta->field_count;
- *fetched_anything = TRUE;
+ set->data_cursor += field_count;
MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
+ *fetched_anything = TRUE;
ret = PASS;
} else {
set->data_cursor = NULL;
+ DBG_INF("EOF reached");
*fetched_anything = FALSE;
ret = PASS;
- DBG_INF("EOF reached");
}
DBG_INF_FMT("ret=PASS fetched=%u", *fetched_anything);
DBG_RETURN(ret);
@@ -1071,24 +1111,38 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags
/* }}} */
+/* {{{ mysqlnd_res::fetch_row */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_res, fetch_row)(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC)
+{
+ const mysqlnd_fetch_row_func f = result->stored_data? result->stored_data->m.fetch_row:(result->unbuf? result->unbuf->m.fetch_row:NULL);
+ if (f) {
+ return f(result, param, flags, fetched_anything TSRMLS_CC);
+ }
+ *fetched_anything = FALSE;
+ return PASS;
+}
+/* }}} */
+
+
#define STORE_RESULT_PREALLOCATED_SET_IF_NOT_EMPTY 2
/* {{{ mysqlnd_res::store_result_fetch_data */
enum_func_status
MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const conn, MYSQLND_RES * result,
- MYSQLND_RES_METADATA *meta,
+ MYSQLND_RES_METADATA * meta,
zend_bool binary_protocol TSRMLS_DC)
{
enum_func_status ret;
- MYSQLND_PACKET_ROW *row_packet = NULL;
+ MYSQLND_PACKET_ROW * row_packet = NULL;
unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET_IF_NOT_EMPTY, free_rows = 1;
MYSQLND_RES_BUFFERED *set;
DBG_ENTER("mysqlnd_res::store_result_fetch_data");
- result->stored_data = set = mnd_ecalloc(1, sizeof(MYSQLND_RES_BUFFERED));
+ set = result->stored_data;
+
if (!set) {
- SET_OOM_ERROR(*conn->error_info);
ret = FAIL;
goto end;
}
@@ -1109,7 +1163,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c
ret = FAIL;
goto end;
}
- row_packet->result_set_memory_pool = result->result_set_memory_pool;
+ row_packet->result_set_memory_pool = result->stored_data->result_set_memory_pool;
row_packet->field_count = meta->field_count;
row_packet->binary_protocol = binary_protocol;
row_packet->fields_metadata = meta->fields;
@@ -1203,31 +1257,26 @@ end:
static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
MYSQLND_CONN_DATA * const conn,
- zend_bool ps_protocol TSRMLS_DC)
+ const unsigned int flags TSRMLS_DC)
{
enum_func_status ret;
DBG_ENTER("mysqlnd_res::store_result");
/* We need the conn because we are doing lazy zval initialization in buffered_fetch_row */
- result->conn = conn->m->get_reference(conn TSRMLS_CC);
- result->type = MYSQLND_RES_NORMAL;
- result->m.fetch_row = result->m.fetch_row_normal_buffered;
- result->m.fetch_lengths = mysqlnd_fetch_lengths_buffered;
- result->m.row_decoder = ps_protocol? php_mysqlnd_rowp_read_binary_protocol:
- php_mysqlnd_rowp_read_text_protocol;
+ /* In case of error the reference will be released in free_result_internal() called indirectly by our caller */
+ result->conn = conn->m->get_reference(conn TSRMLS_CC);
+ result->type = MYSQLND_RES_NORMAL;
- result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
- result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
+ CONN_SET_STATE(conn, CONN_FETCHING_DATA);
- if (!result->result_set_memory_pool || !result->lengths) {
+ result->stored_data = mysqlnd_result_buffered_init(result->field_count, flags & MYSQLND_STORE_PS, result->persistent TSRMLS_CC);
+ if (!result->stored_data) {
SET_OOM_ERROR(*conn->error_info);
DBG_RETURN(NULL);
}
- CONN_SET_STATE(conn, CONN_FETCHING_DATA);
-
- ret = result->m.store_result_fetch_data(conn, result, result->meta, ps_protocol TSRMLS_CC);
+ ret = result->m.store_result_fetch_data(conn, result, result->meta, flags & MYSQLND_STORE_PS TSRMLS_CC);
if (FAIL == ret) {
if (result->stored_data) {
COPY_CLIENT_ERROR(*conn->error_info, result->stored_data->error_info);
@@ -1237,20 +1286,21 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
DBG_RETURN(NULL);
} else {
/* Overflow ? */
+ MYSQLND_RES_METADATA * meta = result->meta;
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) {
+ if (set->row_count * 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 *)));
+ set->data = mnd_emalloc((size_t)(set->row_count * 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 *)));
+ memset(set->data, 0, (size_t)(set->row_count * meta->field_count * sizeof(zval *)));
}
/* Position at the first row */
set->data_cursor = set->data;
@@ -1276,9 +1326,7 @@ MYSQLND_METHOD(mysqlnd_res, skip_result)(MYSQLND_RES * const result TSRMLS_DC)
A PS could be prepared - there is metadata and thus a stmt->result but the
fetch_row function isn't actually set (NULL), thus we have to skip these.
*/
- if (!result->stored_data && result->unbuf &&
- !result->unbuf->eof_reached && result->m.fetch_row)
- {
+ if (result->unbuf && !result->unbuf->eof_reached) {
DBG_INF("skipping result");
/* We have to fetch all data to clean the line */
MYSQLND_INC_CONN_STATISTIC(result->conn->stats,
@@ -1300,7 +1348,6 @@ MYSQLND_METHOD(mysqlnd_res, free_result)(MYSQLND_RES * result, zend_bool implici
{
DBG_ENTER("mysqlnd_res::free_result");
- result->m.skip_result(result TSRMLS_CC);
MYSQLND_INC_CONN_STATISTIC(result->conn? result->conn->stats : NULL,
implicit == TRUE? STAT_FREE_RESULT_IMPLICIT:
STAT_FREE_RESULT_EXPLICIT);
@@ -1313,20 +1360,27 @@ MYSQLND_METHOD(mysqlnd_res, free_result)(MYSQLND_RES * result, zend_bool implici
/* {{{ mysqlnd_res::data_seek */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES * result, uint64_t row TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES * const result, const uint64_t row TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res::data_seek");
DBG_INF_FMT("row=%lu", row);
- if (!result->stored_data) {
- return FAIL;
- }
+ DBG_RETURN(result->stored_data? result->stored_data->m.data_seek(result->stored_data, row TSRMLS_CC) : FAIL);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered::data_seek */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_result_buffered, data_seek)(MYSQLND_RES_BUFFERED * const result, const uint64_t row TSRMLS_DC)
+{
+ DBG_ENTER("mysqlnd_result_buffered::data_seek");
/* libmysql just moves to the end, it does traversing of a linked list */
- if (row >= result->stored_data->row_count) {
- result->stored_data->data_cursor = NULL;
+ if (row >= result->row_count) {
+ result->data_cursor = NULL;
} else {
- result->stored_data->data_cursor = result->stored_data->data + row * result->meta->field_count;
+ result->data_cursor = result->data + row * result->field_count;
}
DBG_RETURN(PASS);
@@ -1334,12 +1388,32 @@ MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES * result, uint64_t row TSRMLS
/* }}} */
+/* {{{ mysqlnd_result_unbuffered::num_rows */
+static uint64_t
+MYSQLND_METHOD(mysqlnd_result_unbuffered, num_rows)(const MYSQLND_RES_UNBUFFERED * const result TSRMLS_DC)
+{
+ /* Be compatible with libmysql. We count row_count, but will return 0 */
+ return result->eof_reached? result->row_count:0;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered::num_rows */
+static uint64_t
+MYSQLND_METHOD(mysqlnd_result_buffered, num_rows)(const MYSQLND_RES_BUFFERED * const result TSRMLS_DC)
+{
+ return result->row_count;
+}
+/* }}} */
+
+
/* {{{ mysqlnd_res::num_rows */
static uint64_t
MYSQLND_METHOD(mysqlnd_res, num_rows)(const MYSQLND_RES * const result TSRMLS_DC)
{
- /* Be compatible with libmysql. We count row_count, but will return 0 */
- return result->stored_data? result->stored_data->row_count:(result->unbuf && result->unbuf->eof_reached? result->unbuf->row_count:0);
+ return result->stored_data?
+ result->stored_data->m.num_rows(result->stored_data TSRMLS_CC) :
+ (result->unbuf? result->unbuf->m.num_rows(result->unbuf TSRMLS_CC) : 0);
}
/* }}} */
@@ -1373,7 +1447,9 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC)
if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) {
DBG_INF_FMT("We have decode the whole result set to be able to satisfy this meta request");
/* we have to initialize the rest to get the updated max length */
- if (PASS != result->m.initialize_result_set_rest(result TSRMLS_CC)) {
+ if (PASS != result->stored_data->m.initialize_result_set_rest(result->stored_data, result->meta, result->conn->stats,
+ result->conn->options->int_and_float_native TSRMLS_CC))
+ {
break;
}
}
@@ -1387,7 +1463,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC)
/* {{{ mysqlnd_res::fetch_field_direct */
static const MYSQLND_FIELD *
-MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result, const MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res::fetch_field_direct");
do {
@@ -1405,7 +1481,9 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result, MYSQ
if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) {
DBG_INF_FMT("We have decode the whole result set to be able to satisfy this meta request");
/* we have to initialized the rest to get the updated max length */
- if (PASS != result->m.initialize_result_set_rest(result TSRMLS_CC)) {
+ if (PASS != result->stored_data->m.initialize_result_set_rest(result->stored_data, result->meta, result->conn->stats,
+ result->conn->options->int_and_float_native TSRMLS_CC))
+ {
break;
}
}
@@ -1427,7 +1505,9 @@ MYSQLND_METHOD(mysqlnd_res, fetch_fields)(MYSQLND_RES * const result TSRMLS_DC)
if (result->meta) {
if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) {
/* we have to initialize the rest to get the updated max length */
- if (PASS != result->m.initialize_result_set_rest(result TSRMLS_CC)) {
+ if (PASS != result->stored_data->m.initialize_result_set_rest(result->stored_data, result->meta, result->conn->stats,
+ result->conn->options->int_and_float_native TSRMLS_CC))
+ {
break;
}
}
@@ -1439,17 +1519,11 @@ MYSQLND_METHOD(mysqlnd_res, fetch_fields)(MYSQLND_RES * const result TSRMLS_DC)
/* }}} */
-
/* {{{ mysqlnd_res::field_seek */
static MYSQLND_FIELD_OFFSET
-MYSQLND_METHOD(mysqlnd_res, field_seek)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET field_offset TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_res, field_seek)(MYSQLND_RES * const result, const MYSQLND_FIELD_OFFSET field_offset TSRMLS_DC)
{
- MYSQLND_FIELD_OFFSET return_value = 0;
- if (result->meta) {
- return_value = result->meta->current_field;
- result->meta->current_field = field_offset;
- }
- return return_value;
+ return result->meta? result->meta->m->field_seek(result->meta, field_offset TSRMLS_CC) : 0;
}
/* }}} */
@@ -1473,10 +1547,6 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, unsigned int flags
DBG_ENTER("mysqlnd_res::fetch_into");
- if (!result->m.fetch_row) {
- RETVAL_NULL();
- DBG_VOID_RETURN;
- }
/*
Hint Zend how many elements we will have in the hash. Thus it won't
extend and rehash the hash constantly.
@@ -1511,17 +1581,17 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, unsigned int flags
static MYSQLND_ROW_C
MYSQLND_METHOD(mysqlnd_res, fetch_row_c)(MYSQLND_RES * result TSRMLS_DC)
{
+ zend_bool fetched_anything;
MYSQLND_ROW_C ret = NULL;
DBG_ENTER("mysqlnd_res::fetch_row_c");
- if (result->m.fetch_row) {
- if (result->m.fetch_row == result->m.fetch_row_normal_buffered) {
- DBG_RETURN(mysqlnd_fetch_row_buffered_c(result TSRMLS_CC));
- } else if (result->m.fetch_row == result->m.fetch_row_normal_unbuffered) {
- DBG_RETURN(mysqlnd_fetch_row_unbuffered_c(result TSRMLS_CC));
- } else {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "result->m.fetch_row has invalid value. Report to the developers");
- }
+ if (result->stored_data && result->stored_data->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row)) {
+ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row_c)(result, (void *) &ret, 0, &fetched_anything TSRMLS_CC);
+ } else if (result->unbuf && result->unbuf->m.fetch_row == MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)) {
+ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(result, (void *) &ret, 0, &fetched_anything TSRMLS_CC);
+ } else {
+ ret = NULL;
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "result->m.fetch_row has invalid value. Report to the developers");
}
DBG_RETURN(ret);
}
@@ -1575,11 +1645,6 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_data)(MYSQLND_RES * result, unsigned int
DBG_ENTER("mysqlnd_res::fetch_field_data");
DBG_INF_FMT("offset=%u", offset);
-
- if (!result->m.fetch_row) {
- RETVAL_NULL();
- DBG_VOID_RETURN;
- }
/*
Hint Zend how many elements we will have in the hash. Thus it won't
extend and rehash the hash constantly.
@@ -1610,9 +1675,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_data)(MYSQLND_RES * result, unsigned int
MYSQLND_CLASS_METHODS_START(mysqlnd_res)
- NULL, /* fetch_row */
- mysqlnd_fetch_row_buffered,
- mysqlnd_fetch_row_unbuffered,
+ MYSQLND_METHOD(mysqlnd_res, fetch_row),
MYSQLND_METHOD(mysqlnd_res, use_result),
MYSQLND_METHOD(mysqlnd_res, store_result),
MYSQLND_METHOD(mysqlnd_res, fetch_into),
@@ -1629,19 +1692,34 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_res)
MYSQLND_METHOD(mysqlnd_res, fetch_field_direct),
MYSQLND_METHOD(mysqlnd_res, fetch_fields),
MYSQLND_METHOD(mysqlnd_res, read_result_metadata),
- NULL, /* fetch_lengths */
+ MYSQLND_METHOD(mysqlnd_res, fetch_lengths),
MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data),
- MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest),
MYSQLND_METHOD(mysqlnd_res, free_result_buffers),
MYSQLND_METHOD(mysqlnd_res, free_result),
+ MYSQLND_METHOD(mysqlnd_res, free_result_internal),
+ MYSQLND_METHOD(mysqlnd_res, free_result_contents_internal),
+ mysqlnd_result_meta_init
+MYSQLND_CLASS_METHODS_END;
- mysqlnd_internal_free_result, /* free_result_internal */
- mysqlnd_internal_free_result_contents, /* free_result_contents */
- MYSQLND_METHOD(mysqlnd_res, free_buffered_data),
- MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data),
- NULL /* row_decoder */,
- mysqlnd_result_meta_init
+MYSQLND_CLASS_METHODS_START(mysqlnd_result_unbuffered)
+ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row),
+ NULL, /* row_decoder */
+ MYSQLND_METHOD(mysqlnd_result_unbuffered, num_rows),
+ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_lengths),
+ MYSQLND_METHOD(mysqlnd_result_unbuffered, free_last_data),
+ MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)
+MYSQLND_CLASS_METHODS_END;
+
+
+MYSQLND_CLASS_METHODS_START(mysqlnd_result_buffered)
+ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_row),
+ NULL, /* row_decoder */
+ MYSQLND_METHOD(mysqlnd_result_buffered, num_rows),
+ MYSQLND_METHOD(mysqlnd_result_buffered, fetch_lengths),
+ MYSQLND_METHOD(mysqlnd_result_buffered, data_seek),
+ MYSQLND_METHOD(mysqlnd_result_buffered, initialize_result_set_rest),
+ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)
MYSQLND_CLASS_METHODS_END;
@@ -1650,7 +1728,7 @@ PHPAPI MYSQLND_RES *
mysqlnd_result_init(unsigned int field_count, zend_bool persistent TSRMLS_DC)
{
size_t alloc_size = sizeof(MYSQLND_RES) + mysqlnd_plugin_count() * sizeof(void *);
- MYSQLND_RES *ret = mnd_pecalloc(1, alloc_size, persistent);
+ MYSQLND_RES * ret = mnd_pecalloc(1, alloc_size, persistent);
DBG_ENTER("mysqlnd_result_init");
@@ -1667,6 +1745,86 @@ mysqlnd_result_init(unsigned int field_count, zend_bool persistent TSRMLS_DC)
/* }}} */
+/* {{{ mysqlnd_result_unbuffered_init */
+PHPAPI MYSQLND_RES_UNBUFFERED *
+mysqlnd_result_unbuffered_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC)
+{
+ size_t alloc_size = sizeof(MYSQLND_RES_UNBUFFERED) + mysqlnd_plugin_count() * sizeof(void *);
+ MYSQLND_RES_UNBUFFERED * ret = mnd_pecalloc(1, alloc_size, persistent);
+
+ DBG_ENTER("mysqlnd_result_unbuffered_init");
+
+ if (!ret) {
+ DBG_RETURN(NULL);
+ }
+
+ if (!(ret->lengths = mnd_pecalloc(field_count, sizeof(unsigned long), persistent))) {
+ mnd_pefree(ret, persistent);
+ DBG_RETURN(NULL);
+ }
+ if (!(ret->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC))) {
+ mnd_efree(ret->lengths);
+ mnd_pefree(ret, persistent);
+ DBG_RETURN(NULL);
+ }
+
+ ret->persistent = persistent;
+ ret->field_count= field_count;
+ ret->ps = ps;
+
+ ret->m = *mysqlnd_result_unbuffered_get_methods();
+
+ if (ps) {
+ ret->m.fetch_lengths = NULL; /* makes no sense */
+ ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
+ } else {
+ ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol;
+ }
+
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_result_buffered_init */
+PHPAPI MYSQLND_RES_BUFFERED *
+mysqlnd_result_buffered_init(unsigned int field_count, zend_bool ps, zend_bool persistent TSRMLS_DC)
+{
+ size_t alloc_size = sizeof(MYSQLND_RES_BUFFERED) + mysqlnd_plugin_count() * sizeof(void *);
+ MYSQLND_RES_BUFFERED * ret = mnd_pecalloc(1, alloc_size, persistent);
+
+ DBG_ENTER("mysqlnd_result_buffered_init");
+
+ if (!ret) {
+ DBG_RETURN(NULL);
+ }
+ if (!(ret->lengths = mnd_pecalloc(field_count, sizeof(unsigned long), persistent))) {
+ mnd_pefree(ret, persistent);
+ DBG_RETURN(NULL);
+ }
+ if (!(ret->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC))) {
+ mnd_efree(ret->lengths);
+ mnd_pefree(ret, persistent);
+ DBG_RETURN(NULL);
+ }
+
+ ret->persistent = persistent;
+ ret->field_count= field_count;
+ ret->ps = ps;
+ ret->m = *mysqlnd_result_buffered_get_methods();
+
+ if (ps) {
+ ret->m.fetch_lengths = NULL; /* makes no sense */
+ ret->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol;
+ } else {
+ ret->m.row_decoder = php_mysqlnd_rowp_read_text_protocol;
+ }
+
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
/*
* Local variables:
* tab-width: 4