MDEV-36047 Package body variables are not allowed as FETCH targets

It was not possible to use a package body variable as a
fetch target:

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; -- this returned "Undeclared variable: vc" error.
    CLOSE cur;
    RETURN vc;
  END;
END;

FETCH assumed that all fetch targets reside of the same sp_rcontext
instance with the cursor. This patch fixes the problem.
Now a cursor and its fetch target can reside in different sp_rcontext
instances.

Details:

- Adding a helper class sp_rcontext_addr
  (a combination of Sp_rcontext_handler pointer and an offset in the rcontext)

- Adding a new class sp_fetch_target deriving from sp_rcontext_addr.
  Fetch targets in "FETCH cur INTO target1, target2 ..." are now collected
  into this structure instead of sp_variable.
  sp_variable cannot be used any more to store fetch targets,
  because it does not have a pointer to Sp_rcontext_handler
  (it only has the current rcontext offset).

- Removing members sp_instr_set members m_rcontext_handler and m_offset.
  Deriving sp_instr_set from sp_rcontext_addr instead.

- Renaming sp_instr_cfetch member  "List<sp_variable> m_varlist"
  to "List<sp_fetch_target> m_fetch_target_list".

- Fixing LEX::sp_add_cfetch() to return the pointer to the
  created sp_fetch_target instance (instead of returning bool).
  This helps to make the grammar in sql_yacc.c simpler

- Renaming LEX::sp_add_cfetch() to LEX::sp_add_instr_cfetch(),
  as `if(sp_add_cfetch())` changed its meaning to the opposite,
  to avoid automatic wrong merge from earlier versions.

- Chaning the "List<sp_variable> *vars" parameter to sp_cursor::fetch
  to have the data type "List<sp_fetch_target> *".

- Changing the data type of "List<sp_variable> &vars" in
  sp_cursor::Select_fetch_into_spvars::send_data_to_variable_list()
  to "List<sp_fetch_target> &".

- Adding THD helper methods get_rcontext() and get_variable().

- Moving the code from sql_yacc.yy into a new LEX method
  LEX::make_fetch_target().

- Simplifying the grammar in sql_yacc.yy using the new LEX method.
  Changing the data type of the bison rule sp_fetch_list from "void"
  to "List<sp_fetch_target> *".
This commit is contained in:
Alexander Barkov 2025-02-08 17:39:27 +04:00
parent 6be0940f10
commit b7d67ceb5f
25 changed files with 731 additions and 72 deletions

View File

@ -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 ;$$

View File

@ -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 ;$$

View File

@ -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 ;$$

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ;$$

View File

@ -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 ;$$

View File

@ -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 ;$$

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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<sp_variable> li(m_varlist);
sp_variable *pv;
List_iterator_fast<sp_fetch_target> 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());
}
}

View File

@ -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<sp_fetch_target> *list)
{
m_fetch_target_list= *list;
}
private:
uint m_cursor;
List<sp_variable> m_varlist;
List<sp_fetch_target> m_fetch_target_list;
bool m_error_on_no_data;
public:

View File

@ -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

View File

@ -788,7 +788,8 @@ void sp_cursor::destroy()
}
int sp_cursor::fetch(THD *thd, List<sp_variable> *vars, bool error_on_no_data)
int sp_cursor::fetch(THD *thd, List<sp_fetch_target> *vars,
bool error_on_no_data)
{
if (! server_side_cursor)
{
@ -798,8 +799,7 @@ int sp_cursor::fetch(THD *thd, List<sp_variable> *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<Item> &fields,
bool sp_cursor::Select_fetch_into_spvars::
send_data_to_variable_list(List<sp_variable> &vars, List<Item> &items)
send_data_to_variable_list(List<sp_fetch_target> &vars,
List<Item> &items)
{
List_iterator_fast<sp_variable> spvar_iter(vars);
List_iterator_fast<sp_fetch_target> spvar_iter(vars);
List_iterator_fast<Item> 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<Item> &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<Item> &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)) &&
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 ?
thd->spcont->set_variable_row(thd, spvar_list->head()->offset, items) :
send_data_to_variable_list(*spvar_list, items);
item->cols() == items.elements)
return rctx->set_variable_row(thd, target->offset(), items);
}
return send_data_to_variable_list(*m_fetch_target_list, items);
}

View File

@ -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<Item> &items)
{
DBUG_ENTER("select_dumpvar::send_data_to_var_list");

View File

@ -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 <cname> INTO <varlist>.
class Select_fetch_into_spvars: public select_result_interceptor
{
List<sp_variable> *spvar_list;
List<sp_fetch_target> *m_fetch_target_list;
uint field_count;
bool m_view_structure_only;
bool send_data_to_variable_list(List<sp_variable> &vars, List<Item> &items);
bool send_data_to_variable_list(List<sp_fetch_target> &vars,
List<Item> &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<sp_variable> *vars) { spvar_list= vars; }
void set_spvar_list(List<sp_fetch_target> *vars)
{
m_fetch_target_list= vars;
}
bool send_eof() override { return FALSE; }
int send_data(List<Item> &items) override;
@ -6376,7 +6383,7 @@ public:
my_bool is_open()
{ return MY_TEST(server_side_cursor); }
int fetch(THD *, List<sp_variable> *vars, bool error_on_no_data);
int fetch(THD *, List<sp_fetch_target> *vars, bool error_on_no_data);
bool export_structure(THD *thd, Row_definition_list *list);

View File

@ -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;
}

View File

@ -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, &not_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,

View File

@ -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<Statement_information_item> *stmt_info_list;
List<String> *string_list;
List<Lex_ident_sys> *ident_sys_list;
List<sp_fetch_target> *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 <instr_cfetch>
sp_proc_stmt_fetch_head
%type <fetch_target_list>
sp_fetch_list
%type <expr_lex>
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<sp_fetch_target>::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;
}
;

View File

@ -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 */