Handle problems in the row_decoder, return type used to be void,

now it can return on problems.
This commit is contained in:
Andrey Hristov 2010-05-31 17:57:03 +00:00
parent b61d7501c9
commit 047d6f2855
5 changed files with 215 additions and 152 deletions

View File

@ -680,6 +680,7 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
unsigned int field_count = result->meta->field_count;
DBG_ENTER("mysqlnd_fetch_stmt_row_buffered");
*fetched_anything = FALSE;
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
/* If we haven't read everything */
@ -694,15 +695,18 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
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],
current_row,
meta->field_count,
meta->fields,
result->stored_data->persistent,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (PASS != rc) {
DBG_RETURN(FAIL);
}
set->initialized_rows++;
result->m.row_decoder(set->row_buffers[row_num],
current_row,
meta->field_count,
meta->fields,
result->stored_data->persistent,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (stmt->update_max_length) {
for (i = 0; i < result->field_count; i++) {
/*
@ -757,7 +761,6 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
DBG_INF("row fetched");
} else {
set->data_cursor = NULL;
*fetched_anything = FALSE;
DBG_INF("no more data");
}
DBG_INF("PASS");
@ -777,9 +780,10 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
*fetched_anything = FALSE;
if (result->unbuf->eof_reached) {
/* No more rows obviously */
*fetched_anything = FALSE;
DBG_INF("eof reached");
DBG_RETURN(PASS);
}
@ -798,8 +802,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
unsigned int i, field_count = result->field_count;
result->unbuf->row_count++;
*fetched_anything = TRUE;
if (!row_packet->skip_extraction) {
result->m.unbuffered_free_last_data(result TSRMLS_CC);
@ -810,14 +812,17 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC))
{
DBG_RETURN(FAIL);
}
for (i = 0; i < field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
@ -858,8 +863,10 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
row_packet->row_buffer = NULL;
}
result->unbuf->row_count++;
*fetched_anything = TRUE;
} else if (ret == FAIL) {
*fetched_anything = FALSE;
if (row_packet->error_info.error_no) {
stmt->conn->error_info = row_packet->error_info;
stmt->error_info = row_packet->error_info;
@ -867,7 +874,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
CONN_SET_STATE(result->conn, CONN_READY);
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
} else if (row_packet->eof) {
*fetched_anything = FALSE;
DBG_INF("EOF");
/* Mark the connection as usable again */
result->unbuf->eof_reached = TRUE;
@ -975,8 +981,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
unsigned int i, field_count = result->field_count;
result->unbuf->row_count++;
*fetched_anything = TRUE;
DBG_INF_FMT("skip_extraction=%d", row_packet->skip_extraction);
if (!row_packet->skip_extraction) {
@ -988,14 +992,17 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (PASS != result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC))
{
DBG_RETURN(FAIL);
}
/* If no result bind, do nothing. We consumed the data */
for (i = 0; i < field_count; i++) {
@ -1044,6 +1051,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
row_packet->row_buffer = NULL;
}
MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
result->unbuf->row_count++;
*fetched_anything = TRUE;
} else {
*fetched_anything = FALSE;

View File

@ -35,31 +35,36 @@
/* {{{ mysqlnd_res::initialize_result_set_rest */
static void
static enum_func_status
MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC)
{
unsigned int i;
zval **data_cursor = result->stored_data->data;
zval **data_begin = result->stored_data->data;
unsigned int field_count = result->meta->field_count;
unsigned int row_count = result->stored_data->row_count;
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;
unsigned int row_count = result->stored_data? result->stored_data->row_count:0;
enum_func_status ret = PASS;
DBG_ENTER("mysqlnd_res::initialize_result_set_rest");
if (!data_cursor || row_count == result->stored_data->initialized_rows) {
DBG_VOID_RETURN;
DBG_RETURN(ret);
}
while ((data_cursor - data_begin) < (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],
data_cursor,
result->meta->field_count,
result->meta->fields,
result->stored_data->persistent,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (rc != PASS) {
ret = FAIL;
break;
}
result->stored_data->initialized_rows++;
result->m.row_decoder(
result->stored_data->row_buffers[(data_cursor - data_begin) / field_count],
data_cursor,
result->meta->field_count,
result->meta->fields,
result->stored_data->persistent,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@ -76,7 +81,7 @@ MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const resu
}
data_cursor += field_count;
}
DBG_VOID_RETURN;
DBG_RETURN(ret);
}
/* }}} */
@ -633,6 +638,10 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(retrow);
}
if (!row_packet) {
/* Not fully initialized object that is being cleaned up */
DBG_RETURN(retrow);
}
/* Let the row packet fill our buffer and skip additional mnd_malloc + memcpy */
row_packet->skip_extraction = FALSE;
@ -656,14 +665,17 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
MYSQLND_FIELD *field = result->meta->fields;
struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys;
result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
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,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (PASS != rc) {
DBG_RETURN(retrow);
}
retrow = mnd_malloc(result->field_count * sizeof(char *));
if (retrow) {
@ -733,15 +745,19 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
DBG_ENTER("mysqlnd_fetch_row_unbuffered");
DBG_INF_FMT("flags=%d", flags);
*fetched_anything = FALSE;
if (result->unbuf->eof_reached) {
/* No more rows obviously */
*fetched_anything = FALSE;
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(FAIL);
}
if (!row_packet) {
/* Not fully initialized object that is being cleaned up */
DBG_RETURN(FAIL);
}
/* Let the row packet fill our buffer and skip additional mnd_malloc + memcpy */
row_packet->skip_extraction = row? FALSE:TRUE;
@ -750,9 +766,6 @@ 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->unbuf->row_count++;
*fetched_anything = TRUE;
result->m.unbuffered_free_last_data(result TSRMLS_CC);
result->unbuf->last_row_data = row_packet->fields;
@ -760,7 +773,6 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
MYSQLND_INC_CONN_STATISTIC(result->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF);
if (!row_packet->skip_extraction) {
@ -770,15 +782,17 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
unsigned int i, field_count = result->field_count;
unsigned long *lengths = result->lengths;
result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
enum_func_status rc = result->m.row_decoder(result->unbuf->last_row_buffer,
result->unbuf->last_row_data,
field_count,
row_packet->fields_metadata,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (PASS != rc) {
DBG_RETURN(FAIL);
}
for (i = 0; i < field_count; i++, field++, zend_hash_key++) {
zval *data = result->unbuf->last_row_data[i];
unsigned int len = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data);
@ -825,12 +839,13 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
}
}
}
*fetched_anything = TRUE;
result->unbuf->row_count++;
} else if (ret == FAIL) {
if (row_packet->error_info.error_no) {
result->conn->error_info = row_packet->error_info;
DBG_ERR_FMT("errorno=%d error=%s", row_packet->error_info.error_no, row_packet->error_info.error);
}
*fetched_anything = FALSE;
CONN_SET_STATE(result->conn, CONN_READY);
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
} else if (row_packet->eof) {
@ -849,7 +864,6 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
CONN_SET_STATE(result->conn, CONN_READY);
}
result->m.unbuffered_free_last_data(result TSRMLS_CC);
*fetched_anything = FALSE;
}
DBG_INF_FMT("ret=%s fetched=%d", ret == PASS? "PASS":"FAIL", *fetched_anything);
@ -867,11 +881,6 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
SET_EMPTY_ERROR(result->conn->error_info);
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) {
goto oom;
}
if (ps == FALSE) {
result->type = MYSQLND_RES_NORMAL;
@ -884,12 +893,19 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
}
} 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) {
goto oom;
}
/*
Will be freed in the mysqlnd_internal_free_result_contents() called
by the resource destructor. mysqlnd_fetch_row_unbuffered() expects
@ -935,15 +951,18 @@ mysqlnd_fetch_row_buffered_c(MYSQLND_RES * result TSRMLS_DC)
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],
current_row,
result->meta->field_count,
result->meta->fields,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (rc != PASS) {
DBG_RETURN(ret);
}
set->initialized_rows++;
result->m.row_decoder(set->row_buffers[row_num],
current_row,
result->meta->field_count,
result->meta->fields,
FALSE,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@ -992,6 +1011,7 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags
unsigned int i;
zval *row = (zval *) param;
MYSQLND_RES_BUFFERED *set = result->stored_data;
enum_func_status ret = FAIL;
DBG_ENTER("mysqlnd_fetch_row_buffered");
DBG_INF_FMT("flags=%u row=%p", flags, row);
@ -1006,15 +1026,18 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags
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],
current_row,
result->meta->field_count,
result->meta->fields,
result->stored_data->persistent,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
if (rc != PASS) {
DBG_RETURN(FAIL);
}
set->initialized_rows++;
result->m.row_decoder(set->row_buffers[row_num],
current_row,
result->meta->field_count,
result->meta->fields,
result->stored_data->persistent,
result->conn->options.numeric_and_datetime_as_unicode,
result->conn->options.int_and_float_native,
result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@ -1070,13 +1093,15 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags
set->data_cursor += result->meta->field_count;
*fetched_anything = TRUE;
MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
ret = PASS;
} else {
set->data_cursor = NULL;
*fetched_anything = FALSE;
ret = PASS;
DBG_INF("EOF reached");
}
DBG_INF_FMT("ret=PASS fetched=%d", *fetched_anything);
DBG_RETURN(PASS);
DBG_RETURN(ret);
}
/* }}} */
@ -1210,11 +1235,11 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL
/* libmysql's documentation says it should be so for SELECT statements */
conn->upsert_status.affected_rows = set->row_count;
}
DBG_INF_FMT("ret=%s row_count=%u warnings=%u server_status=%u", ret == PASS? "PASS":"FAIL",
set->row_count, conn->upsert_status.warning_count, conn->upsert_status.server_status);
end:
PACKET_FREE(row_packet);
DBG_INF_FMT("ret=%s row_count=%u warnings=%u server_status=%u", ret == PASS? "PASS":"FAIL",
set->row_count, conn->upsert_status.warning_count, conn->upsert_status.server_status);
DBG_RETURN(ret);
}
/* }}} */
@ -1232,6 +1257,12 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
DBG_ENTER("mysqlnd_res::store_result");
DBG_INF_FMT("conn=%d ps_protocol=%d", conn->thread_id, ps_protocol);
/* 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->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
if (!result->result_set_memory_pool || !result->lengths) {
@ -1239,17 +1270,15 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
DBG_RETURN(NULL);
}
/* 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;
CONN_SET_STATE(conn, CONN_FETCHING_DATA);
ret = result->m.store_result_fetch_data(conn, result, result->meta, ps_protocol, to_cache TSRMLS_CC);
if (FAIL == ret) {
conn->error_info = result->stored_data->error_info;
if (result->stored_data) {
conn->error_info = result->stored_data->error_info;
} else {
SET_OOM_ERROR(conn->error_info);
}
DBG_RETURN(NULL);
}
/* libmysql's documentation says it should be so for SELECT statements */
@ -1357,24 +1386,28 @@ static const MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res::fetch_field");
if (result->meta) {
/*
We optimize the result set, so we don't convert all the data from raw buffer format to
zval arrays during store. In the case someone doesn't read all the lines this will
save time. However, when a metadata call is done, we need to calculate max_length.
We don't have control whether max_length will be used, unfortunately. Otherwise we
could have been able to skip that step.
Well, if the mysqli API switches from returning stdClass to class like mysqli_field_metadata,
then we can have max_length as dynamic property, which will be calculated during runtime and
not during mysqli_fetch_field() time.
*/
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 */
result->m.initialize_result_set_rest(result TSRMLS_CC);
do {
if (result->meta) {
/*
We optimize the result set, so we don't convert all the data from raw buffer format to
zval arrays during store. In the case someone doesn't read all the lines this will
save time. However, when a metadata call is done, we need to calculate max_length.
We don't have control whether max_length will be used, unfortunately. Otherwise we
could have been able to skip that step.
Well, if the mysqli API switches from returning stdClass to class like mysqli_field_metadata,
then we can have max_length as dynamic property, which will be calculated during runtime and
not during mysqli_fetch_field() time.
*/
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)) {
break;
}
}
DBG_RETURN(result->meta->m->fetch_field(result->meta TSRMLS_CC));
}
DBG_RETURN(result->meta->m->fetch_field(result->meta TSRMLS_CC));
}
} while (0);
DBG_RETURN(NULL);
}
/* }}} */
@ -1385,24 +1418,28 @@ static const MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res::fetch_field_direct");
if (result->meta) {
/*
We optimize the result set, so we don't convert all the data from raw buffer format to
zval arrays during store. In the case someone doesn't read all the lines this will
save time. However, when a metadata call is done, we need to calculate max_length.
We don't have control whether max_length will be used, unfortunately. Otherwise we
could have been able to skip that step.
Well, if the mysqli API switches from returning stdClass to class like mysqli_field_metadata,
then we can have max_length as dynamic property, which will be calculated during runtime and
not during mysqli_fetch_field_direct() time.
*/
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 */
result->m.initialize_result_set_rest(result TSRMLS_CC);
do {
if (result->meta) {
/*
We optimize the result set, so we don't convert all the data from raw buffer format to
zval arrays during store. In the case someone doesn't read all the lines this will
save time. However, when a metadata call is done, we need to calculate max_length.
We don't have control whether max_length will be used, unfortunately. Otherwise we
could have been able to skip that step.
Well, if the mysqli API switches from returning stdClass to class like mysqli_field_metadata,
then we can have max_length as dynamic property, which will be calculated during runtime and
not during mysqli_fetch_field_direct() time.
*/
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)) {
break;
}
}
DBG_RETURN(result->meta->m->fetch_field_direct(result->meta, fieldnr TSRMLS_CC));
}
DBG_RETURN(result->meta->m->fetch_field_direct(result->meta, fieldnr TSRMLS_CC));
}
} while (0);
DBG_RETURN(NULL);
}
@ -1414,13 +1451,17 @@ static const MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res, fetch_fields)(MYSQLND_RES * const result TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res::fetch_fields");
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 */
result->m.initialize_result_set_rest(result TSRMLS_CC);
do {
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)) {
break;
}
}
DBG_RETURN(result->meta->m->fetch_fields(result->meta TSRMLS_CC));
}
DBG_RETURN(result->meta->m->fetch_fields(result->meta TSRMLS_CC));
}
} while (0);
DBG_RETURN(NULL);
}
/* }}} */

