Commit 30ea6ddd authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-6603 SBR failure upon executing a prepared statement with input...

MDEV-6603 SBR failure upon executing a prepared statement with input placeholder under anonymous block

Normally, Prepared_statement object rewrites the query on execution
to replace ?-placeholders with values. The rewritten query may be written
to logs (including binlog) or stored in the query cache.

But for compound statements, the whole block is prepared and executed,
while contained statements are logged individually. So it doesn't make
sense to rewrite the original statement block. Instead, we need to rewrite
every contained statement. SP is already doing it to replace SP variables
with values. Let it rewrite PS parameters too in the same loop.
parent 013f0f6c
......@@ -15,6 +15,7 @@ PREPARE stmt FROM "BEGIN NOT ATOMIC
INSERT INTO t1 VALUES (?);
END";
SET @val = 6|
reset master|
EXECUTE stmt USING @val|
SELECT * FROM t1|
a
......@@ -24,6 +25,17 @@ a
4
5
6
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6)
master-bin.000001 # Query # # COMMIT
PREPARE stmt FROM "BEGIN NOT ATOMIC
DECLARE v_res INT;
SELECT COUNT(*) INTO v_res FROM t1;
......@@ -119,3 +131,35 @@ executing: drop table t1
executing: drop table t2
executing: drop table t3
executing: drop table t4
create table t1 (x int)|
create function fn(a int) returns int
begin
insert t1 values (a+7);
return a+8;
end|
reset master|
/**/ if fn(9) > 5 then
select 1;
end if|
1
1
prepare stmt from "if fn(?) > 6 then
begin
declare a int;
set a=?*2;
insert t1 values(a+?);
end;
end if"|
set @a=1, @b=2, @c=3|
execute stmt using @a, @b, @c|
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; SELECT "test"."fn"(9)
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; SELECT "test"."fn"(1)
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; insert t1 values( NAME_CONST('a',4)+3)
master-bin.000001 # Query # # COMMIT
drop function fn|
drop table t1|
#
# MDEV-5317 Compound statement / anonymous blocks
#
source include/have_log_bin.inc;
delimiter |;
CREATE TABLE t1 (a INT PRIMARY KEY)|
......@@ -18,9 +19,15 @@ PREPARE stmt FROM "BEGIN NOT ATOMIC
INSERT INTO t1 VALUES (?);
END";
SET @val = 6|
reset master|
EXECUTE stmt USING @val|
SELECT * FROM t1|
# see how ?-placeholder was replaced with the value
delimiter ;|
source include/show_binlog_events.inc;
delimiter |;
PREPARE stmt FROM "BEGIN NOT ATOMIC
DECLARE v_res INT;
SELECT COUNT(*) INTO v_res FROM t1;
......@@ -113,3 +120,31 @@ do
execute dt;
end while|
--horizontal_results
# see how ?-placeholder and SP variables are replaced with values
create table t1 (x int)|
create function fn(a int) returns int
begin
insert t1 values (a+7);
return a+8;
end|
reset master|
/**/ if fn(9) > 5 then
select 1;
end if|
prepare stmt from "if fn(?) > 6 then
begin
declare a int;
set a=?*2;
insert t1 values(a+?);
end;
end if"|
set @a=1, @b=2, @c=3|
execute stmt using @a, @b, @c|
delimiter ;|
source include/show_binlog_events.inc;
delimiter |;
drop function fn|
drop table t1|
......@@ -890,7 +890,8 @@ sp_head::create_result_field(uint field_max_length, const char *field_name,
}
int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
int cmp_rqp_locations(Rewritable_query_parameter * const *a,
Rewritable_query_parameter * const *b)
{
return (int)((*a)->pos_in_query - (*b)->pos_in_query);
}
......@@ -996,30 +997,29 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
{
DBUG_ENTER("subst_spvars");
Dynamic_array<Item_splocal*> sp_vars_uses;
Dynamic_array<Rewritable_query_parameter*> rewritables;
char *pbuf;
StringBuffer<512> qbuf;
Copy_query_with_rewrite acc(thd, query_str->str, query_str->length, &qbuf);
/* Find all instances of Item_splocal used in this statement */
/* Find rewritable Items used in this statement */
for (Item *item= instr->free_list; item; item= item->next)
{
Item_splocal *item_spl= item->get_item_splocal();
if (item_spl && item_spl->pos_in_query)
sp_vars_uses.append(item_spl);
Rewritable_query_parameter *rqp= item->get_rewritable_query_parameter();
if (rqp && rqp->pos_in_query)
rewritables.append(rqp);
}
if (!sp_vars_uses.elements())
if (!rewritables.elements())
DBUG_RETURN(FALSE);
/* Sort SP var refs by their occurences in the query */
sp_vars_uses.sort(cmp_splocal_locations);
rewritables.sort(cmp_rqp_locations);
thd->query_name_consts= sp_vars_uses.elements();
thd->query_name_consts= rewritables.elements();
for (Item_splocal **splocal= sp_vars_uses.front();
splocal <= sp_vars_uses.back(); splocal++)
for (Rewritable_query_parameter **rqp= rewritables.front();
rqp <= rewritables.back(); rqp++)
{
if (acc.append(*splocal))
if (acc.append(*rqp))
DBUG_RETURN(TRUE);
}
if (acc.finalize())
......
......@@ -3235,6 +3235,8 @@ void Prepared_statement::setup_set_params()
replace_params_with_values|= opt_log || thd->variables.sql_log_slow;
// query cache
replace_params_with_values|= query_cache_is_cacheable_query(lex);
// but never for compound statements
replace_params_with_values&= lex->sql_command != SQLCOM_COMPOUND;
if (replace_params_with_values)
{
......
......@@ -13333,7 +13333,9 @@ param_marker:
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
MYSQL_YYABORT;
}
item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query()));
const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
: thd->query();
item= new (thd->mem_root) Item_param(lip->get_tok_start() - query_start);
if (!($$= item) || lex->param_list.push_back(item))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment