Skip to content

Commit 33e9049

Browse files
committed
MySQLnd: Clean up and optimize mysqlnd result set handling
This is a larger overhaul of the mysqlnd result set infrastructure: * Drop support for two different types of buffered results sets ("c" and "zval"). Possibly these made sense at some earlier time, but now (with minor adjustments) one option is strictly worse than the other. Buffered result sets already buffer the full row packets, from which zvals can be decoded. The "zval" style additionally also buffered the decoded zvals. As result sets, even buffered ones, are generally only traversed once, this just ends up wasting memory. Now, a potentially useful variation here would be to buffer the decoded zvals instead of the row packets, but that's not what the code was doing. * To make it really strictly better, pre-allocate the zval row buffer and reuse it for all rows. Previously the "c" style always allocated a new buffer for each row. * The fetch_row API now provides a populated zval[]. The task of populating an array is deferred to fetch_row_into, which also avoids duplicating this code in multiple places. The fetch_row_c API is also implemented on top of fetch_row now, rather than duplicating large parts of the code. * The row fetching code for prepared statements and normal result sets has been mostly merged. These already used the same infrastructure, but prepared statements used separate row fetching functions that were nearly the same as the normal ones. This requires passing the stmt into the result set, rather than just a flag. The only part that remains separate is reading of unbuffered results in the presence of PS cursors.
1 parent 890e4ca commit 33e9049

17 files changed

+257
-1073
lines changed

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ PHP 8.1 UPGRADE NOTES
2525
result set and taking the maximum length. This is what PHP was doing
2626
internally previously.
2727
. The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has an effect.
28+
. The MYSQLI_STORE_RESULT_COPY_DATA option no longer has an effect.
29+
30+
- MySQLnd:
31+
. The mysqlnd.fetch_copy_data ini setting has been removed. However, this
32+
should not result in user-visible behavior changes.
2833

2934
- Standard:
3035
. version_compare() no longer accepts undocumented operator abbreviations.

