diff options
Diffstat (limited to 'ext/mysqlnd/mysqlnd_wireprotocol.c')
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 93 |
1 files changed, 44 insertions, 49 deletions
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index cc8b29ad3b..6015aac6eb 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -43,12 +43,11 @@ #define MYSQLND_DUMP_HEADER_N_BODY2 #define MYSQLND_DUMP_HEADER_N_BODY_FULL2 -#define MYSQLND_MAX_PACKET_SIZE (256L*256L*256L-1) #define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type) \ { \ if (FAIL == mysqlnd_read_header((conn), &((packet)->header) TSRMLS_CC)) {\ - conn->state = CONN_QUIT_SENT; \ + CONN_SET_STATE(conn, CONN_QUIT_SENT); \ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \ DBG_ERR_FMT("Can't read %s's header", (packet_type)); \ @@ -60,7 +59,7 @@ }\ if (!mysqlnd_read_body((conn), (buf), \ MIN((buf_size), (packet)->header.size) TSRMLS_CC)) { \ - conn->state = CONN_QUIT_SENT; \ + CONN_SET_STATE(conn, CONN_QUIT_SENT); \ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \ DBG_ERR_FMT("Empty %s packet body", (packet_type)); \ @@ -490,7 +489,7 @@ size_t mysqlnd_read_body(MYSQLND *conn, zend_uchar *buf, size_t size TSRMLS_DC) net->stream->chunk_size = MIN(size, conn->options.net_read_buffer_size); do { size -= (ret = php_stream_read(net->stream, p, size)); - if (size || iter++) { + if (size > 0 || iter++) { DBG_INF_FMT("read=%d buf=%p p=%p chunk_size=%d left=%d", ret, buf, p , net->stream->chunk_size, size); } @@ -1234,13 +1233,13 @@ void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) static enum_func_status -php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size, - size_t *data_size, zend_bool persistent_alloc, +php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer, + uint64 *data_size, zend_bool persistent_alloc, unsigned int prealloc_more_bytes TSRMLS_DC) { enum_func_status ret = PASS; mysqlnd_packet_header header; - zend_uchar *new_buf = NULL, *p = *buf; + zend_uchar *p = NULL; zend_bool first_iteration = TRUE; DBG_ENTER("php_mysqlnd_read_row_ex"); @@ -1262,13 +1261,14 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size, *data_size += header.size; - if (first_iteration && header.size > buf_size) { + if (first_iteration) { first_iteration = FALSE; /* We need a trailing \0 for the last string, in case of text-mode, to be able to implement read-only variables. Thus, we add + 1. */ - p = new_buf = mnd_pemalloc(*data_size + 1, persistent_alloc); + *buffer = mysqlnd_memory_pool.get_chunk(&mysqlnd_memory_pool, *data_size + 1 TSRMLS_CC); + p = (*buffer)->ptr; } else if (!first_iteration) { /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */ if (!header.size) { @@ -1281,9 +1281,9 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size, We need a trailing \0 for the last string, in case of text-mode, to be able to implement read-only variables. */ - new_buf = mnd_perealloc(new_buf, *data_size + 1, persistent_alloc); + (*buffer)->resize_chunk((*buffer), *data_size + 1 TSRMLS_CC); /* The position could have changed, recalculate */ - p = new_buf + (*data_size - header.size); + p = (*buffer)->ptr + (*data_size - header.size); } if (!mysqlnd_read_body(conn, p, header.size TSRMLS_CC)) { @@ -1297,8 +1297,9 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size, break; } } - if (ret == PASS && new_buf) { - *buf = new_buf; + if (ret == FAIL) { + (*buffer)->free_chunk((*buffer), TRUE TSRMLS_CC); + *buffer = NULL; } *data_size -= prealloc_more_bytes; DBG_RETURN(ret); @@ -1306,11 +1307,11 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size, /* {{{ php_mysqlnd_rowp_read_binary_protocol */ -static -void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND *conn, - zend_uchar *p, size_t data_size TSRMLS_DC) +void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields, + uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC) { - unsigned int i; + int i; + zend_uchar *p = row_buffer->ptr; zend_uchar *null_ptr, bit; zval **current_field, **end_field, **start_field; zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode; @@ -1319,14 +1320,14 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol"); - end_field = (current_field = start_field = packet->fields) + packet->field_count; + end_field = (current_field = start_field = fields) + field_count; /* skip the first byte, not 0xFE -> 0x0, status */ p++; null_ptr= p; - p += (packet->field_count + 9)/8; /* skip null bits */ - bit = 4; /* first 2 bits are reserved */ + p += (field_count + 9)/8; /* skip null bits */ + bit = 4; /* first 2 bits are reserved */ for (i = 0; current_field < end_field; current_field++, i++) { #if 1 @@ -1344,8 +1345,8 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND if (*null_ptr & bit) { ZVAL_NULL(*current_field); } else { - enum_mysqlnd_field_types type = packet->fields_metadata[i].type; - mysqlnd_ps_fetch_functions[type].func(*current_field, &packet->fields_metadata[i], + enum_mysqlnd_field_types type = fields_metadata[i].type; + mysqlnd_ps_fetch_functions[type].func(*current_field, &fields_metadata[i], 0, &p, as_unicode TSRMLS_CC); } if (!((bit<<=1) & 255)) { @@ -1353,8 +1354,6 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND null_ptr++; } } - /* Normal queries: The buffer has one more byte at the end, because we need it */ - packet->row_buffer[data_size] = '\0'; DBG_VOID_RETURN; } @@ -1362,14 +1361,15 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND /* {{{ php_mysqlnd_rowp_read_text_protocol */ -static -void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *conn, - zend_uchar *p, size_t data_size TSRMLS_DC) +void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields, + uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC) { - unsigned int i; - zend_bool last_field_was_string; + int i; + zend_bool last_field_was_string = FALSE; zval **current_field, **end_field, **start_field; - zend_uchar *bit_area = packet->row_buffer + data_size + 1; /* we allocate from here */ + zend_uchar *p = row_buffer->ptr; + size_t data_size = row_buffer->app; + zend_uchar *bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */ zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode; #ifdef MYSQLND_STRING_TO_INT_CONVERSION zend_bool as_int = conn->options.int_and_year_as_int; @@ -1377,7 +1377,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND * DBG_ENTER("php_mysqlnd_rowp_read_text_protocol"); - end_field = (current_field = start_field = packet->fields) + packet->field_count; + end_field = (current_field = start_field = fields) + field_count; for (i = 0; current_field < end_field; current_field++, i++) { /* Don't reverse the order. It is significant!*/ void *obj; @@ -1418,7 +1418,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND * } else { #if PHP_MAJOR_VERSION >= 6 || defined(MYSQLND_STRING_TO_INT_CONVERSION) struct st_mysqlnd_perm_bind perm_bind = - mysqlnd_ps_fetch_functions[packet->fields_metadata[i].type]; + mysqlnd_ps_fetch_functions[fields_metadata[i].type]; #endif #ifdef MYSQLND_STRING_TO_INT_CONVERSION @@ -1453,7 +1453,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND * *(p + len) = save; } else #endif - if (packet->fields_metadata[i].type == MYSQL_TYPE_BIT) { + if (fields_metadata[i].type == MYSQL_TYPE_BIT) { /* BIT fields are specially handled. As they come as bit mask, we have to convert it to human-readable representation. As the bits take @@ -1464,7 +1464,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND * Definitely not nice, _hackish_ :(, but works. */ zend_uchar *start = bit_area; - ps_fetch_from_1_to_8_bytes(*current_field, &(packet->fields_metadata[i]), + ps_fetch_from_1_to_8_bytes(*current_field, &(fields_metadata[i]), 0, &p, as_unicode, len TSRMLS_CC); /* We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because @@ -1532,7 +1532,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND * which will make with this `if` an `else if`. */ if ((perm_bind.is_possibly_blob == TRUE && - packet->fields_metadata[i].charsetnr == MYSQLND_BINARY_CHARSET_NR) || + fields_metadata[i].charsetnr == MYSQLND_BINARY_CHARSET_NR) || (!as_unicode && perm_bind.can_ret_as_str_in_uni == TRUE)) { /* BLOB - no conversion please */ @@ -1561,7 +1561,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND * } if (last_field_was_string) { /* Normal queries: The buffer has one more byte at the end, because we need it */ - packet->row_buffer[data_size] = '\0'; + row_buffer->ptr[data_size] = '\0'; } DBG_VOID_RETURN; @@ -1580,10 +1580,10 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC) MYSQLND_NET *net = &conn->net; zend_uchar *p; enum_func_status ret = PASS; - size_t data_size = 0; size_t old_chunk_size = net->stream->chunk_size; php_mysql_packet_row *packet= (php_mysql_packet_row *) _packet; size_t post_alloc_for_bit_fields = 0; + uint64 data_size = 0; DBG_ENTER("php_mysqlnd_rowp_read"); @@ -1593,17 +1593,18 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC) packet->bit_fields_total_len + packet->bit_fields_count; } - ret = php_mysqlnd_read_row_ex(conn, &packet->row_buffer, 0, &data_size, + ret = php_mysqlnd_read_row_ex(conn, &packet->row_buffer, &data_size, packet->persistent_alloc, post_alloc_for_bit_fields TSRMLS_CC); if (FAIL == ret) { goto end; } - /* packet->row_buffer is of size 'data_size + 1' */ + /* packet->row_buffer->ptr is of size 'data_size + 1' */ packet->header.size = data_size; + packet->row_buffer->app = data_size; - if ((*(p = packet->row_buffer)) == 0xFF) { + if ((*(p = packet->row_buffer->ptr)) == 0xFF) { /* Error message as part of the result set, not good but we should not hang. See: @@ -1646,14 +1647,8 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC) but mostly like old-API unbuffered and thus will populate this array with value. */ - packet->fields = (zval **) mnd_pemalloc(packet->field_count * sizeof(zval *), - packet->persistent_alloc); - } - - if (packet->binary_protocol) { - php_mysqlnd_rowp_read_binary_protocol(packet, conn, p, data_size TSRMLS_CC); - } else { - php_mysqlnd_rowp_read_text_protocol(packet, conn, p, data_size TSRMLS_CC); + packet->fields = (zval **) mnd_pecalloc(packet->field_count, sizeof(zval *), + packet->persistent_alloc); } } else { MYSQLND_INC_CONN_STATISTIC(&conn->stats, @@ -1675,7 +1670,7 @@ void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) { php_mysql_packet_row *p= (php_mysql_packet_row *) _packet; if (p->row_buffer) { - mnd_pefree(p->row_buffer, p->persistent_alloc); + p->row_buffer->free_chunk(p->row_buffer, TRUE TSRMLS_CC); p->row_buffer = NULL; } /* |