diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-05-05 16:12:54 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-05-05 16:12:54 +0400 |
commit | ac53b49b1be807f588aebd83883ec93b764f5d54 (patch) | |
tree | c86cbdb535eefb15e2077a7ac2ffaeff9d76955e /sql | |
parent | 583b68e89961c35fa95a06c38988f82e33c73f4a (diff) | |
parent | db0917f68f2681882974afd53935aa8cba29c6b8 (diff) | |
download | mariadb-git-ac53b49b1be807f588aebd83883ec93b764f5d54.tar.gz |
Merge remote-tracking branch 'origin/10.2' into bb-10.2-ext
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.h | 27 | ||||
-rw-r--r-- | sql/handler.h | 5 | ||||
-rw-r--r-- | sql/item.cc | 20 | ||||
-rw-r--r-- | sql/item.h | 54 | ||||
-rw-r--r-- | sql/item_func.cc | 12 | ||||
-rw-r--r-- | sql/item_func.h | 10 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 4 | ||||
-rw-r--r-- | sql/item_jsonfunc.cc | 14 | ||||
-rw-r--r-- | sql/item_subselect.cc | 45 | ||||
-rw-r--r-- | sql/item_subselect.h | 8 | ||||
-rw-r--r-- | sql/log_event.cc | 5 | ||||
-rw-r--r-- | sql/mysqld.cc | 8 | ||||
-rw-r--r-- | sql/opt_sum.cc | 2 | ||||
-rw-r--r-- | sql/rpl_parallel.cc | 3 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/slave.cc | 3 | ||||
-rw-r--r-- | sql/sql_cte.cc | 72 | ||||
-rw-r--r-- | sql/sql_cte.h | 21 | ||||
-rw-r--r-- | sql/sql_derived.cc | 20 | ||||
-rw-r--r-- | sql/sql_derived.h | 4 | ||||
-rw-r--r-- | sql/sql_load.cc | 61 | ||||
-rw-r--r-- | sql/sql_select.cc | 62 | ||||
-rw-r--r-- | sql/sql_select.h | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 14 | ||||
-rw-r--r-- | sql/sql_window.cc | 7 | ||||
-rw-r--r-- | sql/sys_vars.cc | 15 | ||||
-rw-r--r-- | sql/table.cc | 25 | ||||
-rw-r--r-- | sql/table.h | 2 | ||||
-rw-r--r-- | sql/wsrep_hton.cc | 2 | ||||
-rw-r--r-- | sql/wsrep_mysqld.h | 1 | ||||
-rw-r--r-- | sql/wsrep_thd.cc | 33 |
31 files changed, 436 insertions, 127 deletions
diff --git a/sql/field.h b/sql/field.h index ccc116f7a25..1333c924fa5 100644 --- a/sql/field.h +++ b/sql/field.h @@ -518,7 +518,10 @@ inline bool is_temporal_type(enum_field_types type) enum enum_vcol_info_type { VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, - VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE + VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE, + /* Additional types should be added here */ + /* Following is the highest value last */ + VCOL_TYPE_NONE = 127 // Since the 0 value is already in use }; static inline const char *vcol_type_name(enum_vcol_info_type type) @@ -533,6 +536,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) case VCOL_CHECK_FIELD: case VCOL_CHECK_TABLE: return "CHECK"; + case VCOL_TYPE_NONE: + return "UNTYPED"; } return 0; } @@ -546,7 +551,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) #define VCOL_NON_DETERMINISTIC 2 #define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */ #define VCOL_TIME_FUNC 8 -#define VCOL_IMPOSSIBLE 16 +#define VCOL_AUTO_INC 16 +#define VCOL_IMPOSSIBLE 32 #define VCOL_NOT_STRICTLY_DETERMINISTIC \ (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) @@ -564,6 +570,7 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) class Virtual_column_info: public Sql_alloc { private: + enum_vcol_info_type vcol_type; /* Virtual column expression type */ /* The following data is only updated by the parser and read when a Create_field object is created/initialized. @@ -581,7 +588,8 @@ public: uint flags; Virtual_column_info() - : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), + : vcol_type((enum_vcol_info_type)VCOL_TYPE_NONE), + field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), in_partitioning_expr(FALSE), stored_in_db(FALSE), utf8(TRUE), expr(NULL), flags(0) { @@ -589,6 +597,19 @@ public: name.length= 0; }; ~Virtual_column_info() {} + enum_vcol_info_type get_vcol_type() const + { + return vcol_type; + } + void set_vcol_type(enum_vcol_info_type v_type) + { + vcol_type= v_type; + } + const char *get_vcol_type_name() const + { + DBUG_ASSERT(vcol_type != VCOL_TYPE_NONE); + return vcol_type_name(vcol_type); + } enum_field_types get_real_type() const { return field_type; diff --git a/sql/handler.h b/sql/handler.h index b379f4e8b4d..7966351d02d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2889,10 +2889,9 @@ public: bool keyread_enabled() { return keyread < MAX_KEY; } int ha_start_keyread(uint idx) { - if (keyread_enabled()) - return 0; + int res= keyread_enabled() ? 0 : extra(HA_EXTRA_KEYREAD); keyread= idx; - return extra(HA_EXTRA_KEYREAD); + return res; } int ha_end_keyread() { diff --git a/sql/item.cc b/sql/item.cc index bf962777a48..bb3dd1a1c6a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -604,8 +604,9 @@ void Item::print_value(String *str) str->append("NULL"); else { - switch (result_type()) { + switch (cmp_type()) { case STRING_RESULT: + case TIME_RESULT: append_unescaped(str, ptr->ptr(), ptr->length()); break; case DECIMAL_RESULT: @@ -614,7 +615,6 @@ void Item::print_value(String *str) str->append(*ptr); break; case ROW_RESULT: - case TIME_RESULT: DBUG_ASSERT(0); } } @@ -956,7 +956,7 @@ bool Item_field::register_field_in_write_map(void *arg) This means: - For default fields we can't access the same field or a field after itself that doesn't have a non-constant default value. - - A virtual fields can't access itself or a virtual field after itself. + - A virtual field can't access itself or a virtual field after itself. - user-specified values will not see virtual fields or default expressions, as in INSERT t1 (a) VALUES (b); - no virtual fields can access auto-increment values @@ -4279,7 +4279,7 @@ Item_param::eq(const Item *item, bool binary_cmp) const void Item_param::print(String *str, enum_query_type query_type) { - if (state == NO_VALUE || query_type & QT_NO_DATA_EXPANSION) + if (state == NO_VALUE) { str->append('?'); } @@ -9303,6 +9303,14 @@ void Item_cache::store(Item *item) void Item_cache::print(String *str, enum_query_type query_type) { + if (example && // There is a cached item + (query_type & QT_NO_DATA_EXPANSION)) // Caller is show-create-table + { + // Instead of "cache" or the cached value, print the cached item name + example->print(str, query_type); + return; + } + if (value_cached) { print_value(str); @@ -9538,7 +9546,7 @@ int Item_cache_temporal::save_in_field(Field *field, bool no_conversions) void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg) { - /* An explicit values is given, save it. */ + /* An explicit value is given, save it. */ store(example_arg); value_cached= true; value= val_arg; @@ -10362,7 +10370,7 @@ void Virtual_column_info::print(String *str) (enum_query_type)(QT_ITEM_ORIGINAL_FUNC_NULLIF | QT_ITEM_IDENT_SKIP_DB_NAMES | QT_ITEM_IDENT_SKIP_TABLE_NAMES | - QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS | + QT_NO_DATA_EXPANSION | QT_TO_SYSTEM_CHARSET), LOWEST_PRECEDENCE); } diff --git a/sql/item.h b/sql/item.h index 5b85664bf73..c24ac19e439 100644 --- a/sql/item.h +++ b/sql/item.h @@ -337,6 +337,19 @@ typedef struct replace_equal_field_arg struct st_join_table *context_tab; } REPLACE_EQUAL_FIELD_ARG; + +class Load_data_out_param +{ +public: + Load_data_out_param() { } + virtual ~Load_data_out_param() { } + virtual void load_data_set_null_value(CHARSET_INFO *cs) = 0; + virtual void load_data_set_value(const char *str, uint length, + CHARSET_INFO *cs) = 0; + virtual void load_data_print(THD *thd, String *str) = 0; +}; + + class Settable_routine_parameter { public: @@ -1448,6 +1461,7 @@ public: /*========= Item processors, to be used with Item::walk() ========*/ virtual bool remove_dependence_processor(void *arg) { return 0; } virtual bool cleanup_processor(void *arg); + virtual bool cleanup_excluding_fields_processor(void *arg) { return cleanup_processor(arg); } virtual bool cleanup_excluding_const_fields_processor(void *arg) { return cleanup_processor(arg); } virtual bool collect_item_field_processor(void *arg) { return 0; } virtual bool collect_outer_ref_processor(void *arg) {return 0; } @@ -1689,6 +1703,14 @@ public: delete this; } + virtual Load_data_out_param *get_load_data_out_param() { return 0; } + Load_data_out_param *get_load_data_out_param_or_error() + { + Load_data_out_param *res= get_load_data_out_param(); + if (!res) + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), full_name()); + return res; + } virtual Item_splocal *get_item_splocal() { return 0; } virtual Rewritable_query_parameter *get_rewritable_query_parameter() { return 0; } @@ -2763,6 +2785,11 @@ public: bool check_vcol_func_processor(void *arg) { context= 0; + if (field && (field->unireg_check == Field::NEXT_NUMBER)) + { + // Auto increment fields are unsupported + return mark_unsupported_function(field_name.str, arg, VCOL_FIELD_REF | VCOL_AUTO_INC); + } return mark_unsupported_function(field_name.str, arg, VCOL_FIELD_REF); } void cleanup(); @@ -2781,6 +2808,8 @@ public: virtual void print(String *str, enum_query_type query_type); bool exclusive_dependence_on_table_processor(void *map); bool exclusive_dependence_on_grouping_fields_processor(void *arg); + bool cleanup_excluding_fields_processor(void *arg) + { return field ? 0 : cleanup_processor(arg); } bool cleanup_excluding_const_fields_processor(void *arg) { return field && const_item() ? 0 : cleanup_processor(arg); } @@ -4427,6 +4456,14 @@ public: { return depended_from != NULL; } bool exclusive_dependence_on_grouping_fields_processor(void *arg) { return depended_from != NULL; } + bool cleanup_excluding_fields_processor(void *arg) + { + Item *item= real_item(); + if (item && item->type() == FIELD_ITEM && + ((Item_field *)item)->field) + return 0; + return cleanup_processor(arg); + } bool cleanup_excluding_const_fields_processor(void *arg) { Item *item= real_item(); @@ -5566,8 +5603,25 @@ public: } bool check_vcol_func_processor(void *arg) { + if (example) + { + Item::vcol_func_processor_result *res= (Item::vcol_func_processor_result*)arg; + example->check_vcol_func_processor(arg); + /* + Item_cache of a non-deterministic function requires re-fixing + even if the function itself doesn't (e.g. CURRENT_TIMESTAMP) + */ + if (res->errors & VCOL_NOT_STRICTLY_DETERMINISTIC) + res->errors|= VCOL_SESSION_FUNC; + return false; + } return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); } + void cleanup() + { + clear(); + Item_basic_constant::cleanup(); + } /** Check if saved item has a non-NULL value. Will cache value of saved item if not already done. diff --git a/sql/item_func.cc b/sql/item_func.cc index 9fc626b54f5..684b5a4f67d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4425,7 +4425,10 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref) for (derived= unit->derived; derived; derived= derived->select_lex->master_unit()->derived) + { derived->set_materialized_derived(); + derived->prohibit_cond_pushdown= true; + } } return FALSE; @@ -5400,14 +5403,15 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) } -void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs) +void Item_user_var_as_out_param::load_data_set_null_value(CHARSET_INFO* cs) { ::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, 0 /* unsigned_arg */); } -void Item_user_var_as_out_param::set_value(const char *str, uint length, - CHARSET_INFO* cs) +void Item_user_var_as_out_param::load_data_set_value(const char *str, + uint length, + CHARSET_INFO* cs) { ::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, 0 /* unsigned_arg */); @@ -5442,7 +5446,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) } -void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) +void Item_user_var_as_out_param::load_data_print(THD *thd, String *str) { str->append('@'); append_identifier(thd, str, name.str, name.length); diff --git a/sql/item_func.h b/sql/item_func.h index 33726cd2d84..3fcde96b81a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2339,7 +2339,8 @@ public: in List<Item> and desire to place this code somewhere near other functions working with user variables. */ -class Item_user_var_as_out_param :public Item +class Item_user_var_as_out_param :public Item, + public Load_data_out_param { LEX_CSTRING name; user_var_entry *entry; @@ -2355,9 +2356,10 @@ public: my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); - void print_for_load(THD *thd, String *str); - void set_null_value(CHARSET_INFO* cs); - void set_value(const char *str, uint length, CHARSET_INFO* cs); + Load_data_out_param *get_load_data_out_param() { return this; } + void load_data_print(THD *thd, String *str); + void load_data_set_null_value(CHARSET_INFO* cs); + void load_data_set_value(const char *str, uint length, CHARSET_INFO* cs); enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_user_var_as_out_param>(thd, mem_root, this); } diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 8a61ab583c9..f2162e08323 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1063,11 +1063,11 @@ Item_func_spatial_rel::get_mm_leaf(RANGE_OPT_PARAM *param, tree->max_flag= NO_MAX_RANGE; break; case SP_WITHIN_FUNC: - tree->min_flag= GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512; + tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512; tree->max_flag= NO_MAX_RANGE; break; case SP_CONTAINS_FUNC: - tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512; + tree->min_flag= GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512; tree->max_flag= NO_MAX_RANGE; break; case SP_OVERLAPS_FUNC: diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index b8471dc8244..c7639bc2513 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -444,6 +444,7 @@ void Item_func_json_value::fix_length_and_dec() collation.set(args[0]->collation); max_length= args[0]->max_length; path.set_constant_flag(args[1]->const_item()); + maybe_null= 1; } @@ -582,6 +583,7 @@ void Item_func_json_unquote::fix_length_and_dec() { collation.set(&my_charset_utf8_general_ci); max_length= args[0]->max_length; + maybe_null= 1; } @@ -683,6 +685,7 @@ void Item_func_json_extract::fix_length_and_dec() max_length= args[0]->max_length * (arg_count - 1); mark_constant_paths(paths, args+1, arg_count-1); + maybe_null= 1; } @@ -884,6 +887,7 @@ void Item_func_json_contains::fix_length_and_dec() { a2_constant= args[1]->const_item(); a2_parsed= FALSE; + maybe_null= 1; if (arg_count > 2) path.set_constant_flag(args[2]->const_item()); Item_int_func::fix_length_and_dec(); @@ -1129,6 +1133,7 @@ void Item_func_json_contains_path::fix_length_and_dec() { ooa_constant= args[1]->const_item(); ooa_parsed= FALSE; + maybe_null= 1; mark_constant_paths(paths, args+2, arg_count-2); Item_int_func::fix_length_and_dec(); } @@ -2042,6 +2047,7 @@ void Item_func_json_length::fix_length_and_dec() { if (arg_count > 1) path.set_constant_flag(args[1]->const_item()); + maybe_null= 1; } @@ -2178,6 +2184,7 @@ void Item_func_json_type::fix_length_and_dec() { collation.set(&my_charset_utf8_general_ci); max_length= 12; + maybe_null= 1; } @@ -2245,6 +2252,7 @@ void Item_func_json_insert::fix_length_and_dec() } fix_char_length_ulonglong(char_length); + maybe_null= 1; } @@ -2491,6 +2499,7 @@ void Item_func_json_remove::fix_length_and_dec() max_length= args[0]->max_length; mark_constant_paths(paths, args+1, arg_count-1); + maybe_null= 1; } @@ -2674,6 +2683,7 @@ void Item_func_json_keys::fix_length_and_dec() { collation.set(args[0]->collation); max_length= args[0]->max_length; + maybe_null= 1; if (arg_count > 1) path.set_constant_flag(args[1]->const_item()); } @@ -2815,6 +2825,7 @@ void Item_func_json_search::fix_length_and_dec() if (arg_count > 4) mark_constant_paths(paths, args+4, arg_count-4); + maybe_null= 1; } @@ -2898,7 +2909,7 @@ String *Item_func_json_search::val_str(String *str) json_path_with_flags *c_path= paths + n_arg - 4; if (!c_path->parsed) { - String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-1)); + String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-4)); if (s_p && json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(), (const uchar *) s_p->ptr() + s_p->length())) @@ -2996,6 +3007,7 @@ void Item_func_json_format::fix_length_and_dec() { decimals= 0; max_length= args[0]->max_length; + maybe_null= 1; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8c2afe79d9b..b38bdcb7d4f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -40,6 +40,7 @@ #include "set_var.h" #include "sql_select.h" #include "sql_parse.h" // check_stack_overrun +#include "sql_cte.h" #include "sql_test.h" double get_post_group_estimate(JOIN* join, double join_op_rows); @@ -311,7 +312,8 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) else goto end; - if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN)) + if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + with_recursive_reference) { const_item_cache= 0; if (uncacheable & UNCACHEABLE_RAND) @@ -916,7 +918,7 @@ table_map Item_subselect::used_tables() const bool Item_subselect::const_item() const { DBUG_ASSERT(thd); - return (thd->lex->context_analysis_only ? + return (thd->lex->context_analysis_only || with_recursive_reference ? FALSE : forced_const || const_item_cache); } @@ -936,7 +938,8 @@ void Item_subselect::update_used_tables() if (!(engine->uncacheable() & ~UNCACHEABLE_EXPLAIN)) { // did all used tables become static? - if (!(used_tables_cache & ~engine->upper_select_const_tables())) + if (!(used_tables_cache & ~engine->upper_select_const_tables()) && + ! with_recursive_reference) const_item_cache= 1; } } @@ -1739,7 +1742,7 @@ bool Item_in_subselect::val_bool() if (forced_const) return value; DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || - ! engine->is_executed()); + ! engine->is_executed() || with_recursive_reference); null_value= was_null= FALSE; if (exec()) { @@ -2393,7 +2396,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, &list_ref)); Item *col_item= new (thd->mem_root) Item_cond_or(thd, item_eq, item_isnull); - if (!abort_on_null && left_expr->element_index(i)->maybe_null) + if (!abort_on_null && left_expr->element_index(i)->maybe_null && + get_cond_guard(i)) { disable_cond_guard_for_const_null_left_expr(i); if (!(col_item= new (thd->mem_root) @@ -2411,7 +2415,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, ref_pointer_array[i], (char *)"<no matter>", &list_ref)); - if (!abort_on_null && left_expr->element_index(i)->maybe_null) + if (!abort_on_null && left_expr->element_index(i)->maybe_null && + get_cond_guard(i) ) { disable_cond_guard_for_const_null_left_expr(i); if (!(item_nnull_test= @@ -2471,7 +2476,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, (char *)"<no matter>", &list_ref)); item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull); - if (left_expr->element_index(i)->maybe_null) + if (left_expr->element_index(i)->maybe_null && get_cond_guard(i)) { disable_cond_guard_for_const_null_left_expr(i); if (!(item= new (thd->mem_root) @@ -2483,7 +2488,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, } *having_item= and_items(thd, *having_item, having_col_item); } - if (!abort_on_null && left_expr->element_index(i)->maybe_null) + if (!abort_on_null && left_expr->element_index(i)->maybe_null && + get_cond_guard(i)) { if (!(item= new (thd->mem_root) Item_func_trig_cond(thd, item, get_cond_guard(i)))) @@ -2835,7 +2841,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg) join->having || first_select->with_sum_func || !first_select->leaf_tables.elements|| - !join->conds) + !join->conds || + with_recursive_reference) DBUG_RETURN(FALSE); DBUG_ASSERT(first_select->order_list.elements == 0 && @@ -3487,6 +3494,11 @@ int subselect_single_select_engine::get_identifier() return select_lex->select_number; } +void subselect_single_select_engine::force_reexecution() +{ + executed= false; +} + void subselect_single_select_engine::cleanup() { DBUG_ENTER("subselect_single_select_engine::cleanup"); @@ -3515,6 +3527,11 @@ bool subselect_union_engine::is_executed() const return unit->executed; } +void subselect_union_engine::force_reexecution() +{ + unit->executed= false; +} + /* Check if last execution of the subquery engine produced any rows @@ -3831,7 +3848,8 @@ int subselect_single_select_engine::exec() tab->read_record.read_record= tab->save_read_record; } executed= 1; - if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN)) + if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN) && + !item->with_recursive_reference) item->make_const(); thd->where= save_where; thd->lex->current_select= save_select; @@ -6678,6 +6696,13 @@ void subselect_table_scan_engine::cleanup() } +void Item_subselect::register_as_with_rec_ref(With_element *with_elem) +{ + with_elem->sq_with_rec_ref.link_in_list(this, &this->next_with_rec_ref); + with_recursive_reference= true; +} + + /* Create an execution tracker for the expression cache we're using for this subselect; add the tracker to the query plan. diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 22fc48391de..4c4af25edf5 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -32,6 +32,7 @@ class subselect_engine; class subselect_hash_sj_engine; class Item_bool_func2; class Comp_creator; +class With_element; typedef class st_select_lex SELECT_LEX; @@ -135,6 +136,9 @@ public: */ bool with_recursive_reference; + /* To link Item_subselects containing references to the same recursive CTE */ + Item_subselect *next_with_rec_ref; + enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS}; @@ -256,6 +260,7 @@ public: return TRUE; } + void register_as_with_rec_ref(With_element *with_elem); void init_expr_cache_tracker(THD *thd); Item* build_clone(THD *thd, MEM_ROOT *mem_root) { return 0; } @@ -831,6 +836,7 @@ public: virtual bool no_rows() = 0; virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; } virtual int get_identifier() { DBUG_ASSERT(0); return 0; } + virtual void force_reexecution() {} protected: void set_row(List<Item> &item_list, Item_cache **row); }; @@ -864,6 +870,7 @@ public: bool no_rows(); virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; } int get_identifier(); + void force_reexecution(); friend class subselect_hash_sj_engine; friend class Item_in_subselect; @@ -894,6 +901,7 @@ public: bool temp= FALSE); bool no_tables(); bool is_executed() const; + void force_reexecution(); bool no_rows(); virtual enum_engine_type engine_type() { return UNION_ENGINE; } }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 1dca656ee08..383972d1a54 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8403,6 +8403,11 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) Record any GTID in the same transaction, so slave state is transactionally consistent. */ +#ifdef WITH_WSREP + /*Set wsrep_affected_rows = 0 */ + thd->wsrep_affected_rows= 0; +#endif + if (rgi->gtid_pending) { sub_id= rgi->gtid_sub_id; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 915387d6ba9..065f4d83367 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -9445,14 +9445,6 @@ static int get_options(int *argc_ptr, char ***argv_ptr) between options, setting of multiple variables, etc. Do them here. */ - - if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes || - opt_log_slow_slave_statements) && - !global_system_variables.sql_log_slow) - sql_print_information("options --log-slow-admin-statements, " - "--log-queries-not-using-indexes and " - "--log-slow-slave-statements have no " - "effect if --log-slow-queries is not set"); if (global_system_variables.net_buffer_length > global_system_variables.max_allowed_packet) { diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index e7bf4658d5c..9bc21ab3ac3 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -461,7 +461,7 @@ int opt_sum_query(THD *thd, { if (recalc_const_item) item->update_used_tables(); - if (!item->const_item()) + if (!item->const_item() && item->type() != Item::WINDOW_FUNC_ITEM) const_result= 0; } } diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 6788f422cbd..aaa72da29db 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -1164,7 +1164,8 @@ handle_rpl_parallel_thread(void *arg) thd->wait_for_commit_ptr= &rgi->commit_orderer; - if (opt_gtid_ignore_duplicates) + if (opt_gtid_ignore_duplicates && + rgi->rli->mi->using_gtid != Master_info::USE_GTID_NO) { int res= rpl_global_gtid_slave_state->check_duplicate_gtid(&rgi->current_gtid, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b2e895b0775..97a6421ec5c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7453,6 +7453,8 @@ ER_JSON_PATH_EMPTY eng "Path expression '$' is not allowed in argument %d to function '%s'." ER_SLAVE_SAME_ID eng "A slave with the same server_uuid/server_id as this slave has connected to the master" +ER_FLASHBACK_NOT_SUPPORTED + eng "Flashback does not support %s %s" ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION eng "Illegal parameter data types %s and %s for operation '%s'" ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION diff --git a/sql/slave.cc b/sql/slave.cc index 3ebd1b2ec46..b28bc1d8dc5 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3977,7 +3977,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, DBUG_RETURN(1); } - if (opt_gtid_ignore_duplicates) + if (opt_gtid_ignore_duplicates && + rli->mi->using_gtid != Master_info::USE_GTID_NO) { int res= rpl_global_gtid_slave_state->check_duplicate_gtid (&serial_rgi->current_gtid, serial_rgi); diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 7c2a8cf9e65..c163044547f 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -141,7 +141,7 @@ bool With_clause::check_dependencies() /* Mark those elements where tables are defined with direct or indirect - make recursion. + recursion. */ for (With_element *with_elem= with_list.first; with_elem; @@ -342,6 +342,8 @@ void With_element::check_dependencies_in_select(st_select_lex *sl, tbl->with_internal_reference_map= get_elem_map(); if (in_subq) sq_dep_map|= tbl->with->get_elem_map(); + else + top_level_dep_map|= tbl->with->get_elem_map(); } } /* Now look for the dependencies in the subqueries of sl */ @@ -353,6 +355,53 @@ void With_element::check_dependencies_in_select(st_select_lex *sl, /** @brief + Find a recursive reference to this with element in subqueries of a select + + @param sel The select in whose subqueries the reference + to be looked for + + @details + The function looks for a recursive reference to this with element in + subqueries of select sl. When the first such reference is found + it is returned as the result. + The function assumes that the identification of all CTE references + has been performed earlier. + + @retval + Pointer to the found recursive reference if the search succeeded + NULL - otherwise +*/ + +TABLE_LIST *With_element::find_first_sq_rec_ref_in_select(st_select_lex *sel) +{ + TABLE_LIST *rec_ref= NULL; + st_select_lex_unit *inner_unit= sel->first_inner_unit(); + for (; inner_unit; inner_unit= inner_unit->next_unit()) + { + st_select_lex *sl= inner_unit->first_select(); + for (; sl; sl= sl->next_select()) + { + for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local) + { + if (tbl->derived || tbl->nested_join) + continue; + if (tbl->with && tbl->with->owner== this->owner && + (tbl->with_internal_reference_map & mutually_recursive)) + { + rec_ref= tbl; + return rec_ref; + } + } + if ((rec_ref= find_first_sq_rec_ref_in_select(sl))) + return rec_ref; + } + } + return 0; +} + + +/** + @brief Find the dependencies of this element on its siblings in a unit @param unit The unit where to look for the dependencies @@ -602,6 +651,10 @@ void With_clause::move_anchors_ahead() @details If the specification of this with element contains anchors the method moves them at the very beginning of the specification. + Additionally for the other selects of the specification if none of them + contains a recursive reference to this with element or a mutually recursive + one the method looks for the first such reference in the first recursive + select and set a pointer to it in this->sq_rec_ref. */ void With_element::move_anchors_ahead() @@ -618,6 +671,11 @@ void With_element::move_anchors_ahead() sl->move_node(new_pos); new_pos= sl->next_select(); } + else if (!sq_rec_ref && no_rec_ref_on_top_level()) + { + sq_rec_ref= find_first_sq_rec_ref_in_select(sl); + DBUG_ASSERT(sq_rec_ref != NULL); + } last_sl= sl; } if (spec->union_distinct) @@ -967,6 +1025,17 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) { + if (table) + { + /* + This table was prematurely identified as a temporary table. + We correct it here, but it's not a nice solution in the case + when the temporary table with this name is not used anywhere + else in the query. + */ + thd->mark_tmp_table_as_free_for_reuse(table); + table= 0; + } with= with_elem; if (!with_elem->is_referenced() || with_elem->is_recursive) derived= with_elem->spec; @@ -1228,6 +1297,7 @@ bool st_select_lex::check_subqueries_with_recursive_references() continue; Item_subselect *subq= (Item_subselect *) sl_master->item; subq->with_recursive_reference= true; + subq->register_as_with_rec_ref(tbl->with); } } return false; diff --git a/sql/sql_cte.h b/sql/sql_cte.h index a87c1b8acbd..85676df9d39 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -46,6 +46,16 @@ private: /* Dependency map of with elements mutually recursive with this with element */ table_map mutually_recursive; /* + Dependency map built only for the top level references i.e. for those that + are encountered in from lists of the selects of the specification unit + */ + table_map top_level_dep_map; + /* + Points to a recursive reference in subqueries. + Used only for specifications without recursive references on the top level. + */ + TABLE_LIST *sq_rec_ref; + /* The next with element from the circular chain of the with elements mutually recursive with this with element. (If This element is simply recursive than next_mutually_recursive contains @@ -119,11 +129,15 @@ public: */ select_union_recursive *rec_result; + /* List of Item_subselects containing recursive references to this CTE */ + SQL_I_List<Item_subselect> sq_with_rec_ref; + With_element(LEX_CSTRING *name, List <LEX_CSTRING> list, st_select_lex_unit *unit) : next(NULL), base_dep_map(0), derived_dep_map(0), sq_dep_map(0), work_dep_map(0), mutually_recursive(0), + top_level_dep_map(0), sq_rec_ref(NULL), next_mutually_recursive(NULL), references(0), query_name(name), column_list(list), spec(unit), is_recursive(false), with_anchor(false), @@ -151,6 +165,8 @@ public: bool check_dependency_on(With_element *with_elem) { return base_dep_map & with_elem->get_elem_map(); } + TABLE_LIST *find_first_sq_rec_ref_in_select(st_select_lex *sel); + bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end); st_select_lex_unit *clone_parsed_spec(THD *thd, TABLE_LIST *with_table); @@ -174,11 +190,16 @@ public: bool contains_sq_with_recursive_reference() { return sq_dep_map & mutually_recursive; } + bool no_rec_ref_on_top_level() + { return !(top_level_dep_map & mutually_recursive); } + table_map get_mutually_recursive() { return mutually_recursive; } With_element *get_next_mutually_recursive() { return next_mutually_recursive; } + TABLE_LIST *get_sq_rec_ref() { return sq_rec_ref; } + bool is_anchor(st_select_lex *sel); void move_anchors_ahead(); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 827fb21edf4..cd8540eb072 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -646,6 +646,23 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX *first_select= unit->first_select(); + if (derived->is_recursive_with_table() && + !derived->is_with_table_recursive_reference() && + !derived->with->rec_result && derived->with->get_sq_rec_ref()) + { + /* + This is a non-recursive reference to a recursive CTE whose + specification unit has not been prepared at the regular processing of + derived table references. This can happen only in the case when + the specification unit has no recursive references at the top level. + Force the preparation of the specification unit. Use a recursive + table reference from a subquery for this. + */ + DBUG_ASSERT(derived->with->get_sq_rec_ref()); + if (mysql_derived_prepare(lex->thd, lex, derived->with->get_sq_rec_ref())) + DBUG_RETURN(TRUE); + } + if (unit->prepared && derived->is_recursive_with_table() && !derived->table) { @@ -1148,6 +1165,9 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) st_select_lex_unit *unit= derived->get_unit(); st_select_lex *sl= unit->first_select(); + if (derived->prohibit_cond_pushdown) + DBUG_RETURN(false); + /* Do not push conditions into constant derived */ if (unit->executed) DBUG_RETURN(false); diff --git a/sql/sql_derived.h b/sql/sql_derived.h index c451e423032..f098cf39083 100644 --- a/sql/sql_derived.h +++ b/sql/sql_derived.h @@ -39,10 +39,6 @@ bool mysql_derived_cleanup(THD *thd, LEX *lex, TABLE_LIST *derived); Item *delete_not_needed_parts(THD *thd, Item *cond); -#if 0 -bool pushdown_cond_for_derived(THD *thd, Item **cond, TABLE_LIST *derived); -#else bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived); -#endif #endif /* SQL_DERIVED_INCLUDED */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index b430aea4c0b..1a5fac30536 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -431,7 +431,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else tot_length+= field->field_length; } - else if (item->type() == Item::STRING_ITEM) + else if (item->get_load_data_out_param()) use_vars= 1; } if (use_blobs && !ex->line_term->length() && !field_term->length()) @@ -814,11 +814,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, if (item->real_type() == Item::FIELD_ITEM) append_identifier(thd, &query_str, item->name.str, item->name.length); else - { - /* Actually Item_user_var_as_out_param despite claiming STRING_ITEM. */ - DBUG_ASSERT(item->type() == Item::STRING_ITEM); - ((Item_user_var_as_out_param *)item)->print_for_load(thd, &query_str); - } + item->get_load_data_out_param()->load_data_print(thd, &query_str); } query_str.append(")"); } @@ -1062,6 +1058,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, uint length; uchar *pos; Item *real_item; + Load_data_out_param *out_param; if (read_info.read_field()) break; @@ -1104,18 +1101,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, } /* Do not auto-update this field. */ field->set_has_explicit_value(); - } - else if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_null_value( - read_info.read_charset); } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_null_value(read_info.read_charset); else - { - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); DBUG_RETURN(1); - } - continue; } @@ -1129,16 +1119,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, field->store((char*) pos, length, read_info.read_charset); field->set_has_explicit_value(); } - else if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, - read_info.read_charset); - } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_value((const char *) pos, length, + read_info.read_charset); else - { - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); DBUG_RETURN(1); - } } if (thd->is_error()) @@ -1158,6 +1143,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { + Load_data_out_param *out_param; Item *real_item= item->real_item(); if (real_item->type() == Item::FIELD_ITEM) { @@ -1183,16 +1169,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), thd->get_stmt_da()->current_row_for_warning()); } - else if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_null_value( - read_info.read_charset); - } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_null_value(read_info.read_charset); else - { - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); DBUG_RETURN(1); - } } } @@ -1288,6 +1268,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, while ((item= it++)) { + Load_data_out_param *out_param; /* If this line is to be skipped we don't want to fill field or var */ if (skip_lines) continue; @@ -1319,14 +1300,15 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, /* Do not auto-update this field. */ field->set_has_explicit_value(); } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_null_value(cs); else - ((Item_user_var_as_out_param *) item)->set_null_value(cs); + DBUG_RETURN(1); continue; } if (item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; field->set_notnull(); if (field == table->next_number_field) @@ -1334,10 +1316,12 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, field->store((char *) tag->value.ptr(), tag->value.length(), cs); field->set_has_explicit_value(); } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_value((const char *) tag->value.ptr(), + tag->value.length(), cs); else - ((Item_user_var_as_out_param *) item)->set_value( - (char *) tag->value.ptr(), - tag->value.length(), cs); + DBUG_RETURN(1); + } if (read_info.error) @@ -1357,6 +1341,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, for ( ; item; item= it++) { + Load_data_out_param *out_param; if (item->type() == Item::FIELD_ITEM) { /* @@ -1371,8 +1356,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), thd->get_stmt_da()->current_row_for_warning()); } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_null_value(cs); else - ((Item_user_var_as_out_param *)item)->set_null_value(cs); + DBUG_RETURN(1); } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b3c427bf043..280849b8b33 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -868,7 +868,8 @@ JOIN::prepare(TABLE_LIST *tables_init, select_lex->check_unrestricted_recursive( thd->variables.only_standard_compliant_cte)) DBUG_RETURN(-1); - select_lex->check_subqueries_with_recursive_references(); + if (select_lex->first_execution) + select_lex->check_subqueries_with_recursive_references(); int res= check_and_do_in_subquery_rewrites(this); @@ -1091,7 +1092,7 @@ int JOIN::optimize() !skip_sort_order && !no_order && (order || group_list), select_distinct); uint select_nr= select_lex->select_number; - JOIN_TAB *curr_tab= join_tab + top_join_tab_count; + JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); for (uint i= 0; i < aggr_tables; i++, curr_tab++) { if (select_nr == INT_MAX) @@ -1445,7 +1446,8 @@ JOIN::optimize_inner() } DBUG_PRINT("info",("Select tables optimized away")); - zero_result_cause= "Select tables optimized away"; + if (!select_lex->have_window_funcs()) + zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved const_tables= top_join_tab_count= table_count; /* @@ -2238,13 +2240,14 @@ bool JOIN::make_aggr_tables_info() bool implicit_grouping_with_window_funcs= implicit_grouping && select_lex->have_window_funcs(); - + bool implicit_grouping_without_tables= implicit_grouping && + !tables_list; /* Setup last table to provide fields and all_fields lists to the next node in the plan. */ - if (join_tab && top_join_tab_count) + if (join_tab && top_join_tab_count && tables_list) { join_tab[top_join_tab_count - 1].fields= &fields_list; join_tab[top_join_tab_count - 1].all_fields= &all_fields; @@ -2290,7 +2293,7 @@ bool JOIN::make_aggr_tables_info() order= query.order_by; aggr_tables++; - curr_tab= join_tab + top_join_tab_count; + curr_tab= join_tab + exec_join_tab_cnt(); bzero(curr_tab, sizeof(JOIN_TAB)); curr_tab->ref.key= -1; curr_tab->join= this; @@ -2368,7 +2371,7 @@ bool JOIN::make_aggr_tables_info() single table queries, thus it is sufficient to test only the first join_tab element of the plan for its access method. */ - if (join_tab && top_join_tab_count && + if (join_tab && top_join_tab_count && tables_list && join_tab->is_using_loose_index_scan()) tmp_table_param.precomputed_group_by= !join_tab->is_using_agg_loose_index_scan(); @@ -2378,7 +2381,7 @@ bool JOIN::make_aggr_tables_info() if (need_tmp) { aggr_tables++; - curr_tab= join_tab + top_join_tab_count; + curr_tab= join_tab + exec_join_tab_cnt(); bzero(curr_tab, sizeof(JOIN_TAB)); curr_tab->ref.key= -1; if (only_const_tables()) @@ -2437,8 +2440,9 @@ bool JOIN::make_aggr_tables_info() /* Change sum_fields reference to calculated fields in tmp_table */ items1= ref_ptr_array_slice(2); - if (sort_and_group || curr_tab->table->group || - tmp_table_param.precomputed_group_by) + if ((sort_and_group || curr_tab->table->group || + tmp_table_param.precomputed_group_by) && + !implicit_grouping_without_tables) { if (change_to_use_tmp_fields(thd, items1, tmp_fields_list1, tmp_all_fields1, @@ -2778,7 +2782,7 @@ bool JOIN::make_aggr_tables_info() - duplicate value removal Both of these operations are done after window function computation step. */ - curr_tab= join_tab + top_join_tab_count + aggr_tables - 1; + curr_tab= join_tab + exec_join_tab_cnt() + aggr_tables - 1; if (select_lex->window_funcs.elements) { curr_tab->window_funcs_step= new Window_funcs_computation; @@ -2793,7 +2797,7 @@ bool JOIN::make_aggr_tables_info() // Reset before execution set_items_ref_array(items0); if (join_tab) - join_tab[top_join_tab_count + aggr_tables - 1].next_select= + join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select= setup_end_select_func(this, NULL); group= has_group_by; @@ -2834,7 +2838,7 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields, tmp_table_param.using_outer_summary_function= tab->tmp_table_param->using_outer_summary_function; tab->join= this; - DBUG_ASSERT(tab > join_tab || select_lex->have_window_funcs()); + DBUG_ASSERT(tab > tab->join->join_tab || !top_join_tab_count || !tables_list); if (tab > join_tab) (tab - 1)->next_select= sub_select_postjoin_aggr; tab->aggr= new (thd->mem_root) AGGR_OP(tab); @@ -2861,7 +2865,8 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields, if (make_sum_func_list(all_fields, fields_list, true)) goto err; if (prepare_sum_aggregators(sum_funcs, - !join_tab->is_using_agg_loose_index_scan())) + !(tables_list && + join_tab->is_using_agg_loose_index_scan()))) goto err; if (setup_sum_funcs(thd, sum_funcs)) goto err; @@ -3122,7 +3127,7 @@ JOIN::reinit() if (aggr_tables) { - JOIN_TAB *curr_tab= join_tab + top_join_tab_count; + JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); JOIN_TAB *end_tab= curr_tab + aggr_tables; for ( ; curr_tab < end_tab; curr_tab++) { @@ -3249,7 +3254,7 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite, Explain_union *eu= output->get_union(nr); explain= &eu->fake_select_lex_explain; join_tab[0].tracker= eu->get_fake_select_lex_tracker(); - for (uint i=0 ; i < top_join_tab_count + aggr_tables; i++) + for (uint i=0 ; i < exec_join_tab_cnt() + aggr_tables; i++) { if (join_tab[i].filesort) { @@ -3318,7 +3323,8 @@ void JOIN::exec_inner() if (result->prepare2()) DBUG_VOID_RETURN; - if (!tables_list && (table_count || !select_lex->with_sum_func)) + if (!tables_list && (table_count || !select_lex->with_sum_func) && + !select_lex->have_window_funcs()) { // Only test of functions if (select_options & SELECT_DESCRIBE) select_describe(this, FALSE, FALSE, FALSE, @@ -12010,7 +12016,7 @@ void JOIN::cleanup(bool full) w/o tables: they don't have some members initialized and WALK_OPTIMIZATION_TABS may not work correctly for them. */ - if (table_count) + if (top_join_tab_count && tables_list) { for (tab= first_breadth_first_tab(); tab; tab= next_breadth_first_tab(first_breadth_first_tab(), @@ -12024,7 +12030,7 @@ void JOIN::cleanup(bool full) cleaned= true; //psergey2: added (Q: why not in the above loop?) { - JOIN_TAB *curr_tab= join_tab + top_join_tab_count; + JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); for (uint i= 0; i < aggr_tables; i++, curr_tab++) { if (curr_tab->aggr) @@ -17785,7 +17791,7 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab) } } else if (join->sort_and_group && !tmp_tbl->precomputed_group_by && - !join->sort_and_group_aggr_tab) + !join->sort_and_group_aggr_tab && join->tables_list) { DBUG_PRINT("info",("Using end_write_group")); aggr->set_write_func(end_write_group); @@ -17877,7 +17883,8 @@ do_select(JOIN *join, Procedure *procedure) if (join->pushdown_query->store_data_in_temp_table) { - JOIN_TAB *last_tab= join->join_tab + join->table_count; + JOIN_TAB *last_tab= join->join_tab + join->table_count - + join->exec_join_tab_cnt(); last_tab->next_select= end_send; enum_nested_loop_state state= last_tab->aggr->end_send(); @@ -17948,7 +17955,8 @@ do_select(JOIN *join, Procedure *procedure) dbug_serve_apcs(join->thd, 1); ); - JOIN_TAB *join_tab= join->join_tab + join->const_tables; + JOIN_TAB *join_tab= join->join_tab + + (join->tables_list ? join->const_tables : 0); if (join->outer_ref_cond && !join->outer_ref_cond->val_int()) error= NESTED_LOOP_NO_MORE_ROWS; else @@ -23188,8 +23196,11 @@ change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, uint i, border= all_fields.elements - elements; for (i= 0; (item= it++); i++) { - res_all_fields.push_back(new_item= item->get_tmp_table_item(thd), - thd->mem_root); + if (item->type() == Item::SUM_FUNC_ITEM && item->const_item()) + new_item= item; + else + new_item= item->get_tmp_table_item(thd); + res_all_fields.push_back(new_item, thd->mem_root); ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]= new_item; } @@ -24444,7 +24455,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) { - JOIN_TAB *join_tab=join->join_tab + join->top_join_tab_count; + JOIN_TAB *join_tab=join->join_tab + join->exec_join_tab_cnt(); Explain_aggr_node *prev_node; Explain_aggr_node *node= xpl_sel->aggr_tree; bool is_analyze= join->thd->lex->analyze_stmt; @@ -24536,6 +24547,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, if (select_lex->master_unit()->derived) explain->connection_type= Explain_node::EXPLAIN_NODE_DERIVED; + save_agg_explain_data(this, explain); output->add_node(explain); } else if (pushdown_query) diff --git a/sql/sql_select.h b/sql/sql_select.h index 86b8a56fb43..96764fd7f00 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1492,6 +1492,8 @@ public: /* True if the plan guarantees that it will be returned zero or one row */ bool only_const_tables() { return const_tables == table_count; } + /* Number of tables actually joined at the top level */ + uint exec_join_tab_cnt() { return tables_list ? top_join_tab_count : 0; } int prepare(TABLE_LIST *tables, uint wind_num, COND *conds, uint og_num, ORDER *order, bool skip_order_by, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index ff455e680f7..bf25c0be74e 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -302,7 +302,8 @@ int select_union_recursive::send_data(List<Item> &values) { int rc= select_unit::send_data(values); - if (write_err != HA_ERR_FOUND_DUPP_KEY) + if (write_err != HA_ERR_FOUND_DUPP_KEY && + write_err != HA_ERR_FOUND_DUPP_UNIQUE) { int err; if ((err= incr_table->file->ha_write_tmp_row(table->record[0]))) @@ -1205,7 +1206,8 @@ bool st_select_lex_unit::exec() if (executed && !uncacheable && !describe) DBUG_RETURN(FALSE); executed= 1; - if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item) + if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item && + !item->with_recursive_reference) item->make_const(); saved_error= optimize(); @@ -1537,9 +1539,15 @@ bool st_select_lex_unit::exec_recursive() !is_unrestricted); if (!with_element->rec_result->first_rec_table_to_update) with_element->rec_result->first_rec_table_to_update= rec_table; - if (with_element->level == 1) + if (with_element->level == 1 && rec_table->reginfo.join_tab) rec_table->reginfo.join_tab->preread_init_done= true; } + for (Item_subselect *sq= with_element->sq_with_rec_ref.first; + sq; + sq= sq->next_with_rec_ref) + { + sq->engine->force_reexecution(); + } thd->lex->current_select= lex_select_save; err: diff --git a/sql/sql_window.cc b/sql/sql_window.cc index ac70d3d0f32..74e1ad25183 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -2761,7 +2761,7 @@ bool Window_func_runner::exec(THD *thd, TABLE *tbl, SORT_INFO *filesort_result) bool Window_funcs_sort::exec(JOIN *join) { THD *thd= join->thd; - JOIN_TAB *join_tab= &join->join_tab[join->top_join_tab_count]; + JOIN_TAB *join_tab= join->join_tab + join->exec_join_tab_cnt(); /* Sort the table based on the most specific sorting criteria of the window functions. */ @@ -2841,11 +2841,6 @@ bool Window_funcs_sort::setup(THD *thd, SQL_SELECT *sel, sort_order= order; } filesort= new (thd->mem_root) Filesort(sort_order, HA_POS_ERROR, true, NULL); - if (!join_tab->join->top_join_tab_count) - { - filesort->tracker= - new (thd->mem_root) Filesort_tracker(thd->lex->analyze_stmt); - } /* Apply the same condition that the subsequent sort has. */ filesort->select= sel; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b4583b1c187..e5fe26c6b94 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -456,11 +456,22 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "MariaDB Galera and flashback do not support binlog format: %s", binlog_format_names[var->save_result.ulonglong_value]); + /* + We allow setting up binlog_format other then ROW for session scope when + wsrep/flasback is enabled.This is done because of 2 reasons + 1. User might want to run pt-table-checksum. + 2. SuperUser knows what is doing :-) + For refrence:- MDEV-7322 + */ if (var->type == OPT_GLOBAL) { - WSREP_ERROR("MariaDB Galera and flashback do not support binlog format: %s", - binlog_format_names[var->save_result.ulonglong_value]); + if (WSREP(thd)) + WSREP_ERROR("MariaDB Galera does not support binlog format: %s", + binlog_format_names[var->save_result.ulonglong_value]); + else + my_error(ER_FLASHBACK_NOT_SUPPORTED,MYF(0),"binlog_format", + binlog_format_names[var->save_result.ulonglong_value]); return true; } } diff --git a/sql/table.cc b/sql/table.cc index eac12578b15..fa8ed3c2587 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1980,6 +1980,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, unireg_check == Field::TIMESTAMP_DN_FIELD) { reg_field->default_value= new (&share->mem_root) Virtual_column_info(); + reg_field->default_value->set_vcol_type(VCOL_DEFAULT); reg_field->default_value->stored_in_db= 1; share->default_expressions++; } @@ -2378,6 +2379,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (!(vcol_info= new (&share->mem_root) Virtual_column_info())) goto err; + /* The following can only be true for check_constraints */ if (field_nr != UINT_MAX16) @@ -2387,6 +2389,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE; + vcol_info->set_vcol_type((enum_vcol_info_type) type); if (name_length) { vcol_info->name.str= strmake_root(&share->mem_root, @@ -2739,7 +2742,7 @@ bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol) if (!(vcol->flags & (VCOL_TIME_FUNC|VCOL_SESSION_FUNC))) DBUG_RETURN(0); - vcol->expr->cleanup(); + vcol->expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0); DBUG_ASSERT(!vcol->expr->fixed); DBUG_RETURN(fix_vcol_expr(thd, vcol)); } @@ -2823,9 +2826,24 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, int error= func_expr->walk(&Item::check_vcol_func_processor, 0, &res); if (error || (res.errors & VCOL_IMPOSSIBLE)) - { // this can only happen if the frm was corrupted + { + // this can only happen if the frm was corrupted my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), res.name, - "???", "?????"); + vcol->get_vcol_type_name(), vcol->name.str); + DBUG_RETURN(1); + } + else if (res.errors & VCOL_AUTO_INC) + { + /* + An auto_increment field may not be used in an expression for + a check constraint, a default value or a generated column + + Note that this error condition is not detected during parsing + of the statement because the field item does not have a field + pointer at that time + */ + my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), + "AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name); DBUG_RETURN(1); } vcol->flags= res.errors; @@ -2896,6 +2914,7 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table, if (error) goto end; + vcol_storage.vcol_info->set_vcol_type(vcol->get_vcol_type()); vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db; vcol_storage.vcol_info->name= vcol->name; vcol_storage.vcol_info->utf8= vcol->utf8; diff --git a/sql/table.h b/sql/table.h index ebe5ced5bc1..a3690b0e8ca 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2157,6 +2157,8 @@ struct TABLE_LIST /* I_S: Flags to open_table (e.g. OPEN_TABLE_ONLY or OPEN_VIEW_ONLY) */ uint i_s_requested_object; + bool prohibit_cond_pushdown; + /* I_S: how to read the tables (SKIP_OPEN_TABLE/OPEN_FRM_ONLY/OPEN_FULL_TABLE) */ diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index 0ccd533eac1..1121bb65fe3 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -323,7 +323,7 @@ wsrep_run_wsrep_commit(THD *thd, bool all) DBUG_ENTER("wsrep_run_wsrep_commit"); if (thd->get_stmt_da()->is_error()) { - WSREP_ERROR("commit issue, error: %d %s", + WSREP_DEBUG("commit issue, error: %d %s", thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); } diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index c553b4ba27e..7eae366df7a 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -51,6 +51,7 @@ struct wsrep_thd_shadow { char *db; size_t db_length; my_hrtime_t user_time; + longlong row_count_func; }; // Global wsrep parameters diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index a2d3b4923ab..4acf8a3bf1e 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -167,6 +167,7 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) shadow->db = thd->db; shadow->db_length = thd->db_length; shadow->user_time = thd->user_time; + shadow->row_count_func= thd->get_row_count_func(); thd->reset_db(NULL, 0); } @@ -187,6 +188,7 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) thd->wsrep_rgi->cleanup_after_session(); delete thd->wsrep_rgi; thd->wsrep_rgi = NULL; + thd->set_row_count_func(shadow->row_count_func); } void wsrep_replay_transaction(THD *thd) @@ -201,12 +203,31 @@ void wsrep_replay_transaction(THD *thd) WSREP_ERROR("replay issue, thd has reported status already"); } + /* PS reprepare observer should have been removed already. open_table() will fail if we have dangling observer here. */ DBUG_ASSERT(thd->m_reprepare_observer == NULL); + struct da_shadow + { + enum Diagnostics_area::enum_diagnostics_status status; + ulonglong affected_rows; + ulonglong last_insert_id; + char message[MYSQL_ERRMSG_SIZE]; + }; + struct da_shadow da_status; + da_status.status= thd->get_stmt_da()->status(); + if (da_status.status == Diagnostics_area::DA_OK) + { + da_status.affected_rows= thd->get_stmt_da()->affected_rows(); + da_status.last_insert_id= thd->get_stmt_da()->last_insert_id(); + strmake(da_status.message, + thd->get_stmt_da()->message(), + sizeof(da_status.message)-1); + } + thd->get_stmt_da()->reset_diagnostics_area(); thd->wsrep_conflict_state= REPLAYING; @@ -274,7 +295,17 @@ void wsrep_replay_transaction(THD *thd) } else { - my_ok(thd); + if (da_status.status == Diagnostics_area::DA_OK) + { + my_ok(thd, + da_status.affected_rows, + da_status.last_insert_id, + da_status.message); + } + else + { + my_ok(thd); + } } break; case WSREP_TRX_FAIL: |