ext/mysqli/mysqli_api.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,7 +1459,7 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_method)
14591459
We create always persistent, as if the user want to connect
14601460
to p:somehost, we can't convert the handle then
14611461
*/
1462-
if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, TRUE)))
1462+
if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, TRUE)))
14631463
#endif
14641464
{
14651465
efree(mysql);
@@ -2527,11 +2527,7 @@ PHP_FUNCTION(mysqli_store_result)
25272527
RETURN_THROWS();
25282528
}
25292529
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
2530-
#ifdef MYSQLI_USE_MYSQLND
2531-
result = flags & MYSQLI_STORE_RESULT_COPY_DATA? mysqlnd_store_result_ofs(mysql->mysql) : mysqlnd_store_result(mysql->mysql);
2532-
#else
25332530
result = mysql_store_result(mysql->mysql);
2534-
#endif
25352531
if (!result) {
25362532
MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
25372533
RETURN_FALSE;

ext/mysqli/mysqli_nonapi.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne
245245
#ifndef MYSQLI_USE_MYSQLND
246246
if (!(mysql->mysql = mysql_init(NULL))) {
247247
#else
248-
if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA, persistent))) {
248+
if (!(mysql->mysql = mysqlnd_init(MYSQLND_CLIENT_NO_FLAG, persistent))) {
249249
#endif
250250
goto err;
251251
}
@@ -307,7 +307,7 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne
307307
}
308308
}
309309
if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len,
310-
port, socket, flags, MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA) == NULL)
310+
port, socket, flags, MYSQLND_CLIENT_NO_FLAG) == NULL)
311311
#endif
312312
{
313313
/* Save error messages - for mysqli_connect_error() & mysqli_connect_errno() */
@@ -689,12 +689,7 @@ PHP_FUNCTION(mysqli_query)
689689
switch (resultmode & ~MYSQLI_ASYNC) {
690690
#endif
691691
case MYSQLI_STORE_RESULT:
692-
#ifdef MYSQLI_USE_MYSQLND
693-
if (resultmode & MYSQLI_STORE_RESULT_COPY_DATA) {
694-
result = mysqlnd_store_result_ofs(mysql->mysql);
695-
} else
696-
#endif
697-
result = mysql_store_result(mysql->mysql);
692+
result = mysql_store_result(mysql->mysql);
698693
break;
699694
case MYSQLI_USE_RESULT:
700695
result = mysql_use_result(mysql->mysql);

ext/mysqli/mysqli_warning.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ MYSQLI_WARNING * php_get_warnings(MYSQLND_CONN_DATA * mysql)
125125
return NULL;
126126
}
127127

128-
result = mysql->m->use_result(mysql, 0);
128+
result = mysql->m->use_result(mysql);
129129

130130
for (;;) {
131131
zval *entry;

ext/mysqlnd/mysqlnd.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ PHPAPI void mysqlnd_debug(const char *mode);
112112

113113
PHPAPI enum_func_status mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num);
114114

115-
#define mysqlnd_use_result(conn) ((conn)->data)->m->use_result((conn)->data, 0)
116-
#define mysqlnd_store_result(conn) ((conn)->data)->m->store_result((conn)->data, MYSQLND_STORE_NO_COPY)
117-
#define mysqlnd_store_result_ofs(conn) ((conn)->data)->m->store_result((conn)->data, MYSQLND_STORE_COPY)
115+
#define mysqlnd_use_result(conn) ((conn)->data)->m->use_result((conn)->data)
116+
#define mysqlnd_store_result(conn) ((conn)->data)->m->store_result((conn)->data)
118117
#define mysqlnd_next_result(conn) ((conn)->data)->m->next_result((conn)->data)
119118
#define mysqlnd_more_results(conn) ((conn)->data)->m->more_results((conn)->data)
120119
#define mysqlnd_free_result(r,e_or_i) ((MYSQLND_RES*)r)->m.free_result(((MYSQLND_RES*)(r)), (e_or_i))
@@ -311,7 +310,6 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqlnd)
311310
zend_long debug_calloc_fail_threshold;
312311
zend_long debug_realloc_fail_threshold;
313312
char * sha256_server_public_key;
314-
zend_bool fetch_data_copy;
315313
zend_bool collect_statistics;
316314
zend_bool collect_memory_statistics;
317315
ZEND_END_MODULE_GLOBALS(mysqlnd)

ext/mysqlnd/mysqlnd_connection.c

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, execute_init_commands)(MYSQLND_CONN_DATA * con
456456
}
457457
do {
458458
if (conn->last_query_type == QUERY_SELECT) {
459-
MYSQLND_RES * result = conn->m->use_result(conn, 0);
459+
MYSQLND_RES * result = conn->m->use_result(conn);
460460
if (result) {
461461
result->m.free_result(result, TRUE);
462462
}
@@ -928,7 +928,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, list_method)(MYSQLND_CONN_DATA * conn, const c
928928
}
929929

930930
if (PASS == conn->m->query(conn, show_query, show_query_len)) {
931-
result = conn->m->store_result(conn, MYSQLND_STORE_NO_COPY);
931+
result = conn->m->store_result(conn);
932932
}
933933
if (show_query != query) {
934934
mnd_sprintf_free(show_query);
@@ -1810,7 +1810,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d)(MYSQLND_CONN_DATA * cons
18101810

18111811
/* {{{ mysqlnd_conn_data::use_result */
18121812
static MYSQLND_RES *
1813-
MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags)
1813+
MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn)
18141814
{
18151815
const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), use_result);
18161816
MYSQLND_RES * result = NULL;
@@ -1852,7 +1852,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn, co
18521852

18531853
/* {{{ mysqlnd_conn_data::store_result */
18541854
static MYSQLND_RES *
1855-
MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags)
1855+
MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn)
18561856
{
18571857
const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), store_result);
18581858
MYSQLND_RES * result = NULL;
@@ -1862,7 +1862,6 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn,
18621862

