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.c198
1 files changed, 95 insertions, 103 deletions
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
index 83ae2a7977..2aa7afde0d 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -69,14 +69,12 @@
static const char *unknown_sqlstate= "HY000";
-
const char * const mysqlnd_empty_string = "";
/* Used in mysqlnd_debug.c */
const char mysqlnd_read_header_name[] = "mysqlnd_read_header";
const char mysqlnd_read_body_name[] = "mysqlnd_read_body";
-
#define ERROR_MARKER 0xFF
#define EODATA_MARKER 0xFE
@@ -161,7 +159,7 @@ php_mysqlnd_net_field_length(zend_uchar **packet)
uint64_t
php_mysqlnd_net_field_length_ll(zend_uchar **packet)
{
- register zend_uchar *p= (zend_uchar *)*packet;
+ register zend_uchar *p = (zend_uchar *)*packet;
if (*p < 251) {
(*packet)++;
@@ -561,9 +559,10 @@ size_t php_mysqlnd_auth_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC
}
if (packet->connect_attr && zend_hash_num_elements(packet->connect_attr)) {
+ size_t ca_payload_len = 0;
+#ifdef OLD_CODE
HashPosition pos_value;
const char ** entry_value;
- size_t ca_payload_len = 0;
zend_hash_internal_pointer_reset_ex(packet->connect_attr, &pos_value);
while (SUCCESS == zend_hash_get_current_data_ex(packet->connect_attr, (void **)&entry_value, &pos_value)) {
char *s_key;
@@ -579,10 +578,28 @@ size_t php_mysqlnd_auth_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC
}
zend_hash_move_forward_ex(conn->options->connect_attr, &pos_value);
}
+#else
+ {
+ zend_string * key;
+ unsigned long unused_num_key;
+ zval * entry_value;
+ ZEND_HASH_FOREACH_KEY_VAL(packet->connect_attr, unused_num_key, key, entry_value) {
+ if (key) { /* HASH_KEY_IS_STRING */
+ size_t value_len = Z_STRLEN_P(entry_value);
+
+ ca_payload_len += php_mysqlnd_net_store_length_size(key->len);
+ ca_payload_len += key->len;
+ ca_payload_len += php_mysqlnd_net_store_length_size(value_len);
+ ca_payload_len += value_len;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+#endif
if ((sizeof(buffer) - (p - buffer)) >= (ca_payload_len + php_mysqlnd_net_store_length_size(ca_payload_len))) {
p = php_mysqlnd_net_store_length(p, ca_payload_len);
+#ifdef OLD_CODE
zend_hash_internal_pointer_reset_ex(packet->connect_attr, &pos_value);
while (SUCCESS == zend_hash_get_current_data_ex(packet->connect_attr, (void **)&entry_value, &pos_value)) {
char *s_key;
@@ -601,6 +618,27 @@ size_t php_mysqlnd_auth_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC
}
zend_hash_move_forward_ex(conn->options->connect_attr, &pos_value);
}
+#else
+ {
+ zend_string * key;
+ unsigned long unused_num_key;
+ zval * entry_value;
+ ZEND_HASH_FOREACH_KEY_VAL(packet->connect_attr, unused_num_key, key, entry_value) {
+ if (key) { /* HASH_KEY_IS_STRING */
+ size_t value_len = Z_STRLEN_P(entry_value);
+
+ /* copy key */
+ p = php_mysqlnd_net_store_length(p, key->len);
+ memcpy(p, key->val, key->len);
+ p+= key->len;
+ /* copy value */
+ p = php_mysqlnd_net_store_length(p, value_len);
+ memcpy(p, Z_STRVAL_P(entry_value), value_len);
+ p+= value_len;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+#endif
} else {
/* cannot put the data - skip */
}
@@ -1177,7 +1215,7 @@ static size_t rset_field_offsets[] =
STRUCT_OFFSET(MYSQLND_FIELD, name),
STRUCT_OFFSET(MYSQLND_FIELD, name_length),
STRUCT_OFFSET(MYSQLND_FIELD, org_name),
- STRUCT_OFFSET(MYSQLND_FIELD, org_name_length)
+ STRUCT_OFFSET(MYSQLND_FIELD, org_name_length),
};
@@ -1186,7 +1224,7 @@ static enum_func_status
php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
/* Should be enough for the metadata of a single row */
- MYSQLND_PACKET_RES_FIELD *packet= (MYSQLND_PACKET_RES_FIELD *) _packet;
+ MYSQLND_PACKET_RES_FIELD *packet = (MYSQLND_PACKET_RES_FIELD *) _packet;
size_t buf_len = conn->net->cmd_buffer.length, total_len = 0;
zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
zend_uchar *p = buf;
@@ -1249,6 +1287,7 @@ php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol error. Server sent false length. Expected 12");
}
+
p++;
BAIL_IF_NO_MORE_DATA;
@@ -1305,17 +1344,25 @@ php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
memcpy(meta->def, p, len);
meta->def[len] = '\0';
meta->def_length = len;
- p += len;
- }
+ p += len;
+ }
- DBG_INF_FMT("allocing root. persistent=%u", packet->persistent_alloc);
root_ptr = meta->root = mnd_pemalloc(total_len, packet->persistent_alloc);
if (!root_ptr) {
SET_OOM_ERROR(*conn->error_info);
DBG_RETURN(FAIL);
}
-
+
meta->root_len = total_len;
+
+ if (meta->name != mysqlnd_empty_string) {
+ meta->sname = STR_INIT(meta->name, meta->name_length, packet->persistent_alloc);
+ } else {
+ meta->sname = STR_EMPTY_ALLOC();
+ }
+ meta->name = meta->sname->val;
+ meta->name_length = meta->sname->len;
+
/* Now do allocs */
if (meta->catalog && meta->catalog != mysqlnd_empty_string) {
len = meta->catalog_length;
@@ -1345,13 +1392,6 @@ php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
root_ptr++;
}
- if (meta->name && meta->name != mysqlnd_empty_string) {
- len = meta->name_length;
- meta->name = memcpy(root_ptr, meta->name, len);
- *(root_ptr +=len) = '\0';
- root_ptr++;
- }
-
if (meta->org_name && meta->org_name != mysqlnd_empty_string) {
len = meta->org_name_length;
meta->org_name = memcpy(root_ptr, meta->org_name, len);
@@ -1359,6 +1399,8 @@ php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
root_ptr++;
}
+ DBG_INF_FMT("allocing root. persistent=%u", packet->persistent_alloc);
+
DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
meta->name? meta->name:"*NA*");
@@ -1382,7 +1424,7 @@ premature_end:
static
void php_mysqlnd_rset_field_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
{
- MYSQLND_PACKET_RES_FIELD *p= (MYSQLND_PACKET_RES_FIELD *) _packet;
+ MYSQLND_PACKET_RES_FIELD *p = (MYSQLND_PACKET_RES_FIELD *) _packet;
/* p->metadata was passed to us as temporal buffer */
if (!stack_allocation) {
mnd_pefree(p, p->header.persistent);
@@ -1424,11 +1466,7 @@ php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn, MYSQLND_MEMORY_POOL * result_s
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.
- */
- *buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size + 1 TSRMLS_CC);
+ *buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size TSRMLS_CC);
if (!*buffer) {
ret = FAIL;
break;
@@ -1442,11 +1480,8 @@ php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn, MYSQLND_MEMORY_POOL * result_s
/*
We have to realloc the buffer.
-
- We need a trailing \0 for the last string, in case of text-mode,
- to be able to implement read-only variables.
*/
- if (FAIL == (*buffer)->resize_chunk((*buffer), *data_size + 1 TSRMLS_CC)) {
+ if (FAIL == (*buffer)->resize_chunk((*buffer), *data_size TSRMLS_CC)) {
SET_OOM_ERROR(*conn->error_info);
ret = FAIL;
break;
@@ -1477,14 +1512,14 @@ php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn, MYSQLND_MEMORY_POOL * result_s
/* {{{ php_mysqlnd_rowp_read_binary_protocol */
enum_func_status
-php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
{
unsigned int i;
- zend_uchar * p = row_buffer->ptr;
- zend_uchar * null_ptr, bit;
- zval **current_field, **end_field, **start_field;
+ zend_uchar *p = row_buffer->ptr;
+ zend_uchar *null_ptr, bit;
+ zval *current_field, *end_field, *start_field;
DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
@@ -1501,28 +1536,20 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
bit = 4; /* first 2 bits are reserved */
for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
- DBG_INF("Directly creating zval");
- MAKE_STD_ZVAL(*current_field);
- if (!*current_field) {
- DBG_RETURN(FAIL);
- }
- }
-
- for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
enum_mysqlnd_collected_stats statistic;
zend_uchar * orig_p = p;
DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u",
- *current_field, i,
+ current_field, i,
fields_metadata[i].db, fields_metadata[i].table, fields_metadata[i].name, fields_metadata[i].type,
fields_metadata[i].flags & UNSIGNED_FLAG, fields_metadata[i].flags, fields_metadata[i].type == MYSQL_TYPE_BIT);
if (*null_ptr & bit) {
DBG_INF("It's null");
- ZVAL_NULL(*current_field);
+ ZVAL_NULL(current_field);
statistic = STAT_BINARY_TYPE_FETCHED_NULL;
} else {
enum_mysqlnd_field_types type = fields_metadata[i].type;
- mysqlnd_ps_fetch_functions[type].func(*current_field, &fields_metadata[i], 0, &p TSRMLS_CC);
+ mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], 0, &p TSRMLS_CC);
if (MYSQLND_G(collect_statistics)) {
switch (fields_metadata[i].type) {
@@ -1559,8 +1586,8 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
}
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1,
STAT_BYTES_RECEIVED_PURE_DATA_PS,
- (Z_TYPE_PP(current_field) == IS_STRING)?
- Z_STRLEN_PP(current_field) : (p - orig_p));
+ (Z_TYPE_P(current_field) == IS_STRING)?
+ Z_STRLEN_P(current_field) : (p - orig_p));
if (!((bit<<=1) & 255)) {
bit = 1; /* to the following byte */
@@ -1572,16 +1599,15 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv
}
/* }}} */
+
/* {{{ php_mysqlnd_rowp_read_text_protocol */
enum_func_status
-php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
- zend_bool as_int_or_float, zend_bool copy_data, MYSQLND_STATS * stats TSRMLS_DC)
+ zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
{
-
unsigned int i;
- zend_bool last_field_was_string = FALSE;
- zval **current_field, **end_field, **start_field;
+ zval *current_field, *end_field, *start_field;
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 */
@@ -1595,39 +1621,12 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
end_field = (start_field = fields) + field_count;
for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
- DBG_INF("Directly creating zval");
- MAKE_STD_ZVAL(*current_field);
- if (!*current_field) {
- DBG_RETURN(FAIL);
- }
- }
-
- for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
- /* Don't reverse the order. It is significant!*/
- zend_uchar *this_field_len_pos = p;
/* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
unsigned long len = php_mysqlnd_net_field_length(&p);
- if (copy_data == FALSE && current_field > start_field && last_field_was_string) {
- /*
- Normal queries:
- We have to put \0 now to the end of the previous field, if it was
- a string. IS_NULL doesn't matter. Because we have already read our
- length, then we can overwrite it in the row buffer.
- This statement terminates the previous field, not the current one.
-
- NULL_LENGTH is encoded in one byte, so we can stick a \0 there.
- Any string's length is encoded in at least one byte, so we can stick
- a \0 there.
- */
-
- *this_field_len_pos = '\0';
- }
-
/* NULL or NOT NULL, this is the question! */
if (len == MYSQLND_NULL_LENGTH) {
- ZVAL_NULL(*current_field);
- last_field_was_string = FALSE;
+ ZVAL_NULL(current_field);
} else {
#if defined(MYSQLND_STRING_TO_INT_CONVERSION)
struct st_mysqlnd_perm_bind perm_bind =
@@ -1680,7 +1679,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
#else
_atoi64((char *) p);
#endif
- ZVAL_LONG(*current_field, (long) v); /* the cast is safe */
+ ZVAL_LONG(current_field, (long) v); /* the cast is safe */
} else {
uint64_t v =
#ifndef PHP_WIN32
@@ -1700,9 +1699,9 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
#error Need fix for this architecture
#endif /* SIZEOF */
{
- ZVAL_STRINGL(*current_field, (char *)p, len, 0);
+ ZVAL_STRINGL(current_field, (char *)p, len);
} else {
- ZVAL_LONG(*current_field, (long) v); /* the cast is safe */
+ ZVAL_LONG(current_field, (long) v); /* the cast is safe */
}
}
*(p + len) = save;
@@ -1710,7 +1709,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
zend_uchar save = *(p + len);
/* We have to make it ASCIIZ temporarily */
*(p + len) = '\0';
- ZVAL_DOUBLE(*current_field, atof((char *) p));
+ ZVAL_DOUBLE(current_field, atof((char *) p));
*(p + len) = save;
} else
#endif /* MYSQLND_STRING_TO_INT_CONVERSION */
@@ -1725,33 +1724,28 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
Definitely not nice, _hackish_ :(, but works.
*/
zend_uchar *start = bit_area;
- ps_fetch_from_1_to_8_bytes(*current_field, &(fields_metadata[i]), 0, &p, len TSRMLS_CC);
+ ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, &p, len TSRMLS_CC);
/*
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
later in this function there will be an advancement.
*/
p -= len;
- if (Z_TYPE_PP(current_field) == IS_LONG) {
- bit_area += 1 + sprintf((char *)start, "%ld", Z_LVAL_PP(current_field));
- ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, copy_data);
- } else if (Z_TYPE_PP(current_field) == IS_STRING){
- memcpy(bit_area, Z_STRVAL_PP(current_field), Z_STRLEN_PP(current_field));
- bit_area += Z_STRLEN_PP(current_field);
+ if (Z_TYPE_P(current_field) == IS_LONG) {
+ bit_area += 1 + sprintf((char *)start, "%ld", Z_LVAL_P(current_field));
+ ZVAL_STRINGL(current_field, (char *) start, bit_area - start - 1);
+ } else if (Z_TYPE_P(current_field) == IS_STRING){
+ memcpy(bit_area, Z_STRVAL_P(current_field), Z_STRLEN_P(current_field));
+ bit_area += Z_STRLEN_P(current_field);
*bit_area++ = '\0';
- zval_dtor(*current_field);
- ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, copy_data);
+ zval_dtor(current_field);
+ ZVAL_STRINGL(current_field, (char *) start, bit_area - start - 1);
}
} else {
- ZVAL_STRINGL(*current_field, (char *)p, len, copy_data);
+ ZVAL_STRINGL(current_field, (char *)p, len);
}
p += len;
- last_field_was_string = TRUE;
}
}
- if (copy_data == FALSE && last_field_was_string) {
- /* Normal queries: The buffer has one more byte at the end, because we need it */
- row_buffer->ptr[data_size] = '\0';
- }
DBG_RETURN(PASS);
}
@@ -1760,13 +1754,13 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
/* {{{ php_mysqlnd_rowp_read_text_protocol_zval */
enum_func_status
-php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
{
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, FALSE, stats TSRMLS_CC);
+ ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats TSRMLS_CC);
DBG_RETURN(ret);
}
/* }}} */
@@ -1774,20 +1768,18 @@ php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
/* {{{ php_mysqlnd_rowp_read_text_protocol_c */
enum_func_status
-php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
{
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, TRUE, stats TSRMLS_CC);
+ ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats TSRMLS_CC);
DBG_RETURN(ret);
}
/* }}} */
-
-
/* {{{ php_mysqlnd_rowp_read */
/*
if normal statements => packet->fields is created by this function,
@@ -1868,7 +1860,7 @@ php_mysqlnd_rowp_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
but mostly like old-API unbuffered and thus will populate this array with
value.
*/
- packet->fields = (zval **) mnd_pecalloc(packet->field_count, sizeof(zval *),
+ packet->fields = mnd_pecalloc(packet->field_count, sizeof(zval),
packet->persistent_alloc);
}
} else {