From 4870e8f85bd1c8d762885fb1fef34dd6b8b1e313 Mon Sep 17 00:00:00 2001 From: PeterWeiWang <715533650@qq.com> Date: Tue, 22 Feb 2022 19:06:58 +0800 Subject: [PATCH 1/2] support for parallel queries - add item clone. --- sql/pq_clone_item.cc | 1952 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1952 insertions(+) create mode 100644 sql/pq_clone_item.cc diff --git a/sql/pq_clone_item.cc b/sql/pq_clone_item.cc new file mode 100644 index 000000000000..3dad94c35a62 --- /dev/null +++ b/sql/pq_clone_item.cc @@ -0,0 +1,1952 @@ +#ifndef PQ_CLONE_ITEM_H +#define PQ_CLONE_ITEM_H + +/* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, Huawei Technologies Co., Ltd. + + 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 also distributed 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 included with MySQL. + + 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 */ + +#include "item_geofunc.h" +#include "item_inetfunc.h" +#include "item_pfs_func.h" +#include "mem_root_deque.h" +#include "sql/item.h" +#include "sql/item_cmpfunc.h" +#include "sql/item_regexp_func.h" +#include "sql/item_sum.h" +#include "sql/item_timefunc.h" +#include "sql/log.h" +#include "sql/parse_tree_items.h" +#include "sql/parse_tree_nodes.h" +#include "sql/pq_clone.h" +#include "sql/sql_optimizer.h" + +#define CHECK_TYPE(T) \ + if (typeid(*this) != typeid(T) || \ + DBUG_EVALUATE_IF("simulate_item_type_mismatch", true, false)) { \ + sql_print_warning( \ + "Caller's type %s is not equals to this class type %s, " \ + "will not use parallel query, SQL= %s", \ + typeid(*this).name(), typeid(T).name(), thd->query().str); \ + assert(DBUG_EVALUATE_IF("simulate_item_type_mismatch", true, false) || \ + false); \ + return nullptr; \ + } + +#define COPY_FROM_SUPER(D, B) \ + if (B::pq_copy_from(thd, select, item)) { \ + return true; \ + } \ + D *orig_item MY_ATTRIBUTE((unused)) = dynamic_cast(item); \ + assert(orig_item); + +#define COPY_SELF_ATTR(OBJ) \ + if (!OBJ || OBJ->pq_copy_from(thd, select, this)) { \ + return nullptr; \ + } + +#define PQ_CLONE_DEF(T) \ + Item *T::pq_clone(THD *thd, Query_block *select) { \ + CHECK_TYPE(T) \ + T *new_item = nullptr; + +#define PQ_CLONE_RETURN \ + COPY_SELF_ATTR(new_item) \ + return new_item; \ + } + +#define PQ_CLONE_ARGS \ + mem_root_deque item_list(thd->pq_mem_root); \ + for (uint i = 0; i < arg_count; i++) { \ + Item *arg = args[i]->pq_clone(thd, select); \ + if (arg == nullptr) return nullptr; \ + item_list.push_back(arg); \ + } + +#define PQ_COPY_FROM_DEF(D, B) \ + bool D::pq_copy_from(THD *thd, Query_block *select, Item *item) { \ + COPY_FROM_SUPER(D, B) + +#define PQ_COPY_FROM_RETURN \ + return false; \ + } + +#define PQ_REBUILD_SUM_DEF(T) \ + Item_sum *T::pq_rebuild_sum_func(THD *thd, Query_block *select, \ + Item *item) { \ + CHECK_TYPE(T) \ + T *new_item = nullptr; + +#define PQ_REBUILD_SUM_RETURN \ + COPY_SELF_ATTR(new_item) \ + return new_item; \ + } + +#define ARG0 copy_args[0] +#define ARG1 copy_args[1] +#define ARG2 copy_args[2] +#define ARG3 copy_args[3] +#define ARG4 copy_args[4] +#define COPY_FUNC_ITEM(T, ...) \ + Item *T::pq_clone(THD *thd, Query_block *select) { \ + CHECK_TYPE(T); \ + Item *copy_args[5]; \ + assert(arg_count < 5); \ + for (uint i = 0; i < arg_count; i++) { \ + copy_args[i] = args[i]->pq_clone(thd, select); \ + if (copy_args[i] == nullptr) { \ + return nullptr; \ + } \ + } \ + Item *new_item = nullptr; \ + new_item = new (thd->pq_mem_root) T(__VA_ARGS__); \ + COPY_SELF_ATTR(new_item) \ + return new_item; \ + } + +Item *Item::pq_clone(THD *thd MY_ATTRIBUTE((unused)), + Query_block *select MY_ATTRIBUTE((unused))) { + sql_print_warning( + "Item type %s's deep copy method is not implemented, " + "will not use parallel query, SQL= %s", + typeid(*this).name(), thd->query().str); + assert(DBUG_EVALUATE_IF("simulate_no_item_copy_function", true, false) || + false); + return nullptr; +} + +bool Item::pq_copy_from(THD *thd MY_ATTRIBUTE((unused)), + Query_block *select MY_ATTRIBUTE((unused)), + Item *item) { + cmp_context = item->cmp_context; + marker = item->marker; + + collation = item->collation; + item_name.copy(item->item_name.ptr(), item->item_name.length(), + system_charset_info, item->item_name.is_autogenerated()); + orig_name.copy(item->orig_name.ptr(), item->orig_name.length(), + system_charset_info, item->orig_name.is_autogenerated()); + decimals = item->decimals; + derived_used = item->derived_used; + is_expensive_cache = item->is_expensive_cache; + m_accum_properties = item->m_accum_properties; + m_data_type = item->m_data_type; + m_is_window_function = item->m_is_window_function; + max_length = item->max_length; + m_nullable = item->is_nullable(); + null_value = item->null_value; + str_value = item->str_value; + hidden = item->hidden; + +#ifndef NDEBUG + contextualized = item->contextualized; +#endif + unsigned_flag = item->unsigned_flag; + + if (!pq_alloc_item && item->pq_alloc_item) thd->add_item(this); + + return false; +} + +/* Item_basic_constant start */ +PQ_COPY_FROM_DEF(Item_basic_constant, Item) { + if (orig_item != nullptr) { + used_table_map = orig_item->used_table_map; + } +} +PQ_COPY_FROM_RETURN + +/* Item_cache start */ +PQ_COPY_FROM_DEF(Item_cache, Item_basic_constant) { + if (orig_item != nullptr) { + used_table_map = orig_item->used_table_map; + cached_field = orig_item->cached_field; + } + if (orig_item != nullptr && orig_item->example != nullptr) { + Item *example_arg = orig_item->example->pq_clone(thd, select); + if (example_arg == nullptr) return true; + if (!example_arg->fixed) { + example_arg->fix_fields(thd, &example_arg); + } + setup(example_arg); + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_cache_datetime) { + new_item = new (thd->pq_mem_root) Item_cache_datetime(data_type()); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_cache_decimal) { + new_item = new (thd->pq_mem_root) Item_cache_decimal(); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_cache_int) { + new_item = new (thd->pq_mem_root) Item_cache_int(); + if (new_item == nullptr) { + return nullptr; + } + if (origin_item) { + new_item->example = origin_item->pq_clone(thd, select); + if (new_item->example == nullptr) { + return nullptr; + } + } +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_cache_real) { + new_item = new (thd->pq_mem_root) Item_cache_real(); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_cache_row) { + new_item = new (thd->pq_mem_root) Item_cache_row(); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_cache_str) { + const Item *item = static_cast(this); + new_item = new (thd->pq_mem_root) Item_cache_str(item); +} +PQ_CLONE_RETURN +/* Item_cache end */ + +/* Item_hex_string start */ +PQ_CLONE_DEF(Item_hex_string) { + new_item = new (thd->pq_mem_root) Item_hex_string(POS()); +} +PQ_CLONE_RETURN + +// TOOD str_value copyed twice +PQ_CLONE_DEF(Item_bin_string) { + new_item = new (thd->pq_mem_root) + Item_bin_string(str_value.ptr(), str_value.length()); +} +PQ_CLONE_RETURN +/* Item_hex_string end */ + +/* Item_null start */ +PQ_CLONE_DEF(Item_null) { new_item = new (thd->pq_mem_root) Item_null(POS()); } +PQ_CLONE_RETURN +/* Item_null end */ + +/* Item_num start */ +PQ_CLONE_DEF(Item_int_with_ref) { + Item *pq_ref = ref->pq_clone(thd, select); + if (pq_ref == nullptr) return nullptr; + new_item = new (thd->pq_mem_root) + Item_int_with_ref(pq_ref->data_type(), value, pq_ref, unsigned_flag); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_datetime_with_ref) { + if (origin_item) { + return origin_item->pq_clone(thd, select); + } + Item *pq_ref = ref->pq_clone(thd, select); + if (pq_ref == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) + Item_datetime_with_ref(pq_ref->data_type(), decimals, value, pq_ref); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_time_with_ref) { + if (origin_item) { + return origin_item->pq_clone(thd, select); + } + Item *pq_ref = ref->pq_clone(thd, select); + if (pq_ref == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) Item_time_with_ref(decimals, value, pq_ref); +} +PQ_CLONE_RETURN +/* Item_num end */ + +/* Item_string start */ +PQ_CLONE_DEF(Item_string) { + if (origin_item) return origin_item->pq_clone(thd, select); + + new_item = new (thd->pq_mem_root) Item_string( + static_cast(item_name), str_value.ptr(), str_value.length(), + collation.collation, collation.derivation, collation.repertoire); + if (new_item) { + new_item->set_cs_specified(m_cs_specified); + } +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_static_string_func) { + if (origin_item) return origin_item->pq_clone(thd, select); + + new_item = new (thd->pq_mem_root) + Item_static_string_func(func_name, str_value.ptr(), str_value.length(), + collation.collation, collation.derivation); +} +PQ_CLONE_RETURN +/* Item_string end */ +/* Item_basic_constant end */ + +/* Item_ident start */ +PQ_COPY_FROM_DEF(Item_ident, Item) { + DBUG_EXECUTE_IF("simulate_item_clone_attr_copy_error", return true;); + + context = &select->context; + + if (orig_item->cached_table == nullptr) { + m_tableno = orig_item->m_tableno; + } else { + m_tableno = orig_item->cached_table->m_tableno; + } +} +PQ_COPY_FROM_RETURN + +PQ_COPY_FROM_DEF(Item_field, Item_ident) { + DBUG_EXECUTE_IF("simulate_item_field_copy_error", return true;); + + if (orig_item->table_ref != nullptr) { + m_tableno = orig_item->table_ref->m_tableno; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_field) { + DBUG_EXECUTE_IF("simulate_item_clone_error", return nullptr;); + DBUG_EXECUTE_IF("simulate_no_item_copy_function", + return Item::pq_clone(thd, select);); + + new_item = + new (thd->pq_mem_root) Item_field(POS(), db_name, table_name, field_name); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_default_value) { + Item *new_arg = nullptr; + if (arg) { + new_arg = arg->pq_clone(thd, select); + if (new_arg == nullptr) return nullptr; + } + new_item = new (thd->pq_mem_root) Item_default_value(POS(), new_arg); +} +PQ_CLONE_RETURN + +int find_ref_in_table(TABLE_LIST *tl, Item **ref) { + int count = tl->field_translation_end - tl->field_translation; + if (count <= 0) { + return -1; + } + for (int i = 0; i < count; i++) { + if (*ref == tl->field_translation[i].item) { + return i; + } + } + return -1; +} + +TABLE_LIST *get_table_in_merge_tablelist(Query_block *select, TABLE_LIST *tb) { + int tableindex = 0; + for (TABLE_LIST *tbl_list = select->orig->table_list.first; + tbl_list != nullptr; tbl_list = tbl_list->next_local) { + if (tbl_list->merge_underlying_list != nullptr) { + int index = get_table_index(tbl_list->merge_underlying_list, + TABLE_LIST_TYPE_MERGE, tb); + if (index != -1) { + TABLE_LIST *tbl = get_table_by_index( + select->table_list.first, TABLE_LIST_TYPE_DEFAULT, tableindex); + return get_table_by_index(tbl, TABLE_LIST_TYPE_MERGE, index); + } + } + tableindex++; + } + return nullptr; +} + +Item *Item_view_ref::pq_clone(class THD *thd, class Query_block *select) { + Item_view_ref *item = nullptr; + Item **item_ref = nullptr; + + if (select->orig != nullptr) { + TABLE_LIST *found_table = nullptr; + int index = get_table_index(select->orig->table_list.first, + TABLE_LIST_TYPE_DEFAULT, cached_table); + if (index != -1) { + found_table = get_table_by_index(select->table_list.first, + TABLE_LIST_TYPE_DEFAULT, index); + } + + if (found_table == nullptr) { + index = get_table_index(select->orig->leaf_tables, TABLE_LIST_TYPE_GLOBAL, + cached_table); + if (index != -1) { + found_table = get_table_by_index(select->leaf_tables, + TABLE_LIST_TYPE_GLOBAL, index); + } + } + + if (found_table == nullptr) { + found_table = get_table_in_merge_tablelist(select, cached_table); + } + + if (found_table == nullptr) { + return nullptr; + } + + int field_index = find_ref_in_table(cached_table, ref); + if (field_index == -1 || found_table->field_translation == nullptr || + found_table->field_translation_end - found_table->field_translation <= + field_index) { + return nullptr; + } + + item_ref = &found_table->field_translation[field_index].item; + item = new (thd->pq_mem_root) + Item_view_ref(&select->context, item_ref, db_name, table_name, + orig_table_name(), field_name, found_table); + } else { + item_ref = new (thd->pq_mem_root) Item *(); + if (item_ref == nullptr) return nullptr; + *item_ref = (*ref)->pq_clone(thd, select); + if (*item_ref == nullptr) return nullptr; + item = new (thd->pq_mem_root) + Item_view_ref(&select->context, item_ref, db_name, table_name, + orig_table_name(), field_name, cached_table); + } + + if (item == nullptr || item->pq_copy_from(thd, select, this)) { + return nullptr; + } + + return item; +} + +/** + Item_aggregate_ref wil be created from ref in setup_fields() afterwards, + so clone ref for the item. +*/ +Item *Item_aggregate_ref::pq_clone(class THD *thd, class Query_block *select) { + Item *item_ref = (*ref)->pq_clone(thd, select); + if (item_ref == nullptr) { + return nullptr; + } + + return item_ref; +} + +Item *Item_ref::pq_clone(class THD *thd, class Query_block *select) { + /* + * c1: (Name_resolution_context, db_name, table_name, field_name) + * c2: (pos, db_name, table_name, field_name) + * c3: (context, ref, db_name, table_name, field_name) + * c4: (thd, ref_item) + */ + Item_ref *new_item = nullptr; + Name_resolution_context *new_context = &select->context; + + if (copy_type == WITH_CONTEXT) + new_item = new (thd->pq_mem_root) + Item_ref(new_context, db_name, table_name, field_name); + else if (copy_type == WITHOUT_CONTEXT) + new_item = + new (thd->pq_mem_root) Item_ref(POS(), db_name, table_name, field_name); + else if (copy_type == WITH_CONTEXT_REF) { + // ref has been pointed to appropriate item + uint counter; + enum_resolution_type resolution; + Item **select_item = + find_item_in_list(thd, *ref, &select->fields, &counter, + REPORT_EXCEPT_NOT_FOUND, &resolution); + + if (!select_item || select_item == not_found_item) return NULL; + + new_item = new (thd->pq_mem_root) + Item_ref(new_context, select_item, db_name, table_name, field_name, + m_alias_of_expr); + } else { + assert(copy_type == WITH_REF_ONLY); + new_item = new (thd->pq_mem_root) Item_ref(thd, this); + } + if (new_item == nullptr || new_item->pq_copy_from(thd, select, this)) + return nullptr; + + new_item->context = &select->context; + return new_item; +} + +PQ_CLONE_DEF(Item_name_const) { + Item *name_arg, *val_arg; + if (name_item == nullptr) { + name_arg = nullptr; + } else { + name_arg = name_item->pq_clone(thd, select); + if (name_arg == nullptr) return nullptr; + } + if (value_item == nullptr) { + val_arg = nullptr; + } else { + val_arg = value_item->pq_clone(thd, select); + if (val_arg == nullptr) return nullptr; + } + new_item = new (thd->pq_mem_root) Item_name_const(POS(), name_arg, val_arg); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_name_const, Item) { + if (orig_item != nullptr) { + valid_args = orig_item->valid_args; + } +} +PQ_COPY_FROM_RETURN + +/* Item_result_field start */ +/* Item_func start */ +PQ_COPY_FROM_DEF(Item_func, Item_result_field) { + if (orig_item != nullptr) { + null_on_null = orig_item->null_on_null; + used_tables_cache = orig_item->used_tables_cache; + not_null_tables_cache = orig_item->not_null_tables_cache; + } +} +PQ_COPY_FROM_RETURN + +/* Item_func_bit start */ +PQ_COPY_FROM_DEF(Item_func_bit, Item_func) { + if (orig_item != nullptr) { + hybrid_type = orig_item->hybrid_type; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(PTI_literal_underscore_charset_hex_num) { + LEX_STRING str = {const_cast(str_value.ptr()), str_value.length()}; + new_item = new (thd->pq_mem_root) + PTI_literal_underscore_charset_hex_num(POS(), collation.collation, str); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_bit_neg, POS(), ARG0) + +COPY_FUNC_ITEM(Item_func_bit_and, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_bit_or, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_bit_xor, POS(), ARG0, ARG1) + +COPY_FUNC_ITEM(Item_func_shift_left, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_shift_right, POS(), ARG0, ARG1) +/* Item_func_bit end */ + +PQ_CLONE_DEF(Item_func_case) { + PQ_CLONE_ARGS + new_item = new (thd->pq_mem_root) + Item_func_case(POS(), &item_list, nullptr, nullptr); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_case, Item_func) { + if (orig_item != nullptr) { + first_expr_num = orig_item->first_expr_num; + else_expr_num = orig_item->else_expr_num; + cached_result_type = orig_item->cached_result_type; + left_result_type = orig_item->left_result_type; + ncases = orig_item->ncases; + cmp_type = orig_item->cmp_type; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_if, ARG0, ARG1, ARG2) +COPY_FUNC_ITEM(Item_func_month, POS(), ARG0) + +/* Item_func_coalesce start */ +PQ_CLONE_DEF(Item_func_coalesce) { + assert(arg_count < 3); + Item *new_args[2] = {nullptr}; + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + if (arg_count == 1) { + new_item = new (thd->pq_mem_root) Item_func_coalesce(POS(), new_args[0]); + } else if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_coalesce(POS(), new_args[0], new_args[1]); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_any_value, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_ifnull, POS(), ARG0, ARG1) +/* Item_func_coalesce end */ + +/* Item_func_min_max start */ +PQ_CLONE_DEF(Item_func_max) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) Item_func_max(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_min) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) Item_func_min(POS(), &pt_item_list); +} +PQ_CLONE_RETURN +/* Item_func_min_max end */ + +/* Item_func_num1 start */ +COPY_FUNC_ITEM(Item_func_abs, POS(), ARG0) + +COPY_FUNC_ITEM(Item_func_ceiling, ARG0) +COPY_FUNC_ITEM(Item_func_floor, ARG0) + +COPY_FUNC_ITEM(Item_func_neg, ARG0) +COPY_FUNC_ITEM(Item_func_round, ARG0, ARG1, truncate) +/* Item_func_num1 end */ + +/* Item_num_op start */ +COPY_FUNC_ITEM(Item_func_plus, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_minus, ARG0, ARG1) + +COPY_FUNC_ITEM(Item_func_div, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mod, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mul, ARG0, ARG1) +/* Item_num_op end */ + +/* Item_func_regexp start */ +PQ_CLONE_DEF(Item_func_regexp_instr) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + new_item = + new (thd->pq_mem_root) Item_func_regexp_instr(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_regexp_like) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) Item_func_regexp_like(POS(), &pt_item_list); +} +PQ_CLONE_RETURN +/* Item_func_regexp end */ + +/* Item_func_weekday start */ +PQ_CLONE_DEF(Item_func_weekday) { + PQ_CLONE_ARGS + new_item = new (thd->pq_mem_root) + Item_func_weekday(POS(), item_list[0], this->odbc_type); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_dayname, POS(), ARG0) +/* Item_func_weekday end */ + +/* Item_int_func start */ +/* Item_bool_func2 start */ +COPY_FUNC_ITEM(Item_func_eq, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_equal, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_ge, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_gt, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_le, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_lt, ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_ne, ARG0, ARG1) + +PQ_CLONE_DEF(Item_func_like) { + Item *arg0 = args[0]->pq_clone(thd, select); + if (arg0 == nullptr) return nullptr; + + Item *arg1 = args[1]->pq_clone(thd, select); + if (arg1 == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) Item_func_like(arg0, arg1); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_nullif, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrcontains, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_strcmp, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_xor, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_contains, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrcoveredby, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrcovers, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_crosses, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_disjoint, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_equals, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_intersects, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_overlaps, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_touches, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_st_within, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrwithin, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrtouches, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbroverlaps, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrintersects, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrequals, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_mbrdisjoint, POS(), ARG0, ARG1) +/* Item_bool_func2 end */ + +/* Item_cond start */ +PQ_COPY_FROM_DEF(Item_cond, Item_bool_func) { + Item *list_item; + List_iterator_fast list_it(orig_item->list); + while ((list_item = list_it++)) { + Item *arg = list_item->pq_clone(thd, select); + if (arg == nullptr) return true; + list.push_back(arg); + } + if (orig_item != nullptr) { + abort_on_null = orig_item->abort_on_null; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_cond_and) { + new_item = new (thd->pq_mem_root) Item_cond_and(); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_cond_and, Item_cond) { + if (orig_item != nullptr) { + cond_equal.max_members = orig_item->cond_equal.max_members; + } + Item_equal *item_equal; + List_iterator_fast it(orig_item->cond_equal.current_level); + for (size_t i = 0; (item_equal = it++); i++) { + Item_equal *new_item_equal = + dynamic_cast(item_equal->pq_clone(thd, select)); + if (new_item_equal == nullptr) return true; + cond_equal.current_level.push_back(new_item_equal); + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_cond_or) { new_item = new (thd->pq_mem_root) Item_cond_or(); } +PQ_CLONE_RETURN +/* Item_cond end */ + +PQ_CLONE_DEF(Item_equal) { new_item = new (thd->pq_mem_root) Item_equal(); } +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_equal, Item_bool_func) { + Item_field *item_field; + List_iterator_fast it(orig_item->fields); + for (size_t i = 0; (item_field = it++); i++) { + Item_field *new_field = + dynamic_cast(item_field->pq_clone(thd, select)); + if (new_field == nullptr) return true; + fields.push_back(new_field); + } + if (orig_item != nullptr && orig_item->const_item != nullptr) { + const_item = orig_item->const_item->pq_clone(thd, select); + if (const_item == nullptr) { + return true; + } + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_true, POS()) + +COPY_FUNC_ITEM(Item_func_isnotnull, ARG0) + +PQ_CLONE_DEF(Item_func_isnull) { + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + new_item = new (thd->pq_mem_root) Item_func_isnull(POS(), arg); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_isnull, Item_bool_func) { + if (orig_item != nullptr) { + cached_value = orig_item->cached_value; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_json_schema_valid, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_not, ARG0) + +PQ_CLONE_DEF(Item_func_truth) { + PQ_CLONE_ARGS + new_item = + new (thd->pq_mem_root) Item_func_truth(POS(), item_list[0], truth_test); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_extract) { + PQ_CLONE_ARGS + new_item = + new (thd->pq_mem_root) Item_extract(POS(), this->int_type, item_list[0]); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_extract, Item_int_func) { + if (orig_item != nullptr) { + date_value = orig_item->date_value; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_ascii, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_bit_count, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_char_length) { + assert(arg_count == 1); + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + new_item = new (thd->pq_mem_root) Item_func_char_length(POS(), arg); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_char_length, Item_int_func) { + if (orig_item != nullptr) { + value.copy(orig_item->value); + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_coercibility, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_crc32, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_dayofmonth, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_dayofyear, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_field) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) Item_func_field(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_find_in_set, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_get_lock, POS(), ARG0, ARG1); +COPY_FUNC_ITEM(Item_func_hour, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_inet_aton, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_int_div, POS(), ARG0, ARG1) + +PQ_CLONE_DEF(Item_func_interval) { + assert(arg_count == 1 && args[0]->type() == Item::ROW_ITEM); + Item_row *row = down_cast(args[0]->pq_clone(thd, select)); + if (nullptr == row) return nullptr; + new_item = new (thd->pq_mem_root) Item_func_interval(POS(), row); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_interval, Item_int_func) { + if (orig_item != nullptr) { + use_decimal_comparison = orig_item->use_decimal_comparison; + intervals = orig_item->intervals; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_func_json_contains) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = + new (thd->pq_mem_root) Item_func_json_contains(thd, POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_json_depth, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_last_insert_id) { + Item *item_arg = nullptr; + if (arg_count == 1) { + item_arg = args[0]->pq_clone(thd, select); + if (item_arg == nullptr) { + return nullptr; + } + } + + if (arg_count == 0) { + new_item = new (thd->pq_mem_root) Item_func_last_insert_id(POS()); + } else if (arg_count == 1) { + new_item = new (thd->pq_mem_root) Item_func_last_insert_id(POS(), item_arg); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_length, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_bit_length, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_minute, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_locate) { + assert(arg_count < 4); + Item *new_args[4] = {nullptr}; + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_locate(POS(), new_args[0], new_args[1]); + } else if (arg_count == 3) { + new_item = new (thd->pq_mem_root) + Item_func_locate(POS(), new_args[0], new_args[1], new_args[2]); + } +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_locate, Item_int_func) { + if (orig_item != nullptr) { + cmp_collation = orig_item->cmp_collation; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_instr, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_microsecond, POS(), ARG0) + +PQ_COPY_FROM_DEF(Item_func_opt_neg, Item_int_func) { + if (orig_item != nullptr) { + negated = orig_item->negated; + pred_level = orig_item->pred_level; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_between, POS(), ARG0, ARG1, ARG2, negated); + +PQ_CLONE_DEF(Item_func_in) { + PT_select_item_list pt_item; + for (uint i = 0; i < arg_count; i++) { + Item *arg = args[i]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + pt_item.value.push_back(arg); + } + new_item = new (thd->pq_mem_root) Item_func_in(POS(), &pt_item, negated); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_ord, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_period_add, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_period_diff, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_quarter, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_second, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_sleep, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_time_to_sec, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_timestamp_diff, POS(), ARG0, ARG1, int_type) +COPY_FUNC_ITEM(Item_func_to_days, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_to_seconds, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_uncompressed_length, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_week, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_year, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_yearweek, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_typecast_signed, POS(), ARG0) +COPY_FUNC_ITEM(Item_typecast_unsigned, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_can_access_table, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_is_visible_dd_object, POS(), ARG0) +/* Item_int_func end */ + +/* Item_real_func start */ +/* Item_dec_func start*/ +COPY_FUNC_ITEM(Item_func_sin, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_sqrt, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_cos, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_tan, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_cot, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_pow, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_ln, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_log2, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_log10, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_asin, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_acos, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_exp, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_atan) { + Item *item_args[2]; + assert(arg_count < 3); + for (uint i = 0; i < arg_count; i++) { + item_args[i] = args[i]->pq_clone(thd, select); + if (item_args[i] == nullptr) return nullptr; + } + + if (arg_count == 1) + new_item = new (thd->pq_mem_root) Item_func_atan(POS(), item_args[0]); + else if (arg_count == 2) + new_item = new (thd->pq_mem_root) + Item_func_atan(POS(), item_args[0], item_args[1]); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_log) { + Item *item_args[2]; + assert(arg_count < 3); + for (uint i = 0; i < arg_count; i++) { + item_args[i] = args[i]->pq_clone(thd, select); + if (item_args[i] == nullptr) return nullptr; + } + + if (arg_count == 1) + new_item = new (thd->pq_mem_root) Item_func_log(POS(), item_args[0]); + else if (arg_count == 2) + new_item = + new (thd->pq_mem_root) Item_func_log(POS(), item_args[0], item_args[1]); +} +PQ_CLONE_RETURN + +/* Item_dec_func end*/ + +COPY_FUNC_ITEM(Item_func_longfromgeohash, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_rand) { + new_item = new (thd->pq_mem_root) Item_func_rand(POS()); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_latfromgeohash, POS(), ARG0) +/* Item_real_func end */ + +/* Item_str_func start */ +PQ_CLONE_DEF(Item_func_aes_decrypt) { + assert(arg_count < 4); + Item *new_args[4] = {nullptr}; + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_aes_decrypt(POS(), new_args[0], new_args[1]); + } else if (arg_count == 3) { + new_item = new (thd->pq_mem_root) + Item_func_aes_decrypt(POS(), new_args[0], new_args[1], new_args[2]); + } +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_aes_encrypt) { + assert(arg_count < 4); + Item *new_args[4] = {nullptr}; + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_aes_encrypt(POS(), new_args[0], new_args[1]); + } else if (arg_count == 3) { + new_item = new (thd->pq_mem_root) + Item_func_aes_encrypt(POS(), new_args[0], new_args[1], new_args[2]); + } +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_char) { + PQ_CLONE_ARGS + PT_item_list pt_item_list; + pt_item_list.value = item_list; + new_item = new (thd->pq_mem_root) Item_func_char(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_charset, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_collation, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_compress, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_concat) { + PQ_CLONE_ARGS + PT_item_list pt_item_list; + pt_item_list.value = item_list; + new_item = new (thd->pq_mem_root) Item_func_concat(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_concat_ws) { + PQ_CLONE_ARGS + PT_item_list pt_item_list; + pt_item_list.value = item_list; + new_item = new (thd->pq_mem_root) Item_func_concat_ws(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_conv, POS(), ARG0, ARG1, ARG2) +COPY_FUNC_ITEM(Item_func_conv_charset, POS(), ARG0, conv_charset) + +PQ_CLONE_DEF(Item_func_date_format) { + PQ_CLONE_ARGS + new_item = new (thd->pq_mem_root) Item_func_date_format( + POS(), item_list[0], item_list[1], this->is_time_format); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_date_format, Item_str_func) { + if (orig_item != nullptr) { + value.copy(orig_item->value); + fixed_length = orig_item->fixed_length; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_func_elt) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) Item_func_elt(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_export_set) { + PQ_CLONE_ARGS + + if (arg_count == 3) { + new_item = new (thd->pq_mem_root) + Item_func_export_set(POS(), item_list[0], item_list[1], item_list[2]); + } else if (arg_count == 4) { + new_item = new (thd->pq_mem_root) Item_func_export_set( + POS(), item_list[0], item_list[1], item_list[2], item_list[3]); + } else if (arg_count == 5) { + new_item = new (thd->pq_mem_root) + Item_func_export_set(POS(), item_list[0], item_list[1], item_list[2], + item_list[3], item_list[4]); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_from_base64, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_inet_ntoa, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_insert, POS(), ARG0, ARG1, ARG2, ARG3) + +PQ_CLONE_DEF(Item_func_json_quote) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) Item_func_json_quote(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_left, POS(), ARG0, ARG1) + +COPY_FUNC_ITEM(Item_func_lpad, POS(), ARG0, ARG1, ARG2) + +PQ_COPY_FROM_DEF(Item_func_lpad, Item_str_func) { + if (orig_item != nullptr) lpad_str.copy(orig_item->lpad_str); +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_func_make_set) { + Item *arg_a = item->pq_clone(thd, select); + if (arg_a == nullptr) return nullptr; + + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = + new (thd->pq_mem_root) Item_func_make_set(POS(), arg_a, &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_table_rows) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_table_rows(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_avg_row_length) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_avg_row_length(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_data_length) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_data_length(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_max_data_length) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_max_data_length(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_index_length) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_index_length(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_data_free) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = + new (thd->pq_mem_root) Item_func_internal_data_free(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_auto_increment) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_auto_increment(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_update_time) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_update_time(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_check_time) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = new (thd->pq_mem_root) + Item_func_internal_check_time(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_checksum) { + PQ_CLONE_ARGS + + PT_item_list pt_item_list; + pt_item_list.value = item_list; + + new_item = + new (thd->pq_mem_root) Item_func_internal_checksum(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_internal_get_comment_or_error) { + PQ_CLONE_ARGS + PT_item_list pt_item_list; + pt_item_list.value = item_list; + new_item = new (thd->pq_mem_root) + Item_func_internal_get_comment_or_error(POS(), &pt_item_list); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_monthname, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_pfs_format_bytes, POS(), ARG0) + +PQ_COPY_FROM_DEF(Item_func_pfs_format_bytes, Item_str_func) { + if (orig_item != nullptr) { + m_value = orig_item->m_value; + memcpy(orig_item->m_value_buffer, m_value_buffer, 20); + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_pfs_format_pico_time, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_quote, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_repeat, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_replace, POS(), ARG0, ARG1, ARG2) +COPY_FUNC_ITEM(Item_func_reverse, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_random_bytes, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_right) { + PQ_CLONE_ARGS + new_item = + new (thd->pq_mem_root) Item_func_right(POS(), item_list[0], item_list[1]); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_rpad, POS(), ARG0, ARG1, ARG2) + +PQ_COPY_FROM_DEF(Item_func_rpad, Item_str_func) { + if (orig_item != nullptr) { + rpad_str.copy(orig_item->rpad_str); + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_set_collation, POS(), ARG0, collation_string) + +PQ_COPY_FROM_DEF(Item_func_set_collation, Item_str_func) { + if (orig_item != nullptr && orig_item->args[1] != nullptr) { + args[1] = orig_item->args[1]->pq_clone(thd, select); + if (args[1] == nullptr) return true; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_soundex, ARG0) +COPY_FUNC_ITEM(Item_func_space, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_substr) { + assert(arg_count < 4); + Item *new_args[4] = {nullptr}; + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_substr(POS(), new_args[0], new_args[1]); + } else if (arg_count == 3) { + new_item = new (thd->pq_mem_root) + Item_func_substr(POS(), new_args[0], new_args[1], new_args[2]); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_substr_index, POS(), ARG0, ARG1, ARG2) +COPY_FUNC_ITEM(Item_func_database, POS()) +COPY_FUNC_ITEM(Item_func_user, POS()) + +PQ_CLONE_DEF(Item_func_trim) { + PQ_CLONE_ARGS + + if (arg_count > 1) + new_item = new (thd->pq_mem_root) + Item_func_trim(POS(), item_list[0], item_list[1], m_trim_mode); + else + new_item = + new (thd->pq_mem_root) Item_func_trim(POS(), item_list[0], m_trim_mode); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_ltrim, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_rtrim, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_uncompress, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_unhex, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_uuid, POS()) +COPY_FUNC_ITEM(Item_func_get_dd_create_options, POS(), ARG0, ARG1, ARG2) +PQ_CLONE_DEF(Item_func_uuid_to_bin) { + assert(arg_count < 3); + Item *new_args[4] = {nullptr}; + + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 1) { + new_item = new (thd->pq_mem_root) Item_func_uuid_to_bin(POS(), new_args[0]); + } else if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_uuid_to_bin(POS(), new_args[0], new_args[1]); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_weight_string, POS(), ARG0, result_length, + num_codepoints, flags, as_binary) +COPY_FUNC_ITEM(Item_func_st_srid_mutator, POS(), ARG0, ARG1) + +PQ_CLONE_DEF(Item_func_bin_to_uuid) { + assert(arg_count < 3); + Item *new_args[4] = {nullptr}; + + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 1) { + new_item = new (thd->pq_mem_root) Item_func_bin_to_uuid(POS(), new_args[0]); + } else if (arg_count == 2) { + new_item = new (thd->pq_mem_root) + Item_func_bin_to_uuid(POS(), new_args[0], new_args[1]); + } +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_format) { + assert(arg_count < 4); + Item *new_args[4] = {nullptr}; + for (uint i = 0; i < arg_count; i++) { + new_args[i] = args[i]->pq_clone(thd, select); + if (new_args[i] == nullptr) return nullptr; + } + + if (arg_count == 2) + new_item = new (thd->pq_mem_root) + Item_func_format(POS(), new_args[0], new_args[1]); + else if (arg_count == 3) + new_item = new (thd->pq_mem_root) + Item_func_format(POS(), new_args[0], new_args[1], new_args[2]); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_get_format) { + assert(arg_count == 1); + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) Item_func_get_format(POS(), type, arg); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_hex, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_inet6_aton, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_inet6_ntoa, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_md5, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_sha, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_sha2, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_to_base64, POS(), ARG0) + +PQ_COPY_FROM_DEF(Item_str_conv, Item_str_func) { + if (orig_item != nullptr) { + multiply = orig_item->multiply; + converter = orig_item->converter; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_func_upper, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_lower, POS(), ARG0) + +PQ_COPY_FROM_DEF(Item_temporal_hybrid_func, Item_str_func) { + if (orig_item != nullptr) { + sql_mode = orig_item->sql_mode; + ascii_buf.copy(orig_item->ascii_buf); + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_date_add_interval) { + Item *arg_a = args[0]->pq_clone(thd, select); + Item *arg_b = args[1]->pq_clone(thd, select); + if (arg_a == nullptr || arg_b == nullptr) return nullptr; + new_item = new (thd->pq_mem_root) + Item_date_add_interval(arg_a, arg_b, int_type, date_sub_interval); + if (new_item) { + new_item->set_data_type(data_type()); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_add_time, POS(), ARG0, ARG1, is_date, + sign == -1 ? true : false) + +COPY_FUNC_ITEM(Item_func_str_to_date, POS(), ARG0, ARG1) + +PQ_COPY_FROM_DEF(Item_func_str_to_date, Item_temporal_hybrid_func) { + if (orig_item != nullptr) { + cached_timestamp_type = orig_item->cached_timestamp_type; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_typecast_char, ARG0, cast_length, cast_cs) + +PQ_CLONE_DEF(Item_date_literal) { + MYSQL_TIME ltime; + cached_time.get_time(<ime); + new_item = new (thd->pq_mem_root) Item_date_literal(<ime); +} +PQ_CLONE_RETURN +/* Item_str_func end */ + +COPY_FUNC_ITEM(Item_func_curdate_utc, POS()) +COPY_FUNC_ITEM(Item_func_curdate_local, POS()) +COPY_FUNC_ITEM(Item_func_from_days, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_makedate, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_typecast_date, POS(), ARG0) + +PQ_CLONE_DEF(Item_datetime_literal) { + MYSQL_TIME *ltime = new (thd->pq_mem_root) MYSQL_TIME(); + if (ltime != nullptr) { + this->get_date(ltime, 0); + new_item = new (thd->pq_mem_root) Item_datetime_literal( + ltime, this->cached_time.decimals(), thd->variables.time_zone); + } +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_convert_tz, POS(), ARG0, ARG1, ARG2) +COPY_FUNC_ITEM(Item_func_from_unixtime, POS(), ARG0) + +PQ_CLONE_DEF(Item_func_sysdate_local) { + new_item = new (thd->pq_mem_root) Item_func_sysdate_local(decimals); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_typecast_datetime) { + if (origin_item) { + return origin_item->pq_clone(thd, select); + } + Item *arg_item = args[0]->pq_clone(thd, select); + if (arg_item == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) Item_typecast_datetime(POS(), arg_item); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_typecast_datetime, Item_datetime_func) { + if (orig_item != nullptr) { + detect_precision_from_arg = orig_item->detect_precision_from_arg; + decimals = orig_item->decimals; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_func_curtime_local) { + PQ_CLONE_ARGS + new_item = + new (thd->pq_mem_root) Item_func_curtime_local(POS(), this->decimals); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_func_maketime, POS(), ARG0, ARG1, ARG2) +COPY_FUNC_ITEM(Item_func_sec_to_time, POS(), ARG0) +COPY_FUNC_ITEM(Item_func_timediff, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_typecast_time, POS(), ARG0) + +PQ_COPY_FROM_DEF(Item_typecast_time, Item_time_func) { + if (orig_item != nullptr) { + detect_precision_from_arg = orig_item->detect_precision_from_arg; + decimals = orig_item->decimals; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_time_literal) { + MYSQL_TIME *ltime = new (thd->pq_mem_root) MYSQL_TIME(); + if (ltime == nullptr) return nullptr; + cached_time.get_time(ltime); + new_item = new (thd->pq_mem_root) Item_time_literal(ltime, pq_dec_arg); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_typecast_decimal) { + Item *item_arg = args[0]->pq_clone(thd, select); + if (item_arg == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) + Item_typecast_decimal(POS(), item_arg, pq_precision, decimals); +} +PQ_CLONE_RETURN + +COPY_FUNC_ITEM(Item_typecast_real, ARG0) + +PQ_CLONE_DEF(Item_func_get_system_var) { + new_item = new (thd->pq_mem_root) Item_func_get_system_var( + var, var_type, &component, item_name.ptr(), item_name.length()); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_get_system_var, Item_var_func) { + if (orig_item != nullptr) { + cached_llval = orig_item->cached_llval; + cached_dval = orig_item->cached_dval; + cached_strval.copy(orig_item->cached_strval); + cached_null_value = orig_item->cached_null_value; + used_query_id = orig_item->used_query_id; + cache_present = orig_item->cache_present; + } +} +PQ_COPY_FROM_RETURN +/* Item_func end */ + +/* Item sum start */ +PQ_COPY_FROM_DEF(Item_sum, Item_result_field) { + if (orig_item != nullptr) { + force_copy_fields = orig_item->force_copy_fields; + with_distinct = orig_item->with_distinct; + max_aggr_level = orig_item->max_aggr_level; + max_sum_func_level = orig_item->max_sum_func_level; + allow_group_via_temp_table = orig_item->allow_group_via_temp_table; + save_deny_window_func = orig_item->save_deny_window_func; + used_tables_cache = orig_item->used_tables_cache; + forced_const = orig_item->forced_const; + } +} +PQ_COPY_FROM_RETURN + +Item_sum *Item_sum::pq_rebuild_sum_func( + THD *thd MY_ATTRIBUTE((unused)), Query_block *select MY_ATTRIBUTE((unused)), + Item *item MY_ATTRIBUTE((unused))) { + sql_print_warning( + "Item type %s's rebuild sum method is not implemented, " + "will not use parallel query, SQL= %s", + typeid(*this).name(), thd->query().str); + assert(DBUG_EVALUATE_IF("simulate_no_item_rebuild_function", true, false) || + false); + return nullptr; +} + +PQ_COPY_FROM_DEF(Item_sum_bit, Item_sum) { + if (orig_item != nullptr) { + reset_bits = orig_item->reset_bits; + bits = orig_item->bits; + hybrid_type = orig_item->hybrid_type; + m_count = orig_item->m_count; + m_frame_null_count = orig_item->m_frame_null_count; + } + m_digit_cnt = nullptr; + m_digit_cnt_card = 0; + if (orig_item != nullptr) { + m_is_xor = orig_item->m_is_xor; + } +} +PQ_COPY_FROM_RETURN + +PQ_REBUILD_SUM_DEF(Item_sum_and) { + new_item = new (thd->pq_mem_root) Item_sum_and(POS(), item, nullptr); +} +PQ_REBUILD_SUM_RETURN + +PQ_CLONE_DEF(Item_sum_and) { + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) Item_sum_and(POS(), arg, nullptr); +} +PQ_CLONE_RETURN + +PQ_REBUILD_SUM_DEF(Item_sum_or) { + new_item = new (thd->pq_mem_root) Item_sum_or(POS(), item, nullptr); +} +PQ_REBUILD_SUM_RETURN + +PQ_CLONE_DEF(Item_sum_or) { + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + + new_item = new (thd->pq_mem_root) Item_sum_or(POS(), arg, nullptr); +} +PQ_CLONE_RETURN + +PQ_REBUILD_SUM_DEF(Item_sum_xor) { + new_item = new (thd->pq_mem_root) Item_sum_xor(POS(), item, nullptr); +} +PQ_REBUILD_SUM_RETURN + +PQ_CLONE_DEF(Item_sum_xor) { + Item *arg = args[0]->pq_clone(thd, select); + if (nullptr == arg) return nullptr; + + new_item = new (thd->pq_mem_root) Item_sum_xor(POS(), arg, nullptr); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_sum_hybrid, Item_sum) { + if (orig_item == nullptr) { + return true; + } + + hybrid_type = orig_item->hybrid_type; + was_values = orig_item->was_values; + m_nulls_first = orig_item->m_nulls_first; + m_optimize = orig_item->m_optimize; + m_want_first = orig_item->m_want_first; + m_cnt = orig_item->m_cnt; + m_saved_last_value_at = orig_item->m_saved_last_value_at; +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_sum_max, ARG0); + +PQ_REBUILD_SUM_DEF(Item_sum_max) { + new_item = new (thd->pq_mem_root) Item_sum_max(POS(), item, nullptr); +} +PQ_REBUILD_SUM_RETURN + +COPY_FUNC_ITEM(Item_sum_min, ARG0); + +PQ_REBUILD_SUM_DEF(Item_sum_min) { + new_item = new (thd->pq_mem_root) Item_sum_min(POS(), item, nullptr); +} +PQ_REBUILD_SUM_RETURN + +PQ_COPY_FROM_DEF(Item_sum_num, Item_sum) { + DBUG_EXECUTE_IF("simulate_item_rebuild_attr_copy_error", return true;); + if (orig_item != nullptr) { + is_evaluated = orig_item->is_evaluated; + } +} +PQ_COPY_FROM_RETURN + +COPY_FUNC_ITEM(Item_sum_count, POS(), ARG0, nullptr) + +Item_sum *Item_sum_count::pq_rebuild_sum_func(THD *thd, Query_block *select, + Item *item) { + DBUG_EXECUTE_IF("simulate_item_rebuild_error", return nullptr;); + DBUG_EXECUTE_IF("simulate_no_item_rebuild_function", + return Item_sum::pq_rebuild_sum_func(thd, select, item);); + + Item_sum_count *new_item_sum = + new (thd->pq_mem_root) Item_sum_count(POS(), item, nullptr, true); + if (new_item_sum == nullptr || + new_item_sum->Item_sum_num::pq_copy_from(thd, select, this)) + return nullptr; + return new_item_sum; +} + +Item *PTI_count_sym::pq_clone(THD *thd, Query_block *select) { + CHECK_TYPE(PTI_count_sym) + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + Item_sum_count *new_count = + new (thd->pq_mem_root) Item_sum_count(POS(), arg, nullptr); + if (new_count == nullptr || new_count->pq_copy_from(thd, select, this)) + return nullptr; + return new_count; +} + +COPY_FUNC_ITEM(Item_sum_sum, POS(), ARG0, has_with_distinct(), nullptr) + +PQ_REBUILD_SUM_DEF(Item_sum_sum) { + new_item = new (thd->pq_mem_root) + Item_sum_sum(POS(), item, has_with_distinct(), nullptr); +} +PQ_REBUILD_SUM_RETURN + +PQ_CLONE_DEF(Item_sum_avg) { + assert(arg_count == 1); + Item *arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + new_item = new (thd->pq_mem_root) + Item_sum_avg(POS(), arg, has_with_distinct(), nullptr); + if (new_item) { + new_item->pq_avg_type = PQ_WORKER; + } +} +PQ_CLONE_RETURN + +PQ_REBUILD_SUM_DEF(Item_sum_avg) { + new_item = new (thd->pq_mem_root) + Item_sum_avg(POS(), item, has_with_distinct(), nullptr); + if (new_item) { + new_item->pq_avg_type = PQ_REBUILD; + } +} +PQ_REBUILD_SUM_RETURN +/* Item sum end */ +/* Item_result_field end */ + +PQ_CLONE_DEF(Item_row) { + assert(arg_count > 0); + Item *arg_head = items[0]->pq_clone(thd, select); + if (arg_head == nullptr) return nullptr; + mem_root_deque tail(thd->pq_mem_root); + for (uint i = 1; i < arg_count; i++) { + Item *arg_tail = items[i]->pq_clone(thd, select); + if (arg_tail == nullptr) return nullptr; + tail.push_back(arg_tail); + } + new_item = new (thd->pq_mem_root) Item_row(arg_head, tail); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_row, Item) { + // generated a random item_name for item_row + if (orig_item != nullptr) { + if (orig_item->item_name.length() == 0) { + assert(orig_item->item_name.ptr() == nullptr); + uint32 addr_mid_8 = ((uint64)this >> 32) << 24; + std::string std_addr = "ITEM_ROW" + std::to_string(addr_mid_8); + item_name.copy(std_addr.c_str(), std_addr.length(), system_charset_info, + true); + } + used_tables_cache = orig_item->used_tables_cache; + not_null_tables_cache = orig_item->not_null_tables_cache; + with_null = orig_item->with_null; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_float) { + new_item = + new (thd->pq_mem_root) Item_float(item_name, value, decimals, max_length); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_int) { new_item = new (thd->pq_mem_root) Item_int(this); } +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_int, Item_num) { + if (orig_item != nullptr) { + value = orig_item->value; + } +} +PQ_COPY_FROM_RETURN + +PQ_CLONE_DEF(Item_uint) { + new_item = new (thd->pq_mem_root) Item_uint(item_name, value, max_length); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_decimal) { + new_item = new (thd->pq_mem_root) + Item_decimal(item_name, &decimal_value, decimals, max_length); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_version) { + new_item = new (thd->pq_mem_root) Item_func_version(POS()); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(PTI_function_call_nonkeyword_now) { + new_item = + new (thd->pq_mem_root) PTI_function_call_nonkeyword_now(POS(), decimals); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(PTI_text_literal_text_string) { + new_item = new (thd->pq_mem_root) + PTI_text_literal_text_string(POS(), is_7bit, literal); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(PTI_text_literal_nchar_string) { + new_item = new (thd->pq_mem_root) + PTI_text_literal_nchar_string(POS(), is_7bit, literal); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(PTI_text_literal_underscore_charset) { + new_item = new (thd->pq_mem_root) + PTI_text_literal_underscore_charset(POS(), is_7bit, cs, literal); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_get_user_var) { + new_item = new (thd->pq_mem_root) Item_func_get_user_var(POS(), name); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_connection_id) { + new_item = new (thd->pq_mem_root) Item_func_connection_id(POS()); +} +PQ_CLONE_RETURN + +PQ_CLONE_DEF(Item_func_trig_cond) { + Item *arg = nullptr; + if (arg_count > 0) arg = args[0]->pq_clone(thd, select); + if (arg == nullptr) return nullptr; + new_item = new (thd->pq_mem_root) Item_func_trig_cond( + arg, trig_var, thd->lex->unit->first_query_block()->join, m_idx, + trig_type); +} +PQ_CLONE_RETURN + +PQ_COPY_FROM_DEF(Item_func_connection_id, Item_int_func) { + if (orig_item != nullptr) { + value = orig_item->value; + } +} +PQ_COPY_FROM_RETURN + +Item *Item_func_unix_timestamp::pq_clone(THD *thd, Query_block *select) { + Item *arg_item = nullptr; + if (arg_count > 0) { + arg_item = args[0]->pq_clone(thd, select); + if (arg_item == nullptr) return nullptr; + } + + Item_func_unix_timestamp *new_item = nullptr; + if (arg_count) { + new_item = new (thd->pq_mem_root) Item_func_unix_timestamp(POS(), arg_item); + } else { + new_item = new (thd->pq_mem_root) Item_func_unix_timestamp(POS()); + } + + if (!new_item || new_item->pq_copy_from(thd, select, this)) return nullptr; + + return new_item; +} + +Item *Item_func_current_user::pq_clone(THD *thd, Query_block *select) { + Item_func_current_user *new_item = + new (thd->pq_mem_root) Item_func_current_user(POS()); + if (!new_item || new_item->pq_copy_from(thd, select, this)) return nullptr; + + new_item->context = &select->context; + return new_item; +} + +COPY_FUNC_ITEM(Item_func_benchmark, POS(), ARG0, ARG1) +COPY_FUNC_ITEM(Item_func_found_rows, POS()) + +Item *Item_func_false::pq_clone(THD *thd, Query_block *select) { + CHECK_TYPE(Item_func_false); + + Item *new_item = new (thd->pq_mem_root) Item_func_false(POS()); + COPY_SELF_ATTR(new_item) + + if (item_name.ptr() == antijoin_null_cond) { + new_item->item_name.set(antijoin_null_cond); + } + + return new_item; +} + +#endif From 4d81f264dc8e45b72a5d69b868d88083393d2dde Mon Sep 17 00:00:00 2001 From: PeterWeiWang <715533650@qq.com> Date: Tue, 22 Feb 2022 19:10:25 +0800 Subject: [PATCH 2/2] support for parallel queries - add THD Query_block JOIN QEP_TAB TABLE clone. --- sql/pq_clone.cc | 1214 +++++++++++++++++++++++++++++++++++++++++++++++ sql/pq_clone.h | 58 +++ 2 files changed, 1272 insertions(+) create mode 100644 sql/pq_clone.cc create mode 100644 sql/pq_clone.h diff --git a/sql/pq_clone.cc b/sql/pq_clone.cc new file mode 100644 index 000000000000..e6b0d4000ea8 --- /dev/null +++ b/sql/pq_clone.cc @@ -0,0 +1,1214 @@ +/* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, Huawei Technologies Co., Ltd. + + 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 also distributed 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 included with MySQL. + + 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 */ + +#include "sql/pq_clone.h" +#include "include/my_dbug.h" +#include "include/mysql/psi/mysql_thread.h" +#include "sql/mysqld.h" +#include "sql/opt_range.h" +#include "sql/sql_base.h" +#include "sql/sql_lex.h" +#include "sql/sql_opt_exec_shared.h" +#include "sql/sql_optimizer.h" +#include "sql/sql_parallel.h" +#include "sql/sql_resolver.h" +#include "sql/system_variables.h" + +class COND_CMP; +bool propagate_cond_constants(THD *thd, I_List *save_list, + Item *and_father, Item *cond); + +bool POSITION::pq_copy(THD *thd, POSITION *orig) { + rows_fetched = orig->rows_fetched; + read_cost = orig->read_cost; + filter_effect = orig->filter_effect; + prefix_rowcount = orig->prefix_rowcount; + prefix_cost = orig->prefix_cost; + table = orig->table; + if (orig->key) { + key = orig->key->pq_clone(thd); + if (key == nullptr) { + return true; + } + } else { + key = nullptr; + } + ref_depend_map = orig->ref_depend_map; + use_join_buffer = orig->use_join_buffer; + sj_strategy = orig->sj_strategy; + n_sj_tables = orig->n_sj_tables; + dups_producing_tables = orig->dups_producing_tables; + first_loosescan_table = orig->first_loosescan_table; + loosescan_need_tables = orig->loosescan_need_tables; + loosescan_key = orig->loosescan_key; + loosescan_parts = orig->loosescan_parts; + first_firstmatch_table = orig->first_firstmatch_table; + first_firstmatch_rtbl = orig->first_firstmatch_rtbl; + firstmatch_need_tables = orig->firstmatch_need_tables; + first_dupsweedout_table = orig->first_dupsweedout_table; + dupsweedout_tables = orig->dupsweedout_tables; + sjm_scan_last_inner = orig->sjm_scan_last_inner; + sjm_scan_need_tables = orig->sjm_scan_need_tables; + + return false; +} + +bool QEP_TAB::pq_copy(THD *thd, QEP_TAB *orig) { + set_type(orig->type()); + set_index(orig->index()); + set_first_inner(orig->first_inner()); + set_last_inner(orig->last_inner()); + set_first_sj_inner(orig->first_sj_inner()); + set_last_sj_inner(orig->last_sj_inner()); + keys().merge(orig->keys()); + m_reversed_access = orig->m_reversed_access; + do_parallel_scan = orig->do_parallel_scan; + firstmatch_return = orig->firstmatch_return; + cache_idx_cond = orig->cache_idx_cond; + loosescan_key_len = orig->loosescan_key_len; + POSITION *position = new (thd->pq_mem_root) POSITION; + if (!position || position->pq_copy(thd, orig->position())) { + return true; + } + + set_position(position); + if (orig->pq_cond) { + JOIN *join = this->join(); + if (join == nullptr) { + return true; + } + pq_cond = orig->pq_cond->pq_clone(join->thd, join->query_block); + if (pq_cond == nullptr) { + return true; + } + } + + return false; +} + +bool TABLE::pq_copy(THD *thd, void *select_arg, TABLE *orig) { + Query_block *select = static_cast(select_arg); + possible_quick_keys = orig->possible_quick_keys; + covering_keys = orig->covering_keys; + key_read = orig->key_read; + const_table = orig->const_table; + nullable = orig->nullable; + null_row = orig->null_row; + m_cost_model = orig->m_cost_model; + memcpy(record[0], orig->record[0], orig->s->rec_buff_length); + + reginfo = orig->reginfo; + + file->pushed_idx_cond_keyno = orig->file->pushed_idx_cond_keyno; + Item *index_pushdown = orig->file->pushed_idx_cond; + // needs deep copy + file->pushed_idx_cond = + index_pushdown ? index_pushdown->pq_clone(thd, select) : nullptr; + Item *copy_index_pushdown = file->pushed_idx_cond; + if ((index_pushdown && copy_index_pushdown == nullptr) || + (copy_index_pushdown && + copy_index_pushdown->fix_fields(thd, ©_index_pushdown))) { + return true; + } + + return false; +} + +/* + * copy table_ref info. + * + * @retval: + * false if copy successfully, and otherwise true. + */ +bool TABLE_REF::pq_copy(JOIN *join, TABLE_REF *ref, QEP_TAB *qep_tab) { + THD *thd = join->thd; + key_parts = ref->key_parts; + key_length = ref->key_length; + key_err = ref->key_err; + key = ref->key; + null_rejecting = ref->null_rejecting; + depend_map = ref->depend_map; + use_count = ref->use_count; + disable_cache = ref->disable_cache; + + if (!(key_buff = (uchar *)thd->mem_calloc(ALIGN_SIZE(key_length) * 2)) || + !(key_copy = (store_key **)thd->mem_calloc( + (sizeof(store_key *) * (key_parts)))) || + !(items = (Item **)thd->mem_calloc(sizeof(Item *) * key_parts)) || + !(cond_guards = (bool **)thd->mem_calloc(sizeof(uint *) * key_parts))) { + return true; + } + + if (ref->null_ref_key != nullptr) { + null_ref_key = key_buff; + } + + key_buff2 = key_buff + ALIGN_SIZE(key_length); + memcpy(key_buff, ref->key_buff, ALIGN_SIZE(key_length) * 2); + uchar *key_buff_tmp = key_buff; + + for (uint i = 0; i < key_parts; i++) { + items[i] = ref->items[i]->pq_clone(thd, join->query_block); + if (items[i] == nullptr) { + return true; + } + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || items[i]); + if (!items[i]->fixed) { + items[i]->fix_fields(thd, &items[i]); + } + + if (qep_tab->table()->key_info) { + KEY *const keyinfo = qep_tab->table()->key_info + key; + bool maybe_null = keyinfo->key_part[i].null_bit; + qep_tab->position()->key->val = items[i]; + qep_tab->position()->key->used_tables = + qep_tab->position()->key->val->used_tables(); + if (ref->key_copy[i] != nullptr) { + key_copy[i] = get_store_key( + thd, qep_tab->position()->key->val, + qep_tab->position()->key->used_tables, join->const_table_map, + &keyinfo->key_part[i], key_buff_tmp, maybe_null); + } + + key_buff_tmp += keyinfo->key_part[i].store_length; + } + + if (!key_copy[i]) { + key_copy[i] = ref->key_copy[i]; + } + cond_guards[i] = ref->cond_guards[i]; + } + return false; +} +/* + * get table index + * + * @retval: + * -1 means not found. + */ +int get_qep_tab_index(QEP_TAB *src, TABLE_LIST *first_tbl) { + int index = 0; + for (TABLE_LIST *tl = first_tbl; tl != nullptr; tl = tl->next_leaf) { + if (src->table_ref == tl) { + return index; + } + index++; + } + return -1; +} + +TABLE_LIST *get_next_table(TABLE_LIST *start_table, + table_list_type_enum list_type) { + if (list_type == TABLE_LIST_TYPE_DEFAULT) { + return start_table->next_local; + } else if (list_type == TABLE_LIST_TYPE_LEAF) { + return start_table->next_leaf; + } else if (list_type == TABLE_LIST_TYPE_MERGE) { + return start_table->merge_underlying_list; + } else { + return start_table->next_global; + } + return nullptr; +} + +TABLE_LIST *get_table_by_index(TABLE_LIST *start_table, + table_list_type_enum list_type, int index) { + if (start_table == nullptr) { + return nullptr; + } + if (list_type == TABLE_LIST_TYPE_MERGE) { + start_table = start_table->merge_underlying_list; + } + int it = 0; + for (TABLE_LIST *tbl_list = start_table; tbl_list != nullptr; it++) { + if (it == index) { + return tbl_list; + } + tbl_list = get_next_table(tbl_list, list_type); + } + return nullptr; +} + +int get_qep_tab_index(QEP_TAB *tab, JOIN *join) { + for (uint i = 0; i < join->tables; i++) { + if (&join->qep_tab0[i] == tab) { + return i; + } + } + return -1; +} + +bool copy_flush(QEP_TAB *des, JOIN *orig, int index, JOIN *join) { + QEP_TAB *src = &orig->qep_tab[index]; + SJ_TMP_TABLE_TAB sjtabs[MAX_TABLES]; + SJ_TMP_TABLE_TAB *last_tab = sjtabs; + if (src->flush_weedout_table->tabs != nullptr) { + for (SJ_TMP_TABLE_TAB *t = src->flush_weedout_table->tabs; + t < src->flush_weedout_table->tabs_end; t++) { + int n = get_qep_tab_index(t->qep_tab, orig); + if (n == -1) { + return false; + } + last_tab->qep_tab = &join->qep_tab[n]; + ++last_tab; + } + } + + SJ_TMP_TABLE *sjtbl = create_sj_tmp_table(join->thd, join, sjtabs, last_tab); + des->flush_weedout_table = sjtbl; + QEP_TAB *start = &orig->qep_tab[index]; + int dis = 0; + for (uint i = index + 1; i < orig->tables; i++) { + QEP_TAB *t = &orig->qep_tab[i]; + if (t->check_weed_out_table == start->flush_weedout_table) { + dis = i - index; + break; + } + } + + QEP_TAB *last_sj_tab = des + dis; + last_sj_tab->check_weed_out_table = sjtbl; + return true; +} +/** + * duplicate qep_tabs in JOIN + * + * @join : target JOIN + * @orig : origin JOIN + * @setup : setup qep_tab object + * + */ +bool pq_dup_tabs(JOIN *join, JOIN *orig, bool setup MY_ATTRIBUTE((unused))) { + Item *m_having_cond = nullptr; + + join->const_tables = orig->const_tables; + join->primary_tables = orig->primary_tables; + Query_block *select = join->query_block; + + // phase 1. Create qep_tab and qep_tab->qs; + QEP_shared *qs = new (join->thd->pq_mem_root) QEP_shared[join->tables + 1]; + if (qs == nullptr) { + goto err; + } + join->qep_tab0 = new (join->thd->pq_mem_root) QEP_TAB[join->tables + 1]; + if (join->qep_tab0 == nullptr) { + goto err; + } + join->qep_tab = join->qep_tab0; + + for (uint i = 0; i < join->tables; i++) { + join->qep_tab[i].set_qs(&qs[i]); + join->qep_tab[i].set_join(join); + join->qep_tab[i].set_idx(i); + join->qep_tab[i].match_tab = orig->qep_tab[i].match_tab; + join->qep_tab[i].flush_weedout_table = orig->qep_tab[i].flush_weedout_table; + join->qep_tab[i].check_weed_out_table = + orig->qep_tab[i].check_weed_out_table; + join->qep_tab[i].op_type = orig->qep_tab[i].op_type; + join->qep_tab[i].table_ref = orig->qep_tab[i].table_ref; + join->qep_tab[i].using_dynamic_range = orig->qep_tab[i].using_dynamic_range; + } + + for (uint i = 0; i < join->primary_tables; i++) { + QEP_TAB *tab = &join->qep_tab[i]; + QEP_TAB *orig_tab = &orig->qep_tab[i]; + + // phase 3. Set tables to qep_tab according to db/table name + if (tab->pq_copy(join->thd, orig_tab)) { + goto err; + } + TABLE *tb = orig_tab->table(); + tab->table_name = new (join->thd->pq_mem_root) + LEX_CSTRING{tb->s->table_name.str, tb->s->table_name.length}; + + tab->db = new (join->thd->pq_mem_root) + LEX_CSTRING{tb->s->db.str, tb->s->db.length}; + if (tab->table_name == nullptr || tab->db == nullptr) { + goto err; + } + + /* + * note: currently, setup is true. + * Because duplicate qep_tabs in JOIN need fix_field to convert item to + * field. + */ + assert(select->leaf_tables); + /* + * setup physic table object + * Sometimes there are multiple tables with the same name in the + * leaf_tables, such as select empnum from t1 where hours in (select hours + * from t1); The leaf_tables has two t1's in it,at this point we need to + * copy the corresponding table of the same name. + */ + int index = get_qep_tab_index(orig_tab, orig->query_block->leaf_tables); + if (index == -1) { + goto err; + } + TABLE_LIST *tl = + get_table_by_index(select->leaf_tables, TABLE_LIST_TYPE_LEAF, index); + if (tl == nullptr) { + goto err; + } + bitmap_copy(tl->table->read_set, tab->table_ref->table->read_set); + bitmap_copy(tl->table->write_set, tab->table_ref->table->write_set); + tab->set_table(tl->table); + tab->table_ref = tl; + + // phase 4. Copy table properties from leader + if (tab->ref().pq_copy(join, &orig_tab->ref(), tab)) { + goto err; + } + + if (orig_tab->table()) { + if (tab->table()->pq_copy(join->thd, (void *)select, orig_tab->table())) { + goto err; + } + tab->set_keyread_optim(); + } + + // phase 2. clone conditions in qep_tab + Item *condition = orig_tab->condition(); + if ((condition != nullptr) && i < orig->primary_tables) { + Item *cond = condition->pq_clone(join->thd, select); + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || cond); + if (cond == nullptr) { + goto err; + } + if (cond->fix_fields(join->thd, &cond)) { + goto err; + } + tab->set_condition(cond); + tab->set_condition_optim(); + } + + // phase 2. clone cache_idx_cond in qep_tab + Item *cache_idx_cond = orig_tab->cache_idx_cond; + if ((cache_idx_cond != nullptr) && i < orig->primary_tables) { + Item *cond = cache_idx_cond->pq_clone(join->thd, select); + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || cond); + if (cond == nullptr) { + goto err; + } + if (cond->fix_fields(join->thd, &cond)) { + goto err; + } + tab->cache_idx_cond = cond; + } + + // phase 5. setup pq condition for index push down + if ((tab->has_pq_cond && !tab->pq_cond) || + (tab->pq_cond && tab->pq_cond->fix_fields(join->thd, &tab->pq_cond)) || + DBUG_EVALUATE_IF("pq_clone_error2", true, false)) { + sql_print_warning("[Parallel query]: ICP condition pushdown failed"); + goto err; + } + + // phase 6. copy quick select + MEM_ROOT *saved_mem_root = join->thd->mem_root; + if (orig_tab->quick()) { + QUICK_SELECT_I *quick = + orig_tab->quick()->pq_clone(join->thd, tab->table()); + assert(DBUG_EVALUATE_IF("pq_clone_error1", true, false) || quick); + if (quick == nullptr) { + goto err; + } + tab->set_quick(quick); + tab->set_quick_optim(); + } + join->thd->mem_root = saved_mem_root; + } + + // phase 7. Copy having condition + m_having_cond = select->having_cond(); + if (m_having_cond) { + assert(m_having_cond->is_bool_func()); + join->thd->where = "having clause"; + select->having_fix_field = true; + select->resolve_place = Query_block::RESOLVE_HAVING; + if (!m_having_cond->fixed && + (m_having_cond->fix_fields(join->thd, &m_having_cond) || + m_having_cond->check_cols(1))) { + goto err; + } + + select->having_fix_field = false; + select->resolve_place = Query_block::RESOLVE_NONE; + } + + for (uint i = 0; i < join->tables; i++) { + QEP_TAB *t = &orig->qep_tab[i]; + if (t->flush_weedout_table != nullptr) { + if (!copy_flush(&join->qep_tab[i], orig, i, join)) { + goto err; + } + } + } + return false; + +err: + return true; +} + +/* + * clone order structure + */ +ORDER *pq_dup_order(THD *thd, Query_block *select, ORDER *orig) { + ORDER *order = new (thd->pq_mem_root) ORDER(); + if (order == nullptr) { + return nullptr; + } + + if ((*orig->item)->is_derived_used() || !orig->in_field_list) { + order->item_initial = (*orig->item)->pq_clone(thd, select); + } else { + order->item_initial = orig->item_initial->pq_clone(thd, select); + } + + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || + order->item_initial); + if (order->item_initial == nullptr) { + return nullptr; + } + + order->next = nullptr; + order->item = &order->item_initial; + order->direction = orig->direction; + order->in_field_list = orig->in_field_list; + order->used_alias = orig->used_alias; + order->field_in_tmp_table = nullptr; + order->buff = nullptr; + order->used = 0; + order->depend_map = 0; + order->is_position = orig->is_position; + order->is_explicit = orig->is_explicit; + + return order; +} + +int get_table_index(TABLE_LIST *start_table, table_list_type_enum list_type, + TABLE_LIST *tl) { + if (start_table == nullptr) { + return -1; + } + int index = 0; + for (TABLE_LIST *tbl_list = start_table; tbl_list != nullptr; index++) { + if (tbl_list == tl) { + return index; + } + tbl_list = get_next_table(tbl_list, list_type); + } + return -1; +} + +TABLE_LIST *copy_table(THD *thd, TABLE_LIST *src, Query_block *select, + Query_block *orig) { + TABLE_LIST *ptr = new (thd->mem_root) TABLE_LIST; + if (ptr == nullptr) { + return nullptr; + } + ptr->query_block = select; + ptr->derived = src->derived; + ptr->effective_algorithm = src->effective_algorithm; + ptr->outer_join = src->outer_join; + if (src->merge_underlying_list != nullptr) { + TABLE_LIST *foundtable = nullptr; + int index = get_table_index(orig->leaf_tables, TABLE_LIST_TYPE_GLOBAL, + src->merge_underlying_list); + if (index != -1) { + foundtable = get_table_by_index(select->leaf_tables, + TABLE_LIST_TYPE_GLOBAL, index); + if (foundtable == nullptr) { + return nullptr; + } + ptr->merge_underlying_list = foundtable; + } else { + ptr->merge_underlying_list = + copy_table(thd, src->merge_underlying_list, select, orig); + } + } + ptr->field_translation = nullptr; + ptr->table_name = src->table_name; + ptr->table_name_length = src->table_name_length; + ptr->alias = src->alias; + ptr->is_alias = src->is_alias; + ptr->table_function = src->table_function; + if (src->table_function) { + ptr->derived_key_list.clear(); + } + ptr->is_fqtn = src->is_fqtn; + ptr->db = src->db; + ptr->db_length = src->db_length; + ptr->set_tableno(src->tableno()); + ptr->set_lock({TL_UNLOCK, THR_DEFAULT}); + ptr->updating = false; + ptr->ignore_leaves = false; + ptr->is_system_view = src->is_system_view; + + if (!ptr->is_derived() && !ptr->is_table_function() && + is_infoschema_db(ptr->db, ptr->db_length)) { + dd::info_schema::convert_table_name_case( + const_cast(ptr->db), const_cast(ptr->table_name)); + ST_SCHEMA_TABLE *schema_table = nullptr; + if (!ptr->is_system_view) { + schema_table = find_schema_table(thd, ptr->table_name); + if (schema_table) { + ptr->schema_table = schema_table; + } + } + } + ptr->cacheable_table = true; + ptr->index_hints = nullptr; + ptr->option = nullptr; + ptr->next_name_resolution_table = nullptr; + ptr->partition_names = nullptr; + MDL_REQUEST_INIT(&ptr->mdl_request, MDL_key::TABLE, ptr->db, ptr->table_name, + MDL_SHARED_READ, MDL_TRANSACTION); + return ptr; +} + +bool copy_table_field(TABLE_LIST *src, TABLE_LIST *des, THD *thd, + Query_block *dest_select) { + int count = src->field_translation_end - src->field_translation; + if (count <= 0) { + return false; + } + if (des->field_translation_end - des->field_translation != count) { + return true; + } + if (des->field_translation[0].item != nullptr) { + return false; + } + for (int i = 0; i < count; i++) { + des->field_translation[i].name = src->field_translation[i].name; + if (src->field_translation[i].item == nullptr) { + return true; + } + des->field_translation[i].item = + src->field_translation[i].item->pq_clone(thd, dest_select); + if (des->field_translation[i].item == nullptr) { + return true; + } + } + return false; +} + +bool copy_merge_table_field(THD *thd, Query_block *dest_select, int tableindex, + int mergeindex, TABLE_LIST *srctb) { + TABLE_LIST *tb = get_table_by_index(dest_select->table_list.first, + TABLE_LIST_TYPE_DEFAULT, tableindex); + if (tb == nullptr) { + return true; + } + TABLE_LIST *mergetable = + get_table_by_index(tb, TABLE_LIST_TYPE_MERGE, mergeindex); + if (mergetable == nullptr) { + return true; + } + if (copy_table_field(srctb, mergetable, thd, dest_select)) { + return true; + } + return false; +} + +bool copy_global_table_list_field(THD *thd, Query_block *orig, + Query_block *dest_select) { + int tableindex = 0; + for (TABLE_LIST *tbl_list = orig->leaf_tables; tbl_list != nullptr; + tbl_list = tbl_list->next_global) { + if (tbl_list->field_translation != nullptr) { + TABLE_LIST *src = get_table_by_index(dest_select->leaf_tables, + TABLE_LIST_TYPE_GLOBAL, tableindex); + if (src == nullptr) { + return true; + } + if (copy_table_field(tbl_list, src, thd, dest_select)) { + return true; + } + } + tableindex++; + } + return false; +} + +bool init_table_field_space(THD *thd, TABLE_LIST *src, TABLE_LIST *des) { + int count = src->field_translation_end - src->field_translation; + if (count > 0 && des->field_translation == nullptr) { + Field_translator *transl = (Field_translator *)thd->stmt_arena->alloc( + count * sizeof(Field_translator)); + if (transl == nullptr) { + return true; + } + for (int i = 0; i < count; i++) { + transl[i].name = nullptr; + transl[i].item = nullptr; + } + des->field_translation = transl; + des->field_translation_end = transl + count; + } + return false; +} + +bool copy_leaf_tables(THD *thd, Query_block *orig, Query_block *dest_select) { + TABLE_LIST *last = nullptr; + dest_select->leaf_tables = nullptr; + for (TABLE_LIST *tbl_list = orig->leaf_tables; tbl_list != nullptr; + tbl_list = tbl_list->next_leaf) { + TABLE_LIST *tl = copy_table(thd, tbl_list, dest_select, orig); + if (tl == nullptr) { + return true; + } + if (dest_select->leaf_tables == nullptr) { + dest_select->leaf_tables = tl; + last = tl; + } else { + last->next_name_resolution_table = tl; + last->next_leaf = tl; + last = tl; + } + } + last->next_leaf = nullptr; + return false; +} + +void set_up_leaf_tables(THD *thd, Query_block *select) { + select->partitioned_table_count = 0; + for (TABLE_LIST *tr = select->leaf_tables; tr != nullptr; + tr = tr->next_leaf) { + TABLE *const table = tr->table; + select->leaf_table_count++; + if (select->first_execution && + select->opt_hints_qb && // QB hints initialized + !tr->opt_hints_table) // Table hints are not adjusted yet + { + tr->opt_hints_table = select->opt_hints_qb->adjust_table_hints(tr); + } + if (table == nullptr) { + continue; + } + table->pos_in_table_list = tr; + } + if (select->opt_hints_qb) { + select->opt_hints_qb->check_unresolved(thd); + } +} + +bool copy_global_tables(THD *thd, Query_block *orig, Query_block *dest_select) { + for (TABLE_LIST *tbl_list = orig->leaf_tables; tbl_list != nullptr; + tbl_list = tbl_list->next_global) { + int index = + get_table_index(orig->leaf_tables, TABLE_LIST_TYPE_LEAF, tbl_list); + TABLE_LIST *tmp = nullptr; + if (index != -1) { + tmp = get_table_by_index(dest_select->leaf_tables, TABLE_LIST_TYPE_LEAF, + index); + } else { + tmp = copy_table(thd, tbl_list, dest_select, orig); + } + if (tmp == nullptr) { + return true; + } + thd->lex->add_to_query_tables(tmp); + } + return false; +} + +bool copy_table_list(THD *thd, Query_block *orig, Query_block *dest_select) { + for (TABLE_LIST *tbl_list = orig->table_list.first; tbl_list != nullptr; + tbl_list = tbl_list->next_local) { + int index = + get_table_index(orig->leaf_tables, TABLE_LIST_TYPE_GLOBAL, tbl_list); + TABLE_LIST *tmp = nullptr; + if (index != -1) { + tmp = get_table_by_index(dest_select->leaf_tables, TABLE_LIST_TYPE_GLOBAL, + index); + } else { + tmp = copy_table(thd, tbl_list, dest_select, orig); + } + if (tmp == nullptr) { + return true; + } + dest_select->table_list.link_in_list(tmp, &tmp->next_local); + } + return false; +} + +bool init_table_list_field_space(THD *thd, Query_block *select, + table_list_type_enum list_type) { + TABLE_LIST *start_src = nullptr; + TABLE_LIST *start_des = nullptr; + if (list_type == TABLE_LIST_TYPE_DEFAULT) { + start_src = select->orig->table_list.first; + start_des = select->table_list.first; + } else { + start_src = select->orig->leaf_tables; + start_des = select->leaf_tables; + } + int tableindex = 0; + for (TABLE_LIST *tbl_list = start_src; tbl_list != nullptr; tableindex++) { + if (tbl_list->field_translation != nullptr) { + TABLE_LIST *des = get_table_by_index(start_des, list_type, tableindex); + if (des == nullptr) { + return true; + } + if (init_table_field_space(thd, tbl_list, des)) { + return true; + } + } + tbl_list = get_next_table(tbl_list, list_type); + } + return false; +} +bool init_field_space(THD *thd, Query_block *orig, Query_block *select) { + if (init_table_list_field_space(thd, select, TABLE_LIST_TYPE_DEFAULT) || + init_table_list_field_space(thd, select, TABLE_LIST_TYPE_GLOBAL)) { + return true; + } + + int tableindex = 0; + for (TABLE_LIST *tbl_list = orig->table_list.first; tbl_list != nullptr; + tbl_list = tbl_list->next_local) { + if (tbl_list->merge_underlying_list != nullptr) { + int mergeindex = 0; + for (TABLE_LIST *tb = tbl_list->merge_underlying_list; tb != nullptr; + tb = tb->merge_underlying_list) { + if (tb->field_translation != nullptr) { + TABLE_LIST *ta = get_table_by_index( + select->table_list.first, TABLE_LIST_TYPE_DEFAULT, tableindex); + if (ta == nullptr) { + return true; + } + TABLE_LIST *mergetable = + get_table_by_index(ta, TABLE_LIST_TYPE_MERGE, mergeindex); + if (mergetable == nullptr) { + return true; + } + if (init_table_field_space(thd, tb, mergetable)) { + return true; + } + } + mergeindex++; + } + } + tableindex++; + } + return false; +} + +bool copy_merge_table_list_field(THD *thd, Query_block *orig, + Query_block *dest_select) { + int tableindex = 0; + int mergeindex = 0; + for (TABLE_LIST *tbl_list = orig->table_list.first; tbl_list != nullptr; + tbl_list = tbl_list->next_local) { + if (tbl_list->merge_underlying_list != nullptr) { + mergeindex = 0; + for (TABLE_LIST *tb = tbl_list->merge_underlying_list; tb != nullptr; + tb = tb->merge_underlying_list) { + if (tb->field_translation != nullptr && + copy_merge_table_field(thd, dest_select, tableindex, mergeindex, + tb)) { + return true; + } + mergeindex++; + } + } + tableindex++; + } + return false; +} + +bool copy_table_list_field(THD *thd, Query_block *orig, + Query_block *dest_select) { + int tableindex = 0; + for (TABLE_LIST *tbl_list = orig->table_list.first; tbl_list != nullptr; + tbl_list = tbl_list->next_local) { + if (tbl_list->field_translation != nullptr) { + TABLE_LIST *src = get_table_by_index(dest_select->table_list.first, + TABLE_LIST_TYPE_DEFAULT, tableindex); + if (src == nullptr) { + return true; + } + if (copy_table_field(tbl_list, src, thd, dest_select)) { + return true; + } + } + tableindex++; + } + return false; +} + +bool copy_all_table_list(THD *thd, Query_block *orig, + Query_block *dest_select) { + if (copy_leaf_tables(thd, orig, dest_select) || + copy_global_tables(thd, orig, dest_select) || + copy_table_list(thd, orig, dest_select)) { + return true; + } + if (init_field_space(thd, orig, dest_select) || + copy_merge_table_list_field(thd, orig, dest_select) || + copy_global_table_list_field(thd, orig, dest_select) || + copy_table_list_field(thd, orig, dest_select)) { + return true; + } + return false; +} + +Query_block *pq_dup_select(THD *thd, Query_block *orig) { + Item *new_item = nullptr; + Item *where = nullptr; + Item *having = nullptr; + ORDER *group = nullptr; + ORDER *group_new = nullptr; + ORDER *order = nullptr; + ORDER *order_new = nullptr; + Query_block *select = nullptr; + SQL_I_List orig_list; + + LEX *lex = new (thd->pq_mem_root) LEX(); + if (lex == nullptr) { + goto err; + } + lex->reset(); + lex->result = orig->parent_lex->result; + lex->sql_command = orig->parent_lex->sql_command; + lex->explain_format = orig->parent_lex->explain_format; + lex->is_explain_analyze = orig->parent_lex->is_explain_analyze; + thd->lex = lex; + lex->thd = thd; + thd->query_plan.set_query_plan(SQLCOM_SELECT, lex, false); + + select = lex->new_query(nullptr); + if (!select || DBUG_EVALUATE_IF("dup_select_abort1", true, false)) { + goto err; + } + select->orig = orig; + select->renumber(thd->lex); + select->with_sum_func = orig->with_sum_func; + select->n_child_sum_items = orig->n_child_sum_items; + select->n_sum_items = orig->n_sum_items; + select->select_n_having_items = orig->select_n_having_items; + select->select_n_where_fields = orig->select_n_where_fields; + select->m_active_options = orig->m_active_options; + lex->set_current_query_block(select); + lex->unit = select->master_query_expression(); + thd->lex->query_block = select; + + // phase 1. clone tables and open/lock them + if (copy_all_table_list(thd, orig, select)) { + goto err; + } + + assert(select->context.query_block == select); + select->context.table_list = select->context.first_name_resolution_table = + select->leaf_tables; + + // phase 1. open tables and lock them + if (open_tables_for_query(thd, thd->lex->query_tables, 0) || + lock_tables(thd, thd->lex->query_tables, thd->lex->table_count, 0)) { + goto err; + } + set_up_leaf_tables(thd, select); + // phase 1. copy table->nullable + // before setup_fields, propagate_nullability will change table->nullable, + // which may affect item->maybe_null, so we copy it here. + // see in Query_block:: prepare + for (TABLE_LIST *tl = orig->leaf_tables; tl != nullptr; tl = tl->next_leaf) { + for (TABLE_LIST *tbl_list = select->leaf_tables; tbl_list != nullptr; + tbl_list = tbl_list->next_leaf) { + const char *db = tbl_list->db; + const char *table_name = tbl_list->table_name; + const char *alias = tbl_list->alias; + + if (!strncmp(db, tl->db, strlen(db)) && strlen(tl->db) == strlen(db) && + !strncmp(table_name, tl->table_name, strlen(table_name)) && + strlen(tl->table_name) == strlen(table_name) && + !strncmp(alias, tl->alias, strlen(alias)) && + strlen(tl->alias) == strlen(alias)) { + if (tl->table != nullptr && tl->table->is_nullable()) { + tbl_list->table->set_nullable(); + } + break; + } + } + } + + // phase 2. clone select fields list + for (Item *item : orig->fields) { + if (item->hidden) { + continue; + } + new_item = item->pq_clone(thd, select); + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || new_item); + if (new_item == nullptr) { + goto err; + } + + select->fields.push_back(new_item); + } + + // phase 3. duplicate group list + /* + * for template select_lex, we use leader's saved_group_list_ptrs to + * restore original group_list, and then copy it to template. For + * worker's select_lex, we directly use template's info to generate + * its group_list. + */ + if (orig->saved_group_list_ptrs) { + restore_list(orig->saved_group_list_ptrs, orig_list); + assert(orig_list.elements == orig->group_list.elements); + } else { // the case of template select_lex + orig_list = orig->group_list; + } + + // duplicate group list + if (orig_list.elements) { + for (group = orig_list.first; group; group = group->next) { + group_new = pq_dup_order(thd, select, group); + if (group_new == nullptr) { + goto err; + } + + select->group_list.link_in_list(group_new, &group_new->next); + } + } + + if (orig->saved_order_list_ptrs) { + restore_list(orig->saved_order_list_ptrs, orig_list); + assert(orig_list.elements == orig->order_list.elements); + } else { // the case of template select_lex + orig_list = orig->order_list; + } + + // duplicate order list + if (orig_list.elements) { + for (order = orig_list.first; order; order = order->next) { + order_new = pq_dup_order(thd, select, order); + if (order_new == nullptr) { + goto err; + } + + select->order_list.link_in_list(order_new, &order_new->next); + } + } + + /** mianly used for optimized_group_by */ + if (select->group_list.elements) { + select->fix_prepare_information_for_order(thd, &select->group_list, + &select->saved_group_list_ptrs); + } + if (select->order_list.elements) { + select->fix_prepare_information_for_order(thd, &select->order_list, + &select->saved_order_list_ptrs); + } + + if (select->setup_base_ref_items(thd) || + DBUG_EVALUATE_IF("dup_select_abort2", true, false)) { + goto err; + } + + thd->mark_used_columns = MARK_COLUMNS_READ; + + // phase 5. duplicate where cond + if (orig->where_cond()) { + where = orig->where_cond()->pq_clone(thd, select); + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || where); + if (where == nullptr) { + goto err; + } + select->set_where_cond(where); + } else { + select->set_where_cond(nullptr); + } + + // phase 6. duplicate having cond + if (orig->having_cond()) { + having = orig->having_cond()->pq_clone(thd, select); + assert(DBUG_EVALUATE_IF("skip_pq_clone_check", true, false) || having); + if (having == nullptr) { + goto err; + } + select->set_having_cond(having); + } else { + select->set_having_cond(nullptr); + } + + // phase 7: allow local set functions in HAVING and ORDER BY + lex->allow_sum_func |= (nesting_map)1 << (nesting_map)select->nest_level; + select->set_query_result(lex->result); + return select; + +err: + return nullptr; +} + +/** + * resolve query block, setup tables list, fields list, group list\order list + * + * @select: query block + * + */ +static bool pq_select_prepare(THD *thd, Query_block *select, + mem_root_deque &orig_all_fields) { + // Setup.1 setup all fields + int all_fields_count = select->fields.size(); + thd->mark_used_columns = MARK_COLUMNS_READ; + ulong want_privilege = 0; + if (setup_fields(thd, want_privilege, true, true, false, nullptr, + &select->fields, select->base_ref_items, true)) { + return true; + } + + // Setup.2 setup GROUP BY clause + if (select->group_list.elements && select->setup_group(thd)) { + return true; + } + select->hidden_group_field_count = select->fields.size() - all_fields_count; + + // Setup.3 setup ORDER BY clause + if (select->order_list.elements && + setup_order(thd, select->base_ref_items, select->table_list.first, + &select->fields, select->order_list.first)) { + return true; + } + + select->hidden_order_field_count = select->fields.size() - all_fields_count; + + if (select->order_list.elements && select->setup_order_final(thd)) { + return true; + } + + // Setup.4: check item's property */ + if (select->fields.size() != orig_all_fields.size()) { + return true; + } + + Item *orig_item = nullptr; + uint i = 0; + for (Item *item : select->fields) { + orig_item = orig_all_fields[i]; + if (item == nullptr || (item->type() != orig_item->type())) return true; + i++; + } + + return false; +} + +JOIN *pq_make_join(THD *thd, JOIN *join) { + JOIN *pq_join = nullptr; + Query_block *select = pq_dup_select(thd, join->query_block); + if (!select || pq_select_prepare(thd, select, join->query_block->fields)) { + goto err; + } + + thd->lex->unit->set_prepared(); + + pq_join = new (thd->pq_mem_root) JOIN(thd, select); + if (!pq_join || DBUG_EVALUATE_IF("dup_join_abort", true, false)) { + goto err; + } + pq_join->pq_copy_from(join); + /** + * limit cannot push down to worker, for the cases: + * (1) with aggregation + * (2) with sorting after optimized-group-by + */ + if (join->query_expression()->select_limit_cnt) { + if (join->query_block->with_sum_func || // c1 + (join->pq_rebuilt_group && // c2 + join->pq_last_sort_idx >= (int)join->primary_tables)) { + pq_join->m_select_limit = HA_POS_ERROR; // no limit + pq_join->query_expression()->select_limit_cnt = HA_POS_ERROR; + } + } + return pq_join; + +err: + return nullptr; +} + +bool System_variables::pq_copy_from(struct System_variables orig) { + pseudo_thread_id = orig.pseudo_thread_id; + sql_mode = orig.sql_mode; + collation_connection = orig.collation_connection; + div_precincrement = orig.div_precincrement; + time_zone = orig.time_zone; + big_tables = orig.big_tables; + lc_time_names = orig.lc_time_names; + my_aes_mode = orig.my_aes_mode; + transaction_isolation = orig.transaction_isolation; + option_bits = orig.option_bits; + explicit_defaults_for_timestamp = orig.explicit_defaults_for_timestamp; + sortbuff_size = orig.sortbuff_size; + join_buff_size = orig.join_buff_size; + return false; +} + +bool System_status_var::pq_merge_status(struct System_status_var worker) { + filesort_range_count += worker.filesort_range_count; + filesort_rows += worker.filesort_rows; + filesort_scan_count += worker.filesort_scan_count; + + ha_read_first_count += worker.ha_read_first_count; + ha_read_last_count += worker.ha_read_last_count; + ha_read_key_count += worker.ha_read_key_count; + ha_read_next_count += worker.ha_read_next_count; + ha_read_prev_count += worker.ha_read_prev_count; + ha_read_rnd_count += worker.ha_read_rnd_count; + ha_read_rnd_next_count += worker.ha_read_rnd_next_count; + return false; +} + +bool THD::pq_copy_from(THD *thd) { + variables.pq_copy_from(thd->variables); + start_time = thd->start_time; + user_time = thd->user_time; + m_query_string = thd->m_query_string; + tx_isolation = thd->tx_isolation; + tx_read_only = thd->tx_read_only; + parallel_exec = thd->parallel_exec; + pq_dop = thd->pq_dop; + arg_of_last_insert_id_function = thd->arg_of_last_insert_id_function; + first_successful_insert_id_in_prev_stmt = + thd->first_successful_insert_id_in_prev_stmt; + first_successful_insert_id_in_prev_stmt_for_binlog = + thd->first_successful_insert_id_in_prev_stmt_for_binlog; + first_successful_insert_id_in_cur_stmt = + thd->first_successful_insert_id_in_cur_stmt; + stmt_depends_on_first_successful_insert_id_in_prev_stmt = + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt; + return false; +} + +bool THD::pq_merge_status(THD *thd) { + status_var.pq_merge_status(thd->status_var); + current_found_rows += thd->current_found_rows; + pq_current_found_rows = thd->current_found_rows; + m_examined_row_count += thd->m_examined_row_count; + return false; +} + +bool THD::pq_status_reset() { + current_found_rows = 0; + m_examined_row_count = 0; + return false; +} diff --git a/sql/pq_clone.h b/sql/pq_clone.h new file mode 100644 index 000000000000..9cbcac801229 --- /dev/null +++ b/sql/pq_clone.h @@ -0,0 +1,58 @@ +#ifndef PQ_CLONE_INCLUDE_H +#define PQ_CLONE_INCLUDE_H + +/* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2022, Huawei Technologies Co., Ltd. + + 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 also distributed 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 included with MySQL. + + 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 */ + +#include "sql/sql_list.h" +class Item; +class Item_ident; +class THD; +class Query_block; +class JOIN; +class ORDER; +class ORDER_with_src; +class TABLE_LIST; +enum table_list_type_enum { + TABLE_LIST_TYPE_DEFAULT, + TABLE_LIST_TYPE_LEAF, + TABLE_LIST_TYPE_GLOBAL, + TABLE_LIST_TYPE_MERGE +}; + +bool pq_dup_tabs(JOIN *pq_join, JOIN *join, bool setup); + +TABLE_LIST *get_table_by_index(TABLE_LIST *start_table, + table_list_type_enum list_type, int index); + +int get_table_index(TABLE_LIST *start_table, table_list_type_enum list_type, + TABLE_LIST *tl); + +extern Item **resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, + Query_block *select); + +JOIN *pq_make_join(THD *thd, JOIN *join); + +bool copy_all_table_list(THD *thd, Query_block *orig, Query_block *dest_select); + +#endif // PQ_CLONE_INCLUDE_H