18631863
if (PASS == conn->m->local_tx_start(conn, this_func)) {
18641864
do {
1865-
unsigned int f = flags;
18661865
if (!conn->current_result) {
18671866
break;
18681867
}
@@ -1875,25 +1874,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn,
18751874
}
18761875

18771876
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
1878-
1879-
/* overwrite */
1880-
if ((conn->m->get_client_api_capabilities(conn) & MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA)) {
1881-
if (MYSQLND_G(fetch_data_copy)) {
1882-
f &= ~MYSQLND_STORE_NO_COPY;
1883-
f |= MYSQLND_STORE_COPY;
1884-
}
1885-
} else {
1886-
/* if for some reason PDO borks something */
1887-
if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) {
1888-
f |= MYSQLND_STORE_COPY;
1889-
}
1890-
}
1891-
if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) {
1892-
SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Unknown fetch mode");
1893-
DBG_ERR("Unknown fetch mode");
1894-
break;
1895-
}
1896-
result = conn->current_result->m.store_result(conn->current_result, conn, f);
1877+
result = conn->current_result->m.store_result(conn->current_result, conn, NULL);
18971878
if (!result) {
18981879
conn->current_result->m.free_result(conn->current_result, TRUE);
18991880
}

ext/mysqlnd/mysqlnd_enum_n_def.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -686,18 +686,6 @@ enum php_mysqlnd_server_command
686686
#define MYSQLND_REFRESH_BACKUP_LOG 0x200000L
687687

688688

689-
#define MYSQLND_STORE_PS 1
690-
#define MYSQLND_STORE_NO_COPY 2
691-
#define MYSQLND_STORE_COPY 4
692-
693-
enum mysqlnd_buffered_type
694-
{
695-
MYSQLND_BUFFERED_TYPE_ZVAL = 1,
696-
MYSQLND_BUFFERED_TYPE_C
697-
};
698-
699-
700689
#define MYSQLND_CLIENT_NO_FLAG 0
701-
#define MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA 1
702690

703691
#endif /* MYSQLND_ENUM_N_DEF_H */

ext/mysqlnd/mysqlnd_ext_plugin.c

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,30 +83,16 @@ mysqlnd_plugin__get_plugin_result_unbuffered_data(const MYSQLND_RES_UNBUFFERED *
8383
}
8484
/* }}} */
8585

86-
87-
/* {{{ _mysqlnd_plugin__get_plugin_result_buffered_data */
88-
static void **
89-
mysqlnd_plugin__get_plugin_result_buffered_data_zval(const MYSQLND_RES_BUFFERED_ZVAL * result, const unsigned int plugin_id)
90-
{
91-
DBG_ENTER("_mysqlnd_plugin__get_plugin_result_data");
92-
DBG_INF_FMT("plugin_id=%u", plugin_id);
93-
if (!result || plugin_id >= mysqlnd_plugin_count()) {
94-
return NULL;
95-
}
96-
DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED_ZVAL) + plugin_id * sizeof(void *)));
97-
}
98-
/* }}} */
99-
10086
/* {{{ mysqlnd_plugin__get_plugin_result_buffered_data */
10187
static void **
102-
mysqlnd_plugin__get_plugin_result_buffered_data_c(const MYSQLND_RES_BUFFERED_C * result, const unsigned int plugin_id)
88+
mysqlnd_plugin__get_plugin_result_buffered_data(const MYSQLND_RES_BUFFERED * result, const unsigned int plugin_id)
10389
{
10490
DBG_ENTER("mysqlnd_plugin__get_plugin_result_data");
10591
DBG_INF_FMT("plugin_id=%u", plugin_id);
10692
if (!result || plugin_id >= mysqlnd_plugin_count()) {
10793
return NULL;
10894
}
109-
DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED_C) + plugin_id * sizeof(void *)));
95+
DBG_RETURN((void *)((char *)result + sizeof(MYSQLND_RES_BUFFERED) + plugin_id * sizeof(void *)));
11096
}
11197
/* }}} */
11298

