summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_wireprotocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mysqlnd/mysqlnd_wireprotocol.c')
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.c206
1 files changed, 50 insertions, 156 deletions
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
index ba579ba403..ed36c8404b 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -1074,14 +1074,9 @@ php_mysqlnd_rset_header_read(MYSQLND_CONN_DATA * conn, void * _packet)
*/
len = packet->header.size - 1;
packet->info_or_local_file.s = mnd_emalloc(len + 1);
- if (packet->info_or_local_file.s) {
- memcpy(packet->info_or_local_file.s, p, len);
- packet->info_or_local_file.s[len] = '\0';
- packet->info_or_local_file.l = len;
- } else {
- SET_OOM_ERROR(error_info);
- ret = FAIL;
- }
+ memcpy(packet->info_or_local_file.s, p, len);
+ packet->info_or_local_file.s[len] = '\0';
+ packet->info_or_local_file.l = len;
break;
case 0x00:
DBG_INF("UPSERT");
@@ -1101,14 +1096,9 @@ php_mysqlnd_rset_header_read(MYSQLND_CONN_DATA * conn, void * _packet)
/* Check for additional textual data */
if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
packet->info_or_local_file.s = mnd_emalloc(len + 1);
- if (packet->info_or_local_file.s) {
- memcpy(packet->info_or_local_file.s, p, len);
- packet->info_or_local_file.s[len] = '\0';
- packet->info_or_local_file.l = len;
- } else {
- SET_OOM_ERROR(error_info);
- ret = FAIL;
- }
+ memcpy(packet->info_or_local_file.s, p, len);
+ packet->info_or_local_file.s[len] = '\0';
+ packet->info_or_local_file.l = len;
}
DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%u warning_count=%u",
packet->affected_rows, packet->last_insert_id,
@@ -1380,7 +1370,7 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
*/
/*
- We're allocating an extra byte, as php_mysqlnd_rowp_read_text_protocol_aux
+ We're allocating an extra byte, as php_mysqlnd_rowp_read_text_protocol
needs to be able to append a terminating \0 for atoi/atof.
*/
prealloc_more_bytes = 1;
@@ -1391,53 +1381,41 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
} else {
+ /* If the packet is split in multiple chunks, allocate a temporary buffer that we can
+ * reallocate, and only afterwards copy it to the pool when we know the final size. */
+ zend_uchar *buf = NULL;
+ while (header.size >= MYSQLND_MAX_PACKET_SIZE) {
+ buf = erealloc(buf, *data_size + header.size);
+ p = buf + *data_size;
+ *data_size += header.size;
+
+ if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
+ DBG_ERR("Empty row packet body");
+ SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
+ set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ efree(buf);
+ DBG_RETURN(FAIL);
+ }
+ if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
+ efree(buf);
+ DBG_RETURN(FAIL);
+ }
+ }
+
+ buffer->ptr = pool->get_chunk(pool, *data_size + header.size + prealloc_more_bytes);
+ if (buf) {
+ memcpy(buffer->ptr, buf, *data_size);
+ efree(buf);
+ }
+ p = (zend_uchar *) buffer->ptr + *data_size;
*data_size += header.size;
- buffer->ptr = pool->get_chunk(pool, *data_size + prealloc_more_bytes);
- p = buffer->ptr;
if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
DBG_ERR("Empty row packet body");
SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- } else {
- while (header.size >= MYSQLND_MAX_PACKET_SIZE) {
- if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
- ret = FAIL;
- break;
- }
-
- *data_size += header.size;
-
- /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
- if (!header.size) {
- break;
- }
-
- /*
- We have to realloc the buffer.
- */
- buffer->ptr = pool->resize_chunk(pool, buffer->ptr, *data_size - header.size, *data_size + prealloc_more_bytes);
- if (!buffer->ptr) {
- SET_OOM_ERROR(error_info);
- ret = FAIL;
- break;
- }
- /* The position could have changed, recalculate */
- p = (zend_uchar *) buffer->ptr + (*data_size - header.size);
-
- if (PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info))) {
- DBG_ERR("Empty row packet body");
- SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
- set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- break;
- }
- }
}
}
- if (ret == FAIL && buffer->ptr) {
- pool->free_chunk(pool, buffer->ptr);
- buffer->ptr = NULL;
- }
DBG_RETURN(ret);
}
/* }}} */
@@ -1447,7 +1425,7 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
enum_func_status
php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
- const zend_bool as_int_or_float, MYSQLND_STATS * const stats)
+ const bool as_int_or_float, MYSQLND_STATS * const stats)
{
unsigned int i;
const zend_uchar * p = row_buffer->ptr;
@@ -1536,9 +1514,9 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi
/* {{{ php_mysqlnd_rowp_read_text_protocol */
enum_func_status
-php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
+php_mysqlnd_rowp_read_text_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
- zend_bool as_int_or_float, MYSQLND_STATS * stats)
+ bool as_int_or_float, MYSQLND_STATS * stats)
{
unsigned int i;
zval *current_field, *end_field, *start_field;
@@ -1546,7 +1524,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
const size_t data_size = row_buffer->size;
const zend_uchar * const packet_end = (zend_uchar*) p + data_size;
- DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux");
+ DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
if (!fields) {
DBG_RETURN(FAIL);
@@ -1566,10 +1544,8 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
" bytes after end of packet", (p + len) - packet_end - 1);
DBG_RETURN(FAIL);
} else {
-#ifdef MYSQLND_STRING_TO_INT_CONVERSION
struct st_mysqlnd_perm_bind perm_bind =
mysqlnd_ps_fetch_functions[fields_metadata[i].type];
-#endif
if (MYSQLND_G(collect_statistics)) {
enum_mysqlnd_collected_stats statistic;
switch (fields_metadata[i].type) {
@@ -1624,9 +1600,8 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
} else if (Z_TYPE_P(current_field) == IS_STRING) {
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
}
- }
-#ifdef MYSQLND_STRING_TO_INT_CONVERSION
- else if (as_int_or_float && perm_bind.php_type == IS_LONG) {
+ } else if (as_int_or_float && perm_bind.php_type == IS_LONG
+ && !(fields_metadata[i].flags & ZEROFILL_FLAG)) {
zend_uchar save = *(p + len);
/* We have to make it ASCIIZ temporarily */
*(p + len) = '\0';
@@ -1646,7 +1621,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
#else
(uint64_t) _atoi64((char *) p);
#endif
- zend_bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
+ bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
/* We have to make it ASCIIZ temporarily */
#if SIZEOF_ZEND_LONG==8
if (uns == TRUE && v > 9223372036854775807L)
@@ -1670,9 +1645,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
*(p + len) = '\0';
ZVAL_DOUBLE(current_field, zend_strtod((char *) p, NULL));
*(p + len) = save;
- }
-#endif /* MYSQLND_STRING_TO_INT_CONVERSION */
- else {
+ } else {
ZVAL_STRINGL_FAST(current_field, (char *)p, len);
}
p += len;
@@ -1684,39 +1657,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
/* }}} */
-/* {{{ php_mysqlnd_rowp_read_text_protocol_zval */
-enum_func_status
-php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
- const unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
- const zend_bool as_int_or_float, MYSQLND_STATS * stats)
-{
- enum_func_status ret;
- DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_zval");
- ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
- DBG_RETURN(ret);
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_rowp_read_text_protocol_c */
-enum_func_status
-php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
- const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
- const zend_bool as_int_or_float, MYSQLND_STATS * const stats)
-{
- enum_func_status ret;
- DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_c");
- ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
- DBG_RETURN(ret);
-}
-/* }}} */
-
-
/* {{{ php_mysqlnd_rowp_read */
-/*
- if normal statements => packet->fields is created by this function,
- if PS => packet->fields is passed from outside
-*/
static enum_func_status
php_mysqlnd_rowp_read(MYSQLND_CONN_DATA * conn, void * _packet)
{
@@ -1777,33 +1718,10 @@ php_mysqlnd_rowp_read(MYSQLND_CONN_DATA * conn, void * _packet)
DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
}
} else {
+ packet->eof = FALSE;
MYSQLND_INC_CONN_STATISTIC(stats,
packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
-
- packet->eof = FALSE;
- /* packet->field_count is set by the user of the packet */
-
- if (!packet->skip_extraction) {
- if (!packet->fields) {
- DBG_INF("Allocating packet->fields");
- /*
- old-API will probably set packet->fields to NULL every time, though for
- unbuffered sets it makes not much sense as the zvals in this buffer matter,
- not the buffer. Constantly allocating and deallocating brings nothing.
-
- For PS - if stmt_store() is performed, thus we don't have a cursor, it will
- behave just like old-API buffered. Cursors will behave like a bit different,
- but mostly like old-API unbuffered and thus will populate this array with
- value.
- */
- packet->fields = mnd_ecalloc(packet->field_count, sizeof(zval));
- }
- } else {
- MYSQLND_INC_CONN_STATISTIC(stats,
- packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
- STAT_ROWS_SKIPPED_NORMAL);
- }
}
end:
@@ -1812,30 +1730,6 @@ end:
/* }}} */
-/* {{{ php_mysqlnd_rowp_free_mem */
-static void
-php_mysqlnd_rowp_free_mem(void * _packet)
-{
- MYSQLND_PACKET_ROW *p;
-
- DBG_ENTER("php_mysqlnd_rowp_free_mem");
- p = (MYSQLND_PACKET_ROW *) _packet;
- if (p->row_buffer.ptr) {
- p->result_set_memory_pool->free_chunk(p->result_set_memory_pool, p->row_buffer.ptr);
- p->row_buffer.ptr = NULL;
- }
- /*
- Don't free packet->fields :
- - normal queries -> store_result() | fetch_row_unbuffered() will transfer
- the ownership and NULL it.
- - PS will pass in it the bound variables, we have to use them! and of course
- not free the array. As it is passed to us, we should not clean it ourselves.
- */
- DBG_VOID_RETURN;
-}
-/* }}} */
-
-
/* {{{ php_mysqlnd_stats_read */
static enum_func_status
php_mysqlnd_stats_read(MYSQLND_CONN_DATA * conn, void * _packet)
@@ -2282,7 +2176,7 @@ mysqlnd_packet_methods packet_methods[PROT_LAST] =
{
php_mysqlnd_rowp_read, /* read */
NULL, /* write */
- php_mysqlnd_rowp_free_mem,
+ NULL,
}, /* PROT_ROW_PACKET */
{
php_mysqlnd_stats_read, /* read */
@@ -2515,7 +2409,7 @@ MYSQLND_METHOD(mysqlnd_protocol, send_command)(
MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
const enum php_mysqlnd_server_command command,
const zend_uchar * const arg, const size_t arg_len,
- const zend_bool silent,
+ const bool silent,
struct st_mysqlnd_connection_state * connection_state,
MYSQLND_ERROR_INFO * error_info,
@@ -2581,7 +2475,7 @@ MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK)(
MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
MYSQLND_ERROR_INFO * const error_info,
MYSQLND_UPSERT_STATUS * const upsert_status,
- const zend_bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
+ const bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
MYSQLND_STRING * const last_message)
{
enum_func_status ret = FAIL;
@@ -2675,9 +2569,9 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response)(
MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
const enum mysqlnd_packet_type ok_packet,
- const zend_bool silent,
+ const bool silent,
const enum php_mysqlnd_server_command command,
- const zend_bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
+ const bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
MYSQLND_ERROR_INFO * error_info,
MYSQLND_UPSERT_STATUS * upsert_status,
@@ -2737,7 +2631,7 @@ MYSQLND_CLASS_METHODS_END;
/* {{{ mysqlnd_protocol_payload_decoder_factory_init */
PHPAPI MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
-mysqlnd_protocol_payload_decoder_factory_init(MYSQLND_CONN_DATA * conn, const zend_bool persistent)
+mysqlnd_protocol_payload_decoder_factory_init(MYSQLND_CONN_DATA * conn, const bool persistent)
{
MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * ret;
DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_init");
@@ -2754,7 +2648,7 @@ mysqlnd_protocol_payload_decoder_factory_free(MYSQLND_PROTOCOL_PAYLOAD_DECODER_F
DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_free");
if (factory) {
- zend_bool pers = factory->persistent;
+ bool pers = factory->persistent;
mnd_pefree(factory, pers);
}
DBG_VOID_RETURN;