From 479e303ef3e76a984d7885969863157b220c49d0 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Sun, 26 Sep 2021 01:30:36 +0530 Subject: [PATCH] MDEV-26606: ROW_NUMBER property value isn't passed from inside a stored procedure Analysis: m_current_row_for_warning is reset to 1 during cleanup phase of stored procedure. When we perform a copy because some statement of procedure created warning, this reset value is passed to push_warning(). Hence the output is always 1. Fix: Add a parameter in relevant functions to pass correct value of row_number and don't use m_current_row_for_warning directly. --- mysql-test/main/get_diagnostics.result | 60 ++++++++++++++++++++++- mysql-test/main/get_diagnostics.test | 66 ++++++++++++++++++++++++++ sql/lex.h | 2 + sql/sql_class.cc | 3 +- sql/sql_error.cc | 8 ++-- sql/sql_error.h | 11 +++-- 6 files changed, 140 insertions(+), 10 deletions(-) diff --git a/mysql-test/main/get_diagnostics.result b/mysql-test/main/get_diagnostics.result index fb7598ae043..c7ca21e6040 100644 --- a/mysql-test/main/get_diagnostics.result +++ b/mysql-test/main/get_diagnostics.result @@ -1481,7 +1481,7 @@ ERROR HY000: Can't update table 't1' in stored function/trigger because it is al GET DIAGNOSTICS CONDITION 1 @var119= ROW_NUMBER; SELECT @var119; @var119 -2 +1 INSERT INTO t1 VALUES (1) RETURNING id2; ERROR 42S22: Unknown column 'id2' in 'field list' GET DIAGNOSTICS CONDITION 1 @var120= ROW_NUMBER; @@ -1523,7 +1523,7 @@ ERROR HY000: Can't update table 't1' in stored function/trigger because it is al GET DIAGNOSTICS CONDITION 1 @var125= ROW_NUMBER; SELECT @var125; @var125 -2 +1 REPLACE INTO t1 VALUES (1) RETURNING id2; ERROR 42S22: Unknown column 'id2' in 'field list' GET DIAGNOSTICS CONDITION 1 @var126= ROW_NUMBER; @@ -1552,3 +1552,59 @@ DROP TABLE t1,t2; DROP FUNCTION f1; DROP FUNCTION f2; DROP VIEW v; +# +# MDEV-26606: ROW_NUMBER property value isn't passed from inside a +# stored procedure +# +# Test 1: Without RESIGNAL +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY); +CREATE OR REPLACE PROCEDURE sp(a INT) INSERT INTO t1 VALUES (2),(a); +SET @num=null, @msg=null; +INSERT INTO t1 VALUES(1); +CALL sp(1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +GET DIAGNOSTICS CONDITION 1 @num = ROW_NUMBER, @msg = MESSAGE_TEXT; +SELECT @num, @msg; +@num @msg +2 Duplicate entry '1' for key 'PRIMARY' +DROP PROCEDURE sp; +DROP TABLE t1; +# Test 2: With RESIGNAL +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY); +CREATE OR REPLACE PROCEDURE sp(a INT) +BEGIN +DECLARE n INT; +DECLARE m VARCHAR(255); +DECLARE EXIT HANDLER FOR 1062 +BEGIN +GET DIAGNOSTICS CONDITION 1 n = ROW_NUMBER, m = MESSAGE_TEXT; +SELECT n, m; +RESIGNAL; +END; +INSERT INTO t1 VALUES (2), (a); +END | +SET @num=null, @msg=null; +INSERT INTO t1 VALUES (1); +CALL sp(1); +n m +2 Duplicate entry '1' for key 'PRIMARY' +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +GET DIAGNOSTICS CONDITION 1 @num = ROW_NUMBER, @msg = MESSAGE_TEXT; +SELECT @num, @msg; +@num @msg +2 Duplicate entry '1' for key 'PRIMARY' +DROP PROCEDURE sp; +DROP TABLE t1; +# Checking more errors +CREATE TABLE t1 (val1 TINYINT); +CREATE PROCEDURE sp(a INT) INSERT INTO t1 VALUES (2),(a); +INSERT INTO t1 VALUES(1); +CALL sp(100000); +Warnings: +Warning 1264 Out of range value for column 'val1' at row 2 +GET DIAGNOSTICS CONDITION 1 @var1= ROW_NUMBER; +SELECT @var1; +@var1 +2 +DROP TABLE t1; +DROP PROCEDURE sp; diff --git a/mysql-test/main/get_diagnostics.test b/mysql-test/main/get_diagnostics.test index 0ff67f8ae75..7db3dc95929 100644 --- a/mysql-test/main/get_diagnostics.test +++ b/mysql-test/main/get_diagnostics.test @@ -1430,3 +1430,69 @@ DROP TABLE t1,t2; DROP FUNCTION f1; DROP FUNCTION f2; DROP VIEW v; + +--echo # +--echo # MDEV-26606: ROW_NUMBER property value isn't passed from inside a +--echo # stored procedure +--echo # + +--echo # Test 1: Without RESIGNAL + +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY); +CREATE OR REPLACE PROCEDURE sp(a INT) INSERT INTO t1 VALUES (2),(a); +SET @num=null, @msg=null; + +INSERT INTO t1 VALUES(1); + +--error ER_DUP_ENTRY +CALL sp(1); +GET DIAGNOSTICS CONDITION 1 @num = ROW_NUMBER, @msg = MESSAGE_TEXT; +SELECT @num, @msg; + +DROP PROCEDURE sp; +DROP TABLE t1; + +--echo # Test 2: With RESIGNAL + +CREATE OR REPLACE TABLE t1 (pk INT PRIMARY KEY); + +DELIMITER |; +CREATE OR REPLACE PROCEDURE sp(a INT) +BEGIN + DECLARE n INT; + DECLARE m VARCHAR(255); + DECLARE EXIT HANDLER FOR 1062 + BEGIN + GET DIAGNOSTICS CONDITION 1 n = ROW_NUMBER, m = MESSAGE_TEXT; + SELECT n, m; + RESIGNAL; + END; + INSERT INTO t1 VALUES (2), (a); +END | +DELIMITER ;| + +SET @num=null, @msg=null; +INSERT INTO t1 VALUES (1); + +--error ER_DUP_ENTRY +CALL sp(1); +GET DIAGNOSTICS CONDITION 1 @num = ROW_NUMBER, @msg = MESSAGE_TEXT; +SELECT @num, @msg; + +DROP PROCEDURE sp; +DROP TABLE t1; + +--echo # Checking more errors + +CREATE TABLE t1 (val1 TINYINT); + +CREATE PROCEDURE sp(a INT) INSERT INTO t1 VALUES (2),(a); + +INSERT INTO t1 VALUES(1); + +CALL sp(100000); +GET DIAGNOSTICS CONDITION 1 @var1= ROW_NUMBER; +SELECT @var1; + +DROP TABLE t1; +DROP PROCEDURE sp; diff --git a/sql/lex.h b/sql/lex.h index 4ce88ccc2ee..1ae577328ee 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -567,6 +567,8 @@ SYMBOL symbols[] = { { "ROWS", SYM(ROWS_SYM)}, { "ROWTYPE", SYM(ROWTYPE_MARIADB_SYM)}, { "ROW_COUNT", SYM(ROW_COUNT_SYM)}, + /** sql_function and condition_property_name for GET DIAGNOSTICS */ + { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)}, { "ROW_FORMAT", SYM(ROW_FORMAT_SYM)}, /** sql_function and condition_property_name for GET DIAGNOSTICS */ { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)}, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 31f5faa72ed..4d7093763ae 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1149,7 +1149,8 @@ Sql_condition* THD::raise_condition(uint sql_errno, if (likely(!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY || sql_errno == ER_OUTOFMEMORY)))) { - cond= da->push_warning(this, sql_errno, sqlstate, level, ucid, msg); + cond= da->push_warning(this, sql_errno, sqlstate, level, ucid, msg, + da->current_row_for_warning()); } DBUG_RETURN(cond); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 7b6e6a83d2f..a2178831697 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -663,7 +663,8 @@ void Warning_info::reserve_space(THD *thd, uint count) Sql_condition *Warning_info::push_warning(THD *thd, const Sql_condition_identity *value, - const char *msg) + const char *msg, + ulong current_row_number) { Sql_condition *cond= NULL; @@ -673,7 +674,7 @@ Sql_condition *Warning_info::push_warning(THD *thd, m_warn_list.elements() < thd->variables.max_error_count) { cond= new (& m_warn_root) Sql_condition(& m_warn_root, *value, msg, - m_current_row_for_warning); + current_row_number); if (cond) m_warn_list.push_back(cond); } @@ -689,7 +690,8 @@ Sql_condition *Warning_info::push_warning(THD *thd, const Sql_condition *sql_condition) { Sql_condition *new_condition= push_warning(thd, sql_condition, - sql_condition->get_message_text()); + sql_condition->get_message_text(), + sql_condition->m_row_number); if (new_condition) new_condition->copy_opt_attributes(sql_condition); diff --git a/sql/sql_error.h b/sql/sql_error.h index e7f1a27a6a7..ae33a53f80d 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -748,7 +748,8 @@ private: */ Sql_condition *push_warning(THD *thd, const Sql_condition_identity *identity, - const char* msg); + const char* msg, + ulong current_row_number); /** Add a new SQL-condition to the current list and increment the respective @@ -1179,10 +1180,12 @@ public: const char* sqlstate, Sql_condition::enum_warning_level level, const Sql_user_condition_identity &ucid, - const char* msg) + const char* msg, + ulong current_row_number) { Sql_condition_identity tmp(sql_errno_arg, sqlstate, level, ucid); - return get_warning_info()->push_warning(thd, &tmp, msg); + return get_warning_info()->push_warning(thd, &tmp, msg, + current_row_number); } Sql_condition *push_warning(THD *thd, @@ -1192,7 +1195,7 @@ public: const char* msg) { return push_warning(thd, sqlerrno, sqlstate, level, - Sql_user_condition_identity(), msg); + Sql_user_condition_identity(), msg, 0); } void mark_sql_conditions_for_removal() { get_warning_info()->mark_sql_conditions_for_removal(); }