From 6718d3bc3241f72e07504133371cf3813d2e6fe9 Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Fri, 25 May 2018 22:16:04 +0400 Subject: [PATCH 1/4] MDEV-21082: isnan/isinf compilation errors, isfinite warnings on MacOS The fix consists of three commits backported from 10.3: 1) Cleanup isnan() portability checks (cherry picked from commit 7ffd7fe9627d1f750a3712aebb4503e5ae8aea8e) 2) Cleanup isinf() portability checks Original problem reported by Wlad: re-compilation of 10.3 on top of 10.2 build would cache undefined HAVE_ISINF from 10.2, whereas it is expected to be 1 in 10.3. std::isinf() seem to be available on all supported platforms. (cherry picked from commit bc469a0bdf85400f7a63834f5b7af1a513dcdec9) 3) Use std::isfinite in C++ code This is addition to parent revision fixing build failures. (cherry picked from commit 54999f4e75f42baca484ae436b382ca8817df1dd) --- cmake/os/Windows.cmake | 1 - config.h.cmake | 2 -- configure.cmake | 11 ----------- include/my_global.h | 20 +------------------- sql/field.cc | 6 +++--- sql/item_func.cc | 6 +++--- sql/item_func.h | 2 +- sql/item_strfunc.cc | 2 +- sql/item_sum.cc | 4 ++-- storage/heap/hp_hash.c | 2 -- storage/innobase/gis/gis0geo.cc | 2 +- storage/innobase/gis/gis0rtree.cc | 2 +- storage/maria/ma_key.c | 2 -- storage/maria/ma_sp_key.c | 2 -- storage/myisam/mi_key.c | 2 -- storage/myisam/sp_key.c | 2 -- 16 files changed, 13 insertions(+), 55 deletions(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index ca6d13e1c1b..1eae92924a6 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -225,7 +225,6 @@ CHECK_SYMBOL_REPLACEMENT(S_IROTH _S_IREAD sys/stat.h) CHECK_SYMBOL_REPLACEMENT(S_IFIFO _S_IFIFO sys/stat.h) CHECK_SYMBOL_REPLACEMENT(SIGQUIT SIGTERM signal.h) CHECK_SYMBOL_REPLACEMENT(SIGPIPE SIGINT signal.h) -CHECK_SYMBOL_REPLACEMENT(isnan _isnan "math.h;float.h") CHECK_SYMBOL_REPLACEMENT(finite _finite "math;float.h") CHECK_FUNCTION_REPLACEMENT(popen _popen) CHECK_FUNCTION_REPLACEMENT(pclose _pclose) diff --git a/config.h.cmake b/config.h.cmake index ae1431c8abe..6e4af65c40e 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -163,7 +163,6 @@ #cmakedefine HAVE_IN_ADDR_T 1 #cmakedefine HAVE_INITGROUPS 1 #cmakedefine HAVE_ISNAN 1 -#cmakedefine HAVE_ISINF 1 #cmakedefine HAVE_LARGE_PAGE_OPTION 1 #cmakedefine HAVE_LDIV 1 #cmakedefine HAVE_LRAND48 1 @@ -423,7 +422,6 @@ #cmakedefine mode_t @mode_t@ #cmakedefine SIGQUIT @SIGQUIT@ #cmakedefine SIGPIPE @SIGPIPE@ -#cmakedefine isnan @isnan@ #cmakedefine finite @finite@ #cmakedefine popen @popen@ #cmakedefine pclose @pclose@ diff --git a/configure.cmake b/configure.cmake index 8677aec44f1..f94fb3642a5 100644 --- a/configure.cmake +++ b/configure.cmake @@ -475,19 +475,8 @@ ELSE() CHECK_SYMBOL_EXISTS(finite "ieeefp.h" HAVE_FINITE) ENDIF() CHECK_SYMBOL_EXISTS(log2 math.h HAVE_LOG2) -CHECK_SYMBOL_EXISTS(isnan math.h HAVE_ISNAN) CHECK_SYMBOL_EXISTS(rint math.h HAVE_RINT) -# isinf() prototype not found on Solaris -CHECK_CXX_SOURCE_COMPILES( -"#include -int main() { - isinf(0.0); - return 0; -}" HAVE_ISINF) - - - # # Test for endianess # diff --git a/include/my_global.h b/include/my_global.h index 4ce4671c571..8103f82a7e2 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -811,26 +811,8 @@ inline unsigned long long my_double2ulonglong(double d) #define SIZE_T_MAX (~((size_t) 0)) #endif -#ifndef isfinite -#ifdef HAVE_FINITE -#define isfinite(x) finite(x) -#else -#define finite(x) (1.0 / fabs(x) > 0.0) -#endif /* HAVE_FINITE */ -#elif (__cplusplus >= 201103L) +#ifdef __cplusplus #include -static inline bool isfinite(double x) { return std::isfinite(x); } -#endif /* isfinite */ - -#ifndef HAVE_ISNAN -#define isnan(x) ((x) != (x)) -#endif -#define my_isnan(x) isnan(x) - -#ifdef HAVE_ISINF -#define my_isinf(X) isinf(X) -#else /* !HAVE_ISINF */ -#define my_isinf(X) (!finite(X) && !isnan(X)) #endif /* Define missing math constants. */ diff --git a/sql/field.cc b/sql/field.cc index a23004ebd96..09e82acb009 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2904,7 +2904,7 @@ int Field_decimal::store(double nr) return 1; } - if (!isfinite(nr)) // Handle infinity as special case + if (!std::isfinite(nr)) // Handle infinity as special case { overflow(nr < 0.0); return 1; @@ -4821,7 +4821,7 @@ int truncate_double(double *nr, uint field_length, uint dec, int error= 0; double res= *nr; - if (isnan(res)) + if (std::isnan(res)) { *nr= 0; return -1; @@ -4843,7 +4843,7 @@ int truncate_double(double *nr, uint field_length, uint dec, max_value-= 1.0 / log_10[dec]; /* Check for infinity so we don't get NaN in calculations */ - if (!my_isinf(res)) + if (!std::isinf(res)) { double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec]; res= floor(res) + tmp; diff --git a/sql/item_func.cc b/sql/item_func.cc index 7719e0faa87..6ca74a79b9c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2553,12 +2553,12 @@ double my_double_round(double value, longlong dec, bool dec_unsigned, volatile double value_div_tmp= value / tmp; volatile double value_mul_tmp= value * tmp; - if (!dec_negative && my_isinf(tmp)) // "dec" is too large positive number + if (!dec_negative && std::isinf(tmp)) // "dec" is too large positive number return value; - if (dec_negative && my_isinf(tmp)) + if (dec_negative && std::isinf(tmp)) tmp2= 0.0; - else if (!dec_negative && my_isinf(value_mul_tmp)) + else if (!dec_negative && std::isinf(value_mul_tmp)) tmp2= value; else if (truncate) { diff --git a/sql/item_func.h b/sql/item_func.h index 1193daea106..496109b0e24 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -241,7 +241,7 @@ public: */ inline double check_float_overflow(double value) { - return isfinite(value) ? value : raise_float_overflow(); + return std::isfinite(value) ? value : raise_float_overflow(); } /** Throw an error if the input BIGINT value represented by the diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index dcfbd272809..8738af7ac56 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2655,7 +2655,7 @@ String *Item_func_format::val_str_ascii(String *str) return 0; /* purecov: inspected */ nr= my_double_round(nr, (longlong) dec, FALSE, FALSE); str->set_real(nr, dec, &my_charset_numeric); - if (!isfinite(nr)) + if (!std::isfinite(nr)) return str; str_length=str->length(); } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 5bed0d32009..06c01c58948 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1808,7 +1808,7 @@ double Item_sum_std::val_real() { DBUG_ASSERT(fixed == 1); double nr= Item_sum_variance::val_real(); - if (isnan(nr)) + if (std::isnan(nr)) { /* variance_fp_recurrence_next() can overflow in some cases and return "nan": @@ -1820,7 +1820,7 @@ double Item_sum_std::val_real() null_value= true; // Convert "nan" to NULL return 0; } - if (my_isinf(nr)) + if (std::isinf(nr)) return DBL_MAX; DBUG_ASSERT(nr >= 0.0); return sqrt(nr); diff --git a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c index 848a9881b20..f0238d06010 100644 --- a/storage/heap/hp_hash.c +++ b/storage/heap/hp_hash.c @@ -778,7 +778,6 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key, uchar *pos= (uchar*) rec + seg->start; DBUG_ASSERT(seg->type != HA_KEYTYPE_BIT); -#ifdef HAVE_ISNAN if (seg->type == HA_KEYTYPE_FLOAT) { float nr; @@ -802,7 +801,6 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key, continue; } } -#endif pos+= length; while (length--) { diff --git a/storage/innobase/gis/gis0geo.cc b/storage/innobase/gis/gis0geo.cc index bd601c2e19e..cad3877d3e9 100644 --- a/storage/innobase/gis/gis0geo.cc +++ b/storage/innobase/gis/gis0geo.cc @@ -367,7 +367,7 @@ mbr_join_square( /* Check if finite (not infinity or NaN), so we don't get NaN in calculations */ - if (!isfinite(square)) { + if (!std::isfinite(square)) { return DBL_MAX; } diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index a9c30ae2a38..ce1749820c3 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -1969,7 +1969,7 @@ rtr_estimate_n_rows_in_range( mtr_commit(&mtr); mem_heap_free(heap); - if (!isfinite(area)) { + if (!std::isfinite(area)) { return(HA_POS_ERROR); } diff --git a/storage/maria/ma_key.c b/storage/maria/ma_key.c index c9db47dd384..9e804a1e9dc 100644 --- a/storage/maria/ma_key.c +++ b/storage/maria/ma_key.c @@ -279,7 +279,6 @@ MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr, } else if (keyseg->flag & HA_SWAP_KEY) { /* Numerical column */ -#ifdef HAVE_ISNAN if (type == HA_KEYTYPE_FLOAT) { float nr; @@ -303,7 +302,6 @@ MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr, continue; } } -#endif pos+=length; while (length--) { diff --git a/storage/maria/ma_sp_key.c b/storage/maria/ma_sp_key.c index 0dc7fe1fe46..1a9abc989ed 100644 --- a/storage/maria/ma_sp_key.c +++ b/storage/maria/ma_sp_key.c @@ -77,7 +77,6 @@ MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr, DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE); val= mbr[start / sizeof (double)]; -#ifdef HAVE_ISNAN if (isnan(val)) { bzero(key, length); @@ -85,7 +84,6 @@ MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr, len+= length; continue; } -#endif if (keyseg->flag & HA_SWAP_KEY) { diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c index c81bc674685..9247fae9e3c 100644 --- a/storage/myisam/mi_key.c +++ b/storage/myisam/mi_key.c @@ -150,7 +150,6 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, } else if (keyseg->flag & HA_SWAP_KEY) { /* Numerical column */ -#ifdef HAVE_ISNAN if (type == HA_KEYTYPE_FLOAT) { float nr; @@ -174,7 +173,6 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, continue; } } -#endif pos+=length; while (length--) { diff --git a/storage/myisam/sp_key.c b/storage/myisam/sp_key.c index c3aeb7553f2..4c6ef75934e 100644 --- a/storage/myisam/sp_key.c +++ b/storage/myisam/sp_key.c @@ -66,7 +66,6 @@ uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE); val= mbr[start / sizeof (double)]; -#ifdef HAVE_ISNAN if (isnan(val)) { bzero(key, length); @@ -74,7 +73,6 @@ uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, len+= length; continue; } -#endif if (keyseg->flag & HA_SWAP_KEY) { From a14544260c33dcdb057d2f62c4aab33cb09ebcb1 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 15 Nov 2019 21:49:04 +0700 Subject: [PATCH 2/4] MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col row_log_table_get_pk_col(): read instant field value from instant alter table when it's required. --- .../suite/innodb/r/instant_alter_debug.result | 18 +++++++++++++ .../suite/innodb/t/instant_alter_debug.test | 26 +++++++++++++++++++ storage/innobase/row/row0log.cc | 4 +++ 3 files changed, 48 insertions(+) diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 62df17e066f..49365b6e9be 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -264,3 +264,21 @@ a b vb 5 NULL NULL DROP TABLE t1; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; +# +# MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col +# +CREATE TABLE t1 (a TEXT) ENGINE = InnoDB ROW_FORMAT=REDUNDANT; +INSERT INTO t1 (a) VALUES ('foo'); +ALTER TABLE t1 ADD COLUMN b INT DEFAULT 0,algorithm=instant; +connect con2,localhost,root,,test; +SET DEBUG_SYNC='innodb_inplace_alter_table_enter SIGNAL onlinealter WAIT_FOR update'; +ALTER TABLE t1 ADD PRIMARY KEY (b); +connection default; +SET DEBUG_SYNC='now WAIT_FOR onlinealter'; +UPDATE t1 SET b = 1; +SET DEBUG_SYNC='now SIGNAL update'; +connection con2; +connection default; +SET DEBUG_SYNC='RESET'; +disconnect con2; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index 5b8624a3186..cec7a05725b 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -293,3 +293,29 @@ SELECT * FROM t1; DROP TABLE t1; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; + +--echo # +--echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col +--echo # +CREATE TABLE t1 (a TEXT) ENGINE = InnoDB ROW_FORMAT=REDUNDANT; +INSERT INTO t1 (a) VALUES ('foo'); + +ALTER TABLE t1 ADD COLUMN b INT DEFAULT 0,algorithm=instant; + +--connect (con2,localhost,root,,test) +SET DEBUG_SYNC='innodb_inplace_alter_table_enter SIGNAL onlinealter WAIT_FOR update'; +--send +ALTER TABLE t1 ADD PRIMARY KEY (b); + +--connection default +SET DEBUG_SYNC='now WAIT_FOR onlinealter'; +UPDATE t1 SET b = 1; +SET DEBUG_SYNC='now SIGNAL update'; + +--connection con2 +--reap + +--connection default +SET DEBUG_SYNC='RESET'; +--disconnect con2 +DROP TABLE t1; diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 9b09b61e119..e2f6450e38d 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -1164,6 +1164,10 @@ row_log_table_get_pk_col( field = rec_get_nth_field(rec, offsets, i, &len); + if (len == UNIV_SQL_DEFAULT) { + field = log->instant_field_value(i, &len); + } + if (len == UNIV_SQL_NULL) { if (!log->allow_not_null) { return(DB_INVALID_NULL); From 0076dce2c89248b6c0252ec4385879194f9aadbf Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 22 Nov 2019 14:29:03 +0300 Subject: [PATCH 3/4] MDEV-18727 improve DML operation of System Versioning MDEV-18957 UPDATE with LIMIT clause is wrong for versioned partitioned tables UPDATE, DELETE: replace linear search of current/historical records with vers_setup_conds(). Additional DML cases in view.test --- mysql-test/suite/versioning/r/delete.result | 6 +- ...{truncate.result => delete_history.result} | 0 .../suite/versioning/r/partition.result | 17 ++++ mysql-test/suite/versioning/r/view.result | 78 +++++++++++++++++-- mysql-test/suite/versioning/t/delete.test | 10 +-- .../t/{truncate.test => delete_history.test} | 0 mysql-test/suite/versioning/t/partition.test | 14 ++++ mysql-test/suite/versioning/t/view.test | 47 +++++++++-- sql/ha_partition.cc | 2 +- sql/mysqld.h | 3 +- sql/sql_delete.cc | 65 ++++++---------- sql/sql_derived.cc | 10 +++ sql/sql_parse.cc | 7 +- sql/sql_select.cc | 47 +++++++++-- sql/sql_union.cc | 16 +++- sql/sql_update.cc | 28 ++++--- sql/sql_yacc.yy | 2 +- sql/table.cc | 2 + sql/table.h | 4 + 19 files changed, 271 insertions(+), 87 deletions(-) rename mysql-test/suite/versioning/r/{truncate.result => delete_history.result} (100%) rename mysql-test/suite/versioning/t/{truncate.test => delete_history.test} (100%) diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 77b7fc80286..26ade83acd7 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -1,3 +1,4 @@ +# Basic + delete from view create or replace table t1( XNo int unsigned, sys_start SYS_DATATYPE as row start invisible, @@ -44,6 +45,7 @@ XNo_vt1 5 drop view vt1; drop table t1; +# Check sys_start, sys_end create or replace table t1( x int, sys_start SYS_DATATYPE as row start invisible, @@ -59,6 +61,7 @@ select x = 1 as A, sys_start = @sys_start as B, sys_end > sys_start as C from t1 A B C 1 1 1 drop table t1; +# Multi-delete create or replace table t1( x int, y int, @@ -103,9 +106,6 @@ t2_x_all 14 drop table t1; drop table t2; -# Basic + delete from view -# Check sys_start, sys_end -# Multi-delete # Update + delete create or replace table t1 (x int) with system versioning; insert into t1 values (1); diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/delete_history.result similarity index 100% rename from mysql-test/suite/versioning/r/truncate.result rename to mysql-test/suite/versioning/r/delete_history.result diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 2163ebeb1a0..315413fbd7d 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -566,3 +566,20 @@ execute immediate 'select * from t1 for update'; pk drop view v1; drop tables t, t1, t2, t3, t4; +# +# MDEV-18957 UPDATE with LIMIT clause is wrong for versioned partitioned tables +# +create or replace table t1 ( +x int, +a varchar(255) +) with system versioning partition by system_time (partition p1 history, partition pn current); +insert into t1 (x) values (1), (2), (3), (4); +update t1 set a= 'foo' limit 3; +update t1 set a= 'bar' limit 4; +select * from t1; +x a +1 bar +2 bar +3 bar +4 bar +drop table t1; diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 850eba32c0d..8b23e87d6a4 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -64,13 +64,13 @@ select * from vt1; x 1 2 -# VIEW with parameters [#151] +# VIEW with parameters [tempesta-tech/mariadb#151] create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; show create view vt1; View Create View character_set_client collation_connection vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `c` from `t1` latin1 latin1_swedish_ci -# VIEW over JOIN of versioned tables [#153] +# VIEW over JOIN of versioned tables [tempesta-tech/mariadb#153] create or replace table t1 (a int) with system versioning; create or replace table t2 (b int) with system versioning; insert into t1 values (1); @@ -82,7 +82,7 @@ a b create or replace view vt12 as select * from t1 for system_time as of timestamp ('0-0-0') cross join t2; select * from vt12; a b -# VIEW improvements [#183] +# VIEW improvements [tempesta-tech/mariadb#183] create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; show create view vt1; @@ -96,12 +96,12 @@ create or replace view vt1 as select a, t2.row_end as endo from t3, t1, t2; show create view vt1; View Create View character_set_client collation_connection vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`row_end` AS `endo` from ((`t3` join `t1`) join `t2`) latin1 latin1_swedish_ci -# VIEW over UNION [#269] +# VIEW over UNION [tempesta-tech/mariadb#269] create or replace view vt1 as select * from t1 union select * from t1; select * from vt1; a 1 -# VIEW over UNION with non-versioned [#393] +# VIEW over UNION with non-versioned [tempesta-tech/mariadb#393] create or replace table t2 (a int); create or replace view vt1 as select * from t1 union select * from t2; select * from vt1; @@ -123,10 +123,10 @@ drop tables t1, t2; # # MDEV-15146 SQLError[4122]: View is not system versioned # -create table t1 (a int) with system versioning; +create or replace table t1 (a int) with system versioning; insert t1 values (1),(2); set @a=now(6); -create view v1 as select * from t1; +create or replace view v1 as select * from t1; delete from t1; select * from v1; a @@ -149,3 +149,67 @@ View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` FOR SYSTEM_TIME AS OF current_timestamp() - interval 6 second latin1 latin1_swedish_ci drop view v1, vt1, vt12; drop tables t1, t3; +# +# MDEV-18727 improve DML operation of System Versioning +# +create or replace table t1 ( +x int, +row_start SYS_DATATYPE as row start invisible, +row_end SYS_DATATYPE as row end invisible, +period for system_time (row_start, row_end) +) with system versioning; +insert into t1 values (1), (2); +create or replace view v1 as select * from t1 where x > 1; +update v1 set x= x + 1; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 CURRENT ROW +insert v1 values (4); +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 CURRENT ROW +4 CURRENT ROW +delete from v1 where x < 4; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 HISTORICAL ROW +4 CURRENT ROW +# multi-update +create or replace table t2 like t1; +insert into t2 values (1), (2); +create or replace view v2 as select * from t2 where x > 1; +update v1, v2 set v1.x= v1.x + 1, v2.x= v2.x + 1 where v1.x = v2.x + 2; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 HISTORICAL ROW +4 HISTORICAL ROW +5 CURRENT ROW +select *, check_row(row_start, row_end) from t2 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 CURRENT ROW +# multi-delete +delete v1, v2 from v1 join v2 where v1.x = v2.x + 2; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 HISTORICAL ROW +4 HISTORICAL ROW +5 HISTORICAL ROW +select *, check_row(row_start, row_end) from t2 for system_time all order by x; +x check_row(row_start, row_end) +1 CURRENT ROW +2 HISTORICAL ROW +3 HISTORICAL ROW +drop view v1, v2; +drop tables t1, t2; diff --git a/mysql-test/suite/versioning/t/delete.test b/mysql-test/suite/versioning/t/delete.test index b9045898bb0..4f1ba4b1d8e 100644 --- a/mysql-test/suite/versioning/t/delete.test +++ b/mysql-test/suite/versioning/t/delete.test @@ -1,6 +1,7 @@ source suite/versioning/engines.inc; source suite/versioning/common.inc; +--echo # Basic + delete from view replace_result $sys_datatype_expl SYS_DATATYPE; eval create or replace table t1( XNo int unsigned, @@ -31,7 +32,7 @@ select XNo as XNo_vt1 from vt1; drop view vt1; drop table t1; - +--echo # Check sys_start, sys_end replace_result $sys_datatype_expl SYS_DATATYPE; eval create or replace table t1( x int, @@ -47,6 +48,7 @@ select * from t1; select x = 1 as A, sys_start = @sys_start as B, sys_end > sys_start as C from t1 for system_time all; drop table t1; +--echo # Multi-delete replace_result $sys_datatype_expl SYS_DATATYPE; eval create or replace table t1( x int, @@ -69,12 +71,6 @@ select x as t2_x_all from t2 for system_time all; drop table t1; drop table t2; ---echo # Basic + delete from view - ---echo # Check sys_start, sys_end - ---echo # Multi-delete - --echo # Update + delete create or replace table t1 (x int) with system versioning; insert into t1 values (1); diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/delete_history.test similarity index 100% rename from mysql-test/suite/versioning/t/truncate.test rename to mysql-test/suite/versioning/t/delete_history.test diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index eca322d9ef4..ce8c2e5ec1a 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -517,4 +517,18 @@ execute immediate 'select * from t1 for update'; drop view v1; drop tables t, t1, t2, t3, t4; +--echo # +--echo # MDEV-18957 UPDATE with LIMIT clause is wrong for versioned partitioned tables +--echo # +create or replace table t1 ( + x int, + a varchar(255) +) with system versioning partition by system_time (partition p1 history, partition pn current); + +insert into t1 (x) values (1), (2), (3), (4); +update t1 set a= 'foo' limit 3; +update t1 set a= 'bar' limit 4; +select * from t1; +drop table t1; + --source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index 5a03a50f1d3..c05fbfd3866 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -52,13 +52,13 @@ prepare stmt from @tmp; execute stmt; drop prepare stmt; select * from vt1; ---echo # VIEW with parameters [#151] +--echo # VIEW with parameters [tempesta-tech/mariadb#151] create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; --replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT show create view vt1; ---echo # VIEW over JOIN of versioned tables [#153] +--echo # VIEW over JOIN of versioned tables [tempesta-tech/mariadb#153] create or replace table t1 (a int) with system versioning; create or replace table t2 (b int) with system versioning; insert into t1 values (1); @@ -68,7 +68,7 @@ select * from vt12; create or replace view vt12 as select * from t1 for system_time as of timestamp ('0-0-0') cross join t2; select * from vt12; ---echo # VIEW improvements [#183] +--echo # VIEW improvements [tempesta-tech/mariadb#183] create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; --replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT @@ -80,11 +80,11 @@ create or replace view vt1 as select a, t2.row_end as endo from t3, t1, t2; --replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT show create view vt1; ---echo # VIEW over UNION [#269] +--echo # VIEW over UNION [tempesta-tech/mariadb#269] create or replace view vt1 as select * from t1 union select * from t1; select * from vt1; ---echo # VIEW over UNION with non-versioned [#393] +--echo # VIEW over UNION with non-versioned [tempesta-tech/mariadb#393] create or replace table t2 (a int); create or replace view vt1 as select * from t1 union select * from t2; select * from vt1; @@ -104,10 +104,10 @@ drop tables t1, t2; --echo # --echo # MDEV-15146 SQLError[4122]: View is not system versioned --echo # -create table t1 (a int) with system versioning; +create or replace table t1 (a int) with system versioning; insert t1 values (1),(2); set @a=now(6); -create view v1 as select * from t1; +create or replace view v1 as select * from t1; delete from t1; select * from v1; select * from v1 for system_time as of @a; @@ -124,4 +124,37 @@ show create view v1; drop view v1, vt1, vt12; drop tables t1, t3; +--echo # +--echo # MDEV-18727 improve DML operation of System Versioning +--echo # +--replace_result $sys_datatype_expl SYS_DATATYPE +eval create or replace table t1 ( + x int, + row_start $sys_datatype_expl as row start invisible, + row_end $sys_datatype_expl as row end invisible, + period for system_time (row_start, row_end) +) with system versioning; +insert into t1 values (1), (2); +create or replace view v1 as select * from t1 where x > 1; +update v1 set x= x + 1; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +insert v1 values (4); +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +delete from v1 where x < 4; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +--echo # multi-update +create or replace table t2 like t1; +insert into t2 values (1), (2); +create or replace view v2 as select * from t2 where x > 1; +update v1, v2 set v1.x= v1.x + 1, v2.x= v2.x + 1 where v1.x = v2.x + 2; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +select *, check_row(row_start, row_end) from t2 for system_time all order by x; +--echo # multi-delete +delete v1, v2 from v1 join v2 where v1.x = v2.x + 2; +select *, check_row(row_start, row_end) from t1 for system_time all order by x; +select *, check_row(row_start, row_end) from t2 for system_time all order by x; + +drop view v1, v2; +drop tables t1, t2; + --source suite/versioning/common_finish.inc diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 232111d5a98..380fc48e915 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4538,7 +4538,7 @@ int ha_partition::delete_row(const uchar *buf) or last historical partition, but DELETE HISTORY can delete from any historical partition. So, skip the check in this case. */ - if (!thd->lex->vers_conditions.is_set()) // if not DELETE HISTORY + if (!thd->lex->vers_conditions.delete_history) { uint32 part_id; error= get_part_for_buf(buf, m_rec0, m_part_info, &part_id); diff --git a/sql/mysqld.h b/sql/mysqld.h index 11871155355..dc0641502ce 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -189,7 +189,8 @@ enum vers_system_time_t SYSTEM_TIME_AS_OF, SYSTEM_TIME_FROM_TO, SYSTEM_TIME_BETWEEN, - SYSTEM_TIME_BEFORE, + SYSTEM_TIME_BEFORE, // used for DELETE HISTORY ... BEFORE + SYSTEM_TIME_HISTORY, // used for DELETE HISTORY SYSTEM_TIME_ALL }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index e3d17174b8b..4245c843968 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -225,19 +225,11 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel, Explain_delete *explain, bool truncate_history) { - bool check_delete= true; - - if (table->versioned()) - { - bool historical= !table->vers_end_field()->is_max(); - check_delete= truncate_history ? historical : !historical; - } - explain->tracker.on_record_read(); thd->inc_examined_row_count(1); if (table->vfield) (void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE); - if (check_delete && (!sel || sel->skip_record(thd) > 0)) + if (!sel || sel->skip_record(thd) > 0) { explain->tracker.on_record_after_where(); return true; @@ -305,29 +297,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, THD_STAGE_INFO(thd, stage_init_update); - bool delete_history= table_list->vers_conditions.is_set(); - if (delete_history) - { - if (table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - DBUG_ASSERT(table_list->table); - - DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute()); - - // conds could be cached from previous SP call - if (!conds) - { - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - conds= table_list->on_expr; - table_list->on_expr= NULL; - } - } + const bool delete_history= table_list->vers_conditions.delete_history; if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT)) DBUG_RETURN(TRUE); @@ -940,16 +910,36 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, select_lex->leaf_tables, FALSE, DELETE_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(TRUE); - if (table_list->vers_conditions.is_set()) + + if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) { - if (table_list->is_view()) + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + +/* 10.4: + if (table_list->has_period()) + { + if (table_list->is_view_or_derived()) { my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); DBUG_RETURN(true); } - if (select_lex->vers_setup_conds(thd, table_list)) + + if (select_lex->period_setup_conds(thd, table_list)) DBUG_RETURN(true); } +*/ + + DBUG_ASSERT(table_list->table); + // conds could be cached from previous SP call + DBUG_ASSERT(!table_list->vers_conditions.is_set() || + !*conds || thd->stmt_arena->is_stmt_execute()); + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(TRUE); + + *conds= select_lex->where; + if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num, &select_lex->hidden_bit_fields)) || setup_fields(thd, Ref_ptr_array(), @@ -1238,11 +1228,6 @@ int multi_delete::send_data(List &values) if (table->status & (STATUS_NULL_ROW | STATUS_DELETED)) continue; - if (table->versioned() && !table->vers_end_field()->is_max()) - { - continue; - } - table->file->position(table->record[0]); found++; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 44ea6a18663..44595746614 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -689,7 +689,17 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) !(derived->is_multitable() && (thd->lex->sql_command == SQLCOM_UPDATE_MULTI || thd->lex->sql_command == SQLCOM_DELETE_MULTI)))) + { + /* + System versioned tables may still require to get versioning conditions + (when updating view). See vers_setup_conds(). + */ + if (!unit->prepared && + derived->table->versioned() && + (res= unit->prepare(derived, derived->derived_result, 0))) + goto exit; DBUG_RETURN(FALSE); + } /* prevent name resolving out of derived table */ for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a8e66d2a230..861d50e8872 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4710,8 +4710,10 @@ mysql_execute_command(THD *thd) { result= new (thd->mem_root) multi_delete(thd, aux_tables, lex->table_count); - if (unlikely(result)) + if (likely(result)) { + if (unlikely(select_lex->vers_setup_conds(thd, aux_tables))) + goto multi_delete_error; res= mysql_select(thd, select_lex->get_table_list(), select_lex->with_wild, @@ -4733,6 +4735,7 @@ mysql_execute_command(THD *thd) if (lex->describe || lex->analyze_stmt) res= thd->lex->explain->send_explain(thd); } + multi_delete_error: delete result; } } @@ -9483,7 +9486,7 @@ bool update_precheck(THD *thd, TABLE_LIST *tables) bool delete_precheck(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("delete_precheck"); - if (tables->vers_conditions.is_set()) + if (tables->vers_conditions.delete_history) { if (check_one_table_access(thd, DELETE_HISTORY_ACL, tables)) DBUG_RETURN(TRUE); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c7501e4fd1d..46e21822cc4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -677,6 +677,7 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) { vers_asof_timestamp_t &in= thd->variables.vers_asof_timestamp; type= (vers_system_time_t) in.type; + delete_history= false; start.unit= VERS_TIMESTAMP; if (type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL) { @@ -709,6 +710,7 @@ void vers_select_conds_t::print(String *str, enum_query_type query_type) const end.print(str, query_type, STRING_WITH_LEN(" AND ")); break; case SYSTEM_TIME_BEFORE: + case SYSTEM_TIME_HISTORY: DBUG_ASSERT(0); break; case SYSTEM_TIME_ALL: @@ -776,9 +778,22 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) } } + bool is_select= false; + switch (thd->lex->sql_command) + { + case SQLCOM_SELECT: + case SQLCOM_INSERT_SELECT: + case SQLCOM_REPLACE_SELECT: + case SQLCOM_DELETE_MULTI: + case SQLCOM_UPDATE_MULTI: + is_select= true; + default: + break; + } + for (table= tables; table; table= table->next_local) { - if (!table->table || !table->table->versioned()) + if (!table->table || table->is_view() || !table->table->versioned()) continue; vers_select_conds_t &vers_conditions= table->vers_conditions; @@ -808,7 +823,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) } // propagate system_time from sysvar - if (!vers_conditions.is_set()) + if (!vers_conditions.is_set() && is_select) { if (vers_conditions.init_from_sysvar(thd)) DBUG_RETURN(-1); @@ -834,7 +849,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) bool timestamps_only= table->table->versioned(VERS_TIMESTAMP); - if (vers_conditions.is_set()) + if (vers_conditions.is_set() && vers_conditions.type != SYSTEM_TIME_HISTORY) { thd->where= "FOR SYSTEM_TIME"; /* TODO: do resolve fix_length_and_dec(), fix_fields(). This requires @@ -861,10 +876,14 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) switch (vers_conditions.type) { case SYSTEM_TIME_UNSPECIFIED: + case SYSTEM_TIME_HISTORY: thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); max_time.second_part= TIME_MAX_SECOND_PART; curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS); - cond1= newx Item_func_eq(thd, row_end, curr); + if (vers_conditions.type == SYSTEM_TIME_UNSPECIFIED) + cond1= newx Item_func_eq(thd, row_end, curr); + else + cond1= newx Item_func_lt(thd, row_end, curr); break; case SYSTEM_TIME_AS_OF: cond1= newx Item_func_le(thd, row_start, point_in_time1); @@ -896,8 +915,12 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) switch (vers_conditions.type) { case SYSTEM_TIME_UNSPECIFIED: + case SYSTEM_TIME_HISTORY: curr= newx Item_int(thd, ULONGLONG_MAX); - cond1= newx Item_func_eq(thd, row_end, curr); + if (vers_conditions.type == SYSTEM_TIME_UNSPECIFIED) + cond1= newx Item_func_eq(thd, row_end, curr); + else + cond1= newx Item_func_lt(thd, row_end, curr); break; case SYSTEM_TIME_AS_OF: trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP @@ -938,7 +961,19 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) { cond1= and_items(thd, cond2, cond1); cond1= and_items(thd, cond3, cond1); - table->on_expr= and_items(thd, table->on_expr, cond1); + if (is_select) + table->on_expr= and_items(thd, table->on_expr, cond1); + else + { + if (join) + { + where= and_items(thd, join->conds, cond1); + join->conds= where; + } + else + where= and_items(thd, where, cond1); + table->where= and_items(thd, table->where, cond1); + } } table->vers_conditions.type= SYSTEM_TIME_ALL; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index c119f1e0116..b71b62b35ed 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -976,9 +976,21 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg, if (sl->tvc->prepare(thd, sl, tmp_result, this)) goto err; } - else if (prepare_join(thd, first_sl, tmp_result, additional_options, + else + { + if (prepare_join(thd, first_sl, tmp_result, additional_options, is_union_select)) - goto err; + goto err; + + if (derived_arg && derived_arg->table && + derived_arg->derived_type == VIEW_ALGORITHM_MERGE && + derived_arg->table->versioned()) + { + /* Got versioning conditions (see vers_setup_conds()), need to update + derived_arg. */ + derived_arg->where= first_sl->where; + } + } types= first_sl->item_list; goto cont; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 32adc4420b3..39d28bfbe50 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -878,11 +878,6 @@ update_begin: THD_STAGE_INFO(thd, stage_updating); while (!(error=info.read_record()) && !thd->killed) { - if (table->versioned() && !table->vers_end_field()->is_max()) - { - continue; - } - explain->tracker.on_record_read(); thd->inc_examined_row_count(1); if (!select || select->skip_record(thd) > 0) @@ -1266,6 +1261,21 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, thd->lex->allow_sum_func.clear_all(); +/* 10.4: + if (table_list->has_period() && + select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); +*/ + + DBUG_ASSERT(table_list->table); + // conds could be cached from previous SP call + DBUG_ASSERT(!table_list->vers_conditions.is_set() || + !*conds || thd->stmt_arena->is_stmt_execute()); + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(TRUE); + + *conds= select_lex->where; + /* We do not call DT_MERGE_FOR_INSERT because it has no sense for simple (not multi-) update @@ -1786,6 +1796,9 @@ bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, thd->abort_on_warning= !ignore && thd->is_strict_mode(); List total_list; + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(1); + res= mysql_select(thd, table_list, select_lex->with_wild, total_list, conds, select_lex->order_list.elements, @@ -2345,11 +2358,6 @@ int multi_update::send_data(List ¬_used_values) if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) continue; - if (table->versioned() && !table->vers_end_field()->is_max()) - { - continue; - } - if (table == table_to_update) { /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 235be9b0f89..bddbec26d67 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13785,7 +13785,7 @@ delete: opt_delete_system_time: /* empty */ { - Lex->vers_conditions.init(SYSTEM_TIME_ALL); + Lex->vers_conditions.init(SYSTEM_TIME_HISTORY); } | BEFORE_SYM SYSTEM_TIME_SYM history_point { diff --git a/sql/table.cc b/sql/table.cc index 278423ec0c2..e008e6a3ded 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9172,6 +9172,8 @@ bool vers_select_conds_t::eq(const vers_select_conds_t &conds) const return true; case SYSTEM_TIME_BEFORE: break; + case SYSTEM_TIME_HISTORY: + break; case SYSTEM_TIME_AS_OF: return start.eq(conds.start); case SYSTEM_TIME_FROM_TO: diff --git a/sql/table.h b/sql/table.h index bec0fdd10ba..1dda70ae0da 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1863,6 +1863,7 @@ struct vers_select_conds_t { vers_system_time_t type; bool used:1; + bool delete_history:1; Vers_history_point start; Vers_history_point end; @@ -1870,6 +1871,7 @@ struct vers_select_conds_t { type= SYSTEM_TIME_UNSPECIFIED; used= false; + delete_history= false; start.empty(); end.empty(); } @@ -1880,6 +1882,8 @@ struct vers_select_conds_t { type= _type; used= false; + delete_history= (type == SYSTEM_TIME_HISTORY || + type == SYSTEM_TIME_BEFORE); start= _start; end= _end; } From 1d5f6a007339ce78471c125a9a5d5a73a5c664ff Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 22 Nov 2019 14:30:13 +0300 Subject: [PATCH 4/4] MDEV-21049 Segfault in create federatedx table with empty hostname Use my_localhost instead of NULL for share->hostname. --- mysql-test/suite/federated/federatedx.result | 16 +++++++++++++++ mysql-test/suite/federated/federatedx.test | 21 ++++++++++++++++++++ storage/federatedx/ha_federatedx.cc | 7 +++---- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/federated/federatedx.result b/mysql-test/suite/federated/federatedx.result index 84dcb0d0a8c..8345f56dba9 100644 --- a/mysql-test/suite/federated/federatedx.result +++ b/mysql-test/suite/federated/federatedx.result @@ -2283,6 +2283,22 @@ connection default; connection master; CREATE TABLE t1 (a INT) ENGINE=FEDERATED CONNECTION='mysql://@127.0.0.1:SLAVE_PORT/federated/t1'; ERROR HY000: Can't create federated table. Foreign data src error: database: 'federated' username: '' hostname: '127.0.0.1' +# +# MDEV-21049 Segfault in create federatedx table with empty hostname +# +connection master; +CREATE TABLE federated.t1 (x int) ENGINE=FEDERATED +CONNECTION='mysql://root@:SLAVE_PORT/federated/t1'; +ERROR HY000: Can't create federated table. Foreign data src error: database: 'federated' username: 'root' hostname: 'localhost' +connection slave; +CREATE TABLE federated.t1(x int); +connection master; +CREATE TABLE federated.t1 (x int) ENGINE=FEDERATED +CONNECTION='mysql://root@:SLAVE_PORT/federated/t1'; +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.t1; +connection default; connection master; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/suite/federated/federatedx.test b/mysql-test/suite/federated/federatedx.test index 29d1eaddc26..fcc0178c024 100644 --- a/mysql-test/suite/federated/federatedx.test +++ b/mysql-test/suite/federated/federatedx.test @@ -2010,4 +2010,25 @@ connection master; --error ER_CANT_CREATE_FEDERATED_TABLE eval CREATE TABLE t1 (a INT) ENGINE=FEDERATED CONNECTION='mysql://@127.0.0.1:$SLAVE_MYPORT/federated/t1'; +--echo # +--echo # MDEV-21049 Segfault in create federatedx table with empty hostname +--echo # +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +--error ER_CANT_CREATE_FEDERATED_TABLE +eval CREATE TABLE federated.t1 (x int) ENGINE=FEDERATED + CONNECTION='mysql://root@:$SLAVE_MYPORT/federated/t1'; + +connection slave; +CREATE TABLE federated.t1(x int); +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 (x int) ENGINE=FEDERATED + CONNECTION='mysql://root@:$SLAVE_MYPORT/federated/t1'; + +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.t1; +connection default; + source include/federated_cleanup.inc; diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc index 74d547cb674..4a717eead20 100644 --- a/storage/federatedx/ha_federatedx.cc +++ b/storage/federatedx/ha_federatedx.cc @@ -798,12 +798,12 @@ static int parse_url(MEM_ROOT *mem_root, FEDERATEDX_SHARE *share, goto error; if (share->hostname[0] == '\0') - share->hostname= NULL; + share->hostname= strdup_root(mem_root, my_localhost); } if (!share->port) { - if (!share->hostname || strcmp(share->hostname, my_localhost) == 0) + if (0 == strcmp(share->hostname, my_localhost)) share->socket= (char *) MYSQL_UNIX_ADDR; else share->port= MYSQL_PORT; @@ -3385,8 +3385,7 @@ int ha_federatedx::create(const char *name, TABLE *table_arg, goto error; /* loopback socket connections hang due to LOCK_open mutex */ - if ((!tmp_share.hostname || !strcmp(tmp_share.hostname,my_localhost)) && - !tmp_share.port) + if (0 == strcmp(tmp_share.hostname, my_localhost) && !tmp_share.port) goto error; /*