/* 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);
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;
/* 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;
/*
/* {{{ 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;
/* 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,
/* {{{ 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");
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);
}
/*
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,
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 */
} 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.
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;
/* {{{ 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;
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);
}
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,
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);
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 */
} 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.
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,
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;
}
#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.
*/
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;
}
}
}
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");
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, ©_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, ©_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;
/* }}} */
-/* {{{ 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");
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, ©_ctor_called TSRMLS_CC);
+ mysqlnd_rset_zval_ptr_dtor(&(current_row[col]), set->ps? MYSQLND_RES_PS_BUF : MYSQLND_RES_NORMAL, ©_ctor_called TSRMLS_CC);
if (copy_ctor_called) {
++copy_on_write_performed;
} else {
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;
}
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);
/* }}} */
-/* {{{ 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) {
/* }}} */
-/* {{{ 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
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:
*/
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]);
}
/* }}} */
-/* {{{ 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;
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;
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);
} 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) {
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;
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,
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);
} 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);
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:
/* }}} */
-/* {{{ 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.
}
}
- 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.
}
}
- 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);
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);
/* }}} */
+/* {{{ 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));
+ result->stored_data = set = mysqlnd_result_buffered_init(result->field_count, binary_protocol, result->persistent TSRMLS_CC);
+
if (!set) {
SET_OOM_ERROR(*conn->error_info);
ret = FAIL;
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;
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;
-
- 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) {
- SET_OOM_ERROR(*conn->error_info);
- DBG_RETURN(NULL);
- }
+ /* 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;
CONN_SET_STATE(conn, CONN_FETCHING_DATA);
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;
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,
{
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);
/* {{{ 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);
/* }}} */
+/* {{{ 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);
}
/* }}} */
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;
}
}
/* {{{ 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 {
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;
}
}
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;
}
}
/* }}} */
-
/* {{{ 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;
}
/* }}} */
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.
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);
}
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.
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),
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;
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");
/* }}} */
+/* {{{ 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