Skip to content

Commit 890e4ca

Browse files
committed
Drop support for max_length in mysqli_fetch_fields()
Retain the field, but always populate it with zero. This was already the case for PS without length updating. max_length has nothing lost in the field metadata -- it is a property of the specific result set, and requires scanning the whole result set to compute. PHP itself never uses max_length with mysqlnd, it is only exposed in the raw mysqli API. Keeping it for just that purpose is not worthwhile given the costs involved. People who actually need this for some reason can easily calculate it themselves, while making it obvious that the calculation requires a full result set scan.
1 parent 95a4e1e commit 890e4ca

10 files changed

+20
-294
lines changed

UPGRADING

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ PHP 8.1 UPGRADE NOTES
1919
1. Backward Incompatible Changes
2020
========================================
2121

22+
- MySQLi:
23+
. mysqli_fetch_fields() and mysqli_fetch_field_direct() will now always return
24+
zero for max_length. You can compute this information by iterating over the
25+
result set and taking the maximum length. This is what PHP was doing
26+
internally previously.
27+
. The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has an effect.
28+
2229
- Standard:
2330
. version_compare() no longer accepts undocumented operator abbreviations.
2431

ext/mysqli/mysqli_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ static void php_add_field_properties(zval *value, const MYSQL_FIELD *field)
11161116
*/
11171117
add_property_string(value, "catalog", "def");
11181118

1119-
add_property_long(value, "max_length", field->max_length);
1119+
add_property_long(value, "max_length", 0);
11201120
add_property_long(value, "length", field->length);
11211121
add_property_long(value, "charsetnr", field->charsetnr);
11221122
add_property_long(value, "flags", field->flags);

ext/mysqli/tests/mysqli_fetch_field.phpt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ require_once('skipifconnectfailure.inc');
3535
printf("[004] Expecting charset %s/%d got %d\n",
3636
$charsetInfo->charset, $charsetInfo->number, $tmp->charsetnr);
3737
}
38-
if ($tmp->length != $charsetInfo->max_length) {
39-
printf("[005] Expecting length %d got %d\n",
40-
$charsetInfo->max_length, $tmp->max_length);
41-
}
4238
if ($tmp->db != $db) {
4339
printf("011] Expecting database '%s' got '%s'\n",
4440
$db, $tmp->db);
@@ -97,7 +93,7 @@ object(stdClass)#%d (13) {
9793
["catalog"]=>
9894
string(%d) "%s"
9995
["max_length"]=>
100-
int(1)
96+
int(0)
10197
["length"]=>
10298
int(11)
10399
["charsetnr"]=>
@@ -159,7 +155,7 @@ object(stdClass)#%d (13) {
159155
["catalog"]=>
160156
string(%d) "%s"
161157
["max_length"]=>
162-
int(1)
158+
int(0)
163159
["length"]=>
164160
int(11)
165161
["charsetnr"]=>

ext/mysqli/tests/mysqli_fetch_field_oo.phpt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ require_once('skipifconnectfailure.inc');
4242
printf("[005] Expecting charset %s/%d got %d\n",
4343
$charsetInfo->charset, $charsetInfo->number, $tmp->charsetnr);
4444
}
45-
if ($tmp->length != $charsetInfo->max_length) {
46-
printf("[006] Expecting length %d got %d\n",
47-
$charsetInfo->max_length, $tmp->max_length);
48-
}
4945
if ($tmp->db != $db) {
5046
printf("[007] Expecting database '%s' got '%s'\n",
5147
$db, $tmp->db);
@@ -86,7 +82,7 @@ object(stdClass)#%d (13) {
8682
["catalog"]=>
8783
string(%d) "%s"
8884
["max_length"]=>
89-
int(1)
85+
int(0)
9086
["length"]=>
9187
int(11)
9288
["charsetnr"]=>

ext/mysqli/tests/mysqli_fetch_fields.phpt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@ require_once('skipifconnectfailure.inc');
3535
$charsetInfo->charset,
3636
$charsetInfo->number, $field->charsetnr);
3737
}
38-
if ($field->length != $charsetInfo->max_length) {
39-
printf("[005] Expecting length %d got %d\n",
40-
$charsetInfo->max_length,
41-
$field->max_length);
42-
}
4338
break;
4439
}
4540
}
@@ -76,7 +71,7 @@ object(stdClass)#%d (13) {
7671
["catalog"]=>
7772
string(%d) "%s"
7873
["max_length"]=>
79-
int(1)
74+
int(0)
8075
["length"]=>
8176
int(11)
8277
["charsetnr"]=>
@@ -104,7 +99,7 @@ object(stdClass)#%d (13) {
10499
["catalog"]=>
105100
string(%d) "%s"
106101
["max_length"]=>
107-
int(1)
102+
int(0)
108103
["length"]=>
109104
int(%d)
110105
["charsetnr"]=>

