diff options
author | Monty <monty@mariadb.org> | 2021-04-18 15:29:13 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2021-04-20 12:30:09 +0300 |
commit | 031f11717d9f351dfb12cd27c225c533e289261a (patch) | |
tree | 66da9cdbd1e8acb82da2e75e36a08b3461504716 /sql | |
parent | eb4123eefc8e0ee4751d3cd3cc49ebf256aa9486 (diff) | |
download | mariadb-git-031f11717d9f351dfb12cd27c225c533e289261a.tar.gz |
Fix all warnings given by UBSAN
The easiest way to compile and test the server with UBSAN is to run:
./BUILD/compile-pentium64-ubsan
and then run mysql-test-run.
After this commit, one should be able to run this without any UBSAN
warnings. There is still a few compiler warnings that should be fixed
at some point, but these do not expose any real bugs.
The 'special' cases where we disable, suppress or circumvent UBSAN are:
- ref10 source (as here we intentionally do some shifts that UBSAN
complains about.
- x86 version of optimized int#korr() methods. UBSAN do not like unaligned
memory access of integers. Fixed by using byte_order_generic.h when
compiling with UBSAN
- We use smaller thread stack with ASAN and UBSAN, which forced me to
disable a few tests that prints the thread stack size.
- Verifying class types does not work for shared libraries. I added
suppression in mysql-test-run.pl for this case.
- Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is
safe to have overflows (two cases, in item_func.cc).
Things fixed:
- Don't left shift signed values
(byte_order_generic.h, mysqltest.c, item_sum.cc and many more)
- Don't assign not non existing values to enum variables.
- Ensure that bool and enum values are properly initialized in
constructors. This was needed as UBSAN checks that these types has
correct values when one copies an object.
(gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...)
- Ensure we do not called handler functions on unallocated objects or
deleted objects.
(events.cc, sql_acl.cc).
- Fixed bugs in Item_sp::Item_sp() where we did not call constructor
on Query_arena object.
- Fixed several cast of objects to an incompatible class!
(Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc,
sql_select.cc ...)
- Ensure we do not do integer arithmetic that causes over or underflows.
This includes also ++ and -- of integers.
(Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...)
- Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that
value_type is initialized to this instead of to -1, which is not a valid
enum value for json_value_types.
- Ensure we do not call memcpy() when second argument could be null.
- Fixed that Item_func_str::make_empty_result() creates an empty string
instead of a null string (safer as it ensures we do not do arithmetic
on null strings).
Other things:
- Changed struct st_position to an OBJECT and added an initialization
function to it to ensure that we do not copy or use uninitialized
members. The change to a class was also motived that we used "struct
st_position" and POSITION randomly trough the code which was
confusing.
- Notably big rewrite in sql_acl.cc to avoid using deleted objects.
- Changed in sql_partition to use '^' instead of '-'. This is safe as
the operator is either 0 or 0x8000000000000000ULL.
- Added check for select_nr < INT_MAX in JOIN::build_explain() to
avoid bug when get_select() could return NULL.
- Reordered elements in POSITION for better alignment.
- Changed sql_test.cc::print_plan() to use pointers instead of objects.
- Fixed bug in find_set() where could could execute '1 << -1'.
- Added variable have_sanitizer, used by mtr. (This variable was before
only in 10.5 and up). It can now have one of two values:
ASAN or UBSAN.
- Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked
it virtual. This was an effort to get UBSAN to work with loaded storage
engines. I kept the change as the new place is better.
- Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast
in tabutil.cpp.
- Added HAVE_REPLICATION around usage of rgi_slave, to get embedded
server to compile with UBSAN. (Patch from Marko).
- Added #ifdef for powerpc64 to avoid a bug in old gcc versions related
to integer arithmetic.
Changes that should not be needed but had to be done to suppress warnings
from UBSAN:
- Added static_cast<<uint16_t>> around shift to get rid of a LOT of
compiler warnings when using UBSAN.
- Had to change some '/' of 2 base integers to shift to get rid of
some compile time warnings.
Reviewed by:
- Json changes: Alexey Botchkov
- Charset changes in ctype-uca.c: Alexander Barkov
- InnoDB changes & Embedded server: Marko Mäkelä
- sql_acl.cc changes: Vicențiu Ciorbaru
- build_explain() changes: Sergey Petrunia
Diffstat (limited to 'sql')
-rw-r--r-- | sql/compat56.h | 4 | ||||
-rw-r--r-- | sql/events.cc | 12 | ||||
-rw-r--r-- | sql/field.h | 8 | ||||
-rw-r--r-- | sql/gcalc_tools.h | 6 | ||||
-rw-r--r-- | sql/ha_partition.cc | 1 | ||||
-rw-r--r-- | sql/item.cc | 18 | ||||
-rw-r--r-- | sql/item_buff.cc | 4 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 10 | ||||
-rw-r--r-- | sql/item_func.cc | 74 | ||||
-rw-r--r-- | sql/item_jsonfunc.cc | 5 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 16 | ||||
-rw-r--r-- | sql/item_strfunc.h | 9 | ||||
-rw-r--r-- | sql/item_sum.cc | 6 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 23 | ||||
-rw-r--r-- | sql/opt_split.cc | 2 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 12 | ||||
-rw-r--r-- | sql/partition_element.h | 3 | ||||
-rw-r--r-- | sql/sql_acl.cc | 117 | ||||
-rw-r--r-- | sql/sql_base.cc | 14 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_partition.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 47 | ||||
-rw-r--r-- | sql/sql_select.h | 97 | ||||
-rw-r--r-- | sql/sql_sequence.cc | 4 | ||||
-rw-r--r-- | sql/sql_sequence.h | 4 | ||||
-rw-r--r-- | sql/sql_show.cc | 3 | ||||
-rw-r--r-- | sql/sql_test.cc | 9 | ||||
-rw-r--r-- | sql/strfunc.cc | 16 | ||||
-rw-r--r-- | sql/sys_vars.cc | 18 | ||||
-rw-r--r-- | sql/temporary_tables.cc | 16 |
32 files changed, 355 insertions, 212 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 195c0fa09e2..5e15b92dc49 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -658,8 +658,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 6cb19d1e238..421d6bddb2d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4534,7 +4534,13 @@ public: void move_field_offset(my_ptrdiff_t ptr_diff) { 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); 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 4c4a62e7fc4..24e08501bed 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6461,6 +6461,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 756f29a3ff8..6c52ade0d9f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2599,9 +2599,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)); } @@ -2612,7 +2610,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)); } @@ -6208,12 +6206,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 875aacec3bc..687aa7e192b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5657,13 +5657,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 837156ce39a..d50fb22a154 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1095,17 +1095,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 @@ -1146,16 +1149,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. @@ -1248,12 +1264,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; @@ -1268,12 +1289,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 { @@ -1294,23 +1311,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. @@ -2130,31 +2159,29 @@ double Item_func_cot::val_real() longlong Item_func_shift_left::val_int() { DBUG_ASSERT(fixed == 1); - uint shift; - ulonglong res= ((ulonglong) args[0]->val_int() << - (shift=(uint) args[1]->val_int())); + uint shift= (uint) args[1]->val_int(); + ulonglong value= args[0]->val_int(); if (args[0]->null_value || args[1]->null_value) { null_value=1; return 0; } null_value=0; - return (shift < sizeof(longlong)*8 ? (longlong) res : 0); + return (shift < sizeof(longlong)*8 ? (value << shift) : 0); } longlong Item_func_shift_right::val_int() { DBUG_ASSERT(fixed == 1); - uint shift; - ulonglong res= (ulonglong) args[0]->val_int() >> - (shift=(uint) args[1]->val_int()); + uint shift= (uint) args[1]->val_int(); + ulonglong value= args[0]->val_int(); if (args[0]->null_value || args[1]->null_value) { null_value=1; return 0; } null_value=0; - return (shift < sizeof(longlong)*8 ? (longlong) res : 0); + return (shift < sizeof(longlong)*8 ? (value >> shift) : 0); } @@ -3054,10 +3081,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); @@ -3222,7 +3250,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 0d15c5e9ad0..4b4a94c814e 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -618,8 +618,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; @@ -982,7 +980,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 ea14e9d44f8..759b18c4657 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1514,17 +1514,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 @@ -3795,13 +3796,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 c13c49b8363..826a978805e 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_sum.cc b/sql/item_sum.cc index c97220fd686..581c94bd191 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2635,9 +2635,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; } @@ -3738,7 +3738,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 b476b5f1f27..7dbc81e8825 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -733,7 +733,10 @@ static bool make_date_time(const LEX_CSTRING &format, 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; @@ -745,11 +748,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/opt_split.cc b/sql/opt_split.cc index c3a2d03a93b..395422de3c3 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -204,7 +204,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 f7349e7a1bf..7bd778e339f 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2990,7 +2990,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(); @@ -3176,7 +3176,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(); @@ -3197,7 +3197,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; /* @@ -3275,7 +3275,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(); @@ -5789,8 +5789,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/sql_acl.cc b/sql/sql_acl.cc index ddaa54588d7..96f1b87d5d7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5348,7 +5348,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); } @@ -5362,6 +5362,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) @@ -5591,6 +5595,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, @@ -5615,7 +5628,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 */ } } @@ -5646,7 +5659,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 @@ -5709,13 +5722,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 */ } @@ -6476,7 +6490,7 @@ static int update_role_table_columns(GRANT_TABLE *merged, privs, cols); merged->init_privs= merged->init_cols= 0; update_role_columns(merged, first, last); - my_hash_insert(&column_priv_hash,(uchar*) merged); + column_priv_insert(merged); return 2; } else if ((privs | cols) == 0) @@ -6796,7 +6810,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, bool revoke_grant) { ulong column_priv= 0; - int result; + int result, res; List_iterator <LEX_USER> str_list (user_list); LEX_USER *Str, *tmp_Str; bool create_new_users=0; @@ -6939,12 +6953,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 */ @@ -6987,22 +7001,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 ((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()) @@ -7014,9 +7030,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); @@ -7704,7 +7718,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; @@ -11100,7 +11114,7 @@ mysql_revoke_sp_privs(THD *thd, Grant_tables *tables, const Sp_handler *sph, bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) { uint counter, revoked; - int result; + int result, res; ACL_DB *acl_db; DBUG_ENTER("mysql_revoke_all"); @@ -11193,36 +11207,35 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) 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, ~(ulong)0, 0, 1)) - { + 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, ~(ulong)0, 1)) result= -1; - } - else + + /* TODO(cvicentiu) refactor replace_db_table to use + Db_table instead of TABLE directly. */ + if ((res= replace_table_table(thd, grant_table, + tables.tables_priv_table().table(), + *lex_user, grant_table->db, + grant_table->tname, ~(ulong)0, 0, 1))) { - 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, ~(ulong)0, 1)) - { - revoked= 1; - continue; - } - result= -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 242f03d536e..a1be9e76fc8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7898,11 +7898,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 81718595fec..093a94f44f8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -784,7 +784,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.m_pending_rows_event= 0; transaction.on= 1; diff --git a/sql/sql_class.h b/sql/sql_class.h index 34a4edbb761..6701c366f0a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6048,11 +6048,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_lex.cc b/sql/sql_lex.cc index ecde337ff6c..60b386f2cf4 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2433,6 +2433,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_partition.cc b/sql/sql_partition.cc index 373326c75c6..43264e3e508 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_select.cc b/sql/sql_select.cc index 1598746b667..44d15327ec1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -350,7 +350,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) @@ -1587,10 +1611,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); @@ -4911,6 +4936,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; @@ -15996,7 +16022,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; @@ -16191,7 +16217,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(); @@ -17131,7 +17157,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); @@ -17376,7 +17402,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(); @@ -25200,8 +25226,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(); } @@ -29024,6 +29050,7 @@ select_handler *SELECT_LEX::find_select_handler(THD *thd) } + /** @} (end of group Query_Optimizer) */ diff --git a/sql/sql_select.h b/sql/sql_select.h index 1d928334bd8..d21d1bcc305 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -698,8 +698,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: @@ -710,7 +708,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, @@ -720,7 +718,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; @@ -751,7 +749,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, @@ -761,7 +759,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); @@ -797,7 +795,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, @@ -806,7 +804,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); @@ -815,6 +813,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; /* @@ -833,14 +832,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, @@ -849,19 +847,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); @@ -888,7 +886,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, @@ -897,7 +895,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); @@ -912,8 +910,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; @@ -925,7 +924,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, @@ -934,8 +933,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; /* @@ -944,29 +941,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 @@ -975,26 +989,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; @@ -1590,6 +1590,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 b88933eac0c..83091cd67da 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -730,8 +730,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 8cb82c602d9..6f0c9761b6c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7096,8 +7096,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_test.cc b/sql/sql_test.cc index 28e3cdc9d69..5ea132c83d4 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -294,7 +294,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; @@ -321,8 +320,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); @@ -338,8 +337,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/strfunc.cc b/sql/strfunc.cc index 99ff9c50588..58647c21e44 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -79,14 +79,17 @@ ulonglong find_set(TYPELIB *lib, const char *str, size_t length, CHARSET_INFO *c 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; @@ -400,4 +403,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 a39928309d8..c52a8f742a8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4834,6 +4834,24 @@ 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 Sys_have_santitizer( + "have_sanitizer", + "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, + IN_FS_CHARSET, DEFAULT(SANITIZER_MODE)); +#endif /* defined(__SANITIZE_ADDRESS__) || defined(WITH_UBSAN) */ + static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type); static Sys_var_mybool Sys_general_log( diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index f2b27b7056b..5e4b5f7a713 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 @@ -875,10 +875,12 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share) inline 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); } @@ -1508,12 +1510,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); } @@ -1534,6 +1538,7 @@ void THD::unlock_temporary_tables() DBUG_VOID_RETURN; } +#ifdef HAVE_REPLICATION if (rgi_slave) { rgi_slave->rli->save_temporary_tables= temporary_tables; @@ -1541,6 +1546,7 @@ void THD::unlock_temporary_tables() mysql_mutex_unlock(&rgi_slave->rli->data_lock); m_tmp_tables_locked= false; } +#endif DBUG_VOID_RETURN; } |