diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-04-21 11:45:00 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-04-21 11:45:00 +0300 |
commit | 4930f9c94bb610f4d76b73a8b6b351d9fa9c5d68 (patch) | |
tree | ed6b2754116233ca8a39515c7ba06e09b2a8cdc8 /sql | |
parent | 502b769561760f35d2b612ab984906c8a4bb9b51 (diff) | |
parent | d104fe6f734df2aebe24b3e5e3dbc189a5302920 (diff) | |
download | mariadb-git-4930f9c94bb610f4d76b73a8b6b351d9fa9c5d68.tar.gz |
Merge 10.5 into 10.6
Diffstat (limited to 'sql')
46 files changed, 544 insertions, 274 deletions
diff --git a/sql/compat56.h b/sql/compat56.h index 347d6145048..65cd36dacfd 100644 --- a/sql/compat56.h +++ b/sql/compat56.h @@ -30,8 +30,8 @@ #define MY_PACKED_TIME_GET_INT_PART(x) ((x) >> 24) #define MY_PACKED_TIME_GET_FRAC_PART(x) ((x) % (1LL << 24)) -#define MY_PACKED_TIME_MAKE(i, f) ((((longlong) (i)) << 24) + (f)) -#define MY_PACKED_TIME_MAKE_INT(i) ((((longlong) (i)) << 24)) +#define MY_PACKED_TIME_MAKE(i, f) ((((ulonglong) (i)) << 24) + (f)) +#define MY_PACKED_TIME_MAKE_INT(i) ((((ulonglong) (i)) << 24)) longlong TIME_to_longlong_datetime_packed(const MYSQL_TIME *); longlong TIME_to_longlong_time_packed(const MYSQL_TIME *); diff --git a/sql/events.cc b/sql/events.cc index 33ddcdac3cb..9f0aef885df 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -662,8 +662,16 @@ Events::drop_schema_events(THD *thd, const char *db) */ if (event_queue) event_queue->drop_schema_events(thd, &db_lex); - db_repository->drop_schema_events(thd, &db_lex); - + if (db_repository) + db_repository->drop_schema_events(thd, &db_lex); + else + { + if ((db_repository= new Event_db_repository)) + { + db_repository->drop_schema_events(thd, &db_lex); + delete db_repository; + } + } DBUG_VOID_RETURN; } diff --git a/sql/field.h b/sql/field.h index d808a9b0401..ba50e0da1d7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4997,7 +4997,13 @@ public: void move_field_offset(my_ptrdiff_t ptr_diff) override { Field::move_field_offset(ptr_diff); - bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); + + /* + clang does not like when things are added to a null pointer, even if + it is never referenced. + */ + if (bit_ptr) + bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); } void hash(ulong *nr, ulong *nr2) override; diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h index 77da791f0b9..e625b355d95 100644 --- a/sql/gcalc_tools.h +++ b/sql/gcalc_tools.h @@ -184,7 +184,11 @@ class Gcalc_result_receiver double first_x, first_y, prev_x, prev_y; double shape_area; public: - Gcalc_result_receiver() : collection_result(FALSE), n_shapes(0), n_holes(0) +Gcalc_result_receiver() : + n_points(0), + common_shapetype(Gcalc_function::shape_point), + collection_result(FALSE), n_shapes(0), n_holes(0), + cur_shape(Gcalc_function::shape_point), shape_pos(0) {} int start_shape(Gcalc_function::shape_type shape); int add_point(double x, double y); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 5acdbe5b7e2..8eddec5511f 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6574,6 +6574,7 @@ int ha_partition::multi_range_read_init(RANGE_SEQ_IF *seq, DBUG_ENTER("ha_partition::multi_range_read_init"); DBUG_PRINT("enter", ("partition this: %p", this)); + eq_range= 0; m_seq_if= seq; m_seq= seq->init(seq_init_param, n_ranges, mrr_mode); if (unlikely((error= multi_range_key_create_key(seq, m_seq)))) diff --git a/sql/item.cc b/sql/item.cc index 152f36bb9e8..5cdbf52e829 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2653,9 +2653,7 @@ Item_sp::Item_sp(THD *thd, Name_resolution_context *context_arg, dummy_table= (TABLE*) thd->calloc(sizeof(TABLE) + sizeof(TABLE_SHARE) + sizeof(Query_arena)); dummy_table->s= (TABLE_SHARE*) (dummy_table + 1); - /* TODO(cvicentiu) Move this sp_query_arena in the class as a direct member. - Currently it can not be done due to header include dependencies. */ - sp_query_arena= (Query_arena *) (dummy_table->s + 1); + sp_query_arena= new(dummy_table->s + 1) Query_arena(); memset(&sp_mem_root, 0, sizeof(sp_mem_root)); } @@ -2666,7 +2664,7 @@ Item_sp::Item_sp(THD *thd, Item_sp *item): dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE) + sizeof(Query_arena)); dummy_table->s= (TABLE_SHARE*) (dummy_table+1); - sp_query_arena= (Query_arena *) (dummy_table->s + 1); + sp_query_arena= new(dummy_table->s + 1) Query_arena(); memset(&sp_mem_root, 0, sizeof(sp_mem_root)); } @@ -6285,12 +6283,14 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg) item_equal->compare_type_handler()->cmp_type()); return const_item2; } - Item_field *subst= - (Item_field *)(item_equal->get_first(param->context_tab, this)); + Item_ident *subst= + (Item_ident *) (item_equal->get_first(param->context_tab, this)); if (subst) - subst= (Item_field *) (subst->real_item()); - if (subst && !field->eq(subst->field)) - return subst; + { + Item_field *subst2= (Item_field *) (subst->real_item()); + if (subst2 && !field->eq(subst2->field)) + return subst2; + } } return this; } diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 9c96fdb1a9a..05cef6871be 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -47,9 +47,9 @@ Cached_item *new_Cached_item(THD *thd, Item *item, bool pass_through_ref) } switch (item->result_type()) { case STRING_RESULT: - return new Cached_item_str(thd, (Item_field *) item); + return new Cached_item_str(thd, item); case INT_RESULT: - return new Cached_item_int((Item_field *) item); + return new Cached_item_int(item); case REAL_RESULT: return new Cached_item_real(item); case DECIMAL_RESULT: diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 4a134e99bfc..97c41373d12 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5800,13 +5800,17 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (!res2) return FALSE; // Null argument - const size_t len = res2->length(); - const char* first = res2->ptr(); - const char* last = first + len - 1; + const size_t len= res2->length(); + /* len must be > 2 ('%pattern%') heuristic: only do TurboBM for pattern_len > 2 */ + if (len <= 2) + return FALSE; + + const char* first= res2->ptr(); + const char* last= first + len - 1; if (len > MIN_TURBOBM_PATTERN_LEN + 2 && *first == wild_many && diff --git a/sql/item_func.cc b/sql/item_func.cc index a0ef4020aae..f308435eea7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1104,17 +1104,20 @@ double Item_func_plus::real_op() return check_float_overflow(value); } +#if defined(__powerpc64__) && GCC_VERSION >= 6003 && GCC_VERSION <= 10002 +#pragma GCC push_options +#pragma GCC optimize ("no-expensive-optimizations") +#endif longlong Item_func_plus::int_op() { longlong val0= args[0]->val_int(); longlong val1= args[1]->val_int(); - longlong res= val0 + val1; bool res_unsigned= FALSE; + longlong res; if ((null_value= args[0]->null_value || args[1]->null_value)) return 0; - /* First check whether the result can be represented as a (bool unsigned_flag, longlong value) pair, then check if it is compatible @@ -1155,16 +1158,29 @@ longlong Item_func_plus::int_op() { if (val0 >=0 && val1 >= 0) res_unsigned= TRUE; - else if (val0 < 0 && val1 < 0 && res >= 0) + else if (val0 < 0 && val1 < 0 && val0 < (LONGLONG_MIN - val1)) goto err; } } + +#ifndef WITH_UBSAN + res= val0 + val1; +#else + if (res_unsigned) + res= (longlong) ((ulonglong) val0 + (ulonglong) val1); + else + res= val0+val1; +#endif /* WITH_UBSAN */ + return check_integer_overflow(res, res_unsigned); err: return raise_integer_overflow(); } +#if defined(__powerpc64__) && GCC_VERSION >= 6003 && GCC_VERSION <= 10002 +#pragma GCC pop_options +#endif /** Calculate plus of two decimals. @@ -1259,12 +1275,17 @@ double Item_func_minus::real_op() } +#if defined(__powerpc64__) && GCC_VERSION >= 6003 && GCC_VERSION <= 10002 +#pragma GCC push_options +#pragma GCC optimize ("no-expensive-optimizations") +#endif + longlong Item_func_minus::int_op() { longlong val0= args[0]->val_int(); longlong val1= args[1]->val_int(); - longlong res= val0 - val1; bool res_unsigned= FALSE; + longlong res; if ((null_value= args[0]->null_value || args[1]->null_value)) return 0; @@ -1279,12 +1300,8 @@ longlong Item_func_minus::int_op() if (args[1]->unsigned_flag) { if ((ulonglong) val0 < (ulonglong) val1) - { - if (res >= 0) - goto err; - } - else - res_unsigned= TRUE; + goto err; + res_unsigned= TRUE; } else { @@ -1305,23 +1322,35 @@ longlong Item_func_minus::int_op() { if (args[1]->unsigned_flag) { - if ((ulonglong) (val0 - LONGLONG_MIN) < (ulonglong) val1) + if (((ulonglong) val0 - (ulonglong) LONGLONG_MIN) < (ulonglong) val1) goto err; } else { if (val0 > 0 && val1 < 0) res_unsigned= TRUE; - else if (val0 < 0 && val1 > 0 && res >= 0) + else if (val0 < 0 && val1 > 0 && val0 < (LONGLONG_MIN + val1)) goto err; } } +#ifndef WITH_UBSAN + res= val0 - val1; +#else + if (res_unsigned) + res= (longlong) ((ulonglong) val0 - (ulonglong) val1); + else + res= val0 - val1; +#endif /* WITH_UBSAN */ + return check_integer_overflow(res, res_unsigned); err: return raise_integer_overflow(); } +#if defined(__powerpc64__) && GCC_VERSION >= 6003 && GCC_VERSION <= 10002 +#pragma GCC pop_options +#endif /** See Item_func_plus::decimal_op for comments. @@ -3114,10 +3143,11 @@ longlong Item_func_locate::val_int() if (arg_count == 3) { - start0= start= args[2]->val_int() - 1; + start0= start= args[2]->val_int(); - if ((start < 0) || (start > a->length())) + if ((start <= 0) || (start > a->length())) return 0; + start0--; start--; /* start is now sufficiently valid to pass to charpos function */ start= a->charpos((int) start); @@ -3281,7 +3311,7 @@ bool Item_func_find_in_set::fix_length_and_dec() find->length(), 0); enum_bit=0; if (enum_value) - enum_bit=1LL << (enum_value-1); + enum_bit= 1ULL << (enum_value-1); } } } diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index af14734eae3..e7f2b3d8eee 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -624,8 +624,6 @@ String *Item_func_json_unquote::read_json(json_engine_t *je) json_scan_start(je, js->charset(),(const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); - je->value_type= (enum json_value_types) -1; /* To report errors right. */ - if (json_read_value(je)) goto error; @@ -988,7 +986,8 @@ my_decimal *Item_func_json_extract::val_decimal(my_decimal *to) case JSON_VALUE_ARRAY: case JSON_VALUE_FALSE: case JSON_VALUE_NULL: - break; + case JSON_VALUE_UNINITALIZED: + break; }; } int2my_decimal(E_DEC_FATAL_ERROR, 0, false/*unsigned_flag*/, to); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5a6cb1a4c8f..3123844865f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1496,17 +1496,18 @@ String *Item_func_insert::val_str(String *str) null_value=0; res=args[0]->val_str(str); res2=args[3]->val_str(&tmp_value); - start= args[1]->val_int() - 1; + start= args[1]->val_int(); length= args[2]->val_int(); if (args[0]->null_value || args[1]->null_value || args[2]->null_value || args[3]->null_value) goto null; /* purecov: inspected */ - if ((start < 0) || (start > res->length())) + if ((start <= 0) || (start > res->length())) return res; // Wrong param; skip insert if ((length < 0) || (length > res->length())) length= res->length(); + start--; /* There is one exception not handled (intentionaly) by the character set @@ -3775,13 +3776,12 @@ String *Item_func_unhex::val_str(String *str) } for (end=res->ptr()+res->length(); from < end ; from+=2, to++) { - int hex_char; - *to= (hex_char= hexchar_to_int(from[0])) << 4; - if ((null_value= (hex_char == -1))) - return 0; - *to|= hex_char= hexchar_to_int(from[1]); - if ((null_value= (hex_char == -1))) + int hex_char1, hex_char2; + hex_char1= hexchar_to_int(from[0]); + hex_char2= hexchar_to_int(from[1]); + if ((null_value= (hex_char1 == -1 || hex_char2 == -1))) return 0; + *to= (char) ((hex_char1 << 4) | hex_char2); } return str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 1ae62a4a6e8..36300e57f03 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -42,8 +42,13 @@ protected: we don't want to free and potentially have to reallocate the buffer for each call. */ - str_value.length(0); - str_value.set_charset(collation.collation); + if (!str_value.is_alloced()) + str_value.set("", 0, collation.collation); /* Avoid null ptrs */ + else + { + str_value.length(0); /* Reuse allocated area */ + str_value.set_charset(collation.collation); + } return &str_value; } public: diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e4e8bf2a1e8..c9afc9c1bcd 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2016, Oracle and/or its affiliates. - Copyright (c) 2010, 2016, MariaDB + Copyright (c) 2010, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -685,6 +685,31 @@ bool Item_subselect::is_expensive() } +static +int walk_items_for_table_list(Item_processor processor, + bool walk_subquery, void *argument, + List<TABLE_LIST>& join_list) +{ + List_iterator<TABLE_LIST> li(join_list); + int res; + while (TABLE_LIST *table= li++) + { + if (table->on_expr) + { + if ((res= table->on_expr->walk(processor, walk_subquery, argument))) + return res; + } + if (table->nested_join) + { + if ((res= walk_items_for_table_list(processor, walk_subquery, argument, + table->nested_join->join_list))) + return res; + } + } + return 0; +} + + bool Item_subselect::unknown_splocal_processor(void *argument) { SELECT_LEX *sl= unit->first_select(); @@ -770,7 +795,6 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, for (SELECT_LEX *lex= unit->first_select(); lex; lex= lex->next_select()) { List_iterator<Item> li(lex->item_list); - Item *item; ORDER *order; if (lex->where && (lex->where)->walk(processor, walk_subquery, argument)) @@ -778,14 +802,16 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, if (lex->having && (lex->having)->walk(processor, walk_subquery, argument)) return 1; - /* TODO: why does this walk WHERE/HAVING but not ON expressions of outer joins? */ - /* Consider walking ON epxression in walk_table_functions_for_list */ + + if (walk_items_for_table_list(processor, walk_subquery, argument, + *lex->join_list)) + return 1; if (walk_table_functions_for_list(processor, walk_subquery, argument, *lex->join_list)) return 1; - while ((item=li++)) + while (Item *item= li++) { if (item->walk(processor, walk_subquery, argument)) return 1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 7106f72e237..537eaaf8dcd 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2639,9 +2639,9 @@ bool Item_sum_bit::add_as_window(ulonglong value) void Item_sum_or::set_bits_from_counters() { ulonglong value= 0; - for (int i= 0; i < NUM_BIT_COUNTERS; i++) + for (uint i= 0; i < NUM_BIT_COUNTERS; i++) { - value|= bit_counters[i] > 0 ? (1 << i) : 0; + value|= bit_counters[i] > 0 ? (1ULL << i) : 0ULL; } bits= value | reset_bits; } @@ -3887,7 +3887,7 @@ Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, arg_count_field(select_list->elements), row_count(0), distinct(distinct_arg), - warning_for_row(FALSE), + warning_for_row(FALSE), always_null(FALSE), force_copy_fields(0), row_limit(NULL), offset_limit(NULL), limit_clause(limit_clause), copy_offset_limit(0), copy_row_limit(0), original(0) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b8650a5c7e9..3707811f3f6 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -729,7 +729,10 @@ static bool make_date_time(const String *format, const MYSQL_TIME *l_time, For example, '1.1' -> '1.100000' */ -static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, size_t count, ulonglong *values, +#define MAX_DIGITS_IN_TIME_SPEC 20 + +static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, + size_t count, ulonglong *values, bool transform_msec) { const char *end=str+length; @@ -741,11 +744,21 @@ static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, s for (i=0 ; i < count ; i++) { - longlong value; + ulonglong value; const char *start= str; - for (value= 0; str != end && my_isdigit(cs, *str); str++) + const char *local_end= end; + + /* + We limit things to 19 digits to not get an overflow. This is ok as + this function is meant to read up to microseconds + */ + if ((local_end-str) > MAX_DIGITS_IN_TIME_SPEC) + local_end= str+ MAX_DIGITS_IN_TIME_SPEC; + + for (value= 0; str != local_end && my_isdigit(cs, *str) ; str++) value= value*10 + *str - '0'; - if ((field_length= (size_t)(str - start)) >= 20) + + if ((field_length= (size_t)(str - start)) >= MAX_DIGITS_IN_TIME_SPEC) return true; values[i]= value; while (str != end && !my_isdigit(cs,*str)) @@ -2070,9 +2083,9 @@ bool Func_handler_date_add_interval_datetime_arg0_time:: bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const { - Item_date_add_interval *other= (Item_date_add_interval*) item; if (!Item_func::eq(item, binary_cmp)) return 0; + Item_date_add_interval *other= (Item_date_add_interval*) item; return ((int_type == other->int_type) && (date_sub_interval == other->date_sub_interval)); } diff --git a/sql/log.cc b/sql/log.cc index a31b8dd5598..be94a7f7523 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -10217,28 +10217,13 @@ int TC_LOG_BINLOG::unlog_xa_prepare(THD *thd, bool all) uint rw_count= ha_count_rw_all(thd, &ha_info); bool rc= false; -#ifndef DBUG_OFF - if (rw_count > 1) - { - /* - There must be no binlog_hton used in a transaction consisting of more - than 1 engine, *when* (at this point) this transaction has not been - binlogged. The one exception is if there is an engine without a - prepare method, as in this case the engine doesn't support XA and - we have to ignore this check. - */ - bool binlog= false, exist_hton_without_prepare= false; - for (ha_info= thd->transaction->all.ha_list; ha_info; - ha_info= ha_info->next()) - { - if (ha_info->ht() == binlog_hton) - binlog= true; - if (!ha_info->ht()->prepare) - exist_hton_without_prepare= true; - } - DBUG_ASSERT(!binlog || exist_hton_without_prepare); - } -#endif + /* + This transaction has not been binlogged as indicated by need_unlog. + Such exceptional cases include transactions with no effect to engines, + e.g REPLACE that does not change the dat but still the Engine + transaction branch claims to be rw, and few more. + In all such cases an empty XA-prepare group of events is bin-logged. + */ if (rw_count > 0) { /* an empty XA-prepare event group is logged */ diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index c9cff6ad930..877a49edbec 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -26,7 +26,7 @@ Used instead of FILE when reading or writing whole files. This will make mf_rec_cache obsolete. One can change info->pos_in_file to a higher value to skip bytes in file if - also info->rc_pos is set to info->rc_end. + also info->read_pos is set to info->read_end. If called through open_cached_file(), then the temporary file will only be created if a write exeeds the file buffer or if one calls flush_io_cache(). diff --git a/sql/opt_split.cc b/sql/opt_split.cc index c81e1ab9e3a..c5bd8076209 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -205,7 +205,7 @@ struct SplM_field_info struct SplM_plan_info { /* The cached splitting execution plan P */ - struct st_position *best_positions; + POSITION *best_positions; /* The cost of the above plan */ double cost; /* Selectivity of splitting used in P */ diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 50be5817df2..582b1b8e8ef 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -3010,7 +3010,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, } -void Sj_materialization_picker::set_from_prev(struct st_position *prev) +void Sj_materialization_picker::set_from_prev(POSITION *prev) { if (prev->sjmat_picker.is_used) set_empty(); @@ -3196,7 +3196,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join, } -void LooseScan_picker::set_from_prev(struct st_position *prev) +void LooseScan_picker::set_from_prev(POSITION *prev) { if (prev->loosescan_picker.is_used) set_empty(); @@ -3217,7 +3217,7 @@ bool LooseScan_picker::check_qep(JOIN *join, double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, - struct st_position *loose_scan_pos) + POSITION *loose_scan_pos) { POSITION *first= join->positions + first_loosescan_table; /* @@ -3295,7 +3295,7 @@ bool LooseScan_picker::check_qep(JOIN *join, return FALSE; } -void Firstmatch_picker::set_from_prev(struct st_position *prev) +void Firstmatch_picker::set_from_prev(POSITION *prev) { if (prev->firstmatch_picker.is_used) invalidate_firstmatch_prefix(); @@ -5831,8 +5831,8 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, ((Item_func *) item)->functype() == Item_func::EQ_FUNC && check_simple_equality(thd, Item::Context(Item::ANY_SUBST, - ((Item_func_equal *)item)->compare_type_handler(), - ((Item_func_equal *)item)->compare_collation()), + ((Item_func_eq *)item)->compare_type_handler(), + ((Item_func_eq *)item)->compare_collation()), ((Item_func *)item)->arguments()[0], ((Item_func *)item)->arguments()[1], &new_cond_equal)) diff --git a/sql/partition_element.h b/sql/partition_element.h index ff0d0d59fc4..e0a519065cc 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -144,6 +144,7 @@ public: part_min_rows(part_elem->part_min_rows), range_value(0), partition_name(NULL), tablespace_name(part_elem->tablespace_name), + log_entry(NULL), part_comment(part_elem->part_comment), data_file_name(part_elem->data_file_name), index_file_name(part_elem->index_file_name), @@ -152,6 +153,8 @@ public: part_state(part_elem->part_state), nodegroup_id(part_elem->nodegroup_id), has_null_value(FALSE), + signed_flag(part_elem->signed_flag), + max_value(part_elem->max_value), id(part_elem->id), empty(part_elem->empty), type(CONVENTIONAL) diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index d0a96a85a60..91b1a48cad7 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -119,15 +119,23 @@ extern "C" my_bool wsrep_get_debug() return wsrep_debug; } +/* + Test if this connection is a true local (user) connection and not + a replication or wsrep applier thread. + + Note that this is only usable for galera (as there are other kinds + of system threads, and only if WSREP_NNULL() is tested by the caller. + */ extern "C" my_bool wsrep_thd_is_local(const THD *thd) { /* - async replication IO and background threads have nothing to replicate in the cluster, - marking them as non-local here to prevent write set population and replication + async replication IO and background threads have nothing to + replicate in the cluster, marking them as non-local here to + prevent write set population and replication - async replication SQL thread, applies client transactions from mariadb master - and will be replicated into cluster - */ + async replication SQL thread, applies client transactions from + mariadb master and will be replicated into cluster + */ return ( thd->system_thread != SYSTEM_THREAD_SLAVE_BACKGROUND && thd->system_thread != SYSTEM_THREAD_SLAVE_IO && diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 2d3eaa609aa..6aac9ac5962 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -32,7 +32,7 @@ #endif -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__FreeBSD__) #include <sys/sysctl.h> #endif @@ -54,7 +54,7 @@ extern const char *optimizer_switch_names[]; static inline void output_core_info() { /* proc is optional on some BSDs so it can't hurt to look */ -#if defined(HAVE_READLINK) && !defined(__APPLE__) +#if defined(HAVE_READLINK) && !defined(__APPLE__) && !defined(__FreeBSD__) char buff[PATH_MAX]; ssize_t len; int fd; @@ -85,7 +85,7 @@ static inline void output_core_info() my_close(fd, MYF(0)); } #endif -#elif defined(__APPLE__) +#elif defined(__APPLE__) || defined(__FreeBSD__) char buff[PATH_MAX]; size_t len = sizeof(buff); if (sysctlbyname("kern.corefile", buff, &len, NULL, 0) == 0) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c127bad8ef1..6e202185d06 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -5486,7 +5486,7 @@ routine_hash_search(const char *host, const char *ip, const char *db, const char *user, const char *tname, const Sp_handler *sph, bool exact) { - return (GRANT_TABLE*) + return (GRANT_NAME*) name_hash_search(sph->get_priv_hash(), host, ip, db, user, tname, exact, TRUE); } @@ -5500,6 +5500,10 @@ table_hash_search(const char *host, const char *ip, const char *db, user, tname, exact, FALSE); } +static bool column_priv_insert(GRANT_TABLE *grant) +{ + return my_hash_insert(&column_priv_hash,(uchar*) grant); +} static GRANT_COLUMN * column_hash_search(GRANT_TABLE *t, const char *cname, size_t length) @@ -5729,6 +5733,15 @@ static inline void get_grantor(THD *thd, char *grantor) strxmov(grantor, user, "@", host, NullS); } + +/** + Revoke rights from a grant table entry. + + @return 0 ok + @return 1 fatal error (error given) + @return -1 grant table was revoked +*/ + static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, TABLE *table, const LEX_USER &combo, const char *db, const char *table_name, @@ -5753,7 +5766,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, { my_message(ER_PASSWORD_NO_MATCH, ER_THD(thd, ER_PASSWORD_NO_MATCH), MYF(0)); /* purecov: deadcode */ - DBUG_RETURN(-1); /* purecov: deadcode */ + DBUG_RETURN(1); /* purecov: deadcode */ } } @@ -5784,7 +5797,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0), combo.user.str, combo.host.str, table_name); /* purecov: deadcode */ - DBUG_RETURN(-1); /* purecov: deadcode */ + DBUG_RETURN(1); /* purecov: deadcode */ } old_row_exists = 0; restore_record(table,record[1]); // Get saved record @@ -5846,13 +5859,14 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, else { my_hash_delete(&column_priv_hash,(uchar*) grant_table); + DBUG_RETURN(-1); // Entry revoked } DBUG_RETURN(0); /* This should never happen */ table_error: table->file->print_error(error,MYF(0)); /* purecov: deadcode */ - DBUG_RETURN(-1); /* purecov: deadcode */ + DBUG_RETURN(1); /* purecov: deadcode */ } @@ -6613,7 +6627,7 @@ static int update_role_table_columns(GRANT_TABLE *merged, privs, cols); merged->init_privs= merged->init_cols= NO_ACL; update_role_columns(merged, first, last); - my_hash_insert(&column_priv_hash,(uchar*) merged); + column_priv_insert(merged); return 2; } else if ((privs | cols) == NO_ACL) @@ -7078,12 +7092,12 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, result= TRUE; continue; } - grant_table = new GRANT_TABLE (Str->host.str, db_name, - Str->user.str, table_name, - rights, - column_priv); + grant_table= new (&grant_memroot) GRANT_TABLE(Str->host.str, db_name, + Str->user.str, table_name, + rights, + column_priv); if (!grant_table || - my_hash_insert(&column_priv_hash,(uchar*) grant_table)) + column_priv_insert(grant_table)) { result= TRUE; /* purecov: deadcode */ continue; /* purecov: deadcode */ @@ -7126,22 +7140,24 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* TODO(cvicentiu) refactor replace_table_table to use Tables_priv_table instead of TABLE directly. */ - if (replace_table_table(thd, grant_table, tables.tables_priv_table().table(), - *Str, db_name, table_name, - rights, column_priv, revoke_grant)) - { - /* Should only happen if table is crashed */ - result= TRUE; /* purecov: deadcode */ - } - else if (tables.columns_priv_table().table_exists()) + if (tables.columns_priv_table().table_exists()) { /* TODO(cvicentiu) refactor replace_column_table to use Columns_priv_table instead of TABLE directly. */ if (replace_column_table(grant_table, tables.columns_priv_table().table(), *Str, columns, db_name, table_name, rights, revoke_grant)) - { result= TRUE; + } + if (int res= replace_table_table(thd, grant_table, + tables.tables_priv_table().table(), + *Str, db_name, table_name, + rights, column_priv, revoke_grant)) + { + if (res > 0) + { + /* Should only happen if table is crashed */ + result= TRUE; /* purecov: deadcode */ } } if (Str->is_role()) @@ -7153,9 +7169,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, mysql_mutex_unlock(&acl_cache->lock); if (!result) /* success */ - { result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - } mysql_rwlock_unlock(&LOCK_grant); @@ -7847,7 +7861,7 @@ static bool grant_load(THD *thd, if (! mem_check->ok()) delete mem_check; - else if (my_hash_insert(&column_priv_hash,(uchar*) mem_check)) + else if (column_priv_insert(mem_check)) { delete mem_check; goto end_unlock; @@ -11339,46 +11353,44 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) { for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; ) { - const char *user,*host; + const char *user,*host; GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash, counter); user= grant_table->user; host= safe_str(grant_table->host.hostname); - if (!strcmp(lex_user->user.str,user) && + if (!strcmp(lex_user->user.str,user) && !strcmp(lex_user->host.str, host)) - { - /* TODO(cvicentiu) refactor replace_db_table to use - Db_table instead of TABLE directly. */ - if (replace_table_table(thd, grant_table, - tables.tables_priv_table().table(), - *lex_user, grant_table->db, - grant_table->tname, ALL_KNOWN_ACL, NO_ACL, 1)) - { - result= -1; - } - else - { - if (!grant_table->cols) - { - revoked= 1; - continue; - } - List<LEX_COLUMN> columns; - /* TODO(cvicentiu) refactor replace_db_table to use - Db_table instead of TABLE directly. */ - if (!replace_column_table(grant_table, - tables.columns_priv_table().table(), - *lex_user, columns, grant_table->db, - grant_table->tname, ALL_KNOWN_ACL, 1)) - { - revoked= 1; - continue; - } - result= -1; - } - } - counter++; + { + List<LEX_COLUMN> columns; + /* TODO(cvicentiu) refactor to use + Db_table instead of TABLE directly. */ + if (replace_column_table(grant_table, + tables.columns_priv_table().table(), + *lex_user, columns, + grant_table->db, grant_table->tname, + ALL_KNOWN_ACL, 1)) + result= -1; + if (int res= replace_table_table(thd, grant_table, + tables.tables_priv_table().table(), + *lex_user, + grant_table->db, grant_table->tname, + ALL_KNOWN_ACL, NO_ACL, 1)) + { + if (res > 0) + result= -1; + else + { + /* + Entry was deleted. We have to retry the loop as the + hash table has probably been reorganized. + */ + revoked= 1; + continue; + } + } + } + counter++; } } while (revoked); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6f6f9da7486..894f457a83c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7875,11 +7875,15 @@ bool setup_tables(THD *thd, Name_resolution_context *context, DBUG_RETURN(1); } tablenr++; - } - if (tablenr > MAX_TABLES) - { - my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES)); - DBUG_RETURN(1); + /* + We test the max tables here as we setup_table_map() should not be called + with tablenr >= 64 + */ + if (tablenr > MAX_TABLES) + { + my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES)); + DBUG_RETURN(1); + } } } else diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c7ad6ff90ad..9c1d1560955 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -822,7 +822,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) net.reading_or_writing= 0; client_capabilities= 0; // minimalistic client system_thread= NON_SYSTEM_THREAD; - cleanup_done= free_connection_done= abort_on_warning= 0; + cleanup_done= free_connection_done= abort_on_warning= got_warning= 0; peer_port= 0; // For SHOW PROCESSLIST transaction= &default_transaction; transaction->m_pending_rows_event= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 9dddc2fc7a9..c9967b98994 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6632,11 +6632,13 @@ public: - The sj-materialization temporary table - Members needed to make index lookup or a full scan of the temptable. */ +class POSITION; + class SJ_MATERIALIZATION_INFO : public Sql_alloc { public: /* Optimal join sub-order */ - struct st_position *positions; + POSITION *positions; uint tables; /* Number of tables in the sj-nest */ diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 29741cb1adb..ecd5e7c21fe 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. - Copyright (c) 2010, 2020, MariaDB + Copyright (c) 2010, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -596,14 +596,20 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived) } -/* +/** @brief - Reset the Name_resolution_context::outer_context for all ON expression - contexts in the given nested join. Do this recursively for all nested joins - it contains. + Prevent name resolution out of context of ON expressions in derived tables + + @param + join_list list of tables used in from list of a derived + + @details + The function sets the Name_resolution_context::outer_context to NULL + for all ON expressions contexts in the given join list. It does this + recursively for all nested joins the list contains. */ -static void reset_on_clauses_context(List<TABLE_LIST>& join_list) +static void nullify_outer_context_for_on_clauses(List<TABLE_LIST>& join_list) { List_iterator<TABLE_LIST> li(join_list); while (TABLE_LIST *table= li++) @@ -611,10 +617,11 @@ static void reset_on_clauses_context(List<TABLE_LIST>& join_list) if (table->on_context) table->on_context->outer_context= NULL; if (table->nested_join) - reset_on_clauses_context(table->nested_join->join_list); + nullify_outer_context_for_on_clauses(table->nested_join->join_list); } } + /* Create temporary table structure (but do not fill it) @@ -783,7 +790,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) sl->context.outer_context= 0; // And for ON clauses, if there are any - reset_on_clauses_context(*sl->join_list); + nullify_outer_context_for_on_clauses(*sl->join_list); if (!derived->is_with_table_recursive_reference() || (!derived->with->with_anchor && diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 00fa2add88b..ea37b0cb100 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2971,6 +2971,7 @@ void st_select_lex::init_query() is_service_select= 0; parsing_place= NO_MATTER; save_parsing_place= NO_MATTER; + context_analysis_place= NO_MATTER; exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 0; link_next= 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a63b5432936..29884cd843e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7641,6 +7641,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) THD *thd= lex->thd; bool new_select= select_lex == NULL; int old_nest_level= lex->current_select->nest_level; + Name_resolution_context *curr_context= lex->context_stack.head(); DBUG_ENTER("mysql_new_select"); if (new_select) @@ -7670,7 +7671,8 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) By default we assume that it is usual subselect and we have outer name resolution context, if no we will assign it to 0 later */ - select_lex->context.outer_context= &select_lex->outer_select()->context; + + select_lex->context.outer_context= curr_context; } else { diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 1a5ba7c320d..74f2e1b33f1 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1505,7 +1505,7 @@ static bool check_list_constants(THD *thd, partition_info *part_info) List_iterator<part_elem_value> list_val_it2(part_def->list_val_list); while ((list_value= list_val_it2++)) { - calc_value= list_value->value - type_add; + calc_value= list_value->value ^ type_add; part_info->list_array[list_index].list_value= calc_value; part_info->list_array[list_index++].partition_id= i; } diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 8f87d633d19..2974c770252 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -417,6 +417,14 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, { if (reinit_ssl()) result= 1; +#ifdef WITH_WSREP + if (!result && + WSREP_ON && wsrep_reload_ssl()) + { + my_message(ER_UNKNOWN_ERROR, "Failed to refresh WSREP SSL.", MYF(0)); + result= 1; + } +#endif } if (options & REFRESH_GENERIC) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 88f3a44358c..849e0943acd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -358,7 +358,31 @@ bool dbug_user_var_equals_int(THD *thd, const char *name, int value) } return FALSE; } -#endif +#endif /* DBUG_OFF */ + +/* + Intialize POSITION structure. +*/ + +POSITION::POSITION() +{ + table= 0; + records_read= cond_selectivity= read_time= 0.0; + prefix_record_count= 0.0; + key= 0; + use_join_buffer= 0; + sj_strategy= SJ_OPT_NONE; + n_sj_tables= 0; + spl_plan= 0; + range_rowid_filter_info= 0; + ref_depend_map= dups_producing_tables= 0; + inner_tables_handled_with_other_sjs= 0; + dups_weedout_picker.set_empty(); + firstmatch_picker.set_empty(); + loosescan_picker.set_empty(); + sjmat_picker.set_empty(); +} + static void trace_table_dependencies(THD *thd, JOIN_TAB *join_tabs, uint table_count) @@ -1604,10 +1628,11 @@ bool JOIN::build_explain() curr_tab->tracker= thd->lex->explain->get_union(select_nr)-> get_tmptable_read_tracker(); } - else + else if (select_nr < INT_MAX) { - curr_tab->tracker= thd->lex->explain->get_select(select_nr)-> - get_using_temporary_read_tracker(); + Explain_select *tmp= thd->lex->explain->get_select(select_nr); + if (tmp) + curr_tab->tracker= tmp->get_using_temporary_read_tracker(); } } DBUG_RETURN(0); @@ -4970,6 +4995,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, /* The following should be optimized to only clear critical things */ bzero((void*)stat, sizeof(JOIN_TAB)* table_count); + /* Initialize POSITION objects */ for (i=0 ; i <= table_count ; i++) (void) new ((char*) (join->positions + i)) POSITION; @@ -16126,7 +16152,7 @@ static void update_const_equal_items(THD *thd, COND *cond, JOIN_TAB *tab, Item_func::COND_AND_FUNC)); } else if (cond->type() == Item::FUNC_ITEM && - ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC) + ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC) { Item_equal *item_equal= (Item_equal *) cond; bool contained_const= item_equal->get_const() != NULL; @@ -16321,7 +16347,7 @@ propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list, (((Item_func*) cond)->functype() == Item_func::EQ_FUNC || ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)) { - Item_func_eq *func=(Item_func_eq*) cond; + Item_bool_func2 *func= dynamic_cast<Item_bool_func2*>(cond); Item **args= func->arguments(); bool left_const= args[0]->const_item() && !args[0]->is_expensive(); bool right_const= args[1]->const_item() && !args[1]->is_expensive(); @@ -17263,7 +17289,7 @@ void propagate_new_equalities(THD *thd, Item *cond, } } else if (cond->type() == Item::FUNC_ITEM && - ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC) + ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC) { Item_equal *equal_item; List_iterator<Item_equal> it(*new_equalities); @@ -17508,7 +17534,7 @@ Item_cond::remove_eq_conds(THD *thd, Item::cond_result *cond_value, } else if (and_level && new_item->type() == Item::FUNC_ITEM && - ((Item_cond*) new_item)->functype() == + ((Item_func*) new_item)->functype() == Item_func::MULT_EQUAL_FUNC) { li.remove(); @@ -25455,8 +25481,8 @@ copy_fields(TMP_TABLE_PARAM *param) (*ptr->do_copy)(ptr); List_iterator_fast<Item> it(param->copy_funcs); - Item_copy_string *item; - while ((item = (Item_copy_string*) it++)) + Item_copy *item; + while ((item= (Item_copy*) it++)) item->copy(); } @@ -29602,6 +29628,7 @@ void unpack_to_base_table_fields(TABLE *table) } + /** @} (end of group Query_Optimizer) */ diff --git a/sql/sql_select.h b/sql/sql_select.h index cf451979f8e..ff2b24fdbf7 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -700,8 +700,6 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records); -struct st_position; - class Semi_join_strategy_picker { public: @@ -712,7 +710,7 @@ public: Update internal state after another table has been added to the join prefix */ - virtual void set_from_prev(struct st_position *prev) = 0; + virtual void set_from_prev(POSITION *prev) = 0; virtual bool check_qep(JOIN *join, uint idx, @@ -722,7 +720,7 @@ public: double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, - struct st_position *loose_scan_pos) = 0; + POSITION *loose_scan_pos) = 0; virtual void mark_used() = 0; @@ -753,7 +751,7 @@ public: first_dupsweedout_table= MAX_TABLES; is_used= FALSE; } - void set_from_prev(struct st_position *prev); + void set_from_prev(POSITION *prev); bool check_qep(JOIN *join, uint idx, @@ -763,7 +761,7 @@ public: double *read_time, table_map *handled_fanout, sj_strategy_enum *stratey, - struct st_position *loose_scan_pos); + POSITION *loose_scan_pos); void mark_used() { is_used= TRUE; } friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); @@ -799,7 +797,7 @@ public: is_used= FALSE; } - void set_from_prev(struct st_position *prev); + void set_from_prev(POSITION *prev); bool check_qep(JOIN *join, uint idx, table_map remaining_tables, @@ -808,7 +806,7 @@ public: double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, - struct st_position *loose_scan_pos); + POSITION *loose_scan_pos); void mark_used() { is_used= TRUE; } friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); @@ -817,6 +815,7 @@ public: class LooseScan_picker : public Semi_join_strategy_picker { +public: /* The first (i.e. driving) table we're doing loose scan for */ uint first_loosescan_table; /* @@ -835,14 +834,13 @@ class LooseScan_picker : public Semi_join_strategy_picker uint loosescan_parts; /* Number of keyparts to be kept distinct */ bool is_used; -public: void set_empty() { first_loosescan_table= MAX_TABLES; is_used= FALSE; } - void set_from_prev(struct st_position *prev); + void set_from_prev(POSITION *prev); bool check_qep(JOIN *join, uint idx, table_map remaining_tables, @@ -851,19 +849,19 @@ public: double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, - struct st_position *loose_scan_pos); + POSITION *loose_scan_pos); void mark_used() { is_used= TRUE; } friend class Loose_scan_opt; friend void best_access_path(JOIN *join, JOIN_TAB *s, table_map remaining_tables, - const struct st_position *join_positions, + const POSITION *join_positions, uint idx, bool disable_jbuf, double record_count, - struct st_position *pos, - struct st_position *loose_scan_pos); + POSITION *pos, + POSITION *loose_scan_pos); friend bool get_best_combination(JOIN *join); friend int setup_semijoin_loosescan(JOIN *join); friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); @@ -890,7 +888,7 @@ public: sjm_scan_last_inner= 0; is_used= FALSE; } - void set_from_prev(struct st_position *prev); + void set_from_prev(POSITION *prev); bool check_qep(JOIN *join, uint idx, table_map remaining_tables, @@ -899,7 +897,7 @@ public: double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, - struct st_position *loose_scan_pos); + POSITION *loose_scan_pos); void mark_used() { is_used= TRUE; } friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); @@ -914,8 +912,9 @@ class Rowid_filter; Information about a position of table within a join order. Used in join optimization. */ -typedef struct st_position +class POSITION { +public: /* The table that's put into join order */ JOIN_TAB *table; @@ -927,7 +926,7 @@ typedef struct st_position double records_read; /* The selectivity of the pushed down conditions */ - double cond_selectivity; + double cond_selectivity; /* Cost accessing the table in course of the entire complete join execution, @@ -936,8 +935,6 @@ typedef struct st_position */ double read_time; - /* Cumulative cost and record count for the join prefix */ - Cost_estimate prefix_cost; double prefix_record_count; /* @@ -946,29 +943,46 @@ typedef struct st_position */ KEYUSE *key; + /* Info on splitting plan used at this position */ + SplM_plan_info *spl_plan; + + /* Cost info for the range filter used at this position */ + Range_rowid_filter_cost_info *range_rowid_filter_info; + /* If ref-based access is used: bitmap of tables this table depends on */ table_map ref_depend_map; - + /* - TRUE <=> join buffering will be used. At the moment this is based on - *very* imprecise guesses made in best_access_path(). + Bitmap of semi-join inner tables that are in the join prefix and for + which there's no provision for how to eliminate semi-join duplicates + they produce. */ - bool use_join_buffer; - + table_map dups_producing_tables; + + table_map inner_tables_handled_with_other_sjs; + + Duplicate_weedout_picker dups_weedout_picker; + Firstmatch_picker firstmatch_picker; + LooseScan_picker loosescan_picker; + Sj_materialization_picker sjmat_picker; + + /* Cumulative cost and record count for the join prefix */ + Cost_estimate prefix_cost; + /* Current optimization state: Semi-join strategy to be used for this and preceding join tables. - + Join optimizer sets this for the *last* join_tab in the - duplicate-generating range. That is, in order to interpret this field, + duplicate-generating range. That is, in order to interpret this field, one needs to traverse join->[best_]positions array from right to left. When you see a join table with sj_strategy!= SJ_OPT_NONE, some other - field (depending on the strategy) tells how many preceding positions + field (depending on the strategy) tells how many preceding positions this applies to. The values of covered_preceding_positions->sj_strategy must be ignored. */ enum sj_strategy_enum sj_strategy; - + /* Valid only after fix_semijoin_strategies_for_picked_join_order() call: if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that @@ -977,26 +991,12 @@ typedef struct st_position uint n_sj_tables; /* - Bitmap of semi-join inner tables that are in the join prefix and for - which there's no provision for how to eliminate semi-join duplicates - they produce. + TRUE <=> join buffering will be used. At the moment this is based on + *very* imprecise guesses made in best_access_path(). */ - table_map dups_producing_tables; - - table_map inner_tables_handled_with_other_sjs; - - Duplicate_weedout_picker dups_weedout_picker; - Firstmatch_picker firstmatch_picker; - LooseScan_picker loosescan_picker; - Sj_materialization_picker sjmat_picker; - - /* Info on splitting plan used at this position */ - SplM_plan_info *spl_plan; - - /* Cost info for the range filter used at this position */ - Range_rowid_filter_cost_info *range_rowid_filter_info; - -} POSITION; + bool use_join_buffer; + POSITION(); +}; typedef Bounds_checked_array<Item_null_result*> Item_null_array; @@ -1592,6 +1592,7 @@ public: fields_list= fields_arg; non_agg_fields.empty(); bzero((char*) &keyuse,sizeof(keyuse)); + having_value= Item::COND_UNDEF; tmp_table_param.init(); tmp_table_param.end_write_records= HA_POS_ERROR; rollup.state= ROLLUP::STATE_NONE; diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index f881f6a8cc6..307a0b29c57 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -727,8 +727,8 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) if (real_increment > 0) { - if (reserved_until + add_to > max_value || - reserved_until > max_value - add_to) + if (reserved_until > max_value - add_to || + reserved_until + add_to > max_value) { reserved_until= max_value + 1; out_of_values= res_value >= reserved_until; diff --git a/sql/sql_sequence.h b/sql/sql_sequence.h index 2d609d8591b..29c589e67cd 100644 --- a/sql/sql_sequence.h +++ b/sql/sql_sequence.h @@ -111,8 +111,8 @@ public: { if (real_increment > 0) { - if (value + real_increment > max_value || - value > max_value - real_increment) + if (value > max_value - real_increment || + value + real_increment > max_value) value= max_value + 1; else value+= real_increment; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b1cc696e9fe..38b3d62d539 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7061,8 +7061,7 @@ static bool store_trigger(THD *thd, Trigger *trigger, (my_time_t)(trigger->create_time/100)); /* timestamp is with 6 digits */ timestamp.second_part= (trigger->create_time % 100) * 10000; - ((Field_temporal_with_date*) table->field[16])->store_time_dec(×tamp, - 2); + table->field[16]->store_time_dec(×tamp, 2); } sql_mode_string_representation(thd, trigger->sql_mode, &sql_mode_rep); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9869de4ba5e..3643b19f8fb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8730,7 +8730,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, If the '0000-00-00' value isn't allowed then raise the error_if_not_empty flag to allow ALTER TABLE only if the table to be altered is empty. */ - if (!alter_ctx->implicit_default_value_error_field && + if (!alter_ctx->implicit_default_value_error_field && !def->field && !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) && def->type_handler()->validate_implicit_default_value(thd, *def)) { @@ -8988,7 +8988,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, key_parts.push_back(new (thd->mem_root) Key_part_spec(&cfield->field_name, key_part_length, true), thd->mem_root); - if (cfield->invisible < INVISIBLE_SYSTEM) + if (!(cfield->invisible == INVISIBLE_SYSTEM && cfield->vers_sys_field())) user_keyparts= true; } if (table->s->tmp_table == NO_TMP_TABLE) @@ -9000,6 +9000,14 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, (void) delete_statistics_for_index(thd, table, key_info, TRUE); } + if (!user_keyparts && key_parts.elements) + { + /* + If we dropped all user key-parts we also drop implicit system fields. + */ + key_parts.empty(); + } + if (key_parts.elements) { KEY_CREATE_INFO key_create_info; @@ -9036,7 +9044,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, key_type= Key::PRIMARY; else key_type= Key::UNIQUE; - if (dropped_key_part && user_keyparts) + if (dropped_key_part) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), dropped_key_part); if (long_hash_key) diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 5ea853ade0b..8c9c56f1db7 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -297,7 +297,6 @@ print_plan(JOIN* join, uint idx, double record_count, double read_time, double current_read_time, const char *info) { uint i; - POSITION pos; JOIN_TAB *join_table; JOIN_TAB **plan_nodes; TABLE* table; @@ -324,8 +323,8 @@ print_plan(JOIN* join, uint idx, double record_count, double read_time, fputs(" POSITIONS: ", DBUG_FILE); for (i= 0; i < idx ; i++) { - pos = join->positions[i]; - table= pos.table->table; + POSITION *pos= join->positions + i; + table= pos->table->table; if (table) fputs(table->s->table_name.str, DBUG_FILE); fputc(' ', DBUG_FILE); @@ -341,8 +340,8 @@ print_plan(JOIN* join, uint idx, double record_count, double read_time, fputs("BEST_POSITIONS: ", DBUG_FILE); for (i= 0; i < idx ; i++) { - pos= join->best_positions[i]; - table= pos.table->table; + POSITION *pos= join->best_positions + i; + table= pos->table->table; if (table) fputs(table->s->table_name.str, DBUG_FILE); fputc(' ', DBUG_FILE); diff --git a/sql/sql_type_int.h b/sql/sql_type_int.h index 9fd4f0c46a0..fca00f25448 100644 --- a/sql/sql_type_int.h +++ b/sql/sql_type_int.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, MariaDB +/* Copyright (c) 2018, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -80,16 +80,20 @@ public: if (is_null() || llshift.is_null()) return Longlong_null(); uint shift= (uint) llshift.value(); - ulonglong res= ((ulonglong) value()) << shift; - return Longlong_null(shift < sizeof(longlong) * 8 ? (longlong) res : 0); + ulonglong res= (shift < sizeof(longlong) * 8) + ? ((ulonglong) value()) << shift + : 0; + return Longlong_null((longlong) res); } Longlong_null operator>>(const Longlong_null &llshift) const { if (is_null() || llshift.is_null()) return Longlong_null(); uint shift= (uint) llshift.value(); - ulonglong res= ((ulonglong) value()) >> shift; - return Longlong_null(shift < sizeof(longlong) * 8 ? (longlong) res : 0); + ulonglong res= (shift < sizeof(longlong) * 8) + ? ((ulonglong) value()) >> shift + : 0; + return Longlong_null((longlong) res); } Longlong_null bit_count() const { diff --git a/sql/strfunc.cc b/sql/strfunc.cc index c488ab1afbb..6c8fd24f780 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -81,14 +81,17 @@ ulonglong find_set(const TYPELIB *lib, var_len= (uint) (pos - start); uint find= cs ? find_type2(lib, start, var_len, cs) : find_type(lib, start, var_len, (bool) 0); - if (unlikely(!find && *err_len == 0)) + if (unlikely(!find)) { - // report the first error with length > 0 - *err_pos= (char*) start; - *err_len= var_len; - *set_warning= 1; + if (*err_len == 0) + { + // report the first error with length > 0 + *err_pos= (char*) start; + *err_len= var_len; + *set_warning= 1; + } } - else + else if (find <= sizeof(longlong) * 8) found|= 1ULL << (find - 1); if (pos >= end) break; @@ -402,4 +405,3 @@ const char *flagset_to_string(THD *thd, LEX_CSTRING *result, ulonglong set, return result->str; } - diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b72d4a3c358..ebec2a203aa 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2015, Oracle and/or its affiliates. - Copyright (c) 2012, 2020, MariaDB Corporation. + Copyright (c) 2012, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -5051,15 +5051,23 @@ static Sys_var_have Sys_have_symlink( "--skip-symbolic-links option.", READ_ONLY GLOBAL_VAR(have_symlink), NO_CMD_LINE); +#if defined(__SANITIZE_ADDRESS__) || defined(WITH_UBSAN) + #ifdef __SANITIZE_ADDRESS__ +#define SANITIZER_MODE "ASAN" +#else +#define SANITIZER_MODE "UBSAN" +#endif /* __SANITIZE_ADDRESS__ */ + static char *have_sanitizer; -static Sys_var_charptr_fscs Sys_have_santitizer( +static Sys_var_charptr Sys_have_santitizer( "have_sanitizer", - "If the server is compiled with ASan (Address sanitizer) this will be " - "set to ASAN", - READ_ONLY GLOBAL_VAR(have_sanitizer), NO_CMD_LINE, - DEFAULT("ASAN")); -#endif + "If the server is compiled with sanitize (compiler option), this " + "variable is set to the sanitizer mode used. Possible values are " + "ASAN (Address sanitizer) or UBSAN (The Undefined Behavior Sanitizer).", + READ_ONLY GLOBAL_VAR(have_sanitizer), NO_CMD_LINE, + DEFAULT(SANITIZER_MODE)); +#endif /* defined(__SANITIZE_ADDRESS__) || defined(WITH_UBSAN) */ static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type); diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 1a8b5c471bd..981958abdb2 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, 2019, MariaDB Corporation. + Copyright (c) 2016, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -872,10 +872,12 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share) bool THD::has_temporary_tables() { DBUG_ENTER("THD::has_temporary_tables"); - bool result= (rgi_slave - ? (rgi_slave->rli->save_temporary_tables && - !rgi_slave->rli->save_temporary_tables->is_empty()) - : (has_thd_temporary_tables())); + bool result= +#ifdef HAVE_REPLICATION + rgi_slave ? (rgi_slave->rli->save_temporary_tables && + !rgi_slave->rli->save_temporary_tables->is_empty()) : +#endif + has_thd_temporary_tables(); DBUG_RETURN(result); } @@ -1506,12 +1508,14 @@ bool THD::lock_temporary_tables() DBUG_RETURN(false); } +#ifdef HAVE_REPLICATION if (rgi_slave) { mysql_mutex_lock(&rgi_slave->rli->data_lock); temporary_tables= rgi_slave->rli->save_temporary_tables; m_tmp_tables_locked= true; } +#endif DBUG_RETURN(m_tmp_tables_locked); } @@ -1532,6 +1536,7 @@ void THD::unlock_temporary_tables() DBUG_VOID_RETURN; } +#ifdef HAVE_REPLICATION if (rgi_slave) { rgi_slave->rli->save_temporary_tables= temporary_tables; @@ -1539,6 +1544,7 @@ void THD::unlock_temporary_tables() mysql_mutex_unlock(&rgi_slave->rli->data_lock); m_tmp_tables_locked= false; } +#endif DBUG_VOID_RETURN; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 018b9aab3a7..1618a8b6d50 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1653,6 +1653,32 @@ exit: return fail; } +bool wsrep_reload_ssl() +{ + try + { + std::string opts= Wsrep_server_state::instance().provider().options(); + if (opts.find("socket.ssl_reload") == std::string::npos) + { + WSREP_DEBUG("Option `socket.ssl_reload` not found in parameters."); + return false; + } + const std::string reload_ssl_param("socket.ssl_reload=1"); + enum wsrep::provider::status ret= Wsrep_server_state::instance().provider().options(reload_ssl_param); + if (ret) + { + WSREP_ERROR("Set options returned %d", ret); + return true; + } + return false; + } + catch (...) + { + WSREP_ERROR("Failed to get provider options"); + return true; + } +} + /*! * @param db Database string * @param table Table string diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 8f20eec0701..0541f2b02ad 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -233,6 +233,7 @@ extern void wsrep_last_committed_id (wsrep_gtid_t* gtid); extern int wsrep_check_opts(); extern void wsrep_prepend_PATH (const char* path); extern bool wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys); +extern bool wsrep_reload_ssl(); /* Other global variables */ extern wsrep_seqno_t wsrep_locked_seqno; diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h index 942363d9886..d79bfa0b39b 100644 --- a/sql/wsrep_trans_observer.h +++ b/sql/wsrep_trans_observer.h @@ -466,6 +466,16 @@ static inline void wsrep_close(THD* thd) DBUG_VOID_RETURN; } +static inline void wsrep_cleanup(THD* thd) +{ + DBUG_ENTER("wsrep_cleanup"); + if (thd->wsrep_cs().state() != wsrep::client_state::s_none) + { + thd->wsrep_cs().cleanup(); + } + DBUG_VOID_RETURN; +} + static inline void wsrep_wait_rollback_complete_and_acquire_ownership(THD *thd) { diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index e0b9ac889db..386da305a26 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -25,6 +25,7 @@ #include <my_dir.h> #include <cstdio> #include <cstdlib> +#include "wsrep_trans_observer.h" ulong wsrep_reject_queries; @@ -102,7 +103,8 @@ void wsrep_set_wsrep_on(THD* thd) bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) { - if (var_type == OPT_GLOBAL) { + if (var_type == OPT_GLOBAL) + { my_bool saved_wsrep_on= global_system_variables.wsrep_on; thd->variables.wsrep_on= global_system_variables.wsrep_on; @@ -110,15 +112,15 @@ bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) // If wsrep has not been inited we need to do it now if (global_system_variables.wsrep_on && wsrep_provider && !wsrep_inited) { - char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider - //when fails - + // wsrep_init() rewrites provide if it fails + char* tmp= strdup(wsrep_provider); mysql_mutex_unlock(&LOCK_global_system_variables); if (wsrep_init()) { my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp, my_error, "wsrep_init failed"); //rcode= true; + saved_wsrep_on= false; } free(tmp); @@ -130,20 +132,69 @@ bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) wsrep_set_wsrep_on(thd); + if (var_type == OPT_GLOBAL) + { + if (thd->variables.wsrep_on && + thd->wsrep_cs().state() == wsrep::client_state::s_none) + { + wsrep_open(thd); + wsrep_before_command(thd); + } + } + return false; } bool wsrep_on_check(sys_var *self, THD* thd, set_var* var) { + bool new_wsrep_on= (bool)var->save_result.ulonglong_value; + if (check_has_super(self, thd, var)) return true; + if (new_wsrep_on) + { + if (!WSREP_PROVIDER_EXISTS) + { + my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) can't be enabled " + "if the wsrep_provider is unset or set to 'none'", MYF(0)); + return true; + } + + if (var->type == OPT_SESSION && + !global_system_variables.wsrep_on) + { + my_message(ER_WRONG_ARGUMENTS, + "Can't enable @@session.wsrep_on, " + "while @@global.wsrep_on is disabled", MYF(0)); + return true; + } + } + if (thd->in_active_multi_stmt_transaction()) { my_error(ER_CANT_DO_THIS_DURING_AN_TRANSACTION, MYF(0)); return true; } + if (var->type == OPT_GLOBAL) + { + /* + The global value is about to change. Cleanup + the transaction state and close the client + state. wsrep_on_update() will take care of + reopening it should wsrep_on be re-enabled. + */ + if (global_system_variables.wsrep_on && !new_wsrep_on) + { + wsrep_commit_empty(thd, true); + wsrep_after_statement(thd); + wsrep_after_command_ignore_result(thd); + wsrep_close(thd); + wsrep_cleanup(thd); + } + } + return false; } |