ext/mysqli/tests/mysqli_stmt_attr_set.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ require_once("connect.inc");
6161
$res->close();
6262
$stmt->close();
6363

64-
// expecting max_length to _be_ set
64+
// MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH is no longer supported, expect no change in behavior.
6565
$stmt = mysqli_stmt_init($link);
6666
$stmt->prepare("SELECT label FROM test");
6767
var_dump($stmt->attr_set(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, 1));
@@ -75,8 +75,8 @@ require_once("connect.inc");
7575
$max_lengths = array();
7676
foreach ($fields as $k => $meta) {
7777
$max_lengths[$meta->name] = $meta->max_length;
78-
if ($meta->max_length === 0)
79-
printf("[008] max_length should be set (!= 0), got %s for field %s\n", $meta->max_length, $meta->name);
78+
if ($meta->max_length !== 0)
79+
printf("[008] max_length should be not set (= 0), got %s for field %s\n", $meta->max_length, $meta->name);
8080
}
8181
$res->close();
8282
$stmt->close();

ext/mysqlnd/mysqlnd_ps.c

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -766,22 +766,6 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, const unsign
766766
if (PASS != rc) {
767767
DBG_RETURN(FAIL);
768768
}
769-
result->stored_data->initialized_rows++;
770-
if (stmt->update_max_length) {
771-
for (i = 0; i < result->field_count; i++) {
772-
/*
773-
NULL fields are 0 length, 0 is not more than 0
774-
String of zero size, definitely can't be the next max_length.
775-
Thus for NULL and zero-length we are quite efficient.
776-
*/
777-
if (Z_TYPE(current_row[i]) == IS_STRING) {
778-
zend_ulong len = Z_STRLEN(current_row[i]);
779-
if (meta->fields[i].max_length < len) {
780-
meta->fields[i].max_length = len;
781-
}
782-
}
783-
}
784-
}
785769
}
786770

787771
for (i = 0; i < result->field_count; i++) {
@@ -820,7 +804,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, const unsi
820804
MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
821805
MYSQLND_PACKET_ROW * row_packet;
822806
MYSQLND_CONN_DATA * conn = result->conn;
823-
const MYSQLND_RES_METADATA * const meta = result->meta;
824807
void *checkpoint;
825808

826809
DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
@@ -873,11 +856,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, const unsi
873856
zval *resultzv = &stmt->result_bind[i].zv;
874857
if (stmt->result_bind[i].bound == TRUE) {
875858
zval *data = &result->unbuf->last_row_data[i];
876-
877-
if (Z_TYPE_P(data) == IS_STRING && (meta->fields[i].max_length < (zend_ulong) Z_STRLEN_P(data))){
878-
meta->fields[i].max_length = Z_STRLEN_P(data);
879-
}
880-
881859
ZEND_TRY_ASSIGN_VALUE_EX(resultzv, data, 0);
882860
/* copied data, thus also the ownership. Thus null data */
883861
ZVAL_NULL(data);
@@ -1026,7 +1004,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
10261004

10271005
UPSERT_STATUS_RESET(stmt->upsert_status);
10281006
if (PASS == (ret = PACKET_READ(conn, row_packet)) && !row_packet->eof) {
1029-
const MYSQLND_RES_METADATA * const meta = result->meta;
10301007
unsigned int i, field_count = result->field_count;
10311008

10321009
if (stmt->result_bind) {
@@ -1055,11 +1032,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
10551032
Z_TYPE_P(data), Z_REFCOUNTED(stmt->result_bind[i].zv)?
10561033
Z_REFCOUNT(stmt->result_bind[i].zv) : 0);
10571034

1058-
if (Z_TYPE_P(data) == IS_STRING &&
1059-
(meta->fields[i].max_length < (zend_ulong) Z_STRLEN_P(data))) {
1060-
meta->fields[i].max_length = Z_STRLEN_P(data);
1061-
}
1062-
10631035
ZEND_TRY_ASSIGN_VALUE_EX(resultzv, data, 0);
10641036
/* copied data, thus also the ownership. Thus null data */
10651037
ZVAL_NULL(data);
@@ -1744,13 +1716,6 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s)
17441716
DBG_RETURN(NULL);
17451717
}
17461718

1747-
if (stmt->update_max_length && stmt->result->stored_data) {
1748-
/* stored result, we have to update the max_length before we clone the meta data :( */
1749-
stmt->result->stored_data->m.initialize_result_set_rest(stmt->result->stored_data,
1750-
stmt->result->meta,
1751-
conn->stats,
1752-
conn->options->int_and_float_native);
1753-
}
17541719
/*
17551720
TODO: This implementation is kind of a hack,
17561721
find a better way to do it. In different functions I have put

0 commit comments

Comments
 (0)