diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-12-16 10:52:27 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-12-16 10:52:27 +0100 |
commit | 315f3f8dc9b3ba3639c9284301933286fc99a825 (patch) | |
tree | 6e22a06c5fde491977e46d4ec57228de00bcd506 | |
parent | 118ff03335d67c19817ff83d89e634fcd39275ff (diff) | |
download | php-git-315f3f8dc9b3ba3639c9284301933286fc99a825.tar.gz |
Fixed bug #67983
We need to check the BIT case first, otherwise it will get skipped
in INT_AND_FLOAT_NATIVE mode.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | ext/mysqli/tests/bug67983.phpt | 35 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 45 |
3 files changed, 62 insertions, 22 deletions
@@ -5,6 +5,10 @@ PHP NEWS - Core: . Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita) +- MySQLi: + . Fixed bug #67983 (mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to + interpret bit columns). (Nikita) + 07 Jan 2021, PHP 7.4.14 - Core: diff --git a/ext/mysqli/tests/bug67983.phpt b/ext/mysqli/tests/bug67983.phpt new file mode 100644 index 0000000000..a72501c076 --- /dev/null +++ b/ext/mysqli/tests/bug67983.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #67983: mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to interpret bit columns +--SKIPIF-- +<?php +require_once('skipif.inc'); +require_once('skipifconnectfailure.inc'); +if (!$IS_MYSQLND) { + die("skip mysqlnd only test"); +} +?> +--FILE-- +<?php + +require_once("connect.inc"); + +$connection = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket); + +mysqli_options($connection, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true); + +mysqli_set_charset($connection, 'utf8'); +mysqli_query($connection, 'DROP TABLE IF EXISTS test'); +mysqli_query($connection, 'CREATE TABLE test (id BIT(8))'); +mysqli_query($connection, 'INSERT INTO test VALUES (0), (1), (42)'); + +$res = mysqli_query($connection, 'SELECT * FROM test'); + +while ($result = mysqli_fetch_assoc($res)) { + var_dump($result['id']); +} + +?> +--EXPECT-- +int(0) +int(1) +int(42) diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 98de05455e..216f420698 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -1616,8 +1616,28 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * } MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len); } + if (fields_metadata[i].type == MYSQL_TYPE_BIT) { + /* + BIT fields are specially handled. As they come as bit mask, they have + to be converted to human-readable representation. + */ + ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len); + /* + 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_P(current_field) == IS_LONG && !as_int_or_float) { + /* we are using the text protocol, so convert to string */ + char tmp[22]; + const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field)); + ZVAL_STRINGL(current_field, tmp, tmp_len); + } else if (Z_TYPE_P(current_field) == IS_STRING) { + /* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */ + } + } #ifdef MYSQLND_STRING_TO_INT_CONVERSION - if (as_int_or_float && perm_bind.php_type == IS_LONG) { + else if (as_int_or_float && perm_bind.php_type == IS_LONG) { zend_uchar save = *(p + len); /* We have to make it ASCIIZ temporarily */ *(p + len) = '\0'; @@ -1661,28 +1681,9 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * *(p + len) = '\0'; ZVAL_DOUBLE(current_field, atof((char *) p)); *(p + len) = save; - } else + } #endif /* MYSQLND_STRING_TO_INT_CONVERSION */ - if (fields_metadata[i].type == MYSQL_TYPE_BIT) { - /* - BIT fields are specially handled. As they come as bit mask, they have - to be converted to human-readable representation. - */ - ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len); - /* - 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_P(current_field) == IS_LONG && !as_int_or_float) { - /* we are using the text protocol, so convert to string */ - char tmp[22]; - const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field)); - ZVAL_STRINGL(current_field, tmp, tmp_len); - } else if (Z_TYPE_P(current_field) == IS_STRING) { - /* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */ - } - } else if (len == 0) { + else if (len == 0) { ZVAL_EMPTY_STRING(current_field); } else if (len == 1) { ZVAL_INTERNED_STR(current_field, ZSTR_CHAR((zend_uchar)*(char *)p)); |