Skip to content

Commit 6c61f15

Browse files
committed
Optimization
1 parent 90edf75 commit 6c61f15

File tree

1 file changed

+71
-100
lines changed

1 file changed

+71
-100
lines changed

ext/mysqlnd/mysqlnd_wireprotocol.c

Lines changed: 71 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include "mysqlnd_debug.h"
2828

2929
#define BAIL_IF_NO_MORE_DATA \
30-
if ((size_t)(p - begin) > packet->header.size) { \
30+
if (UNEXPECTED((size_t)(p - begin) > packet->header.size)) { \
3131
php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \
3232
goto premature_end; \
3333
} \
@@ -1148,21 +1148,20 @@ void php_mysqlnd_rset_header_free_mem(void * _packet)
11481148
}
11491149
/* }}} */
11501150

1151-
static size_t rset_field_offsets[] =
1152-
{
1153-
STRUCT_OFFSET(MYSQLND_FIELD, catalog),
1154-
STRUCT_OFFSET(MYSQLND_FIELD, catalog_length),
1155-
STRUCT_OFFSET(MYSQLND_FIELD, db),
1156-
STRUCT_OFFSET(MYSQLND_FIELD, db_length),
1157-
STRUCT_OFFSET(MYSQLND_FIELD, table),
1158-
STRUCT_OFFSET(MYSQLND_FIELD, table_length),
1159-
STRUCT_OFFSET(MYSQLND_FIELD, org_table),
1160-
STRUCT_OFFSET(MYSQLND_FIELD, org_table_length),
1161-
STRUCT_OFFSET(MYSQLND_FIELD, name),
1162-
STRUCT_OFFSET(MYSQLND_FIELD, name_length),
1163-
STRUCT_OFFSET(MYSQLND_FIELD, org_name),
1164-
STRUCT_OFFSET(MYSQLND_FIELD, org_name_length),
1165-
};
1151+
#define READ_RSET_FIELD(field_name) do { \
1152+
len = php_mysqlnd_net_field_length(&p); \
1153+
if (UNEXPECTED(len == MYSQLND_NULL_LENGTH)) { \
1154+
goto faulty_or_fake; \
1155+
} else if (len != 0) { \
1156+
meta->field_name = (const char *)p; \
1157+
meta->field_name ## _length = len; \
1158+
p += len; \
1159+
total_len += len + 1; \
1160+
} else { \
1161+
meta->field_name = mysqlnd_empty_string; \
1162+
meta->field_name ## _length = 0; \
1163+
} \
1164+
} while (0)
11661165

11671166

11681167
/* {{{ php_mysqlnd_rset_field_read */
@@ -1183,7 +1182,6 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
11831182
char *root_ptr;
11841183
zend_ulong len;
11851184
MYSQLND_FIELD *meta;
1186-
unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
11871185

11881186
DBG_ENTER("php_mysqlnd_rset_field_read");
11891187

@@ -1214,58 +1212,43 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
12141212

12151213
meta = packet->metadata;
12161214

1217-
for (i = 0; i < field_count; i += 2) {
1218-
len = php_mysqlnd_net_field_length(&p);
1219-
BAIL_IF_NO_MORE_DATA;
1220-
switch ((len)) {
1221-
case 0:
1222-
*(const char **)(((char*)meta) + rset_field_offsets[i]) = mysqlnd_empty_string;
1223-
*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
1224-
break;
1225-
case MYSQLND_NULL_LENGTH:
1226-
goto faulty_or_fake;
1227-
default:
1228-
*(const char **)(((char *)meta) + rset_field_offsets[i]) = (const char *)p;
1229-
*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
1230-
p += len;
1231-
total_len += len + 1;
1232-
break;
1233-
}
1234-
BAIL_IF_NO_MORE_DATA;
1235-
}
1215+
READ_RSET_FIELD(catalog);
1216+
READ_RSET_FIELD(db);
1217+
READ_RSET_FIELD(table);
1218+
READ_RSET_FIELD(org_table);
1219+
READ_RSET_FIELD(name);
1220+
READ_RSET_FIELD(org_name);
12361221

