Commit 1164e2bc authored by unknown's avatar unknown

Bug#33851 Passing UNSIGNED param to EXECUTE returns ERROR 1210

The problem is that passing anything other than a integer to a limit
clause in a prepared statement would fail. This limitation was introduced
to avoid replication problems (e.g: replicating the statement with a
string argument would cause a parse failure in the slave).

The solution is to convert arguments to the limit clause to a integer
value and use this converted value when persisting the query to the log.


mysql-test/r/limit.result:
  Update test case result.
mysql-test/r/ps.result:
  Add test case result for Bug#33851
mysql-test/r/rpl_user_variables.result:
  Test case result for replication of prepared statement with
  limit clause.
mysql-test/t/limit.test:
  Test parameters to limit clause.
mysql-test/t/ps.test:
  Add test case for Bug#33851
mysql-test/t/rpl_user_variables.test:
  Test replication of a parameter which value is converted.
sql/item.cc:
  Convert value to integer if it's a parameter to a limit clause.
sql/item.h:
  Flag signal that item is a parameter to a limit clause.
sql/item_func.cc:
  Const member functions, object is not mutated.
sql/sql_class.h:
  Const member functions, object is not mutated.
sql/sql_yacc.yy:
  Flag that item is a parameter to a limit clause.
parent b43f8f69
...@@ -94,6 +94,9 @@ drop table t1; ...@@ -94,6 +94,9 @@ drop table t1;
prepare s from "select 1 limit ?"; prepare s from "select 1 limit ?";
set @a='qwe'; set @a='qwe';
execute s using @a; execute s using @a;
1
set @a=-1;
execute s using @a;
ERROR HY000: Incorrect arguments to EXECUTE ERROR HY000: Incorrect arguments to EXECUTE
prepare s from "select 1 limit 1, ?"; prepare s from "select 1 limit 1, ?";
execute s using @a; execute s using @a;
...@@ -101,4 +104,10 @@ ERROR HY000: Incorrect arguments to EXECUTE ...@@ -101,4 +104,10 @@ ERROR HY000: Incorrect arguments to EXECUTE
prepare s from "select 1 limit ?, ?"; prepare s from "select 1 limit ?, ?";
execute s using @a, @a; execute s using @a, @a;
ERROR HY000: Incorrect arguments to EXECUTE ERROR HY000: Incorrect arguments to EXECUTE
set @a=14632475938453979136;
execute s using @a, @a;
1
set @a=-14632475938453979136;
execute s using @a, @a;
ERROR HY000: Incorrect arguments to EXECUTE
End of 5.0 tests End of 5.0 tests
...@@ -1861,4 +1861,34 @@ prepare stmt from "create view v1 as select * from t1"; ...@@ -1861,4 +1861,34 @@ prepare stmt from "create view v1 as select * from t1";
ERROR 42S02: Table 'test.t1' doesn't exist ERROR 42S02: Table 'test.t1' doesn't exist
prepare stmt from "create view v1 as select * from `t1` `b`"; prepare stmt from "create view v1 as select * from `t1` `b`";
ERROR 42S02: Table 'test.t1' doesn't exist ERROR 42S02: Table 'test.t1' doesn't exist
prepare stmt from "select ?";
set @arg= 123456789.987654321;
select @arg;
@arg
123456789.987654321
execute stmt using @arg;
?
123456789.987654321
set @arg= "string";
select @arg;
@arg
string
execute stmt using @arg;
?
string
set @arg= 123456;
select @arg;
@arg
123456
execute stmt using @arg;
?
123456
set @arg= cast(-12345.54321 as decimal(20, 10));
select @arg;
@arg
-12345.5432100000
execute stmt using @arg;
?
-12345.5432100000
deallocate prepare stmt;
End of 5.0 tests. End of 5.0 tests.
...@@ -290,6 +290,22 @@ select * from t1; ...@@ -290,6 +290,22 @@ select * from t1;
a b a b
2 1 2 1
drop table t1; drop table t1;
create table t1(a int);
insert into t1 values (1),(2);
prepare s1 from 'insert into t1 select a from t1 limit ?';
set @x='1.1';
execute s1 using @x;
select * from t1;
a
1
2
1
select * from t1;
a
1
2
1
drop table t1;
End of 5.0 tests. End of 5.0 tests.
DROP FUNCTION IF EXISTS f1; DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2; DROP FUNCTION IF EXISTS f2;
......
...@@ -76,15 +76,22 @@ drop table t1; ...@@ -76,15 +76,22 @@ drop table t1;
# Bug #28464: a string argument to 'limit ?' PS # Bug #28464: a string argument to 'limit ?' PS
# #
prepare s from "select 1 limit ?"; prepare s from "select 1 limit ?";
set @a='qwe'; set @a='qwe';
--error 1210 execute s using @a;
set @a=-1;
--error ER_WRONG_ARGUMENTS
execute s using @a; execute s using @a;
prepare s from "select 1 limit 1, ?"; prepare s from "select 1 limit 1, ?";
--error 1210 --error ER_WRONG_ARGUMENTS
execute s using @a; execute s using @a;
prepare s from "select 1 limit ?, ?"; prepare s from "select 1 limit ?, ?";
--error 1210 --error ER_WRONG_ARGUMENTS
execute s using @a, @a;
set @a=14632475938453979136;
execute s using @a, @a;
set @a=-14632475938453979136;
--error ER_WRONG_ARGUMENTS
execute s using @a, @a; execute s using @a, @a;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -1947,4 +1947,23 @@ prepare stmt from "create view v1 as select * from t1"; ...@@ -1947,4 +1947,23 @@ prepare stmt from "create view v1 as select * from t1";
--error ER_NO_SUCH_TABLE --error ER_NO_SUCH_TABLE
prepare stmt from "create view v1 as select * from `t1` `b`"; prepare stmt from "create view v1 as select * from `t1` `b`";
#
# Bug#33851: Passing UNSIGNED param to EXECUTE returns ERROR 1210
#
prepare stmt from "select ?";
set @arg= 123456789.987654321;
select @arg;
execute stmt using @arg;
set @arg= "string";
select @arg;
execute stmt using @arg;
set @arg= 123456;
select @arg;
execute stmt using @arg;
set @arg= cast(-12345.54321 as decimal(20, 10));
select @arg;
execute stmt using @arg;
deallocate prepare stmt;
--echo End of 5.0 tests. --echo End of 5.0 tests.
...@@ -337,6 +337,23 @@ select * from t1; ...@@ -337,6 +337,23 @@ select * from t1;
connection master; connection master;
drop table t1; drop table t1;
#
# Bug#33851: Passing UNSIGNED param to EXECUTE returns ERROR 1210
#
connection master;
create table t1(a int);
insert into t1 values (1),(2);
prepare s1 from 'insert into t1 select a from t1 limit ?';
set @x='1.1';
execute s1 using @x;
select * from t1;
sync_slave_with_master;
connection slave;
select * from t1;
connection master;
drop table t1;
--echo End of 5.0 tests. --echo End of 5.0 tests.
# This test uses a stored function that uses user-defined variables to return data # This test uses a stored function that uses user-defined variables to return data
......
...@@ -2385,7 +2385,7 @@ default_set_param_func(Item_param *param, ...@@ -2385,7 +2385,7 @@ default_set_param_func(Item_param *param,
Item_param::Item_param(unsigned pos_in_query_arg) : Item_param::Item_param(unsigned pos_in_query_arg) :
strict_type(FALSE), limit_clause_param(FALSE),
state(NO_VALUE), state(NO_VALUE),
item_result_type(STRING_RESULT), item_result_type(STRING_RESULT),
/* Don't pretend to be a literal unless value for this item is set. */ /* Don't pretend to be a literal unless value for this item is set. */
...@@ -2581,8 +2581,13 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) ...@@ -2581,8 +2581,13 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
{ {
item_result_type= entry->type; item_result_type= entry->type;
unsigned_flag= entry->unsigned_flag; unsigned_flag= entry->unsigned_flag;
if (strict_type && required_result_type != item_result_type) if (limit_clause_param)
DBUG_RETURN(1); {
my_bool unused;
set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS);
item_type= Item::INT_ITEM;
DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
}
switch (item_result_type) { switch (item_result_type) {
case REAL_RESULT: case REAL_RESULT:
set_double(*(double*)entry->value); set_double(*(double*)entry->value);
......
...@@ -1417,8 +1417,6 @@ class Item_param :public Item ...@@ -1417,8 +1417,6 @@ class Item_param :public Item
char cnvbuf[MAX_FIELD_WIDTH]; char cnvbuf[MAX_FIELD_WIDTH];
String cnvstr; String cnvstr;
Item *cnvitem; Item *cnvitem;
bool strict_type;
enum Item_result required_result_type;
public: public:
enum enum_item_param_state enum enum_item_param_state
...@@ -1548,11 +1546,8 @@ public: ...@@ -1548,11 +1546,8 @@ public:
Otherwise return FALSE. Otherwise return FALSE.
*/ */
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
void set_strict_type(enum Item_result result_type_arg) /** Item is a argument to a limit clause. */
{ bool limit_clause_param;
strict_type= TRUE;
required_result_type= result_type_arg;
}
}; };
......
...@@ -3985,7 +3985,7 @@ double user_var_entry::val_real(my_bool *null_value) ...@@ -3985,7 +3985,7 @@ double user_var_entry::val_real(my_bool *null_value)
/* Get the value of a variable as an integer */ /* Get the value of a variable as an integer */
longlong user_var_entry::val_int(my_bool *null_value) longlong user_var_entry::val_int(my_bool *null_value) const
{ {
if ((*null_value= (value == 0))) if ((*null_value= (value == 0)))
return LL(0); return LL(0);
......
...@@ -2329,7 +2329,7 @@ class user_var_entry ...@@ -2329,7 +2329,7 @@ class user_var_entry
bool unsigned_flag; bool unsigned_flag;
double val_real(my_bool *null_value); double val_real(my_bool *null_value);
longlong val_int(my_bool *null_value); longlong val_int(my_bool *null_value) const;
String *val_str(my_bool *null_value, String *str, uint decimals); String *val_str(my_bool *null_value, String *str, uint decimals);
my_decimal *val_decimal(my_bool *null_value, my_decimal *result); my_decimal *val_decimal(my_bool *null_value, my_decimal *result);
DTCollation collation; DTCollation collation;
......
...@@ -6320,7 +6320,7 @@ limit_options: ...@@ -6320,7 +6320,7 @@ limit_options:
limit_option: limit_option:
param_marker param_marker
{ {
((Item_param *) $1)->set_strict_type(INT_RESULT); ((Item_param *) $1)->limit_clause_param= TRUE;
} }
| ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); } | ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); }
| LONG_NUM { $$= new Item_uint($1.str, $1.length); } | LONG_NUM { $$= new Item_uint($1.str, $1.length); }
......
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