View File

@ -503,7 +503,7 @@ typedef const MYSQLND_FIELD *(*func_mysqlnd_res__fetch_fields)(MYSQLND_RES * con
typedef enum_func_status (*func_mysqlnd_res__read_result_metadata)(MYSQLND_RES *result, MYSQLND * conn TSRMLS_DC);
typedef unsigned long * (*func_mysqlnd_res__fetch_lengths)(MYSQLND_RES * const result TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_res__store_result_fetch_data)(MYSQLND * const conn, MYSQLND_RES *result, MYSQLND_RES_METADATA *meta, zend_bool binary_protocol, zend_bool to_cache TSRMLS_DC);
typedef void (*func_mysqlnd_res__initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC);
typedef enum_func_status (*func_mysqlnd_res__initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC);
typedef void (*func_mysqlnd_res__free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
typedef enum_func_status (*func_mysqlnd_res__free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
@ -513,7 +513,7 @@ typedef void (*func_mysqlnd_res__free_buffered_data)(MYSQLND_RES *result TSRM
typedef void (*func_mysqlnd_res__unbuffered_free_last_data)(MYSQLND_RES *result TSRMLS_DC);
/* for decoding - binary or text protocol */
typedef void (*func_mysqlnd_res__row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
typedef enum_func_status (*func_mysqlnd_res__row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, MYSQLND_FIELD *fields_metadata,
zend_bool persistent,
zend_bool as_unicode, zend_bool as_int_or_float,

View File

@ -1202,7 +1202,7 @@ php_mysqlnd_read_row_ex(MYSQLND * conn, MYSQLND_MEMORY_POOL * result_set_memory_
/* {{{ php_mysqlnd_rowp_read_binary_protocol */
void
enum_func_status
php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, MYSQLND_FIELD *fields_metadata,
zend_bool persistent,
@ -1217,7 +1217,9 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
end_field = (current_field = start_field = fields) + field_count;
if (!current_field) {
DBG_RETURN(FAIL);
}
/* skip the first byte, not EODATA_MARKER -> 0x0, status */
p++;
@ -1228,6 +1230,9 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
for (i = 0; current_field < end_field; current_field++, i++) {
DBG_INF("Directly creating zval");
MAKE_STD_ZVAL(*current_field);
if (!*current_field) {
DBG_RETURN(FAIL);
}
DBG_INF_FMT("Into zval=%p decoding column %d [%s.%s.%s] type=%d field->flags&unsigned=%d flags=%u is_bit=%d as_unicode=%d",
*current_field, i,
@ -1282,13 +1287,13 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
}
}
DBG_VOID_RETURN;
DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_rowp_read_text_protocol */
void
enum_func_status
php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, MYSQLND_FIELD *fields_metadata,
zend_bool persistent,
@ -1305,6 +1310,10 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
end_field = (current_field = start_field = fields) + field_count;
if (!current_field) {
DBG_RETURN(FAIL);
}
for (i = 0; current_field < end_field; current_field++, i++) {
/* Don't reverse the order. It is significant!*/
zend_uchar *this_field_len_pos = p;
@ -1313,6 +1322,9 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
DBG_INF("Directly creating zval");
MAKE_STD_ZVAL(*current_field);
if (!*current_field) {
DBG_RETURN(FAIL);
}
if (current_field > start_field && last_field_was_string) {
/*
@ -1503,7 +1515,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval
row_buffer->ptr[data_size] = '\0';
}
DBG_VOID_RETURN;
DBG_RETURN(PASS);
}
/* }}} */

View File

@ -257,14 +257,14 @@ zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length);
PHPAPI const extern char * const mysqlnd_empty_string;
void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
enum_func_status php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, MYSQLND_FIELD *fields_metadata,
zend_bool persistent,
zend_bool as_unicode, zend_bool as_int_or_float,
MYSQLND_STATS * stats TSRMLS_DC);
void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
enum_func_status php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, MYSQLND_FIELD *fields_metadata,
zend_bool persistent,
zend_bool as_unicode, zend_bool as_int_or_float,