Fix for Bug# 4200 "Parse error on LIKE ESCAPE with parameter binding"

Now ESCAPE in LIKE will accept not only string literal but constant 
delimited expression.
parent 6b45c24d
...@@ -45,6 +45,12 @@ a\b ...@@ -45,6 +45,12 @@ a\b
select * from t1 where a like 'a\\%' escape '#' and a like 'a\\\\b'; select * from t1 where a like 'a\\%' escape '#' and a like 'a\\\\b';
a a
a\b a\b
prepare stmt1 from 'select * from t1 where a like \'a\\%\' escape ?';
set @esc='#';
execute stmt1 using @esc;
a
a\b
deallocate prepare stmt1;
drop table t1; drop table t1;
create table t1 (a datetime); create table t1 (a datetime);
insert into t1 values ('2004-03-11 12:00:21'); insert into t1 values ('2004-03-11 12:00:21');
......
...@@ -25,14 +25,23 @@ select * from t1 where a like "%abc\d%"; ...@@ -25,14 +25,23 @@ select * from t1 where a like "%abc\d%";
drop table t1; drop table t1;
create table t1 (a varchar(10), key(a));
# #
# Bug #2231 # Bug #2231
# #
create table t1 (a varchar(10), key(a));
insert into t1 values ('a'), ('a\\b'); insert into t1 values ('a'), ('a\\b');
select * from t1 where a like 'a\\%' escape '#'; select * from t1 where a like 'a\\%' escape '#';
select * from t1 where a like 'a\\%' escape '#' and a like 'a\\\\b'; select * from t1 where a like 'a\\%' escape '#' and a like 'a\\\\b';
#
# Bug #4200: Prepared statement parameter as argument to ESCAPE
#
prepare stmt1 from 'select * from t1 where a like \'a\\%\' escape ?';
set @esc='#';
execute stmt1 using @esc;
deallocate prepare stmt1;
drop table t1; drop table t1;
# #
......
...@@ -2151,9 +2151,22 @@ Item_func::optimize_type Item_func_like::select_optimize() const ...@@ -2151,9 +2151,22 @@ Item_func::optimize_type Item_func_like::select_optimize() const
bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
{ {
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
if (Item_bool_func2::fix_fields(thd, tlist, ref)) if (Item_bool_func2::fix_fields(thd, tlist, ref) ||
escape_item->fix_fields(thd, tlist, &escape_item))
return 1; return 1;
if (!escape_item->const_during_execution())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE");
return 1;
}
if (escape_item->const_item())
{
/* If we are on execution stage */
String *escape_str= escape_item->val_str(&tmp_value1);
escape= escape_str ? *(escape_str->ptr()) : '\\';
/* /*
We could also do boyer-more for non-const items, but as we would have to We could also do boyer-more for non-const items, but as we would have to
recompute the tables for each row it's not worth it. recompute the tables for each row it's not worth it.
...@@ -2181,7 +2194,6 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) ...@@ -2181,7 +2194,6 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ; for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
canDoTurboBM = (tmp == last) && !use_mb(args[0]->collation.collation); canDoTurboBM = (tmp == last) && !use_mb(args[0]->collation.collation);
} }
if (canDoTurboBM) if (canDoTurboBM)
{ {
pattern = first + 1; pattern = first + 1;
...@@ -2196,6 +2208,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) ...@@ -2196,6 +2208,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
DBUG_PRINT("info",("done")); DBUG_PRINT("info",("done"));
} }
} }
}
return 0; return 0;
} }
......
...@@ -841,12 +841,14 @@ class Item_func_like :public Item_bool_func2 ...@@ -841,12 +841,14 @@ class Item_func_like :public Item_bool_func2
bool turboBM_matches(const char* text, int text_len) const; bool turboBM_matches(const char* text, int text_len) const;
enum { alphabet_size = 256 }; enum { alphabet_size = 256 };
Item *escape_item;
public: public:
char escape; char escape;
Item_func_like(Item *a,Item *b, char* escape_arg) Item_func_like(Item *a,Item *b, Item *escape_arg)
:Item_bool_func2(a,b), canDoTurboBM(false), pattern(0), pattern_len(0), :Item_bool_func2(a,b), canDoTurboBM(false), pattern(0), pattern_len(0),
bmGs(0), bmBc(0), escape(*escape_arg) {} bmGs(0), bmBc(0), escape_item(escape_arg) {}
longlong val_int(); longlong val_int();
enum Functype functype() const { return LIKE_FUNC; } enum Functype functype() const { return LIKE_FUNC; }
optimize_type select_optimize() const; optimize_type select_optimize() const;
......
...@@ -626,7 +626,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, ...@@ -626,7 +626,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen,
{ {
Item *cond= new Item_func_like(new Item_field(pfname), Item *cond= new Item_func_like(new Item_field(pfname),
new Item_string(mask,mlen,pfname->charset()), new Item_string(mask,mlen,pfname->charset()),
(char*) "\\"); new Item_string("\\",1,&my_charset_latin1));
if (thd->is_fatal_error) if (thd->is_fatal_error)
return 0; // OOM return 0; // OOM
return prepare_simple_select(thd,cond,tables,table,error); return prepare_simple_select(thd,cond,tables,table,error);
......
...@@ -606,7 +606,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -606,7 +606,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <simple_string> %type <simple_string>
remember_name remember_end opt_ident opt_db text_or_password remember_name remember_end opt_ident opt_db text_or_password
opt_escape opt_constraint constraint opt_constraint constraint
%type <string> %type <string>
text_string opt_gconcat_separator text_string opt_gconcat_separator
...@@ -634,7 +634,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -634,7 +634,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
using_list expr_or_default set_expr_or_default interval_expr using_list expr_or_default set_expr_or_default interval_expr
param_marker singlerow_subselect singlerow_subselect_init param_marker singlerow_subselect singlerow_subselect_init
exists_subselect exists_subselect_init geometry_function exists_subselect exists_subselect_init geometry_function
signed_literal now_or_signed_literal signed_literal now_or_signed_literal opt_escape
%type <item_num> %type <item_num>
NUM_literal NUM_literal
...@@ -3570,8 +3570,12 @@ having_clause: ...@@ -3570,8 +3570,12 @@ having_clause:
; ;
opt_escape: opt_escape:
ESCAPE_SYM TEXT_STRING_literal { $$= $2.str; } ESCAPE_SYM simple_expr { $$= $2; }
| /* empty */ { $$= (char*) "\\"; }; | /* empty */
{
$$= new Item_string("\\", 1, &my_charset_latin1);
}
;
/* /*
......
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