12371222
/* 1 byte length */
1238-
if (12 != *p) {
1223+
if (UNEXPECTED(12 != *p)) {
12391224
DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
12401225
php_error_docref(NULL, E_WARNING, "Protocol error. Server sent false length. Expected 12");
12411226
}
12421227

1228+
if ((size_t)((p - begin) + 12) > packet->header.size) {
1229+
php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__);
1230+
goto premature_end;
1231+
}
1232+
12431233
p++;
1244-
BAIL_IF_NO_MORE_DATA;
12451234

12461235
meta->charsetnr = uint2korr(p);
12471236
p += 2;
1248-
BAIL_IF_NO_MORE_DATA;
12491237

12501238
meta->length = uint4korr(p);
12511239
p += 4;
1252-
BAIL_IF_NO_MORE_DATA;
12531240

12541241
meta->type = uint1korr(p);
12551242
p += 1;
1256-
BAIL_IF_NO_MORE_DATA;
12571243

12581244
meta->flags = uint2korr(p);
12591245
p += 2;
1260-
BAIL_IF_NO_MORE_DATA;
12611246

12621247
meta->decimals = uint1korr(p);
12631248
p += 1;
1264-
BAIL_IF_NO_MORE_DATA;
12651249

12661250
/* 2 byte filler */
12671251
p +=2;
1268-
BAIL_IF_NO_MORE_DATA;
12691252

12701253
/* Should we set NUM_FLAG (libmysql does it) ? */
12711254
if (
@@ -1289,62 +1272,52 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
12891272
BAIL_IF_NO_MORE_DATA;
12901273
DBG_INF_FMT("Def found, length %lu", len);
12911274
meta->def = packet->memory_pool->get_chunk(packet->memory_pool, len + 1);
1292-
if (!meta->def) {
1293-
SET_OOM_ERROR(error_info);
1294-
DBG_RETURN(FAIL);
1295-
}
12961275
memcpy(meta->def, p, len);
12971276
meta->def[len] = '\0';
12981277
meta->def_length = len;
12991278
p += len;
13001279
}
13011280

13021281
root_ptr = meta->root = packet->memory_pool->get_chunk(packet->memory_pool, total_len);
1303-
if (!root_ptr) {
1304-
SET_OOM_ERROR(error_info);
1305-
DBG_RETURN(FAIL);
1306-
}
1307-
13081282
meta->root_len = total_len;
13091283

