/* Copyright (c) 2006, 2024, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_UPDATE_INCLUDED #define SQL_UPDATE_INCLUDED #include #include "mem_root_deque.h" #include "my_alloc.h" #include "my_sqlcommand.h" #include "my_table_map.h" #include "sql/query_result.h" // Query_result_interceptor #include "sql/sql_cmd_dml.h" // Sql_cmd_dml #include "sql/sql_list.h" #include "sql/thr_malloc.h" class COPY_INFO; class Copy_field; class Item; class JOIN; class Query_block; class Query_expression; class RowIterator; class Select_lex_visitor; class THD; class Temp_table_param; struct TABLE; class Table_ref; bool records_are_comparable(const TABLE *table); bool compare_records(const TABLE *table); bool should_switch_to_multi_table_if_subqueries(const THD *thd, const Query_block *select, const Table_ref *table_list); class Query_result_update final : public Query_result_interceptor { /// Number of tables being updated uint update_table_count{0}; /// Pointer to list of updated tables, linked via 'next_local' Table_ref *update_tables{nullptr}; /// Array of references to temporary tables used to store cached updates TABLE **tmp_tables{nullptr}; /// Array of parameter structs for creation of temporary tables Temp_table_param *tmp_table_param{nullptr}; /// The first table in the join operation TABLE *main_table{nullptr}; /** In a multi-table update, this is equal to the first table in the join operation (#main_table) if that table can be updated on the fly while scanning it. It is `nullptr` otherwise. @see safe_update_on_fly */ TABLE *table_to_update{nullptr}; /// List of pointers to fields to update, in order from statement const mem_root_deque *fields; /// List of pointers to values to update with, in order from statement const mem_root_deque *values; /// The fields list decomposed into separate lists per table mem_root_deque **fields_for_table; /// The values list decomposed into separate lists per table mem_root_deque **values_for_table; /** List of tables referenced in the CHECK OPTION condition of the updated view excluding the updated table. */ List unupdated_check_opt_tables; /// ??? Copy_field *copy_field{nullptr}; /** Array of update operations, arranged per _updated_ table. For each _updated_ table in the multiple table update statement, a COPY_INFO pointer is present at the table's position in this array. The array is allocated and populated during Query_result_update::prepare(). The position that each table is assigned is also given here and is stored in the member TABLE::pos_in_table_list::shared. However, this is a publicly available field, so nothing can be trusted about its integrity. This member is NULL when the Query_result_update is created. @see Query_result_update::prepare */ COPY_INFO **update_operations{nullptr}; public: Query_result_update(mem_root_deque *field_list, mem_root_deque *value_list) : Query_result_interceptor(), fields(field_list), values(value_list) {} bool need_explain_interceptor() const override { return true; } bool prepare(THD *thd, const mem_root_deque &list, Query_expression *u) override; bool optimize(); bool start_execution(THD *thd) override; bool send_data(THD *thd, const mem_root_deque &items) override; bool do_updates(THD *thd); bool send_eof(THD *thd) override; void cleanup() override; unique_ptr_destroy_only create_iterator( THD *thd, MEM_ROOT *mem_root, unique_ptr_destroy_only source); }; class Sql_cmd_update final : public Sql_cmd_dml { public: Sql_cmd_update(bool multitable_arg, mem_root_deque *update_values) : multitable(multitable_arg), original_fields(*THR_MALLOC), update_value_list(update_values) {} enum_sql_command sql_command_code() const override { return multitable ? SQLCOM_UPDATE_MULTI : SQLCOM_UPDATE; } bool is_single_table_plan() const override { return !multitable; } protected: bool precheck(THD *thd) override; bool check_privileges(THD *thd) override; bool prepare_inner(THD *thd) override; bool execute_inner(THD *thd) override; private: bool update_single_table(THD *thd); bool multitable; /// Bitmap of all tables which are to be updated table_map tables_for_update{0}; bool accept(THD *thd, Select_lex_visitor *visitor) override; /// Convert list of fields to update to base table fields bool make_base_table_fields(THD *thd, mem_root_deque *items); public: /// The original list of fields to update, used for privilege checking mem_root_deque original_fields; /// The values used to update fields mem_root_deque *update_value_list; }; /// Find out which of the target tables can be updated immediately while /// scanning. This is used by the old optimizer *after* the plan has been /// created. The hypergraph optimizer does not use this function, as it makes /// the decision about immediate update *during* planning, not after planning. /// /// @param join The top-level JOIN object of the UPDATE statement. /// @param single_target True if the UPDATE statement has exactly /// one target table. /// @return Map of tables to update while scanning. table_map GetImmediateUpdateTable(const JOIN *join, bool single_target); /// Makes the TABLE and handler objects ready for being used in an UPDATE /// statement. Called at the beginning of each execution. /// /// @param join The top-level JOIN object of the UPDATE operation. /// @return true on error. bool FinalizeOptimizationForUpdate(JOIN *join); /// Creates an UpdateRowsIterator which updates the rows returned by the given /// "source" iterator. unique_ptr_destroy_only CreateUpdateRowsIterator( THD *thd, MEM_ROOT *mem_root, JOIN *join, unique_ptr_destroy_only source); #endif /* SQL_UPDATE_INCLUDED */