From 1578c004b095ba7aa8a58024755e60affbb34de0 Mon Sep 17 00:00:00 2001 From: Yohan Wal Date: Fri, 22 Nov 2024 10:31:53 +0800 Subject: [PATCH] fix: prepare param mismatch (#5025) * fix: prepare param mismatch * test: clear state * fix: minus 1 --- src/servers/src/mysql/handler.rs | 30 +++++--- .../common/prepare/mysql_prepare.result | 72 +++++++++++++++++++ .../common/prepare/mysql_prepare.sql | 39 ++++++++++ 3 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 tests/cases/standalone/common/prepare/mysql_prepare.result create mode 100644 tests/cases/standalone/common/prepare/mysql_prepare.sql diff --git a/src/servers/src/mysql/handler.rs b/src/servers/src/mysql/handler.rs index 587742687d82..d84a5945cabb 100644 --- a/src/servers/src/mysql/handler.rs +++ b/src/servers/src/mysql/handler.rs @@ -189,8 +189,6 @@ impl MysqlInstanceShim { dummy_params(param_num)? }; - debug_assert_eq!(params.len(), param_num - 1); - let columns = schema .as_ref() .map(|schema| { @@ -205,14 +203,26 @@ impl MysqlInstanceShim { .transpose()? .unwrap_or_default(); - self.save_plan( - SqlPlan { - query: query.to_string(), - plan, - schema, - }, - stmt_key, - ); + // DataFusion may optimize the plan so that some parameters are not used. + if params.len() != param_num - 1 { + self.save_plan( + SqlPlan { + query: query.to_string(), + plan: None, + schema: None, + }, + stmt_key, + ); + } else { + self.save_plan( + SqlPlan { + query: query.to_string(), + plan, + schema, + }, + stmt_key, + ); + } Ok((params, columns)) } diff --git a/tests/cases/standalone/common/prepare/mysql_prepare.result b/tests/cases/standalone/common/prepare/mysql_prepare.result new file mode 100644 index 000000000000..ae6ca4400cab --- /dev/null +++ b/tests/cases/standalone/common/prepare/mysql_prepare.result @@ -0,0 +1,72 @@ +-- invalid prepare, from +-- https://github.com/duckdb/duckdb/blob/00a605270719941ca0412ad5d0a14b1bdfbf9eb5/test/sql/prepared/invalid_prepare.test +-- SQLNESS PROTOCOL MYSQL +SELECT ?; + +Failed to execute query, err: MySqlError { ERROR 1815 (HY000): (PlanQuery): Failed to plan SQL: Error during planning: Placeholder type could not be resolved. Make sure that the placeholder is bound to a concrete type, e.g. by providing parameter values. } + +-- SQLNESS PROTOCOL MYSQL +PREPARE stmt FROM 'SELECT ?::int;'; + +affected_rows: 0 + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 1; + ++----------+ +| Int64(1) | ++----------+ +| 1 | ++----------+ + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 'a'; + +Failed to parse query result, err: MySqlError { ERROR 1815 (HY000): (EngineExecuteQuery): Cast error: Cannot cast string 'a' to value of Int32 type } + +-- SQLNESS PROTOCOL MYSQL +DEALLOCATE stmt; + +affected_rows: 0 + +-- SQLNESS PROTOCOL MYSQL +PREPARE stmt FROM 'SELECT ?::int WHERE 1=0;'; + +affected_rows: 0 + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 1; + +affected_rows: 0 + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 'a'; + +affected_rows: 0 + +-- SQLNESS PROTOCOL MYSQL +DEALLOCATE stmt; + +affected_rows: 0 + +-- parameter variants, from: +-- https://github.com/duckdb/duckdb/blob/2360dd00f193b5d0850f9379d0c3794eb2084f36/test/sql/prepared/parameter_variants.test +-- SQLNESS PROTOCOL MYSQL +PREPARE stmt FROM 'SELECT CAST(? AS INTEGER), CAST(? AS STRING);'; + +affected_rows: 0 + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 1, 'hello'; + ++----------+---------------+ +| Int64(1) | Utf8("hello") | ++----------+---------------+ +| 1 | hello | ++----------+---------------+ + +-- SQLNESS PROTOCOL MYSQL +DEALLOCATE stmt; + +affected_rows: 0 + diff --git a/tests/cases/standalone/common/prepare/mysql_prepare.sql b/tests/cases/standalone/common/prepare/mysql_prepare.sql new file mode 100644 index 000000000000..da1681a790ff --- /dev/null +++ b/tests/cases/standalone/common/prepare/mysql_prepare.sql @@ -0,0 +1,39 @@ +-- invalid prepare, from +-- https://github.com/duckdb/duckdb/blob/00a605270719941ca0412ad5d0a14b1bdfbf9eb5/test/sql/prepared/invalid_prepare.test +-- SQLNESS PROTOCOL MYSQL +SELECT ?; + +-- SQLNESS PROTOCOL MYSQL +PREPARE stmt FROM 'SELECT ?::int;'; + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 1; + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 'a'; + +-- SQLNESS PROTOCOL MYSQL +DEALLOCATE stmt; + +-- SQLNESS PROTOCOL MYSQL +PREPARE stmt FROM 'SELECT ?::int WHERE 1=0;'; + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 1; + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 'a'; + +-- SQLNESS PROTOCOL MYSQL +DEALLOCATE stmt; + +-- parameter variants, from: +-- https://github.com/duckdb/duckdb/blob/2360dd00f193b5d0850f9379d0c3794eb2084f36/test/sql/prepared/parameter_variants.test +-- SQLNESS PROTOCOL MYSQL +PREPARE stmt FROM 'SELECT CAST(? AS INTEGER), CAST(? AS STRING);'; + +-- SQLNESS PROTOCOL MYSQL +EXECUTE stmt USING 1, 'hello'; + +-- SQLNESS PROTOCOL MYSQL +DEALLOCATE stmt;