diff --git a/ext/mysqli/mysqli.stub.php b/ext/mysqli/mysqli.stub.php index d680678d088c0..dbed931c93959 100644 --- a/ext/mysqli/mysqli.stub.php +++ b/ext/mysqli/mysqli.stub.php @@ -400,6 +400,11 @@ * @cvalue FIELD_TYPE_GEOMETRY */ const MYSQLI_TYPE_GEOMETRY = UNKNOWN; +/** + * @var int + * @cvalue FIELD_TYPE_VECTOR + */ +const MYSQLI_TYPE_VECTOR = UNKNOWN; #ifdef FIELD_TYPE_JSON /** * @var int diff --git a/ext/mysqli/mysqli_arginfo.h b/ext/mysqli/mysqli_arginfo.h index 11bf8cae5f61e..2a66413c8012a 100644 --- a/ext/mysqli/mysqli_arginfo.h +++ b/ext/mysqli/mysqli_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6a64c5833a4c83d0bd0e63f34d27d2e696c78b66 */ + * Stub hash: ff768a152d4ee91b184999d351ce39a7d0bfef46 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING) ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0) @@ -1118,6 +1118,7 @@ static void register_mysqli_symbols(int module_number) REGISTER_LONG_CONSTANT("MYSQLI_TYPE_CHAR", FIELD_TYPE_CHAR, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_TYPE_INTERVAL", FIELD_TYPE_INTERVAL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_TYPE_GEOMETRY", FIELD_TYPE_GEOMETRY, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("MYSQLI_TYPE_VECTOR", FIELD_TYPE_VECTOR, CONST_PERSISTENT); #if defined(FIELD_TYPE_JSON) REGISTER_LONG_CONSTANT("MYSQLI_TYPE_JSON", FIELD_TYPE_JSON, CONST_PERSISTENT); #endif diff --git a/ext/mysqli/tests/gh15432.phpt b/ext/mysqli/tests/gh15432.phpt index 50372a1bbc544..5428fb2d14168 100644 --- a/ext/mysqli/tests/gh15432.phpt +++ b/ext/mysqli/tests/gh15432.phpt @@ -1,5 +1,5 @@ --TEST-- -Bug GH-15432 (Heap corruption when querying a vector) +Bug GH-15432 (Heap corruption when querying a vector/PHP crashes when processing a MySQL DB query with a new Vector format introduced in MySQL 9.0) --EXTENSIONS-- mysqli --SKIPIF-- @@ -16,9 +16,49 @@ if ($link->server_version < 90000 || $link->server_version >= 10_00_00) { --FILE-- query('SELECT STRING_TO_VECTOR("[1.05, -17.8, 32]")')); + +$expected = '00000040000040400000a040'; + +mysqli_query($link, "DROP TABLE IF EXISTS test"); +mysqli_query($link, "CREATE TABLE test(vectorfield VECTOR)"); +mysqli_query($link, 'INSERT INTO test VALUES (TO_VECTOR("[2, 3, 5]"))'); + +// Textual protocol +$result = mysqli_query($link, "SELECT vectorfield FROM test")->fetch_column(); +$value = bin2hex($result); +if($value !== $expected) { + printf("[001] Expecting %s/%s, got %s/%s\n", + gettype($expected), $expected, + gettype($value), $value); +} + +// Binary protocol +$result = $link->execute_query("SELECT vectorfield FROM test")->fetch_column(); +$value = bin2hex($result); +if($value !== $expected) { + printf("[002] Expecting %s/%s, got %s/%s\n", + gettype($expected), $expected, + gettype($value), $value); +} + +// Testing inverse to make sure the value hasn't been changed +$expected = '[2.00000e+00,3.00000e+00,5.00000e+00]'; +$result = $link->execute_query("SELECT VECTOR_TO_STRING(0x". $value .")")->fetch_column(); +if($result !== $expected) { + printf("[002] Expecting %s/%s, got %s/%s\n", + gettype($expected), $expected, + gettype($result), $result); +} + +echo "OK"; +?> +--CLEAN-- + ---EXPECTF-- -Warning: mysqli::query(): Unknown type 242 sent by the server. Please send a report to the developers in %s on line %d -bool(false) +--EXPECT-- +OK diff --git a/ext/mysqli/tests/mysqli_constants.phpt b/ext/mysqli/tests/mysqli_constants.phpt index 6bddcb5980e6f..1e51e0c92b096 100644 --- a/ext/mysqli/tests/mysqli_constants.phpt +++ b/ext/mysqli/tests/mysqli_constants.phpt @@ -66,6 +66,8 @@ $expected_constants = array( "MYSQLI_TYPE_NEWDATE" => true, "MYSQLI_TYPE_ENUM" => true, "MYSQLI_TYPE_SET" => true, + "MYSQLI_TYPE_VECTOR" => true, + "MYSQLI_TYPE_JSON" => true, "MYSQLI_TYPE_TINY_BLOB" => true, "MYSQLI_TYPE_MEDIUM_BLOB" => true, "MYSQLI_TYPE_LONG_BLOB" => true, @@ -143,8 +145,6 @@ $expected_constants["MYSQLI_DATA_TRUNCATED"] = true; $expected_constants["MYSQLI_OPT_CAN_HANDLE_EXPIRED_PASSWORDS"] = true; $expected_constants["MYSQLI_CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS"] = true; -$expected_constants["MYSQLI_TYPE_JSON"] = true; - $unexpected_constants = array(); foreach ($constants as $consts) { diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index 1f862141a3d61..5739979eccaa1 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -280,6 +280,7 @@ typedef enum mysqlnd_field_types MYSQL_TYPE_NEWDATE = 14, MYSQL_TYPE_VARCHAR = 15, MYSQL_TYPE_BIT = 16, + MYSQL_TYPE_VECTOR=242, MYSQL_TYPE_JSON=245, MYSQL_TYPE_NEWDECIMAL=246, MYSQL_TYPE_ENUM=247, @@ -322,6 +323,7 @@ typedef enum mysqlnd_server_option #define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE #define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM #define FIELD_TYPE_SET MYSQL_TYPE_SET +#define FIELD_TYPE_VECTOR MYSQL_TYPE_VECTOR #define FIELD_TYPE_JSON MYSQL_TYPE_JSON #define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB #define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index ca6c2112cffa5..a9c420dd1473b 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -414,6 +414,10 @@ void _mysqlnd_init_ps_fetch_subsystem(void) mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN; mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].php_type= IS_STRING; + mysqlnd_ps_fetch_functions[MYSQL_TYPE_VECTOR].func = ps_fetch_string; + mysqlnd_ps_fetch_functions[MYSQL_TYPE_VECTOR].pack_len = MYSQLND_PS_SKIP_RESULT_STR; + mysqlnd_ps_fetch_functions[MYSQL_TYPE_VECTOR].php_type = IS_STRING; + mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].func = ps_fetch_string; mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].pack_len= MYSQLND_PS_SKIP_RESULT_STR; mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].php_type = IS_STRING; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 7c785a31d730f..3b46fb2c985be 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -1468,6 +1468,7 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break; case MYSQL_TYPE_LONG_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break; case MYSQL_TYPE_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break; + case MYSQL_TYPE_VECTOR: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break; case MYSQL_TYPE_VAR_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break; case MYSQL_TYPE_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break; case MYSQL_TYPE_GEOMETRY: statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break; @@ -1553,6 +1554,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fiel case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break; case MYSQL_TYPE_LONG_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break; case MYSQL_TYPE_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break; + case MYSQL_TYPE_VECTOR: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break; case MYSQL_TYPE_VAR_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break; case MYSQL_TYPE_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break; case MYSQL_TYPE_GEOMETRY: statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;