diff options
Diffstat (limited to 'sql/sql_delete.cc')
-rw-r--r-- | sql/sql_delete.cc | 133 |
1 files changed, 61 insertions, 72 deletions
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4d6b6ab57c8..0fe6037e88b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2010, 2021, MariaDB + Copyright (c) 2010, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,7 +30,6 @@ #include "lock.h" // unlock_table_name #include "sql_view.h" // check_key_in_view, mysql_frm_type #include "sql_parse.h" // mysql_init_select -#include "sql_acl.h" // *_ACL #include "filesort.h" // filesort #include "sql_handler.h" // mysql_ha_rm_tables #include "sql_select.h" @@ -199,23 +198,12 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, &explain->mrr_type); } - bool skip= updating_a_view; - /* Save subquery children */ for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit()) { - if (skip) - { - skip= false; - continue; - } - /* - Display subqueries only if they are not parts of eliminated WHERE/ON - clauses. - */ - if (!(unit->item && unit->item->eliminated)) + if (unit->explainable()) explain->add_child(unit->first_select()->select_number); } return 0; @@ -333,10 +321,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order= (ORDER *) ((order_list && order_list->elements) ? order_list->first : NULL); SELECT_LEX *select_lex= thd->lex->first_select_lex(); + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; bool binlog_is_row; - bool with_select= !select_lex->item_list.is_empty(); Explain_delete *explain; Delete_plan query_plan(thd->mem_root); Unique * deltempfile= NULL; @@ -376,20 +364,17 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->map=1; query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; - query_plan.updating_a_view= MY_TEST(table_list->view); promote_select_describe_flag_if_needed(thd->lex); - if (mysql_prepare_delete(thd, table_list, select_lex->with_wild, - select_lex->item_list, &conds, - &delete_while_scanning)) + if (mysql_prepare_delete(thd, table_list, &conds, &delete_while_scanning)) DBUG_RETURN(TRUE); if (delete_history) table->vers_write= false; - if (with_select) - (void) result->prepare(select_lex->item_list, NULL); + if (returning) + (void) result->prepare(returning->item_list, NULL); if (thd->lex->current_select->first_cond_optimization) { @@ -407,8 +392,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, tables.table = table; tables.alias = table_list->alias; - if (select_lex->setup_ref_array(thd, order_list->elements) || - setup_order(thd, select_lex->ref_pointer_array, &tables, + if (select_lex->setup_ref_array(thd, order_list->elements) || + setup_order(thd, select_lex->ref_pointer_array, &tables, fields, all_fields, order)) { free_underlaid_joins(thd, thd->lex->first_select_lex()); @@ -455,9 +440,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, has_triggers= table->triggers && table->triggers->has_delete_triggers(); - if (!with_select && !using_limit && const_cond_result && - (!thd->is_current_stmt_binlog_format_row() && - !has_triggers) + if (!returning && !using_limit && const_cond_result && + (!thd->is_current_stmt_binlog_format_row() && !has_triggers) && !table->versioned(VERS_TIMESTAMP) && !table_list->has_period()) { /* Update the table->file->stats.records number */ @@ -522,7 +506,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, set_statistics_for_table(thd, table); table->covering_keys.clear_all(); - table->quick_keys.clear_all(); // Can't use 'only index' + table->opt_range_keys.clear_all(); select=make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); if (unlikely(error)) @@ -577,10 +561,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else { ha_rows scanned_limit= query_plan.scanned_rows; + table->no_keyread= 1; query_plan.index= get_index_for_order(order, table, select, limit, &scanned_limit, &query_plan.using_filesort, &reverse); + table->no_keyread= 0; if (!query_plan.using_filesort) query_plan.scanned_rows= scanned_limit; } @@ -599,7 +585,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!(explain= query_plan.save_explain_delete_data(thd->mem_root, thd))) goto got_error; - ANALYZE_START_TRACKING(&explain->command_tracker); + ANALYZE_START_TRACKING(thd, &explain->command_tracker); DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start", dbug_serve_apcs(thd, 1);); @@ -628,7 +614,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if ((table->file->ha_table_flags() & HA_CAN_DIRECT_UPDATE_AND_DELETE) && - !has_triggers && !binlog_is_row && !with_select && + !has_triggers && !binlog_is_row && !returning && !table_list->has_period()) { table->mark_columns_needed_for_delete(); @@ -682,7 +668,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DELETE ... RETURNING we can't, because the RETURNING part may have a subquery in it) */ - if (!with_select) + if (!returning) free_underlaid_joins(thd, select_lex); select= 0; } @@ -717,11 +703,15 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, !table->prepare_triggers_for_delete_stmt_or_event()) will_batch= !table->file->start_bulk_delete(); - if (with_select) + /* + thd->get_stmt_da()->is_set() means first iteration of prepared statement + with array binding operation execution (non optimized so it is not + INSERT) + */ + if (returning && !thd->get_stmt_da()->is_set()) { - if (unlikely(result->send_result_set_metadata(select_lex->item_list, - Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF))) + if (result->send_result_set_metadata(returning->item_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) goto cleanup; } @@ -786,6 +776,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, && !table->versioned() && table->file->has_transactions(); + if (table->versioned(VERS_TIMESTAMP) || (table_list->has_period())) + table->file->prepare_for_insert(1); + DBUG_ASSERT(table->file->inited != handler::NONE); + THD_STAGE_INFO(thd, stage_updating); while (likely(!(error=info.read_record())) && likely(!thd->killed) && likely(!thd->is_error())) @@ -803,7 +797,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, break; } - if (with_select && result->send_data(select_lex->item_list) < 0) + // no LIMIT / OFFSET + if (returning && result->send_data(returning->item_list) < 0) { error=1; break; @@ -881,7 +876,7 @@ terminate_delete: table->file->ha_release_auto_increment(); if (options & OPTION_QUICK) (void) table->file->extra(HA_EXTRA_NORMAL); - ANALYZE_STOP_TRACKING(&explain->command_tracker); + ANALYZE_STOP_TRACKING(thd, &explain->command_tracker); cleanup: /* @@ -903,14 +898,14 @@ cleanup: deltempfile=NULL; delete select; select= NULL; - transactional_table= table->file->has_transactions(); + transactional_table= table->file->has_transactions_and_rollback(); if (!transactional_table && deleted > 0) - thd->transaction.stmt.modified_non_trans_table= - thd->transaction.all.modified_non_trans_table= TRUE; + thd->transaction->stmt.modified_non_trans_table= + thd->transaction->all.modified_non_trans_table= TRUE; /* See similar binlogging code in sql_update.cc, for comments */ - if (likely((error < 0) || thd->transaction.stmt.modified_non_trans_table)) + if (likely((error < 0) || thd->transaction->stmt.modified_non_trans_table)) { if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { @@ -939,7 +934,7 @@ cleanup: } } } - DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(transactional_table || !deleted || thd->transaction->stmt.modified_non_trans_table); if (likely(error < 0) || (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) @@ -947,7 +942,7 @@ cleanup: if (thd->lex->analyze_stmt) goto send_nothing_and_leave; - if (with_select) + if (returning) result->send_eof(); else my_ok(thd, deleted); @@ -997,16 +992,13 @@ got_error: mysql_prepare_delete() thd - thread handler table_list - global/local table list - wild_num - number of wildcards used in optional SELECT clause - field_list - list of items in optional SELECT clause conds - conditions RETURN VALUE FALSE OK TRUE error */ -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, - uint wild_num, List<Item> &field_list, Item **conds, +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, bool *delete_while_scanning) { Item *fake_conds= 0; @@ -1016,12 +1008,9 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, *delete_while_scanning= true; thd->lex->allow_sum_func.clear_all(); - if (setup_tables_and_check_access(thd, - &thd->lex->first_select_lex()->context, - &thd->lex->first_select_lex()-> - top_join_list, - table_list, - select_lex->leaf_tables, FALSE, + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, table_list, + select_lex->leaf_tables, FALSE, DELETE_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(TRUE); @@ -1052,10 +1041,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, *conds= select_lex->where; - if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num, - &select_lex->hidden_bit_fields)) || - setup_fields(thd, Ref_ptr_array(), - field_list, MARK_COLUMNS_READ, NULL, NULL, 0) || + if (setup_returning_fields(thd, table_list) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -1079,7 +1065,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) DBUG_RETURN(TRUE); - select_lex->fix_prepare_information(thd, conds, &fake_conds); + select_lex->fix_prepare_information(thd, conds, &fake_conds); DBUG_RETURN(FALSE); } @@ -1277,6 +1263,9 @@ multi_delete::initialize_tables(JOIN *join) normal_tables= 1; tbl->prepare_triggers_for_delete_stmt_or_event(); tbl->prepare_for_position(); + + if (tbl->versioned(VERS_TIMESTAMP)) + tbl->file->prepare_for_insert(1); } else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) && walk == delete_tables) @@ -1363,7 +1352,7 @@ int multi_delete::send_data(List<Item> &values) { deleted++; if (!table->file->has_transactions()) - thd->transaction.stmt.modified_non_trans_table= TRUE; + thd->transaction->stmt.modified_non_trans_table= TRUE; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)) @@ -1399,17 +1388,17 @@ void multi_delete::abort_result_set() /* the error was handled or nothing deleted and no side effects return */ if (error_handled || - (!thd->transaction.stmt.modified_non_trans_table && !deleted)) + (!thd->transaction->stmt.modified_non_trans_table && !deleted)) DBUG_VOID_RETURN; /* Something already deleted so we have to invalidate cache */ if (deleted) query_cache_invalidate3(thd, delete_tables, 1); - if (thd->transaction.stmt.modified_non_trans_table) - thd->transaction.all.modified_non_trans_table= TRUE; - thd->transaction.all.m_unsafe_rollback_flags|= - (thd->transaction.stmt.m_unsafe_rollback_flags & THD_TRANS::DID_WAIT); + if (thd->transaction->stmt.modified_non_trans_table) + thd->transaction->all.modified_non_trans_table= TRUE; + thd->transaction->all.m_unsafe_rollback_flags|= + (thd->transaction->stmt.m_unsafe_rollback_flags & THD_TRANS::DID_WAIT); /* If rows from the first table only has been deleted and it is @@ -1419,7 +1408,7 @@ void multi_delete::abort_result_set() */ if (do_delete && normal_tables && (table_being_deleted != delete_tables || - !table_being_deleted->table->file->has_transactions())) + !table_being_deleted->table->file->has_transactions_and_rollback())) { /* We have to execute the recorded do_deletes() and write info into the @@ -1431,7 +1420,7 @@ void multi_delete::abort_result_set() DBUG_VOID_RETURN; } - if (thd->transaction.stmt.modified_non_trans_table) + if (thd->transaction->stmt.modified_non_trans_table) { /* there is only side effects; to binlog with the error @@ -1568,8 +1557,8 @@ int multi_delete::do_table_deletes(TABLE *table, SORT_INFO *sort_info, table->file->print_error(local_error, MYF(0)); } } - if (last_deleted != deleted && !table->file->has_transactions()) - thd->transaction.stmt.modified_non_trans_table= TRUE; + if (last_deleted != deleted && !table->file->has_transactions_and_rollback()) + thd->transaction->stmt.modified_non_trans_table= TRUE; end_read_record(&info); @@ -1597,10 +1586,10 @@ bool multi_delete::send_eof() /* reset used flags */ THD_STAGE_INFO(thd, stage_end); - if (thd->transaction.stmt.modified_non_trans_table) - thd->transaction.all.modified_non_trans_table= TRUE; - thd->transaction.all.m_unsafe_rollback_flags|= - (thd->transaction.stmt.m_unsafe_rollback_flags & THD_TRANS::DID_WAIT); + if (thd->transaction->stmt.modified_non_trans_table) + thd->transaction->all.modified_non_trans_table= TRUE; + thd->transaction->all.m_unsafe_rollback_flags|= + (thd->transaction->stmt.m_unsafe_rollback_flags & THD_TRANS::DID_WAIT); /* We must invalidate the query cache before binlog writing and @@ -1611,7 +1600,7 @@ bool multi_delete::send_eof() query_cache_invalidate3(thd, delete_tables, 1); } if (likely((local_error == 0) || - thd->transaction.stmt.modified_non_trans_table)) + thd->transaction->stmt.modified_non_trans_table)) { if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { |