diff --git a/mysql-test/suite/compat/oracle/r/binlog_stm_ps.result b/mysql-test/suite/compat/oracle/r/binlog_stm_ps.result new file mode 100644 index 00000000000..c60e3493b3f --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/binlog_stm_ps.result @@ -0,0 +1,67 @@ +SET sql_mode=ORACLE; +# +# MDEV-10801 sql_mode: dynamic SQL placeholders +# +CREATE TABLE t1 (a INT, b INT); +SET @a=10, @b=20; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (?,?)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:a,:b)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:aaa,:bbb)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"a",:"b")'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"aaa",:"bbb")'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:1,:2)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:222,:111)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:0,:65535)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:65535,:0)'; +EXECUTE stmt USING @a, @b; +SELECT * FROM t1; +a b +10 20 +10 20 +10 20 +10 20 +10 20 +10 20 +10 20 +10 20 +10 20 +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`; CREATE TABLE t1 (a INT, b INT) +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (10,20) +master-bin.000001 # Query # # COMMIT +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/r/ps.result b/mysql-test/suite/compat/oracle/r/ps.result new file mode 100644 index 00000000000..79cabf29eac --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/ps.result @@ -0,0 +1,41 @@ +SET sql_mode=ORACLE; +# +# MDEV-10801 sql_mode: dynamic SQL placeholders +# +SET @a=10, @b=20; +PREPARE stmt FROM 'SELECT ?,?'; +EXECUTE stmt USING @a, @b; +? ? +10 20 +PREPARE stmt FROM 'SELECT :a,:b'; +EXECUTE stmt USING @a, @b; +:a :b +10 20 +PREPARE stmt FROM 'SELECT :aaa,:bbb'; +EXECUTE stmt USING @a, @b; +:aaa :bbb +10 20 +PREPARE stmt FROM 'SELECT :"a",:"b"'; +EXECUTE stmt USING @a, @b; +:"a" :"b" +10 20 +PREPARE stmt FROM 'SELECT :"aaa",:"bbb"'; +EXECUTE stmt USING @a, @b; +:"aaa" :"bbb" +10 20 +PREPARE stmt FROM 'SELECT :1,:2'; +EXECUTE stmt USING @a, @b; +:1 :2 +10 20 +PREPARE stmt FROM 'SELECT :222,:111'; +EXECUTE stmt USING @a, @b; +:222 :111 +10 20 +PREPARE stmt FROM 'SELECT :0,:65535'; +EXECUTE stmt USING @a, @b; +:0 :65535 +10 20 +PREPARE stmt FROM 'SELECT :65535,:0'; +EXECUTE stmt USING @a, @b; +:65535 :0 +10 20 diff --git a/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test b/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test new file mode 100644 index 00000000000..996ef574413 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/binlog_stm_ps.test @@ -0,0 +1,37 @@ +--source include/not_embedded.inc +--source include/have_binlog_format_statement.inc + +--disable_query_log +reset master; # get rid of previous tests binlog +--enable_query_log + +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-10801 sql_mode: dynamic SQL placeholders +--echo # + +CREATE TABLE t1 (a INT, b INT); +SET @a=10, @b=20; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (?,?)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:a,:b)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:aaa,:bbb)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"a",:"b")'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:"aaa",:"bbb")'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:1,:2)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:222,:111)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:0,:65535)'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'INSERT INTO t1 VALUES (:65535,:0)'; +EXECUTE stmt USING @a, @b; +SELECT * FROM t1; +--let $binlog_file = LAST +source include/show_binlog_events.inc; +DROP TABLE t1; diff --git a/mysql-test/suite/compat/oracle/t/ps.test b/mysql-test/suite/compat/oracle/t/ps.test new file mode 100644 index 00000000000..e7dcecbaeed --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/ps.test @@ -0,0 +1,25 @@ +SET sql_mode=ORACLE; + +--echo # +--echo # MDEV-10801 sql_mode: dynamic SQL placeholders +--echo # + +SET @a=10, @b=20; +PREPARE stmt FROM 'SELECT ?,?'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :a,:b'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :aaa,:bbb'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :"a",:"b"'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :"aaa",:"bbb"'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :1,:2'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :222,:111'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :0,:65535'; +EXECUTE stmt USING @a, @b; +PREPARE stmt FROM 'SELECT :65535,:0'; +EXECUTE stmt USING @a, @b; diff --git a/sql/item.cc b/sql/item.cc index 308ed1df1a7..c77a488961c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3341,9 +3341,10 @@ default_set_param_func(Item_param *param, } -Item_param::Item_param(THD *thd, uint pos_in_query_arg): +Item_param::Item_param(THD *thd, char *name_arg, + uint pos_in_query_arg, uint len_in_query_arg): Item_basic_value(thd), - Rewritable_query_parameter(pos_in_query_arg, 1), + Rewritable_query_parameter(pos_in_query_arg, len_in_query_arg), Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR), state(NO_VALUE), /* Don't pretend to be a literal unless value for this item is set. */ @@ -3360,7 +3361,7 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg): */ m_is_settable_routine_parameter(true) { - name= (char*) "?"; + name= name_arg; /* Since we can't say whenever this item can be NULL or cannot be NULL before mysql_stmt_execute(), so we assuming that it can be NULL until diff --git a/sql/item.h b/sql/item.h index a02cf8f0d57..1cde032636c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2813,7 +2813,8 @@ public: enum Item_result cmp_type () const { return Type_handler_hybrid_field_type::cmp_type(); } - Item_param(THD *thd, uint pos_in_query_arg); + Item_param(THD *thd, char *name_arg, + uint pos_in_query_arg, uint len_in_query_arg); enum Type type() const { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0c74baaad8e..6d9d6e8365b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5876,6 +5876,33 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd, const char *name, } +Item_param *LEX::add_placeholder(THD *thd, char *name, + uint pos_in_query, uint len_in_query) +{ + if (!parsing_options.allows_variable) + { + my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); + return NULL; + } + Item_param *item= new (thd->mem_root) Item_param(thd, name, + pos_in_query, len_in_query); + if (!item || param_list.push_back(item, thd->mem_root)) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return NULL; + } + return item; +} + + +Item_param *LEX::add_placeholder(THD *thd, char *name, + const char *pos, const char *end) +{ + const char *query_start= sphead ? sphead->m_tmp_query : thd->query(); + return add_placeholder(thd, name, pos - query_start, end - pos); +} + + #ifdef MYSQL_SERVER uint binlog_unsafe_map[256]; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 940a54ff009..8f0e83610cd 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3182,6 +3182,11 @@ public: bool sp_while_loop_expression(THD *thd, Item *expr); bool sp_while_loop_finalize(THD *thd); + Item_param *add_placeholder(THD *thd, char *name, + uint pos_in_query, uint len_in_query); + Item_param *add_placeholder(THD *thd, char *name, + const char *pos, const char *end); + sp_variable *sp_add_for_loop_variable(THD *thd, const LEX_STRING name, Item *value); sp_variable *sp_add_for_loop_upper_bound(THD *thd, Item *value) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index febe0d95239..dd5b1f8cdfc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13464,17 +13464,10 @@ hex_or_bin_String: param_marker: PARAM_MARKER { - LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; - Item_param *item; - if (! lex->parsing_options.allows_variable) - my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); - const char *query_start= lex->sphead ? lex->sphead->m_tmp_query - : thd->query(); - item= new (thd->mem_root) Item_param(thd, lip->get_tok_start() - - query_start); - if (!($$= item) || lex->param_list.push_back(item, thd->mem_root)) - my_yyabort_error((ER_OUT_OF_RESOURCES, MYF(0))); + if (!($$= Lex->add_placeholder(thd, (char *) "?", + YYLIP->get_tok_start(), + YYLIP->get_tok_start() + 1))) + MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index fa7f4ef5f36..9f8bdd1ef38 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -1006,6 +1006,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); remember_name remember_end opt_db remember_tok_start wild_and_where field_length opt_field_length opt_field_length_default_1 + colon_with_pos %type opt_place @@ -8074,6 +8075,13 @@ select_item: } ; +colon_with_pos: + ':' + { + $$= (char *) YYLIP->get_tok_start(); + } + ; + remember_tok_start: { $$= (char*) YYLIP->get_tok_start(); @@ -13142,17 +13150,22 @@ hex_or_bin_String: param_marker: PARAM_MARKER { - LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; - Item_param *item; - if (! lex->parsing_options.allows_variable) - my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); - const char *query_start= lex->sphead ? lex->sphead->m_tmp_query - : thd->query(); - item= new (thd->mem_root) Item_param(thd, lip->get_tok_start() - - query_start); - if (!($$= item) || lex->param_list.push_back(item, thd->mem_root)) - my_yyabort_error((ER_OUT_OF_RESOURCES, MYF(0))); + if (!($$= Lex->add_placeholder(thd, (char *) "?", + YYLIP->get_tok_start(), + YYLIP->get_tok_start() + 1))) + MYSQL_YYABORT; + } + | colon_with_pos ident + { + if (!($$= Lex->add_placeholder(thd, NULL, + $1, YYLIP->get_tok_end()))) + MYSQL_YYABORT; + } + | colon_with_pos NUM + { + if (!($$= Lex->add_placeholder(thd, NULL, + $1, YYLIP->get_ptr()))) + MYSQL_YYABORT; } ; @@ -13538,7 +13551,7 @@ simple_ident_q: MYSQL_YYABORT; } } - | ':' ident '.' ident + | colon_with_pos ident '.' ident { LEX *lex= Lex; if (lex->is_trigger_new_or_old_reference($2)) @@ -14691,7 +14704,7 @@ internal_variable_name_directly_assignable: if (Lex->init_default_internal_variable(&$$, $3)) MYSQL_YYABORT; } - | ':' ident_directly_assignable '.' ident + | colon_with_pos ident_directly_assignable '.' ident { if (!Lex->is_trigger_new_or_old_reference($2)) {