diff options
Diffstat (limited to 'ext/mysqlnd/mysqlnd_wireprotocol.c')
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 206 |
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; |