diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 2ee6950d210..c86a69ab45f 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -801,3 +801,25 @@ execute stmt using @param1; select utext from t1 where utext like '%%'; drop table t1; deallocate prepare stmt; +# +# Bug#11299 "prepared statement makes wrong SQL syntax in binlog which stops +# replication": check that errouneous queries with placeholders are not +# allowed +# +create table t1 (a int); +--error 1064 +prepare stmt from "select ??"; +--error 1064 +prepare stmt from "select ?FROM t1"; +--error 1064 +prepare stmt from "select FROM t1 WHERE?=1"; +--error 1064 +prepare stmt from "update t1 set a=a+?WHERE 1"; +--error 1064 +select ?; +--error 1064 +select ??; +--error 1064 +select ? from t1; +drop table t1; +deallocate prepare stmt; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 218410eed81..a4293fa76bd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -556,6 +556,15 @@ int yylex(void *arg, void *yythd) lex->next_state= MY_LEX_START; // Allow signed numbers if (c == ',') lex->tok_start=lex->ptr; // Let tok_start point at next item + /* + Check for a placeholder: it should not precede a possible identifier + because of binlogging: when a placeholder is replaced with + its value in a query for the binlog, the query must stay + grammatically correct. + */ + else if (c == '?' && ((THD*) yythd)->command == COM_PREPARE && + !ident_map[cs, yyPeek()]) + return(PARAM_MARKER); return((int) c); case MY_LEX_IDENT_OR_NCHAR: diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 84de06d5604..f0ad035ed5a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -465,6 +465,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PACK_KEYS_SYM %token PARTIAL %token PASSWORD +%token PARAM_MARKER %token PHASE_SYM %token POINTFROMTEXT %token POINT_SYM @@ -6933,23 +6934,15 @@ text_string: ; param_marker: - '?' + PARAM_MARKER { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_STMT_PREPARE) + Item_param *item= new Item_param((uint) (lex->tok_start - + (uchar *) thd->query)); + if (!($$= item) || lex->param_list.push_back(item)) { - Item_param *item= new Item_param((uint) (lex->tok_start - - (uchar *) thd->query)); - if (!($$= item) || lex->param_list.push_back(item)) - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - YYABORT; - } - } - else - { - yyerror(ER(ER_SYNTAX_ERROR)); + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); YYABORT; } }