diff --git a/mysql-test/include/sp-cursor-pkg-01.inc b/mysql-test/include/sp-cursor-pkg-01.inc new file mode 100644 index 00000000000..78f2848e221 --- /dev/null +++ b/mysql-test/include/sp-cursor-pkg-01.inc @@ -0,0 +1,24 @@ +DELIMITER $$; +CREATE PACKAGE pkg + FUNCTION f1() RETURNS INT; +END; +$$ +CREATE PACKAGE BODY pkg + DECLARE vc INT DEFAULT 0; + FUNCTION f1() RETURNS INT + BEGIN + DECLARE cur CURSOR FOR SELECT 1 AS c FROM DUAL; + OPEN cur; + FETCH cur INTO vc; -- SHOW CODE should display vc with a "PACKAGE_BODY" prefix + CLOSE cur; + RETURN vc; + END; + BEGIN + DECLARE cur CURSOR FOR SELECT 1 AS c FROM DUAL; + OPEN cur; + FETCH cur INTO vc; -- SHOW CODE should display vc without a prefix + CLOSE cur; + END; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/include/sp-cursor-pkg-02.inc b/mysql-test/include/sp-cursor-pkg-02.inc new file mode 100644 index 00000000000..d84bbac9209 --- /dev/null +++ b/mysql-test/include/sp-cursor-pkg-02.inc @@ -0,0 +1,20 @@ +# Mixing a package body variable and a local variable in the same FETCH. +DELIMITER $$; +CREATE PACKAGE pkg + FUNCTION f1() RETURNS TEXT; +END; +$$ +CREATE PACKAGE BODY pkg + DECLARE vc1 INT DEFAULT 0; + FUNCTION f1() RETURNS TEXT + BEGIN + DECLARE vc2 INT DEFAULT 0; + DECLARE cur CURSOR FOR SELECT 1 AS c1, 2 AS c2 FROM DUAL; + OPEN cur; + FETCH cur INTO vc1, vc2; + CLOSE cur; + RETURN CONCAT(vc1, ' ', vc2); + END; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/include/sp-cursor-pkg-03.inc b/mysql-test/include/sp-cursor-pkg-03.inc new file mode 100644 index 00000000000..900b515ad5f --- /dev/null +++ b/mysql-test/include/sp-cursor-pkg-03.inc @@ -0,0 +1,19 @@ +# Fetching into a PACKAGE BODY variable of the ROW type +DELIMITER $$; +CREATE PACKAGE pkg + FUNCTION f1() RETURNS TEXT; +END; +$$ +CREATE PACKAGE BODY pkg + DECLARE vc ROW(p1 INT, p2 INT); + FUNCTION f1() RETURNS TEXT + BEGIN + DECLARE cur CURSOR FOR SELECT 1 AS c1, 2 AS c2 FROM DUAL; + OPEN cur; + FETCH cur INTO vc; + CLOSE cur; + RETURN CONCAT(vc.p1, ' ', vc.p2); + END; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/main/sp-cursor.result b/mysql-test/main/sp-cursor.result index 83b05264339..7afd4c33aef 100644 --- a/mysql-test/main/sp-cursor.result +++ b/mysql-test/main/sp-cursor.result @@ -852,3 +852,75 @@ ERROR 42000: This version of MariaDB doesn't yet support 'OUT/INOUT cursor param # # End of 10.8 tests # +# Start of 11.4 tests +# +# MDEV-36047 Package body variables are not allowed as FETCH targets +# +CREATE PACKAGE pkg +FUNCTION f1() RETURNS INT; +END; +$$ +CREATE PACKAGE BODY pkg +DECLARE vc INT DEFAULT 0; +FUNCTION f1() RETURNS INT +BEGIN +DECLARE cur CURSOR FOR SELECT 1 AS c FROM DUAL; +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc with a "PACKAGE_BODY" prefix +CLOSE cur; +RETURN vc; +END; +BEGIN +DECLARE cur CURSOR FOR SELECT 1 AS c FROM DUAL; +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc without a prefix +CLOSE cur; +END; +END; +$$ +SELECT pkg.f1(); +pkg.f1() +1 +DROP PACKAGE pkg; +CREATE PACKAGE pkg +FUNCTION f1() RETURNS TEXT; +END; +$$ +CREATE PACKAGE BODY pkg +DECLARE vc1 INT DEFAULT 0; +FUNCTION f1() RETURNS TEXT +BEGIN +DECLARE vc2 INT DEFAULT 0; +DECLARE cur CURSOR FOR SELECT 1 AS c1, 2 AS c2 FROM DUAL; +OPEN cur; +FETCH cur INTO vc1, vc2; +CLOSE cur; +RETURN CONCAT(vc1, ' ', vc2); +END; +END; +$$ +SELECT pkg.f1(); +pkg.f1() +1 2 +DROP PACKAGE pkg; +CREATE PACKAGE pkg +FUNCTION f1() RETURNS TEXT; +END; +$$ +CREATE PACKAGE BODY pkg +DECLARE vc ROW(p1 INT, p2 INT); +FUNCTION f1() RETURNS TEXT +BEGIN +DECLARE cur CURSOR FOR SELECT 1 AS c1, 2 AS c2 FROM DUAL; +OPEN cur; +FETCH cur INTO vc; +CLOSE cur; +RETURN CONCAT(vc.p1, ' ', vc.p2); +END; +END; +$$ +SELECT pkg.f1(); +pkg.f1() +1 2 +DROP PACKAGE pkg; +# End of 11.4 tests diff --git a/mysql-test/main/sp-cursor.test b/mysql-test/main/sp-cursor.test index feb681201a2..d15a0c80a6f 100644 --- a/mysql-test/main/sp-cursor.test +++ b/mysql-test/main/sp-cursor.test @@ -872,3 +872,23 @@ DELIMITER ;$$ --echo # --echo # End of 10.8 tests --echo # + +--echo # Start of 11.4 tests + +--echo # +--echo # MDEV-36047 Package body variables are not allowed as FETCH targets +--echo # + +--source include/sp-cursor-pkg-01.inc +SELECT pkg.f1(); +DROP PACKAGE pkg; + +--source include/sp-cursor-pkg-02.inc +SELECT pkg.f1(); +DROP PACKAGE pkg; + +--source include/sp-cursor-pkg-03.inc +SELECT pkg.f1(); +DROP PACKAGE pkg; + +--echo # End of 11.4 tests diff --git a/mysql-test/main/sp-package-code.result b/mysql-test/main/sp-package-code.result index f69cb7ec671..290c939749f 100644 --- a/mysql-test/main/sp-package-code.result +++ b/mysql-test/main/sp-package-code.result @@ -258,3 +258,105 @@ Pos Instruction 6 set a.a@0["a"] b.a@1["a"] + 1 DROP PACKAGE pkg1; DROP TABLE t1; +# Start of 11.4 tests +# +# MDEV-36047 Package body variables are not allowed as FETCH targets +# +CREATE PACKAGE pkg +FUNCTION f1() RETURNS INT; +END; +$$ +CREATE PACKAGE BODY pkg +DECLARE vc INT DEFAULT 0; +FUNCTION f1() RETURNS INT +BEGIN +DECLARE cur CURSOR FOR SELECT 1 AS c FROM DUAL; +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc with a "PACKAGE_BODY" prefix +CLOSE cur; +RETURN vc; +END; +BEGIN +DECLARE cur CURSOR FOR SELECT 1 AS c FROM DUAL; +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc without a prefix +CLOSE cur; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 +SHOW FUNCTION CODE pkg.f1; +Pos Instruction +0 cpush cur@0 +1 copen cur@0 +2 cfetch cur@0 PACKAGE_BODY.vc@0 +3 cclose cur@0 +4 freturn int PACKAGE_BODY.vc@0 +SHOW PACKAGE BODY CODE pkg; +Pos Instruction +0 set vc@0 0 +1 cpush cur@0 +2 copen cur@0 +3 cfetch cur@0 vc@0 +4 cclose cur@0 +5 cpop 1 +DROP PACKAGE pkg; +CREATE PACKAGE pkg +FUNCTION f1() RETURNS TEXT; +END; +$$ +CREATE PACKAGE BODY pkg +DECLARE vc1 INT DEFAULT 0; +FUNCTION f1() RETURNS TEXT +BEGIN +DECLARE vc2 INT DEFAULT 0; +DECLARE cur CURSOR FOR SELECT 1 AS c1, 2 AS c2 FROM DUAL; +OPEN cur; +FETCH cur INTO vc1, vc2; +CLOSE cur; +RETURN CONCAT(vc1, ' ', vc2); +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 2 +SHOW FUNCTION CODE pkg.f1; +Pos Instruction +0 set vc2@0 0 +1 cpush cur@0 +2 copen cur@0 +3 cfetch cur@0 PACKAGE_BODY.vc1@0 vc2@0 +4 cclose cur@0 +5 freturn blob concat(PACKAGE_BODY.vc1@0,' ',vc2@0) +DROP PACKAGE pkg; +CREATE PACKAGE pkg +FUNCTION f1() RETURNS TEXT; +END; +$$ +CREATE PACKAGE BODY pkg +DECLARE vc ROW(p1 INT, p2 INT); +FUNCTION f1() RETURNS TEXT +BEGIN +DECLARE cur CURSOR FOR SELECT 1 AS c1, 2 AS c2 FROM DUAL; +OPEN cur; +FETCH cur INTO vc; +CLOSE cur; +RETURN CONCAT(vc.p1, ' ', vc.p2); +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 2 +SHOW FUNCTION CODE pkg.f1; +Pos Instruction +0 cpush cur@0 +1 copen cur@0 +2 cfetch cur@0 PACKAGE_BODY.vc@0 +3 cclose cur@0 +4 freturn blob concat(PACKAGE_BODY.vc.p1@0[0],' ',PACKAGE_BODY.vc.p2@0[1]) +DROP PACKAGE pkg; +# End of 11.4 tests diff --git a/mysql-test/main/sp-package-code.test b/mysql-test/main/sp-package-code.test index e99c25e7aa2..740a3eeb8af 100644 --- a/mysql-test/main/sp-package-code.test +++ b/mysql-test/main/sp-package-code.test @@ -198,3 +198,26 @@ DROP PACKAGE pkg1; DROP TABLE t1; +--echo # Start of 11.4 tests + +--echo # +--echo # MDEV-36047 Package body variables are not allowed as FETCH targets +--echo # + +--source include/sp-cursor-pkg-01.inc +SELECT pkg.f1() FROM DUAL; +SHOW FUNCTION CODE pkg.f1; +SHOW PACKAGE BODY CODE pkg; +DROP PACKAGE pkg; + +--source include/sp-cursor-pkg-02.inc +SELECT pkg.f1() FROM DUAL; +SHOW FUNCTION CODE pkg.f1; +DROP PACKAGE pkg; + +--source include/sp-cursor-pkg-03.inc +SELECT pkg.f1() FROM DUAL; +SHOW FUNCTION CODE pkg.f1; +DROP PACKAGE pkg; + +--echo # End of 11.4 tests diff --git a/mysql-test/suite/compat/oracle/r/sp-cursor.result b/mysql-test/suite/compat/oracle/r/sp-cursor.result index aa9c5de8bc9..285934a3e30 100644 --- a/mysql-test/suite/compat/oracle/r/sp-cursor.result +++ b/mysql-test/suite/compat/oracle/r/sp-cursor.result @@ -1020,3 +1020,77 @@ ERROR 42000: This version of MariaDB doesn't yet support 'OUT/INOUT cursor param # # End of 10.8 tests # +# Start of 11.4 tests +# +# MDEV-36047 Package body variables are not allowed as FETCH targets +# +CREATE PACKAGE pkg AS +FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY pkg AS +vc INT := 0; +FUNCTION f1 RETURN INT AS +CURSOR cur IS SELECT 1 AS c FROM DUAL; +BEGIN +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc with a "PACKAGE_BODY" prefix +CLOSE cur; +RETURN vc; +END; +BEGIN +DECLARE +CURSOR cur IS SELECT 1 AS c FROM DUAL; +BEGIN +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc without a prefix +CLOSE cur; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 +DROP PACKAGE pkg; +CREATE PACKAGE pkg AS +FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg AS +vc1 INT := 0; +FUNCTION f1 RETURN TEXT AS +CURSOR cur IS SELECT 1 AS c1, 2 AS c2 FROM DUAL; +vc2 INT := 0; +BEGIN +OPEN cur; +FETCH cur INTO vc1, vc2; +CLOSE cur; +RETURN vc1 || ' ' || vc2; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 2 +DROP PACKAGE pkg; +CREATE PACKAGE pkg AS +FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg AS +vc ROW(p1 INT, p2 INT); +FUNCTION f1 RETURN TEXT AS +CURSOR cur IS SELECT 1 AS c1, 2 AS c2 FROM DUAL; +BEGIN +OPEN cur; +FETCH cur INTO vc; +CLOSE cur; +RETURN vc.p1 || ' ' || vc.p2; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 2 +DROP PACKAGE pkg; +# End of 11.4 tests diff --git a/mysql-test/suite/compat/oracle/r/sp-package-code.result b/mysql-test/suite/compat/oracle/r/sp-package-code.result index 0dea72dba89..52b41a3c64e 100644 --- a/mysql-test/suite/compat/oracle/r/sp-package-code.result +++ b/mysql-test/suite/compat/oracle/r/sp-package-code.result @@ -243,3 +243,107 @@ Pos Instruction 7 jump 11 DROP PACKAGE pkg1; DROP TABLE t1; +# Start of 11.4 tests +# +# MDEV-36047 Package body variables are not allowed as FETCH targets +# +CREATE PACKAGE pkg AS +FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY pkg AS +vc INT := 0; +FUNCTION f1 RETURN INT AS +CURSOR cur IS SELECT 1 AS c FROM DUAL; +BEGIN +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc with a "PACKAGE_BODY" prefix +CLOSE cur; +RETURN vc; +END; +BEGIN +DECLARE +CURSOR cur IS SELECT 1 AS c FROM DUAL; +BEGIN +OPEN cur; +FETCH cur INTO vc; -- SHOW CODE should display vc without a prefix +CLOSE cur; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 +SHOW FUNCTION CODE pkg.f1; +Pos Instruction +0 cpush cur@0 +1 copen cur@0 +2 cfetch cur@0 PACKAGE_BODY.vc@0 +3 cclose cur@0 +4 freturn int PACKAGE_BODY.vc@0 +SHOW PACKAGE BODY CODE pkg; +Pos Instruction +0 set vc@0 0 +1 cpush cur@0 +2 copen cur@0 +3 cfetch cur@0 vc@0 +4 cclose cur@0 +5 cpop 1 +DROP PACKAGE pkg; +CREATE PACKAGE pkg AS +FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg AS +vc1 INT := 0; +FUNCTION f1 RETURN TEXT AS +CURSOR cur IS SELECT 1 AS c1, 2 AS c2 FROM DUAL; +vc2 INT := 0; +BEGIN +OPEN cur; +FETCH cur INTO vc1, vc2; +CLOSE cur; +RETURN vc1 || ' ' || vc2; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 2 +SHOW FUNCTION CODE pkg.f1; +Pos Instruction +0 set vc2@0 0 +1 cpush cur@0 +2 copen cur@0 +3 cfetch cur@0 PACKAGE_BODY.vc1@0 vc2@0 +4 cclose cur@0 +5 freturn blob concat(concat(PACKAGE_BODY.vc1@0,' '),vc2@0) +DROP PACKAGE pkg; +CREATE PACKAGE pkg AS +FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg AS +vc ROW(p1 INT, p2 INT); +FUNCTION f1 RETURN TEXT AS +CURSOR cur IS SELECT 1 AS c1, 2 AS c2 FROM DUAL; +BEGIN +OPEN cur; +FETCH cur INTO vc; +CLOSE cur; +RETURN vc.p1 || ' ' || vc.p2; +END; +END; +$$ +SELECT pkg.f1() FROM DUAL; +pkg.f1() +1 2 +SHOW FUNCTION CODE pkg.f1; +Pos Instruction +0 cpush cur@0 +1 copen cur@0 +2 cfetch cur@0 PACKAGE_BODY.vc@0 +3 cclose cur@0 +4 freturn blob concat(concat(PACKAGE_BODY.vc.p1@0[0],' '),PACKAGE_BODY.vc.p2@0[1]) +DROP PACKAGE pkg; +# End of 11.4 tests diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-01.inc b/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-01.inc new file mode 100644 index 00000000000..6e5aac0b254 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-01.inc @@ -0,0 +1,26 @@ +DELIMITER $$; +CREATE PACKAGE pkg AS + FUNCTION f1 RETURN INT; +END; +$$ +CREATE PACKAGE BODY pkg AS + vc INT := 0; + FUNCTION f1 RETURN INT AS + CURSOR cur IS SELECT 1 AS c FROM DUAL; + BEGIN + OPEN cur; + FETCH cur INTO vc; -- SHOW CODE should display vc with a "PACKAGE_BODY" prefix + CLOSE cur; + RETURN vc; + END; +BEGIN + DECLARE + CURSOR cur IS SELECT 1 AS c FROM DUAL; + BEGIN + OPEN cur; + FETCH cur INTO vc; -- SHOW CODE should display vc without a prefix + CLOSE cur; + END; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-02.inc b/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-02.inc new file mode 100644 index 00000000000..7a1eacee037 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-02.inc @@ -0,0 +1,20 @@ +# Mixing a package body variable and a local variable in the same FETCH. +DELIMITER $$; +CREATE PACKAGE pkg AS + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg AS + vc1 INT := 0; + FUNCTION f1 RETURN TEXT AS + CURSOR cur IS SELECT 1 AS c1, 2 AS c2 FROM DUAL; + vc2 INT := 0; + BEGIN + OPEN cur; + FETCH cur INTO vc1, vc2; + CLOSE cur; + RETURN vc1 || ' ' || vc2; + END; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-03.inc b/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-03.inc new file mode 100644 index 00000000000..e1c9fd6e8c5 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/sp-cursor-pkg-03.inc @@ -0,0 +1,19 @@ +# Fetching into a PACKAGE BODY variable of the ROW type +DELIMITER $$; +CREATE PACKAGE pkg AS + FUNCTION f1 RETURN TEXT; +END; +$$ +CREATE PACKAGE BODY pkg AS + vc ROW(p1 INT, p2 INT); + FUNCTION f1 RETURN TEXT AS + CURSOR cur IS SELECT 1 AS c1, 2 AS c2 FROM DUAL; + BEGIN + OPEN cur; + FETCH cur INTO vc; + CLOSE cur; + RETURN vc.p1 || ' ' || vc.p2; + END; +END; +$$ +DELIMITER ;$$ diff --git a/mysql-test/suite/compat/oracle/t/sp-cursor.test b/mysql-test/suite/compat/oracle/t/sp-cursor.test index d7e2a5dee68..eba00d24b8e 100644 --- a/mysql-test/suite/compat/oracle/t/sp-cursor.test +++ b/mysql-test/suite/compat/oracle/t/sp-cursor.test @@ -1042,3 +1042,24 @@ DELIMITER ;$$ --echo # --echo # End of 10.8 tests --echo # + + +--echo # Start of 11.4 tests + +--echo # +--echo # MDEV-36047 Package body variables are not allowed as FETCH targets +--echo # + +--source sp-cursor-pkg-01.inc +SELECT pkg.f1() FROM DUAL; +DROP PACKAGE pkg; + +--source sp-cursor-pkg-02.inc +SELECT pkg.f1() FROM DUAL; +DROP PACKAGE pkg; + +--source sp-cursor-pkg-03.inc +SELECT pkg.f1() FROM DUAL; +DROP PACKAGE pkg; + +--echo # End of 11.4 tests diff --git a/mysql-test/suite/compat/oracle/t/sp-package-code.test b/mysql-test/suite/compat/oracle/t/sp-package-code.test index 9cca53964ec..1aa2f7cba8b 100644 --- a/mysql-test/suite/compat/oracle/t/sp-package-code.test +++ b/mysql-test/suite/compat/oracle/t/sp-package-code.test @@ -180,3 +180,28 @@ SHOW PROCEDURE CODE pkg1.p1; SHOW PACKAGE BODY CODE pkg1; DROP PACKAGE pkg1; DROP TABLE t1; + + +--echo # Start of 11.4 tests + +--echo # +--echo # MDEV-36047 Package body variables are not allowed as FETCH targets +--echo # + +--source sp-cursor-pkg-01.inc +SELECT pkg.f1() FROM DUAL; +SHOW FUNCTION CODE pkg.f1; +SHOW PACKAGE BODY CODE pkg; +DROP PACKAGE pkg; + +--source sp-cursor-pkg-02.inc +SELECT pkg.f1() FROM DUAL; +SHOW FUNCTION CODE pkg.f1; +DROP PACKAGE pkg; + +--source sp-cursor-pkg-03.inc +SELECT pkg.f1() FROM DUAL; +SHOW FUNCTION CODE pkg.f1; +DROP PACKAGE pkg; + +--echo # End of 11.4 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index aa51d212a8c..abbca16e9c7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3858,8 +3858,10 @@ bool sp_head::add_for_loop_open_cursor(THD *thd, sp_pcontext *spcont, spcont, coffset, false); if (instr_cfetch == NULL || add_instr(instr_cfetch)) return true; - instr_cfetch->add_to_varlist(index); - return false; + const sp_rcontext_addr raddr(&sp_rcontext_handler_local, index->offset); + sp_fetch_target *target= + new (thd->mem_root) sp_fetch_target(index->name, raddr); + return !target || instr_cfetch->add_to_fetch_target_list(target); } diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index 6b70199f513..7e403a24281 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -1923,7 +1923,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) Query_arena backup_arena; DBUG_ENTER("sp_instr_cfetch::execute"); - res= c ? c->fetch(thd, &m_varlist, m_error_on_no_data) : -1; + res= c ? c->fetch(thd, &m_fetch_target_list, m_error_on_no_data) : -1; *nextp= m_ip+1; DBUG_RETURN(res); @@ -1933,8 +1933,8 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) void sp_instr_cfetch::print(String *str) { - List_iterator_fast li(m_varlist); - sp_variable *pv; + List_iterator_fast li(m_fetch_target_list); + sp_fetch_target *pv; const LEX_CSTRING *cursor_name= m_ctx->find_cursor(m_cursor); /* cfetch name@offset vars... */ @@ -1953,12 +1953,14 @@ sp_instr_cfetch::print(String *str) str->qs_append(m_cursor); while ((pv= li++)) { - if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) + const LEX_CSTRING *prefix= pv->rcontext_handler()->get_name_prefix(); + if (str->reserve(pv->name.length+prefix->length+SP_INSTR_UINT_MAXLEN+2)) return; str->qs_append(' '); + str->qs_append(prefix); str->qs_append(&pv->name); str->qs_append('@'); - str->qs_append(pv->offset); + str->qs_append(pv->offset()); } } diff --git a/sql/sp_instr.h b/sql/sp_instr.h index 2717bc85c3b..a93f681e5d1 100644 --- a/sql/sp_instr.h +++ b/sql/sp_instr.h @@ -591,7 +591,8 @@ public: }; // class sp_instr_stmt : public sp_lex_instr -class sp_instr_set : public sp_lex_instr +class sp_instr_set : public sp_lex_instr, + public sp_rcontext_addr { sp_instr_set(const sp_instr_set &); /**< Prevent use of these */ void operator=(sp_instr_set &); @@ -603,8 +604,7 @@ public: LEX *lex, bool lex_resp, const LEX_CSTRING &expr_str) : sp_lex_instr(ip, ctx, lex, lex_resp), - m_rcontext_handler(rh), - m_offset(offset), + sp_rcontext_addr(rh, offset), m_value(val), m_expr_str(expr_str) {} @@ -651,8 +651,6 @@ protected: } sp_rcontext *get_rcontext(THD *thd) const; - const Sp_rcontext_handler *m_rcontext_handler; - uint m_offset; ///< Frame offset Item *m_value; private: @@ -1490,7 +1488,7 @@ public: m_cursor(c), m_error_on_no_data(error_on_no_data) { - m_varlist.empty(); + m_fetch_target_list.empty(); } virtual ~sp_instr_cfetch() = default; @@ -1499,14 +1497,19 @@ public: void print(String *str) override; - void add_to_varlist(sp_variable *var) + bool add_to_fetch_target_list(sp_fetch_target *target) { - m_varlist.push_back(var); + return m_fetch_target_list.push_back(target); + } + + void set_fetch_target_list(List *list) + { + m_fetch_target_list= *list; } private: uint m_cursor; - List m_varlist; + List m_fetch_target_list; bool m_error_on_no_data; public: diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 71846ad4620..bf57e6f5b0e 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -87,6 +87,27 @@ public: uint *row_field_offset); }; + +/* + This class stores FETCH statement target variables: + FETCH cur INTO t1, t2, t2; + Targets can be: + - Local SP variables + - PACKAGE BODY variables +*/ +class sp_fetch_target: public Sql_alloc, + public sp_rcontext_addr +{ +public: + LEX_CSTRING name; + + sp_fetch_target(const LEX_CSTRING &name_arg, const sp_rcontext_addr &addr) + :sp_rcontext_addr(addr), + name(name_arg) + { } +}; + + /////////////////////////////////////////////////////////////////////////// /// This class represents an SQL/PSM label. Can refer to the identifier diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 6c8111a134d..30dcab67600 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -788,7 +788,8 @@ void sp_cursor::destroy() } -int sp_cursor::fetch(THD *thd, List *vars, bool error_on_no_data) +int sp_cursor::fetch(THD *thd, List *vars, + bool error_on_no_data) { if (! server_side_cursor) { @@ -798,8 +799,7 @@ int sp_cursor::fetch(THD *thd, List *vars, bool error_on_no_data) } if (vars->elements != result.get_field_count() && (vars->elements != 1 || - result.get_field_count() != - thd->spcont->get_variable(vars->head()->offset)->cols())) + result.get_field_count() != thd->get_variable(*vars->head())->cols())) { my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS, ER_THD(thd, ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0)); @@ -866,11 +866,12 @@ int sp_cursor::Select_fetch_into_spvars::prepare(List &fields, bool sp_cursor::Select_fetch_into_spvars:: - send_data_to_variable_list(List &vars, List &items) + send_data_to_variable_list(List &vars, + List &items) { - List_iterator_fast spvar_iter(vars); + List_iterator_fast spvar_iter(vars); List_iterator_fast item_iter(items); - sp_variable *spvar; + sp_fetch_target *spvar; Item *item; /* Must be ensured by the caller */ @@ -882,7 +883,7 @@ bool sp_cursor::Select_fetch_into_spvars:: */ for (; spvar= spvar_iter++, item= item_iter++; ) { - if (thd->spcont->set_variable(thd, spvar->offset, &item)) + if (thd->get_rcontext(*spvar)->set_variable(thd, spvar->offset(), &item)) return true; } return false; @@ -891,7 +892,6 @@ bool sp_cursor::Select_fetch_into_spvars:: int sp_cursor::Select_fetch_into_spvars::send_data(List &items) { - Item *item; /* If we have only one variable in spvar_list, and this is a ROW variable, and the number of fields in the ROW variable matches the number of @@ -902,10 +902,15 @@ int sp_cursor::Select_fetch_into_spvars::send_data(List &items) we go through send_data_to_variable_list(). It will report an error on attempt to assign a scalar value to a ROW variable. */ - return spvar_list->elements == 1 && - (item= thd->spcont->get_variable(spvar_list->head()->offset)) && - item->type_handler() == &type_handler_row && - item->cols() == items.elements ? - thd->spcont->set_variable_row(thd, spvar_list->head()->offset, items) : - send_data_to_variable_list(*spvar_list, items); + if (m_fetch_target_list->elements == 1) + { + const sp_fetch_target *target= m_fetch_target_list->head(); + sp_rcontext *rctx= thd->get_rcontext(*target); + Item *item; + if ((item= rctx->get_variable(target->offset())) && + item->type_handler() == &type_handler_row && + item->cols() == items.elements) + return rctx->set_variable_row(thd, target->offset(), items); + } + return send_data_to_variable_list(*m_fetch_target_list, items); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d429b66ba08..ab6bfd9cc3d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4435,6 +4435,18 @@ bool my_var_sp_row_field::set(THD *thd, Item *item) } +sp_rcontext *THD::get_rcontext(const sp_rcontext_addr &addr) +{ + return addr.rcontext_handler()->get_rcontext(spcont); +} + + +Item_field *THD::get_variable(const sp_rcontext_addr &addr) +{ + return get_rcontext(addr)->get_variable(addr.offset()); +} + + bool select_dumpvar::send_data_to_var_list(List &items) { DBUG_ENTER("select_dumpvar::send_data_to_var_list"); diff --git a/sql/sql_class.h b/sql/sql_class.h index d78f8a3e8a3..8cd757cfdaf 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3985,6 +3985,9 @@ public: sp_rcontext *spcont; // SP runtime context + sp_rcontext *get_rcontext(const sp_rcontext_addr &addr); + Item_field *get_variable(const sp_rcontext_addr &addr); + /** number of name_const() substitutions, see sp_head.cc:subst_spvars() */ uint query_name_consts; @@ -6330,10 +6333,11 @@ private: /// FETCH INTO . class Select_fetch_into_spvars: public select_result_interceptor { - List *spvar_list; + List *m_fetch_target_list; uint field_count; bool m_view_structure_only; - bool send_data_to_variable_list(List &vars, List &items); + bool send_data_to_variable_list(List &vars, + List &items); public: Select_fetch_into_spvars(THD *thd_arg, bool view_structure_only) :select_result_interceptor(thd_arg), @@ -6342,11 +6346,14 @@ private: void reset(THD *thd_arg) { select_result_interceptor::reinit(thd_arg); - spvar_list= NULL; + m_fetch_target_list= NULL; field_count= 0; } uint get_field_count() { return field_count; } - void set_spvar_list(List *vars) { spvar_list= vars; } + void set_spvar_list(List *vars) + { + m_fetch_target_list= vars; + } bool send_eof() override { return FALSE; } int send_data(List &items) override; @@ -6376,7 +6383,7 @@ public: my_bool is_open() { return MY_TEST(server_side_cursor); } - int fetch(THD *, List *vars, bool error_on_no_data); + int fetch(THD *, List *vars, bool error_on_no_data); bool export_structure(THD *thd, Row_definition_list *list); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0131068a530..935fbdd2c4c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -6556,6 +6556,21 @@ LEX::find_variable(const LEX_CSTRING *name, } +sp_fetch_target *LEX::make_fetch_target(THD *thd, const Lex_ident_sys_st &name) +{ + sp_pcontext *spc; + const Sp_rcontext_handler *rha; + sp_variable *spv= find_variable(&name, &spc, &rha); + if (unlikely(!spv)) + { + my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str); + return nullptr; + } + return new (thd->mem_root) sp_fetch_target(name, + sp_rcontext_addr(rha, spv->offset)); +} + + static bool is_new(const char *str) { return (str[0] == 'n' || str[0] == 'N') && @@ -7234,8 +7249,11 @@ bool LEX::sp_for_loop_cursor_iterate(THD *thd, const Lex_for_loop_st &loop) spcont, loop.m_cursor_offset, false); if (unlikely(instr == NULL) || unlikely(sphead->add_instr(instr))) return true; - instr->add_to_varlist(loop.m_index); - return false; + const sp_rcontext_addr raddr(&sp_rcontext_handler_local, + loop.m_index->offset); + sp_fetch_target *trg= + new (thd->mem_root) sp_fetch_target(loop.m_index->name, raddr); + return !trg || instr->add_to_fetch_target_list(trg); } @@ -9321,7 +9339,7 @@ int set_statement_var_if_exists(THD *thd, const char *var_name, } -bool LEX::sp_add_cfetch(THD *thd, const LEX_CSTRING *name) +sp_instr_cfetch *LEX::sp_add_instr_cfetch(THD *thd, const LEX_CSTRING *name) { uint offset; sp_instr_cfetch *i; @@ -9329,14 +9347,14 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_CSTRING *name) if (!spcont->find_cursor(name, &offset, false)) { my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name->str); - return true; + return nullptr; } i= new (thd->mem_root) sp_instr_cfetch(sphead->instructions(), spcont, offset, !(thd->variables.sql_mode & MODE_ORACLE)); if (unlikely(i == NULL) || unlikely(sphead->add_instr(i))) - return true; - return false; + return nullptr; + return i; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4d8fb5eceb6..2979d976d8e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -294,8 +294,10 @@ class LEX_COLUMN; class sp_head; class sp_name; class sp_instr; +class sp_instr_cfetch; class sp_pcontext; class sp_variable; +class sp_fetch_target; class sp_expr_lex; class sp_assignment_lex; class partition_info; @@ -3994,6 +3996,7 @@ public: sp_pcontext *not_used_ctx; return find_variable(name, ¬_used_ctx, rh); } + sp_fetch_target *make_fetch_target(THD *thd, const Lex_ident_sys_st &name); bool set_variable(const Lex_ident_sys_st *name, Item *item, const LEX_CSTRING &expr_str); bool set_variable(const Lex_ident_sys_st *name1, @@ -4611,7 +4614,7 @@ public: create_info.add(options); return check_create_options(create_info); } - bool sp_add_cfetch(THD *thd, const LEX_CSTRING *name); + sp_instr_cfetch *sp_add_instr_cfetch(THD *thd, const LEX_CSTRING *name); bool sp_add_agg_cfetch(); bool set_command_with_check(enum_sql_command command, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1f868846f00..d83cd8d2a41 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -253,6 +253,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)() Item_basic_constant *item_basic_constant; Key_part_spec *key_part; LEX *lex; + sp_instr_cfetch *instr_cfetch; sp_expr_lex *expr_lex; sp_assignment_lex *assignment_lex; class sp_lex_cursor *sp_cursor_stmt; @@ -266,6 +267,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)() List *stmt_info_list; List *string_list; List *ident_sys_list; + List *fetch_target_list; Statement_information_item *stmt_info_item; String *string; TABLE_LIST *table_list; @@ -1566,6 +1568,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); sp_cursor_stmt_lex sp_cursor_stmt +%type + sp_proc_stmt_fetch_head + +%type + sp_fetch_list + %type expr_lex @@ -4146,23 +4154,26 @@ sp_proc_stmt_open: sp_proc_stmt_fetch_head: FETCH_SYM ident INTO { - if (unlikely(Lex->sp_add_cfetch(thd, &$2))) + if (unlikely(!($$= Lex->sp_add_instr_cfetch(thd, &$2)))) MYSQL_YYABORT; } | FETCH_SYM FROM ident INTO { - if (unlikely(Lex->sp_add_cfetch(thd, &$3))) + if (unlikely(!($$= Lex->sp_add_instr_cfetch(thd, &$3)))) MYSQL_YYABORT; } | FETCH_SYM NEXT_SYM FROM ident INTO { - if (unlikely(Lex->sp_add_cfetch(thd, &$4))) + if (unlikely(!($$= Lex->sp_add_instr_cfetch(thd, &$4)))) MYSQL_YYABORT; } ; sp_proc_stmt_fetch: - sp_proc_stmt_fetch_head sp_fetch_list { } + sp_proc_stmt_fetch_head sp_fetch_list + { + $1->set_fetch_target_list($2); + } | FETCH_SYM GROUP_SYM NEXT_SYM ROW_SYM { if (unlikely(Lex->sp_add_agg_cfetch())) @@ -4191,35 +4202,16 @@ sp_proc_stmt_close: sp_fetch_list: ident { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - sp_pcontext *spc= lex->spcont; - sp_variable *spv= likely(spc != NULL) - ? spc->find_variable(&$1, false) - : NULL; - - if (unlikely(!spv)) - my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); - - /* An SP local variable */ - sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); - i->add_to_varlist(spv); + sp_fetch_target *target= Lex->make_fetch_target(thd, $1); + if (!target || + !($$= List::make(thd->mem_root, target))) + MYSQL_YYABORT; } | sp_fetch_list ',' ident { - LEX *lex= Lex; - sp_head *sp= lex->sphead; - sp_pcontext *spc= lex->spcont; - sp_variable *spv= likely(spc != NULL) - ? spc->find_variable(&$3, false) - : NULL; - - if (unlikely(!spv)) - my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str)); - - /* An SP local variable */ - sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); - i->add_to_varlist(spv); + sp_fetch_target *target= Lex->make_fetch_target(thd, $3); + if (!target || $1->push_back(target, thd->mem_root)) + MYSQL_YYABORT; } ; diff --git a/sql/structs.h b/sql/structs.h index 8da5d2507f5..ada7a5b77c2 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -1060,4 +1060,29 @@ public: }; +/* + A run-time address of an SP variable. Consists of: + - The rcontext type (LOCAL, PACKAGE BODY), + controlled by m_rcontext_handler + - The frame offset +*/ +class sp_rcontext_addr +{ +public: + sp_rcontext_addr(const class Sp_rcontext_handler *h, uint offset) + :m_rcontext_handler(h), m_offset(offset) + { } + const Sp_rcontext_handler *rcontext_handler() const + { + return m_rcontext_handler; + } + uint offset() const + { + return m_offset; + } +protected: + const class Sp_rcontext_handler *m_rcontext_handler; + uint m_offset; ///< Frame offset +}; + #endif /* STRUCTS_INCLUDED */