From bf58ec77a1adaa653a0b044b950cf420f8c19de9 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 25 Nov 2019 15:44:46 +0300 Subject: [PATCH 01/13] MDEV-18727 cleanup --- sql/sql_delete.cc | 14 -------------- sql/sql_update.cc | 6 ------ 2 files changed, 20 deletions(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 4245c8439686f..78bccd7a5069c 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -917,20 +917,6 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, 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->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() || diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 39d28bfbe50bd..1e5440ee4fef4 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1261,12 +1261,6 @@ 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() || From 3fc1f6260f137790f83865a534cded00a18b3274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 27 Nov 2019 14:00:01 +0200 Subject: [PATCH 02/13] MDEV-21158 trx_undo_seg_free() is never redo-logged As part of commit 3c09f148f362a587ac3267c31fd17da5f71a0b11 trx_undo_commit_cleanup() was always invoked with noredo=true. The impact of this should be that some undo log pages may not be correctly freed if the server is killed and crash recovery will be performed. Similarly, if mariabackup --backup is being executed concurrently with user transaction commits, it could happen that some undo log pages in the backup will never be marked as free for reuse. It seems that this bug should not have any user-visible impact other than some undo pages being wasted. --- storage/innobase/trx/trx0undo.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 7a0accf889f40..2c061965e3487 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2018, MariaDB Corporation. +Copyright (c) 2014, 2019, 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 the Free Software @@ -1607,7 +1607,7 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp) /* Delete first the undo log segment in the file */ mutex_exit(&rseg->mutex); - trx_undo_seg_free(undo, true); + trx_undo_seg_free(undo, is_temp); mutex_enter(&rseg->mutex); ut_ad(rseg->curr_size > undo->size); From 584ffa02f1bef6931b3feb78559841ffe9c8600f Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 27 Nov 2019 20:44:14 +0100 Subject: [PATCH 03/13] MDEV-19669 - fix matching CIDR address for proxy protocol. Prior to this fix, when matching addresses using mask, extra bits could be used for comparison, e.g to match with "a.b.c.d/24" , 27 bits were compared rather than 24. The patch fixes the calculation. --- sql/proxy_protocol.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc index b54af6194874f..550813c645763 100644 --- a/sql/proxy_protocol.cc +++ b/sql/proxy_protocol.cc @@ -470,7 +470,7 @@ static int compare_bits(const void *s1, const void *s2, int bit_count) int byte_count= bit_count / 8; if (byte_count && (result= memcmp(s1, s2, byte_count))) return result; - int rem= byte_count % 8; + int rem= bit_count % 8; if (rem) { // compare remaining bits i.e partial bytes. From ba95c303e379b9f23289aaaffe18fb5d49ddf4a3 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 25 Nov 2019 22:48:50 +0100 Subject: [PATCH 04/13] MDEV-21167 LF_PINS::stack_ends_here inaccurate, leading to alloca() larger than stack Use my_thread_var::stack_ends_here inside lf_pinbox_real_free() for address where thread stack ends. Remove LF_PINS::stack_ends_here. It is not safe to assume that mysys_var that was used during pin allocation, remains correct during free. E.g with binlog group commit in Innodb, that frees pins for multiple Innodb transactions, it does not work correctly. --- include/lf.h | 1 - mysys/lf_alloc-pin.c | 14 +++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/lf.h b/include/lf.h index e4cad7eabb392..10a60c5c949d8 100644 --- a/include/lf.h +++ b/include/lf.h @@ -65,7 +65,6 @@ typedef struct { typedef struct { void * volatile pin[LF_PINBOX_PINS]; LF_PINBOX *pinbox; - void **stack_ends_here; void *purgatory; uint32 purgatory_count; uint32 volatile link; diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index 2a0ee7fddf96e..b98684556c37e 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -151,7 +151,6 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox) */ LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox) { - struct st_my_thread_var *var; uint32 pins, next, top_ver; LF_PINS *el; /* @@ -194,12 +193,7 @@ LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox) el->link= pins; el->purgatory_count= 0; el->pinbox= pinbox; - var= my_thread_var; - /* - Threads that do not call my_thread_init() should still be - able to use the LF_HASH. - */ - el->stack_ends_here= (var ? & var->stack_ends_here : NULL); + return el; } @@ -335,16 +329,18 @@ static void lf_pinbox_real_free(LF_PINS *pins) void *list; void **addr= NULL; void *first= NULL, *last= NULL; + struct st_my_thread_var *var= my_thread_var; + void *stack_ends_here= var ? var->stack_ends_here : NULL; LF_PINBOX *pinbox= pins->pinbox; npins= pinbox->pins_in_array+1; #ifdef HAVE_ALLOCA - if (pins->stack_ends_here != NULL) + if (stack_ends_here != NULL) { int alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins; /* create a sorted list of pinned addresses, to speed up searches */ - if (available_stack_size(&pinbox, *pins->stack_ends_here) > + if (available_stack_size(&pinbox, stack_ends_here) > alloca_size + ALLOCA_SAFETY_MARGIN) { struct st_harvester hv; From dc7d0b503025a6e716a60f2919c4b3686ea54da1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 27 Nov 2019 18:55:14 +0100 Subject: [PATCH 05/13] RPM packaging fixes for FC31 Obsoletes: cannot contain (x86-64) anymore Python shebang must be specific --- cmake/cpack_rpm.cmake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 2d1103ce31c19..6f0166857bca8 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -195,7 +195,7 @@ MACRO(ALTERNATIVE_NAME real alt) SET(p "CPACK_RPM_${real}_PACKAGE_PROVIDES") SET(${p} "${${p}} ${alt} = ${ver} ${alt}%{?_isa} = ${ver} config(${alt}) = ${ver}") SET(o "CPACK_RPM_${real}_PACKAGE_OBSOLETES") - SET(${o} "${${o}} ${alt} ${alt}%{?_isa}") + SET(${o} "${${o}} ${alt}") ENDMACRO(ALTERNATIVE_NAME) ALTERNATIVE_NAME("devel" "mysql-devel") @@ -215,8 +215,9 @@ ELSEIF(RPM MATCHES "fedora" OR RPM MATCHES "(rhel|centos)7") ALTERNATIVE_NAME("server" "mariadb-server") ALTERNATIVE_NAME("server" "mysql-compat-server") ALTERNATIVE_NAME("test" "mariadb-test") -ELSEIF(RPM MATCHES "(rhel|centos)8") - SET(PYTHON_SHEBANG "/usr/bin/python3") +ENDIF() +IF(RPM MATCHES "fedora31" OR RPM MATCHES "(rhel|centos)8") + SET(PYTHON_SHEBANG "/usr/bin/python3" CACHE STRING "python shebang") ENDIF() # If we want to build build MariaDB-shared-compat, @@ -249,6 +250,7 @@ IF(compat53 AND compat101) STRING(REPLACE "\n" " " compat_provides "${compat_provides}") STRING(REPLACE "\n" " " compat_obsoletes "${compat_obsoletes}") + STRING(REGEX REPLACE "[^ ]+\\([^ ]+ *" "" compat_obsoletes "${compat_obsoletes}") SETA(CPACK_RPM_compat_PACKAGE_PROVIDES "${compat_provides}") SETA(CPACK_RPM_compat_PACKAGE_OBSOLETES "${compat_obsoletes}") From 0d345ec2e358ec8f42865be9a17e6f007585931d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 28 Nov 2019 14:01:46 +0100 Subject: [PATCH 06/13] Fix upgrade errors on eoan mariadb packages conflict with mysql-8.0 --- debian/control | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/control b/debian/control index 8896f4d1dcdfe..916b403b33b75 100644 --- a/debian/control +++ b/debian/control @@ -259,6 +259,7 @@ Conflicts: mariadb-client-10.0, mysql-client-core-5.5, mysql-client-core-5.6, mysql-client-core-5.7, + mysql-client-core-8.0, virtual-mysql-client-core Replaces: mariadb-client-10.0, mariadb-client-10.1, @@ -282,6 +283,7 @@ Replaces: mariadb-client-10.0, mysql-client-core-5.5, mysql-client-core-5.6, mysql-client-core-5.7, + mysql-client-core-8.0, virtual-mysql-client-core Provides: default-mysql-client-core, mysql-client-core, @@ -320,6 +322,7 @@ Conflicts: mariadb-client (<< ${source:Version}), mysql-client-5.5, mysql-client-5.6, mysql-client-5.7, + mysql-client-8.0, virtual-mysql-client Replaces: mariadb-client (<< ${source:Version}), mariadb-client-10.0, @@ -335,6 +338,7 @@ Replaces: mariadb-client (<< ${source:Version}), mysql-client-5.5, mysql-client-5.6, mysql-client-5.7, + mysql-client-8.0, virtual-mysql-client Provides: default-mysql-client, mysql-client, @@ -373,6 +377,7 @@ Conflicts: mariadb-server-core-10.0, mysql-server-core-5.5, mysql-server-core-5.6, mysql-server-core-5.7, + mysql-server-core-8.0, virtual-mysql-server-core Breaks: mariadb-client-10.0, mariadb-client-10.1, @@ -397,6 +402,7 @@ Replaces: mariadb-client-10.0, mysql-server-core-5.5, mysql-server-core-5.6, mysql-server-core-5.7, + mysql-server-core-8.0, virtual-mysql-server-core Provides: default-mysql-server-core, mysql-server-core, @@ -457,6 +463,7 @@ Conflicts: mariadb-server (<< ${source:Version}), mysql-server-5.5, mysql-server-5.6, mysql-server-5.7, + mysql-server-8.0, virtual-mysql-server Replaces: libmariadbclient-dev (<< 5.5.0), libmariadbclient16 (<< 5.3.4), @@ -479,6 +486,7 @@ Replaces: libmariadbclient-dev (<< 5.5.0), mysql-server-5.5, mysql-server-5.6, mysql-server-5.7, + mysql-server-8.0, virtual-mysql-server Provides: default-mysql-server, virtual-mysql-server @@ -724,6 +732,7 @@ Breaks: mariadb-server-5.5, mysql-testsuite-5.5, mysql-testsuite-5.6, mysql-testsuite-5.7, + mysql-testsuite-8.0, virtual-mysql-testsuite Replaces: mariadb-server-5.5, mariadb-test-10.0, @@ -734,6 +743,7 @@ Replaces: mariadb-server-5.5, mysql-testsuite-5.5, mysql-testsuite-5.6, mysql-testsuite-5.7, + mysql-testsuite-8.0, virtual-mysql-testsuite Provides: virtual-mysql-testsuite Suggests: patch From 95898ac9bdcfc3973a401be781a4d17d0aa14576 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 29 Nov 2019 09:07:24 +0100 Subject: [PATCH 07/13] Revert "Fix upgrade errors on eoan" This reverts commit 0d345ec2e358ec8f42865be9a17e6f007585931d. Upgrades from 8.0 don't work yet, one has to dump/restore manually to get the metadata out of the data dictionary. --- debian/control | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/debian/control b/debian/control index 916b403b33b75..8896f4d1dcdfe 100644 --- a/debian/control +++ b/debian/control @@ -259,7 +259,6 @@ Conflicts: mariadb-client-10.0, mysql-client-core-5.5, mysql-client-core-5.6, mysql-client-core-5.7, - mysql-client-core-8.0, virtual-mysql-client-core Replaces: mariadb-client-10.0, mariadb-client-10.1, @@ -283,7 +282,6 @@ Replaces: mariadb-client-10.0, mysql-client-core-5.5, mysql-client-core-5.6, mysql-client-core-5.7, - mysql-client-core-8.0, virtual-mysql-client-core Provides: default-mysql-client-core, mysql-client-core, @@ -322,7 +320,6 @@ Conflicts: mariadb-client (<< ${source:Version}), mysql-client-5.5, mysql-client-5.6, mysql-client-5.7, - mysql-client-8.0, virtual-mysql-client Replaces: mariadb-client (<< ${source:Version}), mariadb-client-10.0, @@ -338,7 +335,6 @@ Replaces: mariadb-client (<< ${source:Version}), mysql-client-5.5, mysql-client-5.6, mysql-client-5.7, - mysql-client-8.0, virtual-mysql-client Provides: default-mysql-client, mysql-client, @@ -377,7 +373,6 @@ Conflicts: mariadb-server-core-10.0, mysql-server-core-5.5, mysql-server-core-5.6, mysql-server-core-5.7, - mysql-server-core-8.0, virtual-mysql-server-core Breaks: mariadb-client-10.0, mariadb-client-10.1, @@ -402,7 +397,6 @@ Replaces: mariadb-client-10.0, mysql-server-core-5.5, mysql-server-core-5.6, mysql-server-core-5.7, - mysql-server-core-8.0, virtual-mysql-server-core Provides: default-mysql-server-core, mysql-server-core, @@ -463,7 +457,6 @@ Conflicts: mariadb-server (<< ${source:Version}), mysql-server-5.5, mysql-server-5.6, mysql-server-5.7, - mysql-server-8.0, virtual-mysql-server Replaces: libmariadbclient-dev (<< 5.5.0), libmariadbclient16 (<< 5.3.4), @@ -486,7 +479,6 @@ Replaces: libmariadbclient-dev (<< 5.5.0), mysql-server-5.5, mysql-server-5.6, mysql-server-5.7, - mysql-server-8.0, virtual-mysql-server Provides: default-mysql-server, virtual-mysql-server @@ -732,7 +724,6 @@ Breaks: mariadb-server-5.5, mysql-testsuite-5.5, mysql-testsuite-5.6, mysql-testsuite-5.7, - mysql-testsuite-8.0, virtual-mysql-testsuite Replaces: mariadb-server-5.5, mariadb-test-10.0, @@ -743,7 +734,6 @@ Replaces: mariadb-server-5.5, mysql-testsuite-5.5, mysql-testsuite-5.6, mysql-testsuite-5.7, - mysql-testsuite-8.0, virtual-mysql-testsuite Provides: virtual-mysql-testsuite Suggests: patch From 57cab7cd5114d3ef47203118cddd3ad0a22f2861 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 27 Nov 2019 14:36:21 +0100 Subject: [PATCH 08/13] fix ssl_crl test failures on newer OpenSSL generalize the replacement --- mysql-test/main/ssl_crl.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/ssl_crl.test b/mysql-test/main/ssl_crl.test index dc30a9b593440..e79f8ff32c2fa 100644 --- a/mysql-test/main/ssl_crl.test +++ b/mysql-test/main/ssl_crl.test @@ -7,7 +7,7 @@ --exec $MYSQL --ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem --ssl-key=$MYSQL_TEST_DIR/std_data/server-new-key.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/server-new-cert.pem test -e "SHOW STATUS LIKE 'Ssl_version'" --echo # try logging in with a certificate in the server's --ssl-crl : should fail -# OpenSSL 1.1.1a correctly rejects the certificate, but the error message is wrong ---replace_result "ERROR 2013 (HY000): Lost connection to MySQL server at 'reading authorization packet', system error: 0" "ERROR 2026 (HY000): SSL connection error: sslv3 alert certificate revoked" +# OpenSSL 1.1.1a correctly rejects the certificate, but the error message is different +--replace_regex /ERROR 2013 \(HY000\): Lost connection to MySQL server at '.*', system error: [0-9]+/ERROR 2026 (HY000): SSL connection error: sslv3 alert certificate revoked/ --error 1 --exec $MYSQL --ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem --ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem --ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem test -e "SHOW STATUS LIKE 'Ssl_version'" 2>&1 From 498a96a4789e58549ce87b5843e804e055ab327f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 2 Dec 2019 11:48:37 +0300 Subject: [PATCH 09/13] MDEV-20441 ER_CRASHED_ON_USAGE upon update on versioned Aria table Turn read cache off for update and multi-update for versioned table. no_cache is reinited on each TABLE open because it is applicable for specific algorithms. As a side fix vers_insert_history_row() honors vers_write setting. Aria with row_format=fixed uses IO_CACHE of type READ_CACHE for sequential read in update loop. When history row is inserted inside this loop the cache misses it and fails with error. TODO: Currently maria_extra() does not support SEQ_READ_APPEND. Probably it might be possible to use this type of cache. --- mysql-test/suite/versioning/r/update.result | 9 +++++++++ mysql-test/suite/versioning/t/update.test | 12 +++++++++++- sql/sql_insert.cc | 2 ++ sql/sql_update.cc | 15 +++++++++------ sql/table.cc | 1 + sql/table.h | 11 ++++++++++- storage/maria/ma_check.c | 2 +- 7 files changed, 43 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index eaa8549b38aaf..08b105e952b84 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -276,3 +276,12 @@ update t1 set a= '2012-12-12'; update v set a= '2000-01-01' order by b limit 1; drop view v; drop table t1, t2; +# +# MDEV-20441 ER_CRASHED_ON_USAGE upon update on versioned Aria table +# +create or replace table t1 (a varchar(8)) +engine=aria row_format=fixed +with system versioning; +insert into t1 (a) values ('foo'); +update t1 set a = 'bar'; +drop table t1; diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index e41c7d15995f7..148cbbdc7074e 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -157,7 +157,6 @@ replace t1 values (1,2),(1,3),(2,4); --echo # --echo # MDEV-14829 Assertion `0' failed in Protocol::end_statement upon concurrent UPDATE --echo # - create or replace table t1 (pk int, a char(3), b char(3), primary key(pk)) engine=innodb with system versioning; @@ -192,4 +191,15 @@ drop view v; drop table t1, t2; --enable_warnings +--echo # +--echo # MDEV-20441 ER_CRASHED_ON_USAGE upon update on versioned Aria table +--echo # +create or replace table t1 (a varchar(8)) +engine=aria row_format=fixed +with system versioning; + +insert into t1 (a) values ('foo'); +update t1 set a = 'bar'; +drop table t1; + source suite/versioning/common_finish.inc; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 334b6b2d667a2..e747b645e9dfa 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1646,6 +1646,8 @@ static int last_uniq_key(TABLE *table,uint keynr) int vers_insert_history_row(TABLE *table) { DBUG_ASSERT(table->versioned(VERS_TIMESTAMP)); + if (!table->vers_write) + return 0; restore_record(table,record[1]); // Set Sys_end to now() diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 1e5440ee4fef4..d3b771acdad2b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -184,10 +184,10 @@ static bool check_fields(THD *thd, List &items, bool update_view) return FALSE; } -static bool check_has_vers_fields(TABLE *table, List &items) +bool TABLE::vers_check_update(List &items) { List_iterator it(items); - if (!table->versioned()) + if (!versioned_write()) return false; while (Item *item= it++) @@ -195,8 +195,11 @@ static bool check_has_vers_fields(TABLE *table, List &items) if (Item_field *item_field= item->field_for_view_update()) { Field *field= item_field->field; - if (field->table == table && !field->vers_update_unversioned()) + if (field->table == this && !field->vers_update_unversioned()) + { + no_cache= true; return true; + } } } return false; @@ -415,7 +418,7 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); } - bool has_vers_fields= check_has_vers_fields(table, fields); + bool has_vers_fields= table->vers_check_update(fields); if (check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "UPDATE"); @@ -2133,7 +2136,7 @@ multi_update::initialize_tables(JOIN *join) if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables)) { table_to_update= table; // Update table on the fly - has_vers_fields= check_has_vers_fields(table, *fields); + has_vers_fields= table->vers_check_update(*fields); continue; } } @@ -2609,7 +2612,7 @@ int multi_update::do_updates() if (table->vfield) empty_record(table); - has_vers_fields= check_has_vers_fields(table, *fields); + has_vers_fields= table->vers_check_update(*fields); check_opt_it.rewind(); while(TABLE *tbl= check_opt_it++) diff --git a/sql/table.cc b/sql/table.cc index e008e6a3ded2b..291418f55fe7e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4688,6 +4688,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) cond_selectivity_sampling_explain= NULL; vers_write= s->versioned; quick_condition_rows=0; + no_cache= false; initialize_quick_structures(); #ifdef HAVE_REPLICATION /* used in RBR Triggers */ diff --git a/sql/table.h b/sql/table.h index 1dda70ae0da1b..ca5565250deed 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1536,8 +1536,15 @@ struct TABLE return s->versioned == type; } - bool versioned_write(vers_sys_type_t type= VERS_UNDEFINED) const + bool versioned_write() const { + DBUG_ASSERT(versioned() || !vers_write); + return versioned() ? vers_write : false; + } + + bool versioned_write(vers_sys_type_t type) const + { + DBUG_ASSERT(type); DBUG_ASSERT(versioned() || !vers_write); return versioned(type) ? vers_write : false; } @@ -1557,6 +1564,8 @@ struct TABLE ulonglong vers_start_id() const; ulonglong vers_end_id() const; + bool vers_check_update(List &items); + int delete_row(); void vers_update_fields(); void vers_update_end(); diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index eadac5b04ebfa..101c33b7802a3 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -6183,7 +6183,7 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) } - /* write suffix to data file if neaded */ +/* Write suffix to data file if needed */ int maria_write_data_suffix(MARIA_SORT_INFO *sort_info, my_bool fix_datafile) { From 97aa07abf544870faa0956784f33f158b092b2e5 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 2 Dec 2019 11:48:37 +0300 Subject: [PATCH 10/13] MDEV-21147 Assertion `marked_for_read()' upon UPDATE on versioned table via view "write set" for replication finally got its correct place (mark_columns_per_binlog_row_image()). When done generally in mark_columns_needed_for_update() it affects optimization algorithm. used_key_is_modified, query_plan.using_io_buffer are wrongly set and that leads to wrong prepare_for_keyread() which limits read_set. --- mysql-test/suite/versioning/r/update.result | 12 ++++++++++++ mysql-test/suite/versioning/t/update.test | 16 ++++++++++++++++ sql/table.cc | 16 ++++++++++------ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 08b105e952b84..64aa7c7068cf3 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -285,3 +285,15 @@ with system versioning; insert into t1 (a) values ('foo'); update t1 set a = 'bar'; drop table t1; +# +# MDEV-21147 Assertion `marked_for_read()' upon UPDATE on versioned table via view +# +create or replace table t1 ( +pk int, a char(8), b char(8), +primary key (pk) +) with system versioning; +create or replace view v1 as select * from t1; +insert into t1 values (1, null, 'd') , (2, null, 'i') ; +update v1 set a= null where b = ''; +drop view v1; +drop table t1; diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index 148cbbdc7074e..baf3c1ec8767f 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -202,4 +202,20 @@ insert into t1 (a) values ('foo'); update t1 set a = 'bar'; drop table t1; +--echo # +--echo # MDEV-21147 Assertion `marked_for_read()' upon UPDATE on versioned table via view +--echo # +create or replace table t1 ( + pk int, a char(8), b char(8), + primary key (pk) +) with system versioning; + +create or replace view v1 as select * from t1; +insert into t1 values (1, null, 'd') , (2, null, 'i') ; +update v1 set a= null where b = ''; + +# cleanup +drop view v1; +drop table t1; + source suite/versioning/common_finish.inc; diff --git a/sql/table.cc b/sql/table.cc index 291418f55fe7e..cbf26031658d8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6613,12 +6613,8 @@ void TABLE::mark_columns_needed_for_update() /* For System Versioning we have to read all columns since we store a copy of previous row with modified row_end back to a table. - - Without write_set versioning.rpl,row is unstable until MDEV-16370 is - applied. */ bitmap_union(read_set, &s->all_set); - bitmap_union(write_set, &s->all_set); need_signal= true; } if (check_constraints) @@ -6781,8 +6777,16 @@ void TABLE::mark_columns_per_binlog_row_image() binary log will include all columns read anyway. */ mark_columns_used_by_index_no_reset(s->primary_key, read_set); - /* Only write columns that have changed */ - rpl_write_set= write_set; + if (versioned()) + { + // TODO: After MDEV-18432 we don't pass history rows, so remove this: + rpl_write_set= &s->all_set; + } + else + { + /* Only write columns that have changed */ + rpl_write_set= write_set; + } break; default: From 6dd41e008eb2e384913d970e79aa01cd886891ec Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 2 Dec 2019 11:48:37 +0300 Subject: [PATCH 11/13] MDEV-21155 Assertion with versioned table upon DELETE from view of view after replacing first view When view is merged by DT_MERGE_FOR_INSERT it is then skipped from processing and doesn't update WHERE clause with vers_setup_conds(). Note that view itself cannot work in vers_setup_conds() because it doesn't have row_start, row_end fields. Thus it is required to descend down to material TABLE_LIST through calls of mysql_derived_prepare() and run vers_setup_conds() from there. Luckily, all views (views of views, views of views of views, etc.) are linked in one list through next_global pointer, so we can skip all views of views and get straight to non-view TABLE_LIST by checking its merge_underlying_list property for zero value (it is assigned by DT_MERGE_FOR_INSERT for merged derived tables). We have to do that only for UPDATE and DELETE. Other DML commands don't use WHERE clause. MDEV-21146 Assertion `m_lock_type == 2' in handler::ha_drop_table upon LOAD DATA LOAD DATA does not use WHERE and the above call of vers_setup_conds() is not needed. unit->prepare() led to wrongly locked temporary table. --- mysql-test/suite/versioning/r/view.result | 66 +++++++++++++++++++++++ mysql-test/suite/versioning/t/view.test | 58 +++++++++++++++++++- sql/sql_derived.cc | 23 ++++++-- sql/table.h | 2 +- 4 files changed, 143 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 8b23e87d6a46a..1cb68ea5b933d 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -160,6 +160,7 @@ 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, delete 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) @@ -211,5 +212,70 @@ x check_row(row_start, row_end) 1 CURRENT ROW 2 HISTORICAL ROW 3 HISTORICAL ROW +# replace +create or replace table t1 ( +x int primary key, y 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, 0), (2, 0); +create or replace view v1 as select * from t1 where x > 1; +replace v1 values (1, 1); +replace v1 values (2, 1); +replace v1 values (3, 1); +# REPLACE ignores VIEW condition because itself doesn't use WHERE +select *, check_row(row_start, row_end) from t1 for system_time all order by x, row_end; +x y check_row(row_start, row_end) +1 0 HISTORICAL ROW +1 1 CURRENT ROW +2 0 HISTORICAL ROW +2 1 CURRENT ROW +3 1 CURRENT ROW +# insert-select, on duplicate key +insert v1 select * from t1 where x = 1 on duplicate key update x = v1.x - 1; +select *, check_row(row_start, row_end) from t1 for system_time all order by x, row_end; +x y check_row(row_start, row_end) +0 1 CURRENT ROW +1 0 HISTORICAL ROW +1 1 HISTORICAL ROW +2 0 HISTORICAL ROW +2 1 CURRENT ROW +3 1 CURRENT ROW drop view v1, v2; drop tables t1, t2; +# +# MDEV-21146 Assertion `m_lock_type == 2' in handler::ha_drop_table upon LOAD DATA +# +create table t1 (a int); +create view v1 as select * from t1; +create or replace table t1 (b int) with system versioning; +load data infile 'xx' into table v1; +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +drop view v1; +drop table t1; +# +# MDEV-21155 Assertion with versioned table upon DELETE from view of view after replacing first view +# +create table t1 (a int); +insert into t1 values (1); +create table t2 ( +b 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 t2 values (2); +create view v1 as select * from t1; +create view v2 as select * from v1; +create or replace view v1 as select * from t2; +delete from v2; +select * from t1; +a +1 +select *, check_row(row_start, row_end) from t2 for system_time all; +b check_row(row_start, row_end) +2 HISTORICAL ROW +drop view v2; +drop view v1; +drop table t1, t2; diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index c05fbfd38663c..288f1eb6e21a2 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -136,6 +136,7 @@ eval create or replace table t1 ( ) with system versioning; insert into t1 values (1), (2); create or replace view v1 as select * from t1 where x > 1; +--echo # update, delete 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); @@ -153,8 +154,63 @@ select *, check_row(row_start, row_end) from t2 for system_time all order by x; 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; - +--echo # replace +--replace_result $sys_datatype_expl SYS_DATATYPE +eval create or replace table t1 ( + x int primary key, y 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, 0), (2, 0); +create or replace view v1 as select * from t1 where x > 1; +replace v1 values (1, 1); +replace v1 values (2, 1); +replace v1 values (3, 1); +--echo # REPLACE ignores VIEW condition because itself doesn't use WHERE +select *, check_row(row_start, row_end) from t1 for system_time all order by x, row_end; +--echo # insert-select, on duplicate key +insert v1 select * from t1 where x = 1 on duplicate key update x = v1.x - 1; +select *, check_row(row_start, row_end) from t1 for system_time all order by x, row_end; drop view v1, v2; drop tables t1, t2; +--echo # +--echo # MDEV-21146 Assertion `m_lock_type == 2' in handler::ha_drop_table upon LOAD DATA +--echo # +create table t1 (a int); +create view v1 as select * from t1; +create or replace table t1 (b int) with system versioning; +--error ER_VIEW_INVALID +load data infile 'xx' into table v1; + +# cleanup +drop view v1; +drop table t1; + +--echo # +--echo # MDEV-21155 Assertion with versioned table upon DELETE from view of view after replacing first view +--echo # +create table t1 (a int); +insert into t1 values (1); +--replace_result $sys_datatype_expl SYS_DATATYPE +eval create table t2 ( + b 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 t2 values (2); +create view v1 as select * from t1; +create view v2 as select * from v1; +create or replace view v1 as select * from t2; +delete from v2; +select * from t1; +select *, check_row(row_start, row_end) from t2 for system_time all; + +# cleanup +drop view v2; +drop view v1; +drop table t1, t2; + --source suite/versioning/common_finish.inc diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 4459574661441..652353fb72297 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -692,12 +692,27 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) { /* System versioned tables may still require to get versioning conditions - (when updating view). See vers_setup_conds(). + when modifying view (see vers_setup_conds()). Only UPDATE and DELETE are + affected because they use WHERE condition. */ if (!unit->prepared && derived->table->versioned() && - (res= unit->prepare(derived, derived->derived_result, 0))) - goto exit; + derived->merge_underlying_list && + /* choose only those merged views that do not select from other views */ + !derived->merge_underlying_list->merge_underlying_list) + { + switch (thd->lex->sql_command) + { + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + if ((res= unit->prepare(derived, derived->derived_result, 0))) + goto exit; + default: + break; + } + } DBUG_RETURN(FALSE); } @@ -817,7 +832,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) { if (!derived->is_with_table_recursive_reference()) { - if (derived->table) + if (derived->table && derived->table->s->tmp_table) free_tmp_table(thd, derived->table); delete derived->derived_result; } diff --git a/sql/table.h b/sql/table.h index ca5565250deed..86e300344496f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -321,7 +321,7 @@ typedef struct st_grant_info enum tmp_table_type { - NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE, + NO_TMP_TABLE= 0, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE, INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE }; enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; From a7cf0db3d866d92ca54d4ba5f15f3cc3f8b48d31 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 2 Dec 2019 11:48:37 +0300 Subject: [PATCH 12/13] MDEV-21011 Table corruption reported for versioned partitioned table after DELETE: "Found a misplaced row" LIMIT history partitions cannot be checked by existing algorithm of check_misplaced_rows() because working history partition is incremented each time another one is filled. The existing algorithm gets record and tries to decide partition id for it by get_partition_id(). For LIMIT history it will just get first non-filled partition. To fix such partitions it is required to do REBUILD instead of REPAIR. --- mysql-test/suite/versioning/r/partition.result | 14 ++++++++++++++ mysql-test/suite/versioning/t/partition.test | 15 +++++++++++++++ sql/ha_partition.cc | 15 +++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 315413fbd7daa..3fd6c1f55d4d8 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -583,3 +583,17 @@ x a 3 bar 4 bar drop table t1; +# +# MDEV-21011 Table corruption reported for versioned partitioned table after DELETE: "Found a misplaced row" +# +create table t1 (a int) with system versioning +partition by system_time limit 3 +(partition p1 history, partition p2 history, partition pn current); +insert into t1 values (1),(2),(3),(4); +delete from t1; +delete from t1; +check table t1; +Table Op Msg_type Msg_text +test.t1 check note Not supported for non-INTERVAL history partitions +test.t1 check note The storage engine for the table doesn't support check +drop table t1; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index ce8c2e5ec1a43..5b23d893974cc 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -531,4 +531,19 @@ update t1 set a= 'bar' limit 4; select * from t1; drop table t1; +--echo # +--echo # MDEV-21011 Table corruption reported for versioned partitioned table after DELETE: "Found a misplaced row" +--echo # +create table t1 (a int) with system versioning +partition by system_time limit 3 +(partition p1 history, partition p2 history, partition pn current); +insert into t1 values (1),(2),(3),(4); +delete from t1; +delete from t1; +check table t1; + +# cleanup +drop table t1; + + --source suite/versioning/common_finish.inc diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 380fc48e91591..2dcf2996bf7ce 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -10697,8 +10697,8 @@ int ha_partition::indexes_are_disabled(void) @param repair If true, move misplaced rows to correct partition. @return Operation status. - @retval 0 Success - @retval != 0 Error + @retval HA_ADMIN_OK Success + @retval != HA_ADMIN_OK Error */ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair) @@ -10712,6 +10712,17 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair) DBUG_ASSERT(m_file); + if (m_part_info->vers_info && + read_part_id != m_part_info->vers_info->now_part->id && + !m_part_info->vers_info->interval.is_set()) + { + print_admin_msg(ha_thd(), MYSQL_ERRMSG_SIZE, "note", + table_share->db.str, table->alias, + opt_op_name[CHECK_PARTS], + "Not supported for non-INTERVAL history partitions"); + DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); + } + if (do_repair) { /* We must read the full row, if we need to move it! */ From db32d9457edbcb23b45f433cfcdfc5d86232bbb0 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 2 Dec 2019 11:48:37 +0300 Subject: [PATCH 13/13] MDEV-18929 2nd execution of SP does not detect ER_VERS_NOT_VERSIONED Don't do skip_setup_conds() unless all errors are checked. Fixes following errors: ER_PERIOD_NOT_FOUND ER_VERS_QUERY_IN_PARTITION ER_VERS_ENGINE_UNSUPPORTED ER_VERS_NOT_VERSIONED --- .../suite/versioning/r/partition.result | 8 +++++ mysql-test/suite/versioning/r/select.result | 15 ++++++++++ mysql-test/suite/versioning/r/view.result | 2 +- mysql-test/suite/versioning/t/partition.test | 8 +++++ mysql-test/suite/versioning/t/select.test | 15 ++++++++++ sql/sql_select.cc | 30 +++++++++++-------- sql/table.h | 7 +++++ 7 files changed, 71 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 3fd6c1f55d4d8..a6fa5fcf2ad7c 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -504,6 +504,14 @@ delete from t1 where a is not null; create or replace table t1 (i int) with system versioning partition by system_time limit 10 (partition p0 history, partition pn current); select * from t1 partition (p0) for system_time all; ERROR HY000: SYSTEM_TIME partitions in table `t1` does not support historical query +# MDEV-18929 2nd execution of SP does not detect ER_VERS_NOT_VERSIONED +create or replace procedure sp() +select * from t1 partition (p0) for system_time all; +call sp; +ERROR HY000: SYSTEM_TIME partitions in table `t1` does not support historical query +call sp; +ERROR HY000: SYSTEM_TIME partitions in table `t1` does not support historical query +drop procedure sp; # MDEV-15380 Index for versioned table gets corrupt after partitioning and DELETE create or replace table t1 (pk int primary key) engine=myisam diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index c887e524e6352..9b6738d4eb9f3 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -320,6 +320,21 @@ ERROR HY000: Table `t` is not system-versioned create or replace table t1 (x int) with system versioning engine myisam; select * from t1 for system_time as of transaction 1; ERROR HY000: Transaction-precise system versioning for `t1` is not supported +# MDEV-18929 2nd execution of SP does not detect ER_VERS_NOT_VERSIONED +create or replace procedure sp() +select * from t1 for system_time as of transaction 1; +call sp; +ERROR HY000: Transaction-precise system versioning for `t1` is not supported +call sp; +ERROR HY000: Transaction-precise system versioning for `t1` is not supported +create or replace table t1 (a int); +create or replace procedure sp() +select * from t1 for system_time all; +call sp; +ERROR HY000: Table `t1` is not system-versioned +call sp; +ERROR HY000: Table `t1` is not system-versioned +drop procedure sp; create or replace table t1 ( x int, sys_trx_start bigint unsigned as row start invisible, diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 1cb68ea5b933d..3b3fe580af496 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -146,7 +146,7 @@ i create or replace view v1 as select * from t1 for system_time as of date_sub(now(), interval 6 second); show create view v1; 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 +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 TIMESTAMP current_timestamp() - interval 6 second latin1 latin1_swedish_ci drop view v1, vt1, vt12; drop tables t1, t3; # diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index 5b23d893974cc..dcbb6e4c293de 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -455,6 +455,14 @@ delete from t1 where a is not null; create or replace table t1 (i int) with system versioning partition by system_time limit 10 (partition p0 history, partition pn current); --error ER_VERS_QUERY_IN_PARTITION select * from t1 partition (p0) for system_time all; +--echo # MDEV-18929 2nd execution of SP does not detect ER_VERS_NOT_VERSIONED +create or replace procedure sp() +select * from t1 partition (p0) for system_time all; +--error ER_VERS_QUERY_IN_PARTITION +call sp; +--error ER_VERS_QUERY_IN_PARTITION +call sp; +drop procedure sp; --echo # MDEV-15380 Index for versioned table gets corrupt after partitioning and DELETE create or replace table t1 (pk int primary key) diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 53366994882db..3fbeaf7578f18 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -202,6 +202,21 @@ for system_time all as t; create or replace table t1 (x int) with system versioning engine myisam; --error ER_VERS_ENGINE_UNSUPPORTED select * from t1 for system_time as of transaction 1; +--echo # MDEV-18929 2nd execution of SP does not detect ER_VERS_NOT_VERSIONED +create or replace procedure sp() +select * from t1 for system_time as of transaction 1; +--error ER_VERS_ENGINE_UNSUPPORTED +call sp; +--error ER_VERS_ENGINE_UNSUPPORTED +call sp; +create or replace table t1 (a int); +create or replace procedure sp() +select * from t1 for system_time all; +--error ER_VERS_NOT_VERSIONED +call sp; +--error ER_VERS_NOT_VERSIONED +call sp; +drop procedure sp; create or replace table t1 ( x int, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 46e21822cc438..f9c44600aff4e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -719,23 +719,22 @@ void vers_select_conds_t::print(String *str, enum_query_type query_type) const } } +static +bool skip_setup_conds(THD *thd) +{ + return (!thd->stmt_arena->is_conventional() + && !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) + || thd->lex->is_view_context_analysis(); +} + int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("SELECT_LEX::vers_setup_cond"); #define newx new (thd->mem_root) + const bool update_conds= !skip_setup_conds(thd); TABLE_LIST *table; - if (!thd->stmt_arena->is_conventional() && - !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) - { - // statement is already prepared - DBUG_RETURN(0); - } - - if (thd->lex->is_view_context_analysis()) - DBUG_RETURN(0); - if (!versioned_tables) { for (table= tables; table; table= table->next_local) @@ -805,13 +804,15 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) */ if (table->partition_names && table->table->part_info->vers_info) { - if (vers_conditions.is_set()) + /* If the history is stored in partitions, then partitions + themselves are not versioned. */ + if (vers_conditions.was_set()) { my_error(ER_VERS_QUERY_IN_PARTITION, MYF(0), table->alias.str); DBUG_RETURN(-1); } - else - vers_conditions.init(SYSTEM_TIME_ALL); + else if (!vers_conditions.is_set()) + vers_conditions.type= SYSTEM_TIME_ALL; } #endif @@ -866,6 +867,9 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) } } + if (!update_conds) + continue; + Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL; Item *point_in_time1= vers_conditions.start.item; Item *point_in_time2= vers_conditions.end.item; diff --git a/sql/table.h b/sql/table.h index 86e300344496f..11ede736127e0 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1871,6 +1871,7 @@ class Vers_history_point : public vers_history_point_t struct vers_select_conds_t { vers_system_time_t type; + vers_system_time_t orig_type; bool used:1; bool delete_history:1; Vers_history_point start; @@ -1879,6 +1880,7 @@ struct vers_select_conds_t void empty() { type= SYSTEM_TIME_UNSPECIFIED; + orig_type= SYSTEM_TIME_UNSPECIFIED; used= false; delete_history= false; start.empty(); @@ -1890,6 +1892,7 @@ struct vers_select_conds_t Vers_history_point _end= Vers_history_point()) { type= _type; + orig_type= _type; used= false; delete_history= (type == SYSTEM_TIME_HISTORY || type == SYSTEM_TIME_BEFORE); @@ -1905,6 +1908,10 @@ struct vers_select_conds_t { return type != SYSTEM_TIME_UNSPECIFIED; } + bool was_set() const + { + return orig_type != SYSTEM_TIME_UNSPECIFIED; + } bool resolve_units(THD *thd); bool eq(const vers_select_conds_t &conds) const; };