diff options
| author | Alexander Barkov <bar@mariadb.org> | 2016-10-08 12:32:52 +0400 |
|---|---|---|
| committer | Alexander Barkov <bar@mariadb.org> | 2016-10-08 12:32:52 +0400 |
| commit | e1a212ebbcea6d51a4bc1fe672bc6ff392477a39 (patch) | |
| tree | 293801fd78eeb84b95a7c1b5234a5bca87750e54 /sql | |
| parent | 4c45b820aa0e04fd25527279175fdc7fabcd731e (diff) | |
| download | mariadb-git-e1a212ebbcea6d51a4bc1fe672bc6ff392477a39.tar.gz | |
MDEV-10585 EXECUTE IMMEDIATE statement
Diffstat (limited to 'sql')
| -rw-r--r-- | sql/lex.h | 1 | ||||
| -rw-r--r-- | sql/mysqld.cc | 1 | ||||
| -rw-r--r-- | sql/sp_head.cc | 1 | ||||
| -rw-r--r-- | sql/sql_cmd.h | 1 | ||||
| -rw-r--r-- | sql/sql_lex.h | 13 | ||||
| -rw-r--r-- | sql/sql_parse.cc | 5 | ||||
| -rw-r--r-- | sql/sql_prepare.cc | 90 | ||||
| -rw-r--r-- | sql/sql_prepare.h | 1 | ||||
| -rw-r--r-- | sql/sql_yacc.yy | 8 |
9 files changed, 112 insertions, 9 deletions
diff --git a/sql/lex.h b/sql/lex.h index d82dcf4e94a..dfb874e3463 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -278,6 +278,7 @@ static SYMBOL symbols[] = { { "IGNORE", SYM(IGNORE_SYM)}, { "IGNORE_DOMAIN_IDS", SYM(IGNORE_DOMAIN_IDS_SYM)}, { "IGNORE_SERVER_IDS", SYM(IGNORE_SERVER_IDS_SYM)}, + { "IMMEDIATE", SYM(IMMEDIATE_SYM)}, { "IMPORT", SYM(IMPORT)}, { "IN", SYM(IN_SYM)}, { "INDEX", SYM(INDEX_SYM)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0c742a5c484..310ccb047c4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3886,6 +3886,7 @@ SHOW_VAR com_status_vars[]= { {"drop_user", STMT_STATUS(SQLCOM_DROP_USER)}, {"drop_view", STMT_STATUS(SQLCOM_DROP_VIEW)}, {"empty_query", STMT_STATUS(SQLCOM_EMPTY_QUERY)}, + {"execute_immediate", STMT_STATUS(SQLCOM_EXECUTE_IMMEDIATE)}, {"execute_sql", STMT_STATUS(SQLCOM_EXECUTE)}, {"flush", STMT_STATUS(SQLCOM_FLUSH)}, {"get_diagnostics", STMT_STATUS(SQLCOM_GET_DIAGNOSTICS)}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e2610fd950c..37e449cd666 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -253,6 +253,7 @@ sp_get_flags_for_command(LEX *lex) statement within an IF condition. */ case SQLCOM_EXECUTE: + case SQLCOM_EXECUTE_IMMEDIATE: flags= sp_head::MULTI_RESULTS | sp_head::CONTAINS_DYNAMIC_SQL; break; case SQLCOM_PREPARE: diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 92b74bb88ab..e33f8e443dc 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -95,6 +95,7 @@ enum enum_sql_command { SQLCOM_SHOW_GENERIC, SQLCOM_ALTER_USER, SQLCOM_SHOW_CREATE_USER, + SQLCOM_EXECUTE_IMMEDIATE, /* When a command is added here, be sure it's also added in mysqld.cc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index cb081faa75b..7cfe6448756 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3006,6 +3006,19 @@ public: void init_last_field(Column_definition *field, const char *name, CHARSET_INFO *cs); void set_last_field_type(const Lex_field_type_st &type); bool set_bincmp(CHARSET_INFO *cs, bool bin); + + bool prepared_stmt_params_fix_fields(THD *thd) + { + // Fix Items in the EXECUTE..USING list + List_iterator_fast<Item> param_it(prepared_stmt_params); + while (Item *param= param_it++) + { + if (param->fix_fields(thd, 0) || param->check_cols(1)) + return true; + } + return false; + } + // Check if "KEY IF NOT EXISTS name" used outside of ALTER context bool check_add_key(DDL_options_st ddl) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ac00b21c837..69637f87b8e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3377,6 +3377,11 @@ mysql_execute_command(THD *thd) break; } + case SQLCOM_EXECUTE_IMMEDIATE: + { + mysql_sql_stmt_execute_immediate(thd); + break; + } case SQLCOM_PREPARE: { mysql_sql_stmt_prepare(thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 54a0021daeb..99000573fb8 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -207,6 +207,7 @@ public: bool execute_server_runnable(Server_runnable *server_runnable); /* Destroy this statement */ void deallocate(); + bool execute_immediate(const char *query, uint query_length); private: /** The memory root to allocate parsed tree elements (instances of Item, @@ -218,6 +219,7 @@ private: bool set_parameters(String *expanded_query, uchar *packet, uchar *packet_end); bool execute(String *expanded_query, bool open_cursor); + void deallocate_immediate(); bool reprepare(); bool validate_metadata(Prepared_statement *copy); void swap_prepared_statement(Prepared_statement *copy); @@ -2764,6 +2766,39 @@ void mysql_sql_stmt_prepare(THD *thd) DBUG_VOID_RETURN; } + +void mysql_sql_stmt_execute_immediate(THD *thd) +{ + LEX *lex= thd->lex; + Prepared_statement *stmt; + const char *query; + uint query_len= 0; + DBUG_ENTER("mysql_sql_stmt_execute_immediate"); + + if (lex->prepared_stmt_params_fix_fields(thd)) + DBUG_VOID_RETURN; + + /* + Prepared_statement is quite large, + let's allocate it on the heap rather than on the stack. + */ + if (!(query= get_dynamic_sql_string(lex, &query_len)) || + !(stmt= new Prepared_statement(thd))) + DBUG_VOID_RETURN; // out of memory + + // See comments on thd->free_list in mysql_sql_stmt_execute() + Item *free_list_backup= thd->free_list; + thd->free_list= NULL; + (void) stmt->execute_immediate(query, query_len); + thd->free_items(); + thd->free_list= free_list_backup; + + stmt->lex->restore_set_statement_var(); + delete stmt; + DBUG_VOID_RETURN; +} + + /** Reinit prepared statement/stored procedure before execution. @@ -3034,13 +3069,8 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); - // Fix all Items in the USING list - List_iterator_fast<Item> param_it(lex->prepared_stmt_params); - while (Item *param= param_it++) - { - if (param->fix_fields(thd, 0) || param->check_cols(1)) - DBUG_VOID_RETURN; - } + if (lex->prepared_stmt_params_fix_fields(thd)) + DBUG_VOID_RETURN; /* thd->free_list can already have some Items. @@ -4401,16 +4431,58 @@ error: } -/** Common part of DEALLOCATE PREPARE and mysqld_stmt_close. */ +/** + Prepare, execute and clean-up a statement. + @param query - query text + @param length - query text length + @retval true - the query was not executed (parse error, wrong parameters) + @retval false - the query was prepared and executed -void Prepared_statement::deallocate() + Note, if some error happened during execution, it still returns "false". +*/ +bool Prepared_statement::execute_immediate(const char *query, uint query_len) +{ + DBUG_ENTER("Prepared_statement::execute_immediate"); + String expanded_query; + static LEX_STRING execute_immediate_stmt_name= + {(char*) STRING_WITH_LEN("(immediate)") }; + + set_sql_prepare(); + name= execute_immediate_stmt_name; // for DBUG_PRINT etc + if (prepare(query, query_len)) + DBUG_RETURN(true); + + if (param_count != thd->lex->prepared_stmt_params.elements) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); + deallocate_immediate(); + DBUG_RETURN(true); + } + + (void) execute_loop(&expanded_query, FALSE, NULL, NULL); + deallocate_immediate(); + DBUG_RETURN(false); +} + + +/** + Common part of DEALLOCATE PREPARE, EXECUTE IMMEDIATE, mysqld_stmt_close. +*/ +void Prepared_statement::deallocate_immediate() { /* We account deallocate in the same manner as mysqld_stmt_close */ status_var_increment(thd->status_var.com_stmt_close); /* It should now be safe to reset CHANGE MASTER parameters */ lex_end_stage2(lex); +} + +/** Common part of DEALLOCATE PREPARE and mysqld_stmt_close. */ + +void Prepared_statement::deallocate() +{ + deallocate_immediate(); /* Statement map calls delete stmt on erase */ thd->stmt_map.erase(this); } diff --git a/sql/sql_prepare.h b/sql/sql_prepare.h index aec4ac40036..4a8780c4a02 100644 --- a/sql/sql_prepare.h +++ b/sql/sql_prepare.h @@ -75,6 +75,7 @@ void mysqld_stmt_execute(THD *thd, char *packet, uint packet_length); void mysqld_stmt_close(THD *thd, char *packet); void mysql_sql_stmt_prepare(THD *thd); void mysql_sql_stmt_execute(THD *thd); +void mysql_sql_stmt_execute_immediate(THD *thd); void mysql_sql_stmt_close(THD *thd); void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length); void mysqld_stmt_reset(THD *thd, char *packet); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0da0b442946..2b0e722a2b1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1300,6 +1300,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token IGNORE_DOMAIN_IDS_SYM %token IGNORE_SYM %token IGNORE_SERVER_IDS_SYM +%token IMMEDIATE_SYM /* SQL-2003-R */ %token IMPORT %token INDEXES %token INDEX_SYM @@ -2251,6 +2252,12 @@ execute: } execute_using {} + | EXECUTE_SYM IMMEDIATE_SYM prepare_src + { + Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE; + } + execute_using + {} ; execute_using: @@ -14705,6 +14712,7 @@ keyword_sp: | ID_SYM {} | IDENTIFIED_SYM {} | IGNORE_SERVER_IDS_SYM {} + | IMMEDIATE_SYM {} /* SQL-2003-R */ | INVOKER_SYM {} | IMPORT {} | INDEXES {} |