@@ -172,8 +158,7 @@ struct st_mysqlnd_plugin__plugin_area_getters mysqlnd_plugin_area_getters =
172158
mysqlnd_plugin__get_plugin_connection_data_data,
173159
mysqlnd_plugin__get_plugin_result_data,
174160
mysqlnd_plugin__get_plugin_result_unbuffered_data,
175-
mysqlnd_plugin__get_plugin_result_buffered_data_zval,
176-
mysqlnd_plugin__get_plugin_result_buffered_data_c,
161+
mysqlnd_plugin__get_plugin_result_buffered_data,
177162
mysqlnd_plugin__get_plugin_stmt_data,
178163
mysqlnd_plugin__get_plugin_protocol_data,
179164
mysqlnd_plugin__get_plugin_pfc_data,

ext/mysqlnd/mysqlnd_ext_plugin.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ struct st_mysqlnd_plugin__plugin_area_getters
2525
void ** (*get_connection_data_area)(const MYSQLND_CONN_DATA * conn, const unsigned int plugin_id);
2626
void ** (*get_result_area)(const MYSQLND_RES * result, const unsigned int plugin_id);
2727
void ** (*get_unbuffered_area)(const MYSQLND_RES_UNBUFFERED * result, const unsigned int plugin_id);
28-
void ** (*get_result_buffered_area)(const MYSQLND_RES_BUFFERED_ZVAL * result, const unsigned int plugin_id);
29-
void ** (*get_result_buffered_aread_c)(const MYSQLND_RES_BUFFERED_C * result, const unsigned int plugin_id);
28+
void ** (*get_result_buffered_aread)(const MYSQLND_RES_BUFFERED * result, const unsigned int plugin_id);
3029
void ** (*get_stmt_area)(const MYSQLND_STMT * stmt, const unsigned int plugin_id);
3130
void ** (*get_protocol_decoder_area)(const MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * factory, const unsigned int plugin_id);
3231
void ** (*get_pfc_area)(const MYSQLND_PFC * pfc, const unsigned int plugin_id);
@@ -39,8 +38,7 @@ PHPAPI extern struct st_mysqlnd_plugin__plugin_area_getters mysqlnd_plugin_area_
3938
#define mysqlnd_plugin_get_plugin_connection_data_data(c, p_id) mysqlnd_plugin_area_getters.get_connection_data_area((c), (p_id))
4039
#define mysqlnd_plugin_get_plugin_result_data(res, p_id) mysqlnd_plugin_area_getters.get_result_area((res), (p_id))
4140
#define mysqlnd_plugin_get_plugin_result_unbuffered_data(res, p_id) mysqlnd_plugin_area_getters.get_unbuffered_area((res), (p_id))
42-
#define mysqlnd_plugin_get_plugin_result_buffered_data_zval(res, p_id) mysqlnd_plugin_area_getters.get_result_buffered_area((res), (p_id))
43-
#define mysqlnd_plugin_get_plugin_result_buffered_data_c(res, p_id) mysqlnd_plugin_area_getters.get_result_buffered_aread_c((res), (p_id))
41+
#define mysqlnd_plugin_get_plugin_result_buffered_data_c(res, p_id) mysqlnd_plugin_area_getters.get_result_buffered_aread((res), (p_id))
4442
#define mysqlnd_plugin_get_plugin_stmt_data(stmt, p_id) mysqlnd_plugin_area_getters.get_stmt_area((stmt), (p_id))
4543
#define mysqlnd_plugin_get_plugin_protocol_data(proto, p_id) mysqlnd_plugin_area_getters.get_protocol_decoder_area((proto), (p_id))
4644
#define mysqlnd_plugin_get_plugin_pfc_data(pfc, p_id) mysqlnd_plugin_area_getters.get_pfc_area((pfc), (p_id))

0 commit comments

Comments
 (0)