1310-
if (meta->name != mysqlnd_empty_string) {
1284+
if (EXPECTED(meta->name_length != 0)) {
13111285
meta->sname = zend_string_init_interned(meta->name, meta->name_length, 0);
1286+
meta->name = ZSTR_VAL(meta->sname);
13121287
} else {
13131288
meta->sname = ZSTR_EMPTY_ALLOC();
13141289
}
1315-
meta->name = ZSTR_VAL(meta->sname);
1316-
meta->name_length = ZSTR_LEN(meta->sname);
13171290

13181291
/* Now do allocs */
1319-
if (meta->catalog && meta->catalog != mysqlnd_empty_string) {
1292+
if (meta->catalog_length != 0) {
13201293
len = meta->catalog_length;
13211294
meta->catalog = memcpy(root_ptr, meta->catalog, len);
13221295
*(root_ptr +=len) = '\0';
13231296
root_ptr++;
13241297
}
13251298

1326-
if (meta->db && meta->db != mysqlnd_empty_string) {
1299+
if (meta->db_length != 0) {
13271300
len = meta->db_length;
13281301
meta->db = memcpy(root_ptr, meta->db, len);
13291302
*(root_ptr +=len) = '\0';
13301303
root_ptr++;
13311304
}
13321305

1333-
if (meta->table && meta->table != mysqlnd_empty_string) {
1306+
if (meta->table_length != 0) {
13341307
len = meta->table_length;
13351308
meta->table = memcpy(root_ptr, meta->table, len);
13361309
*(root_ptr +=len) = '\0';
13371310
root_ptr++;
13381311
}
13391312

1340-
if (meta->org_table && meta->org_table != mysqlnd_empty_string) {
1313+
if (meta->org_table_length != 0) {
13411314
len = meta->org_table_length;
13421315
meta->org_table = memcpy(root_ptr, meta->org_table, len);
13431316
*(root_ptr +=len) = '\0';
13441317
root_ptr++;
13451318
}
13461319

1347-
if (meta->org_name && meta->org_name != mysqlnd_empty_string) {
1320+
if (meta->org_name_length != 0) {
13481321
len = meta->org_name_length;
13491322
meta->org_name = memcpy(root_ptr, meta->org_name, len);
13501323
*(root_ptr +=len) = '\0';
@@ -1385,7 +1358,6 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
13851358
enum_func_status ret = PASS;
13861359
MYSQLND_PACKET_HEADER header;
13871360
zend_uchar * p = NULL;
1388-
zend_bool first_iteration = TRUE;
13891361
size_t prealloc_more_bytes;
13901362

13911363
DBG_ENTER("php_mysqlnd_read_row_ex");
@@ -1405,49 +1377,48 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
14051377
prealloc_more_bytes = 1;
14061378

14071379
*data_size = 0;
1408-
while (1) {
1409-
if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
1410-
ret = FAIL;
1411-
break;
1412-
}
1413-
1380+
if (UNEXPECTED(FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info))) {
1381+
ret = FAIL;
1382+
} else {
14141383
*data_size += header.size;
1384+
buffer->ptr = pool->get_chunk(pool, *data_size + prealloc_more_bytes);
1385+
p = buffer->ptr;
14151386

1416-
if (first_iteration) {
1417-
first_iteration = FALSE;
1418-
buffer->ptr = pool->get_chunk(pool, *data_size + prealloc_more_bytes);
1419-
if (!buffer->ptr) {
1420-
ret = FAIL;
1421-
break;
1422-
}
1423-
p = buffer->ptr;
1424-
} else if (!first_iteration) {
1425-
/* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
1426-
if (!header.size) {
1427-
break;
1428-
}
1429-
1430-
/*
1431-
We have to realloc the buffer.
1432-
*/
1433-
buffer->ptr = pool->resize_chunk(pool, buffer->ptr, *data_size - header.size, *data_size + prealloc_more_bytes);
1434-
if (!buffer->ptr) {
1435-
SET_OOM_ERROR(error_info);
1436-
ret = FAIL;
1437-
break;
1438-
}
1439-
/* The position could have changed, recalculate */
1440-
p = (zend_uchar *) buffer->ptr + (*data_size - header.size);
1441-
}
1442-
1443-
if (PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info))) {
1387+
if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
14441388
DBG_ERR("Empty row packet body");
14451389
php_error(E_WARNING, "Empty row packet body");
1446-
break;
1447-
}
1390+
} else {
1391+
while (header.size >= MYSQLND_MAX_PACKET_SIZE) {
1392+
if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
1393+
ret = FAIL;
1394+
break;
1395+
}
14481396

1449-
if (header.size < MYSQLND_MAX_PACKET_SIZE) {
1450-
break;
1397+
*data_size += header.size;
1398+
1399+
/* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
1400+
if (!header.size) {
1401+
break;
1402+
}
1403+
1404+
/*
1405+
We have to realloc the buffer.
1406+
*/
1407+
buffer->ptr = pool->resize_chunk(pool, buffer->ptr, *data_size - header.size, *data_size + prealloc_more_bytes);
1408+
if (!buffer->ptr) {
1409+
SET_OOM_ERROR(error_info);
1410+
ret = FAIL;
1411+
break;
1412+
}
1413+
/* The position could have changed, recalculate */
1414+
p = (zend_uchar *) buffer->ptr + (*data_size - header.size);
1415+
1416+
if (PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info))) {
1417+
DBG_ERR("Empty row packet body");
1418+
php_error(E_WARNING, "Empty row packet body");
1419+
break;
1420+
}
1421+
}
14511422
}
14521423
}
14531424
if (ret == FAIL && buffer->ptr) {

0 commit comments

Comments
 (0)