Skip to content

Commit 315f3f8

Browse files
committed
Fixed bug #67983
We need to check the BIT case first, otherwise it will get skipped in INT_AND_FLOAT_NATIVE mode.
1 parent 118ff03 commit 315f3f8

File tree

3 files changed

+62
-22
lines changed

3 files changed

+62
-22
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ PHP NEWS
55
- Core:
66
. Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita)
77

8+
- MySQLi:
9+
. Fixed bug #67983 (mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to
10+
interpret bit columns). (Nikita)
11+
812
07 Jan 2021, PHP 7.4.14
913

1014
- Core:

ext/mysqli/tests/bug67983.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Bug #67983: mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to interpret bit columns
3+
--SKIPIF--
4+
<?php
5+
require_once('skipif.inc');
6+
require_once('skipifconnectfailure.inc');
7+
if (!$IS_MYSQLND) {
8+
die("skip mysqlnd only test");
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
require_once("connect.inc");
15+
16+
$connection = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
17+
18+
mysqli_options($connection, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
19+
20+
mysqli_set_charset($connection, 'utf8');
21+
mysqli_query($connection, 'DROP TABLE IF EXISTS test');
22+
mysqli_query($connection, 'CREATE TABLE test (id BIT(8))');
23+
mysqli_query($connection, 'INSERT INTO test VALUES (0), (1), (42)');
24+
25+
$res = mysqli_query($connection, 'SELECT * FROM test');
26+
27+
while ($result = mysqli_fetch_assoc($res)) {
28+
var_dump($result['id']);
29+
}
30+
31+
?>
32+
--EXPECT--
33+
int(0)
34+
int(1)
35+
int(42)

ext/mysqlnd/mysqlnd_wireprotocol.c

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,8 +1616,28 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
16161616
}
16171617
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
16181618
}
1619+
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
1620+
/*
1621+
BIT fields are specially handled. As they come as bit mask, they have
1622+
to be converted to human-readable representation.
1623+
*/
1624+
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
1625+
/*
1626+
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
1627+
later in this function there will be an advancement.
1628+
*/
1629+
p -= len;
1630+
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
1631+
/* we are using the text protocol, so convert to string */
1632+
char tmp[22];
1633+
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
1634+
ZVAL_STRINGL(current_field, tmp, tmp_len);
1635+
} else if (Z_TYPE_P(current_field) == IS_STRING) {
1636+
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
1637+
}
1638+
}
16191639
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
1620-
if (as_int_or_float && perm_bind.php_type == IS_LONG) {
1640+
else if (as_int_or_float && perm_bind.php_type == IS_LONG) {
16211641
zend_uchar save = *(p + len);
16221642
/* We have to make it ASCIIZ temporarily */
16231643
*(p + len) = '\0';
@@ -1661,28 +1681,9 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
16611681
*(p + len) = '\0';
16621682
ZVAL_DOUBLE(current_field, atof((char *) p));
16631683
*(p + len) = save;
1664-
} else
1684+
}
16651685
#endif /* MYSQLND_STRING_TO_INT_CONVERSION */
1666-
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
1667-
/*
1668-
BIT fields are specially handled. As they come as bit mask, they have
1669-
to be converted to human-readable representation.
1670-
*/
1671-
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
1672-
/*
1673-
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
1674-
later in this function there will be an advancement.
1675-
*/
1676-
p -= len;
1677-
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
1678-
/* we are using the text protocol, so convert to string */
1679-
char tmp[22];
1680-
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
1681-
ZVAL_STRINGL(current_field, tmp, tmp_len);
1682-
} else if (Z_TYPE_P(current_field) == IS_STRING) {
1683-
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
1684-
}
1685-
} else if (len == 0) {
1686+
else if (len == 0) {
16861687
ZVAL_EMPTY_STRING(current_field);
16871688
} else if (len == 1) {
16881689
ZVAL_INTERNED_STR(current_field, ZSTR_CHAR((zend_uchar)*(char *)p));

0 commit comments

Comments
 (0)