]> granicus.if.org Git - php/commitdiff
Handle problems in the row_decoder, return type used to be void,
authorAndrey Hristov <andrey@php.net>
Mon, 31 May 2010 17:57:03 +0000 (17:57 +0000)
committerAndrey Hristov <andrey@php.net>
Mon, 31 May 2010 17:57:03 +0000 (17:57 +0000)
now it can return on problems.

ext/mysqlnd/mysqlnd_ps.c
ext/mysqlnd/mysqlnd_result.c
ext/mysqlnd/mysqlnd_structs.h
ext/mysqlnd/mysqlnd_wireprotocol.c
ext/mysqlnd/mysqlnd_wireprotocol.h

index b4d610731bbb8fa0214de16b06471c0e6d563228..36c16bdabe0237b9e0fb5d5bc7ceae0d8c6dc431 100644 (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;
 
index 8cf8abb1e8498a21ef106fa605d79a4505025e6f..7769018d51548c724c17f381100694c0c000ce1d 100644 (file)
 
 
 /* {{{ 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);
 }
 /* }}} */
index 21d90d6dc7c419d230fb3356f053e9a60128fa65..fd0f1d1b904f6ece05b58ca16b730eda461d3c24 100644 (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,
index 2896c31280ac726f28a022590e7ed9e8886cb070..0dd076d28e72e2eab613a79fc1ae1f70d123b6ca 100644 (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);
 }
 /* }}} */
 
index 192129678cd19f8024afcb7d09814dd002b81446..2666ecc5081fdaab62d4094d2dfc989d91cc5420 100644 (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,