[Commits] 3d763f5: MDEV-29310 Re-design the upper level of handling INSERT and INSERT_SELECT statements
revision-id: 3d763f5d31da5670ee68cfbc96bf9aa7e84500e9 (mariadb-10.10.1-8-g3d763f5) parent(s): a535590ada1c437608c8a041aa6543f6f62c3ff2 author: Igor Babaev committer: Igor Babaev timestamp: 2022-09-13 09:41:54 -0700 message: MDEV-29310 Re-design the upper level of handling INSERT and INSERT_SELECT statements Saved intermediate code. --- sql/sql_insert.cc | 62 ++++++++++++++++++++++++++++++ sql/sql_insert.h | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_lex.cc | 23 +++++++++++ sql/sql_parse.cc | 6 +++ sql/sql_yacc.yy | 4 ++ 5 files changed, 208 insertions(+) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index baa7f78..63687d7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -5333,3 +5333,65 @@ void select_create::abort_result_set() DBUG_VOID_RETURN; } + + +bool Sql_cmd_insert_base::precheck(THD *thd) +{ + /* + Since INSERT DELAYED doesn't support temporary tables, we could + not pre-open temporary tables for SQLCOM_INSERT / SQLCOM_REPLACE. + Open them here instead. + */ + if (first_table->lock_type != TL_WRITE_DELAYED && + thd->open_temporary_tables(lex->query_tables)) + return true; + + if (insert_precheck(thd, lex->query_tables)) + return true; + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE); + + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; +} + + +bool Sql_cmd_insert_base::prepare_inner(THD *thd) +{ + SELECT_LEX *const select_lex= thd->lex->first_select_lex(); + TABLE_LIST *const table_list= select_lex->get_table_list(); + const bool select_insert= insert_many_values.elements == 0; + TABLE *table; + + DBUG_ENTER("Sql_cmd_delete::prepare_inner"); + + (void) read_statistics_for_tables_if_needed(thd, table_list); + + { + if (mysql_handle_derived(lex, DT_INIT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_PREPARE)) + DBUG_RETURN(TRUE); + } + + if (duplicates == DUP_UPDATE) + { + /* it should be allocated before Item::fix_fields() */ + if (table_list->set_insert_values(thd->mem_root)) + DBUG_RETURN(TRUE); + } + + table= table_list->table; + + if (table->file->check_if_updates_are_ignored("INSERT")) + DBUG_RETURN(-1); + + +} + diff --git a/sql/sql_insert.h b/sql/sql_insert.h index 8b034c2..20ead97a 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -51,4 +51,117 @@ bool binlog_drop_table(THD *thd, TABLE *table); inline void kill_delayed_threads(void) {} #endif + +/** + Base class for all INSERT and REPLACE statements. Abstract class that + is inherited by Sql_cmd_insert_values and Sql_cmd_insert_select. +*/ + +class Sql_cmd_insert_base : public Sql_cmd_dml +{ + protected: + virtual bool precheck(THD *thd) override; + + virtual bool prepare_inner(THD *thd) override; + + private: + bool resolve_update_expressions(THD *thd); + bool prepare_values_table(THD *thd); + bool resolve_values_table_columns(THD *thd); + + /** + Field list to insert/replace + + One of two things: + 1. For the INSERT/REPLACE ... (col1, ... colN) VALUES ... syntax + this is a list of col1, ..., colN fields. + 2. For the INSERT/REPLACE ... SET col1=x1, ... colM=xM syntax extension + this is a list of col1, ... colM fields as well. + */ + List<Item> insert_field_list; + + protected: + const bool is_replace; + + /** + Row data to insert/replace + + One of two things: + 1. For the INSERT/REPLACE ... VALUES (row1), (row2), ... (rowN) syntax + the list contains N List_item lists: one List_item per row. + 2. For the INSERT/REPLACE ... SET col1=x1, ... colM=xM syntax extension + this list contains only 1 List_item of M data values: this way we + emulate this syntax: + INSERT/REPLACE ... (col1, ... colM) VALUE (x1, ..., xM); + */ + List<List_item> insert_many_values; + + /* + Number of values per row in insert_many_values, available after resolving + */ + uint value_count; + + /* ON DUPLICATE KEY UPDATE field list */ + List<Item> update_field_list; + + const enum_duplicates duplicates; + + explicit Sql_cmd_insert_base(bool is_replace_arg, + enum_duplicates duplicates_arg) + : empty_field_list_on_rset(false), + is_replace(is_replace_arg), + value_count(0), + duplicates(duplicates_arg) {} + + virtual void cleanup(THD *) override + { + if (empty_field_list_on_rset) { + empty_field_list_on_rset = false; + insert_field_list.empty(); + } + } + +}; + + +/** + Class that implements INSERT ... VALUES and REPLACE ... VALUES statements. +*/ + +class Sql_cmd_insert_values final : public Sql_cmd_insert_base +{ +public: + explicit Sql_cmd_insert_values(bool is_replace_arg, + enum_duplicates duplicates_arg) + : Sql_cmd_insert_base(is_replace_arg, duplicates_arg) {} + + enum_sql_command sql_command_code() const + { + return is_replace ? SQLCOM_REPLACE : SQLCOM_INSERT; + } + +protected: + bool execute_inner(THD *thd); +}; + + +/** + Class that implements INSERT ... SELECT and REPLACE ... SELECT statements. +*/ + +class Sql_cmd_insert_select final : public Sql_cmd_insert_base +{ +public: + explicit Sql_cmd_insert_select(bool is_replace_arg, + enum_duplicates duplicates_arg) + : Sql_cmd_insert_base(is_replace_arg, duplicates_arg) {} + + enum_sql_command sql_command_code() const + { + return is_replace ? SQLCOM_REPLACE_SELECT : SQLCOM_INSERT_SELECT; + } +}; + + + #endif /* SQL_INSERT_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8f9d042..3fb8231 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -10361,13 +10361,19 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit) bool LEX::parsed_insert_select(SELECT_LEX *first_select) { + bool is_insert_or_replace= false; + bool is_replace= false; if (sql_command == SQLCOM_INSERT || sql_command == SQLCOM_REPLACE) { + is_insert_or_replace= true; if (sql_command == SQLCOM_INSERT) sql_command= SQLCOM_INSERT_SELECT; else + { + is_replace= true; sql_command= SQLCOM_REPLACE_SELECT; + } } insert_select_hack(first_select); if (check_main_unit_semantics()) @@ -10377,6 +10383,23 @@ bool LEX::parsed_insert_select(SELECT_LEX *first_select) SELECT_LEX *blt __attribute__((unused))= pop_select(); DBUG_ASSERT(blt == &builtin_select); push_select(first_select); + + if (is_insert_or_replace) + { + if (sql_command == SQLCOM_INSERT || sql_command == SQLCOM_REPLACE) + { + if (!(m_sql_cmd= new (thd->mem_root) Sql_cmd_insert_values(is_replace, + duplicates))) + return true; + } + else + { + if (!(m_sql_cmd= new (thd->mem_root) Sql_cmd_insert_select(is_replace, + duplicates))) + return true; + } + } + return false; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e638d72..9258012 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4376,6 +4376,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) res = mysql_checksum_table(thd, first_table, &lex->check_opt); break; } + case SQLCOM_REPLACE: + case SQLCOM_INSERT: + case SQLCOM_REPLACE_SELECT: + case SQLCOM_INSERT_SELECT: case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: case SQLCOM_DELETE: @@ -4388,6 +4392,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) thd->abort_on_warning= 0; break; } +#if 0 case SQLCOM_REPLACE: if ((res= generate_incident_event(thd))) break; @@ -4647,6 +4652,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) break; } +#endif case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 13f0dbd..a137887 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12968,6 +12968,10 @@ replace: } insert_start replace_lock_option opt_into insert_table { + if (!(Lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_insert_values(true, + Lex->duplicates))) + MYSQL_YYABORT; Select->set_lock_for_tables($4, true, false); } insert_field_spec opt_returning
participants (1)
-
IgorBabaev