diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake
index 4811eec8f8c..701f913dee2 100644
--- a/cmake/cpack_rpm.cmake
+++ b/cmake/cpack_rpm.cmake
@@ -297,7 +297,7 @@ ELSEIF(RPM MATCHES "sles")
ENDIF()
# MDEV-24629, we need it outside of ELSIFs
-IF(RPM MATCHES "fedora3[234]")
+IF(RPM MATCHES "fedora")
ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1)
ENDIF()
diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc
index 180616f37e9..515a8bd49c6 100644
--- a/extra/mariabackup/xtrabackup.cc
+++ b/extra/mariabackup/xtrabackup.cc
@@ -847,27 +847,49 @@ void mdl_lock_all()
// Convert non-null terminated filename to space name
+// Note that in 10.6 the filename may be an undo file name
static std::string filename_to_spacename(const void *filename, size_t len)
{
- // null- terminate filename
- char *f = (char *)malloc(len + 1);
- ut_a(f);
- memcpy(f, filename, len);
- f[len] = 0;
- for (size_t i = 0; i < len; i++)
- if (f[i] == '\\')
- f[i] = '/';
- char *p = strrchr(f, '.');
- ut_a(p);
- *p = 0;
- char *table = strrchr(f, '/');
- ut_a(table);
- *table = 0;
- char *db = strrchr(f, '/');
- *table = '/';
- std::string s(db ? db+1 : f);
- free(f);
- return s;
+ char f[FN_REFLEN];
+ char *p= 0, *table, *db;
+ DBUG_ASSERT(len < FN_REFLEN);
+
+ strmake(f, (const char*) filename, len);
+
+#ifdef _WIN32
+ for (size_t i = 0; i < len; i++)
+ {
+ if (f[i] == '\\')
+ f[i] = '/';
+ }
+#endif
+
+ /* Remove extension, if exists */
+ if (!(p= strrchr(f, '.')))
+ goto err;
+ *p= 0;
+
+ /* Find table name */
+ if (!(table= strrchr(f, '/')))
+ goto err;
+ *table = 0;
+
+ /* Find database name */
+ db= strrchr(f, '/');
+ *table = '/';
+ if (!db)
+ goto err;
+ {
+ std::string s(db+1);
+ return s;
+ }
+
+err:
+ /* Not a database/table. Return original (converted) name */
+ if (p)
+ *p= '.'; // Restore removed extension
+ std::string s(f);
+ return s;
}
/** Report an operation to create, delete, or rename a file during backup.
diff --git a/include/m_string.h b/include/m_string.h
index 046dc39d13a..6a645b20a7f 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -249,14 +249,15 @@ static inline void lex_string_set3(LEX_CSTRING *lex_str, const char *c_str,
*/
static inline int safe_strcpy(char *dst, size_t dst_size, const char *src)
{
- memset(dst, '\0', dst_size);
- strncpy(dst, src, dst_size - 1);
- /*
- If the first condition is true, we are guaranteed to have src length
- >= (dst_size - 1), hence safe to access src[dst_size - 1].
- */
- if (dst[dst_size - 2] != '\0' && src[dst_size - 1] != '\0')
- return 1; /* Truncation of src. */
+ DBUG_ASSERT(dst_size > 0);
+ /* Note, strncpy will zerofill end of dst if src shorter than dst_size */
+ strncpy(dst, src, dst_size);
+ if (dst[dst_size-1])
+ {
+ /* Ensure string is zero terminated */
+ dst[dst_size-1]= 0;
+ return 1;
+ }
return 0;
}
diff --git a/include/myisammrg.h b/include/myisammrg.h
index 1d7efbe74d6..b3bca218a44 100644
--- a/include/myisammrg.h
+++ b/include/myisammrg.h
@@ -71,6 +71,7 @@ typedef struct st_myrg_info
ulong cache_size;
uint merge_insert_method;
uint tables,options,reclength,keys;
+ uint key_parts;
my_bool cache_in_use;
/* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
my_bool children_attached;
diff --git a/mysql-test/lib/My/File/Path.pm b/mysql-test/lib/My/File/Path.pm
index d60027c909e..fd3cf6dd61c 100644
--- a/mysql-test/lib/My/File/Path.pm
+++ b/mysql-test/lib/My/File/Path.pm
@@ -34,7 +34,7 @@ use strict;
use Exporter;
use base "Exporter";
-our @EXPORT= qw /rmtree mkpath copytree/;
+our @EXPORT= qw /rmtree mkpath copytree make_readonly/;
use File::Find;
use File::Copy;
@@ -184,6 +184,10 @@ sub copytree {
# Only copy plain files
next unless -f "$from_dir/$_";
copy("$from_dir/$_", "$to_dir/$_");
+ if (!$use_umask)
+ {
+ chmod(0666, "$to_dir/$_");
+ }
}
closedir(DIR);
@@ -193,4 +197,29 @@ sub copytree {
}
}
+
+sub make_readonly {
+ my ($dir) = @_;
+
+ die "Usage: make_readonly(
])"
+ unless @_ == 1;
+
+ opendir(DIR, "$dir")
+ or croak("Can't find $dir$!");
+ for(readdir(DIR)) {
+
+ next if "$_" eq "." or "$_" eq "..";
+
+ if ( -d "$dir/$_" )
+ {
+ make_readonly("$dir/$_");
+ next;
+ }
+
+ # Only copy plain files
+ next unless -f "$dir/$_";
+ chmod 0444, "$dir/$_";
+ }
+ closedir(DIR);
+}
1;
diff --git a/mysql-test/lib/My/SafeProcess/Base.pm b/mysql-test/lib/My/SafeProcess/Base.pm
index 818e6e34e11..1cd01cb0ca9 100644
--- a/mysql-test/lib/My/SafeProcess/Base.pm
+++ b/mysql-test/lib/My/SafeProcess/Base.pm
@@ -40,7 +40,7 @@ our @EXPORT= qw(create_process);
# Retry a couple of times if fork returns EAGAIN
#
sub _safe_fork {
- my $retries= 5;
+ my $retries= 100;
my $pid;
FORK:
diff --git a/mysql-test/main/distinct.result b/mysql-test/main/distinct.result
index fa9f0259a0f..ac693421ba2 100644
--- a/mysql-test/main/distinct.result
+++ b/mysql-test/main/distinct.result
@@ -1157,3 +1157,28 @@ explain select * from t1 limit 0 offset 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit
drop table t1, t2;
+#
+# MDEV-28285 Unexpected result when combining DISTINCT, subselect
+# and LIMIT
+#
+create table t1 (a int primary key);
+create table t2 (a int primary key, b int not null);
+insert into t1 select seq from seq_1_to_10;
+insert into t2 select seq,seq from seq_1_to_10;
+select distinct a from t1 where t1.a=1 and t1.a in (select a from t2 where t2.b in (1,2));
+a
+1
+explain select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using index; Using temporary
+1 PRIMARY eq_ref distinct_key distinct_key 8 func 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 10 Using where
+select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
+a
+select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 0,1;
+a
+1
+drop table t1,t2;
+#
+# end of 10.5 tests
+#
diff --git a/mysql-test/main/distinct.test b/mysql-test/main/distinct.test
index 893e2dcc9a7..9aa3b2921aa 100644
--- a/mysql-test/main/distinct.test
+++ b/mysql-test/main/distinct.test
@@ -892,3 +892,24 @@ explain select * from t1 limit 0;
explain select * from t1 limit 0 offset 10;
drop table t1, t2;
+
+--echo #
+--echo # MDEV-28285 Unexpected result when combining DISTINCT, subselect
+--echo # and LIMIT
+--echo #
+
+create table t1 (a int primary key);
+create table t2 (a int primary key, b int not null);
+
+insert into t1 select seq from seq_1_to_10;
+insert into t2 select seq,seq from seq_1_to_10;
+
+select distinct a from t1 where t1.a=1 and t1.a in (select a from t2 where t2.b in (1,2));
+explain select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
+select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
+select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 0,1;
+drop table t1,t2;
+
+--echo #
+--echo # end of 10.5 tests
+--echo #
diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result
index 706a4132614..055bd266e15 100644
--- a/mysql-test/main/group_min_max.result
+++ b/mysql-test/main/group_min_max.result
@@ -4095,6 +4095,116 @@ MIN(pk) a
5 10
DROP TABLE t1;
#
+# MDEV-6768 Wrong result with agregate with join with no resultset
+#
+create table t1
+(
+PARENT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
+PARENT_FIELD VARCHAR(10),
+PRIMARY KEY (PARENT_ID)
+) engine=innodb;
+create table t2
+(
+CHILD_ID INT NOT NULL AUTO_INCREMENT,
+PARENT_ID INT NOT NULL,
+CHILD_FIELD varchar(10),
+PRIMARY KEY (CHILD_ID)
+)engine=innodb;
+INSERT INTO t1 (PARENT_FIELD)
+SELECT 'AAAA';
+INSERT INTO t2 (PARENT_ID, CHILD_FIELD)
+SELECT 1, 'BBBB';
+explain select
+t1.PARENT_ID,
+min(CHILD_FIELD)
+from t1 straight_join t2
+where t1.PARENT_ID = 1
+and t1.PARENT_ID = t2.PARENT_ID
+and t2.CHILD_FIELD = "ZZZZ";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1 Using where
+select
+t1.PARENT_ID,
+min(CHILD_FIELD)
+from t1 straight_join t2
+where t1.PARENT_ID = 1
+and t1.PARENT_ID = t2.PARENT_ID
+and t2.CHILD_FIELD = "ZZZZ";
+PARENT_ID min(CHILD_FIELD)
+NULL NULL
+select
+1,
+min(CHILD_FIELD)
+from t1 straight_join t2
+where t1.PARENT_ID = 1
+and t1.PARENT_ID = t2.PARENT_ID
+and t2.CHILD_FIELD = "ZZZZ";
+1 min(CHILD_FIELD)
+1 NULL
+select
+IFNULL(t1.PARENT_ID,1),
+min(CHILD_FIELD)
+from t1 straight_join t2
+where t1.PARENT_ID = 1
+and t1.PARENT_ID = t2.PARENT_ID
+and t2.CHILD_FIELD = "ZZZZ";
+IFNULL(t1.PARENT_ID,1) min(CHILD_FIELD)
+1 NULL
+# Check that things works with MyISAM (which has different explain)
+alter table t1 engine=myisam;
+alter table t2 engine=myisam;
+explain select
+t1.PARENT_ID,
+min(CHILD_FIELD)
+from t1 straight_join t2
+where t1.PARENT_ID = 1
+and t1.PARENT_ID = t2.PARENT_ID
+and t2.CHILD_FIELD = "ZZZZ";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+select
+t1.PARENT_ID,
+min(CHILD_FIELD)
+from t1 straight_join t2
+where t1.PARENT_ID = 1
+and t1.PARENT_ID = t2.PARENT_ID
+and t2.CHILD_FIELD = "ZZZZ";
+PARENT_ID min(CHILD_FIELD)
+NULL NULL
+drop table t1,t2;
+# Check that things works if sub queries are re-executed
+create table t1 (a int primary key, b int);
+create table t2 (a int primary key, b int);
+create table t3 (a int primary key, b int);
+insert into t1 values (1,1),(2,2),(3,3);
+insert into t2 values (1,1),(2,2),(3,3);
+insert into t3 values (1,1),(3,3);
+explain
+select *,
+(select
+CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
+'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
+from t2,t3
+where t2.a=1 and t1.b = t3.a) as s1
+from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+2 DEPENDENT SUBQUERY t2 const PRIMARY PRIMARY 4 const 1 Using index
+2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1
+select *,
+(select
+CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
+'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
+from t2,t3
+where t2.a=1 and t1.b = t3.a) as s1
+from t1;
+a b s1
+1 1 t2:1;min_t3_b:1
+2 2 t2:t2a-null;min_t3_b:t3b-null
+3 3 t2:1;min_t3_b:3
+drop table t1,t2,t3;
+#
# End of 10.5 tests
#
#
diff --git a/mysql-test/main/group_min_max.test b/mysql-test/main/group_min_max.test
index 1bc334dd3da..9d056473537 100644
--- a/mysql-test/main/group_min_max.test
+++ b/mysql-test/main/group_min_max.test
@@ -1749,6 +1749,116 @@ SELECT MIN(pk), a FROM t1 WHERE pk <> 1 GROUP BY a;
DROP TABLE t1;
+--echo #
+--echo # MDEV-6768 Wrong result with agregate with join with no resultset
+--echo #
+
+create table t1
+(
+ PARENT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
+ PARENT_FIELD VARCHAR(10),
+ PRIMARY KEY (PARENT_ID)
+) engine=innodb;
+
+create table t2
+(
+ CHILD_ID INT NOT NULL AUTO_INCREMENT,
+ PARENT_ID INT NOT NULL,
+ CHILD_FIELD varchar(10),
+ PRIMARY KEY (CHILD_ID)
+)engine=innodb;
+
+INSERT INTO t1 (PARENT_FIELD)
+SELECT 'AAAA';
+
+INSERT INTO t2 (PARENT_ID, CHILD_FIELD)
+SELECT 1, 'BBBB';
+
+explain select
+ t1.PARENT_ID,
+ min(CHILD_FIELD)
+ from t1 straight_join t2
+ where t1.PARENT_ID = 1
+ and t1.PARENT_ID = t2.PARENT_ID
+ and t2.CHILD_FIELD = "ZZZZ";
+
+select
+ t1.PARENT_ID,
+ min(CHILD_FIELD)
+ from t1 straight_join t2
+ where t1.PARENT_ID = 1
+ and t1.PARENT_ID = t2.PARENT_ID
+ and t2.CHILD_FIELD = "ZZZZ";
+
+select
+ 1,
+ min(CHILD_FIELD)
+ from t1 straight_join t2
+ where t1.PARENT_ID = 1
+ and t1.PARENT_ID = t2.PARENT_ID
+ and t2.CHILD_FIELD = "ZZZZ";
+
+select
+ IFNULL(t1.PARENT_ID,1),
+ min(CHILD_FIELD)
+ from t1 straight_join t2
+ where t1.PARENT_ID = 1
+ and t1.PARENT_ID = t2.PARENT_ID
+ and t2.CHILD_FIELD = "ZZZZ";
+
+
+--echo # Check that things works with MyISAM (which has different explain)
+
+alter table t1 engine=myisam;
+alter table t2 engine=myisam;
+
+explain select
+ t1.PARENT_ID,
+ min(CHILD_FIELD)
+ from t1 straight_join t2
+ where t1.PARENT_ID = 1
+ and t1.PARENT_ID = t2.PARENT_ID
+ and t2.CHILD_FIELD = "ZZZZ";
+
+select
+ t1.PARENT_ID,
+ min(CHILD_FIELD)
+ from t1 straight_join t2
+ where t1.PARENT_ID = 1
+ and t1.PARENT_ID = t2.PARENT_ID
+ and t2.CHILD_FIELD = "ZZZZ";
+
+drop table t1,t2;
+
+--echo # Check that things works if sub queries are re-executed
+
+create table t1 (a int primary key, b int);
+create table t2 (a int primary key, b int);
+create table t3 (a int primary key, b int);
+
+insert into t1 values (1,1),(2,2),(3,3);
+insert into t2 values (1,1),(2,2),(3,3);
+insert into t3 values (1,1),(3,3);
+
+explain
+select *,
+ (select
+ CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
+ 'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
+ from t2,t3
+ where t2.a=1 and t1.b = t3.a) as s1
+from t1;
+
+select *,
+ (select
+ CONCAT('t2:', IFNULL(t2.a, 't2a-null'), ';',
+ 'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
+ from t2,t3
+ where t2.a=1 and t1.b = t3.a) as s1
+from t1;
+
+drop table t1,t2,t3;
+
--echo #
--echo # End of 10.5 tests
--echo #
diff --git a/mysql-test/main/merge.result b/mysql-test/main/merge.result
index 230fcf48e9d..e7330b7e54b 100644
--- a/mysql-test/main/merge.result
+++ b/mysql-test/main/merge.result
@@ -3902,6 +3902,18 @@ DROP TABLE t1;
DROP TABLE m1;
set global default_storage_engine=@save_default_storage_engine;
#
+# MDEV-31083 ASAN use-after-poison in myrg_attach_children
+#
+CREATE TABLE t1 (f TEXT, FULLTEXT (f)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('foo'),('bar');
+CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1);
+SELECT * FROM mrg;
+f
+foo
+bar
+DROP TABLE mrg, t1;
+End of 10.5 tests
+#
# End of 10.0 tests
#
#
diff --git a/mysql-test/main/merge.test b/mysql-test/main/merge.test
index 0485f3ed1c3..76903e27ae9 100644
--- a/mysql-test/main/merge.test
+++ b/mysql-test/main/merge.test
@@ -2859,6 +2859,18 @@ set global default_storage_engine=@save_default_storage_engine;
# gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc
+--echo #
+--echo # MDEV-31083 ASAN use-after-poison in myrg_attach_children
+--echo #
+
+CREATE TABLE t1 (f TEXT, FULLTEXT (f)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('foo'),('bar');
+CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1);
+SELECT * FROM mrg;
+DROP TABLE mrg, t1;
+
+--echo End of 10.5 tests
+
--echo #
--echo # End of 10.0 tests
--echo #
diff --git a/mysql-test/main/selectivity.result b/mysql-test/main/selectivity.result
index bbe7948b1b3..3b2aabaffd9 100644
--- a/mysql-test/main/selectivity.result
+++ b/mysql-test/main/selectivity.result
@@ -1824,7 +1824,6 @@ test.t1 analyze status Table is already up to date
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status Table is already up to date
set optimizer_switch='exists_to_in=off';
-set optimizer_use_condition_selectivity=2;
SELECT * FROM t1
WHERE
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
@@ -1849,18 +1848,39 @@ id a
17 17
18 18
19 19
-explain SELECT * FROM t1
+set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
WHERE
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
WHERE A.a=t1.a AND t2.b < 20);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
-2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
-2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
-EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
+set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
+WHERE
+EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
+WHERE A.a=t1.a AND t2.b < 20);
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE A const PRIMARY,a PRIMARY 4 const 1
-1 SIMPLE B ref a a 5 const 1
+1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
+set @query="EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
+set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
+WHERE
+EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
+WHERE A.a=t1.a AND t2.b < 20);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
+set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
+WHERE
+EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
+WHERE A.a=t1.a AND t2.b < 20);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
explain SELECT * FROM t1
WHERE
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
@@ -1870,7 +1890,6 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (10%) Using where; Using rowid filter
set optimizer_switch= @save_optimizer_switch;
-set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
drop table t1,t2;
#
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
diff --git a/mysql-test/main/selectivity.test b/mysql-test/main/selectivity.test
index df3850d74b7..9f21bea442a 100644
--- a/mysql-test/main/selectivity.test
+++ b/mysql-test/main/selectivity.test
@@ -1236,13 +1236,10 @@ set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
drop table t1,t2,t3;
-
--echo #
--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4
--echo #
-
-
create table t1 (id int, a int, PRIMARY KEY(id), key(a));
insert into t1 select seq,seq from seq_1_to_100;
@@ -1252,7 +1249,6 @@ insert into t2 select seq,seq,seq from seq_1_to_100;
analyze table t1,t2 persistent for all;
set optimizer_switch='exists_to_in=off';
-set optimizer_use_condition_selectivity=2;
let $query= SELECT * FROM t1
WHERE
@@ -1260,14 +1256,16 @@ let $query= SELECT * FROM t1
WHERE A.a=t1.a AND t2.b < 20);
eval $query;
-eval explain $query;
+eval set statement optimizer_use_condition_selectivity=2 for explain $query;
+eval set statement optimizer_use_condition_selectivity=4 for explain $query;
-EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
+set @query="EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
+eval set statement optimizer_use_condition_selectivity=2 for explain $query;
+eval set statement optimizer_use_condition_selectivity=4 for explain $query;
eval explain $query;
set optimizer_switch= @save_optimizer_switch;
-set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
drop table t1,t2;
--echo #
diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result
index f35d8b66f8f..cdb609793c8 100644
--- a/mysql-test/main/selectivity_innodb.result
+++ b/mysql-test/main/selectivity_innodb.result
@@ -1836,7 +1836,6 @@ test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
set optimizer_switch='exists_to_in=off';
-set optimizer_use_condition_selectivity=2;
SELECT * FROM t1
WHERE
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
@@ -1861,18 +1860,39 @@ id a
17 17
18 18
19 19
-explain SELECT * FROM t1
+set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
WHERE
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
WHERE A.a=t1.a AND t2.b < 20);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
-2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
-2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
-EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
+set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
+WHERE
+EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
+WHERE A.a=t1.a AND t2.b < 20);
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE A const PRIMARY,a PRIMARY 4 const 1
-1 SIMPLE B ref a a 5 const 1 Using index
+1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
+set @query="EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
+set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
+WHERE
+EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
+WHERE A.a=t1.a AND t2.b < 20);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
+set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
+WHERE
+EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
+WHERE A.a=t1.a AND t2.b < 20);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index
+3 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
+3 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
explain SELECT * FROM t1
WHERE
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
@@ -1882,7 +1902,6 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index
2 DEPENDENT SUBQUERY t2 ref|filter a,b a|b 5|5 test.A.id 1 (19%) Using where; Using rowid filter
set optimizer_switch= @save_optimizer_switch;
-set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
drop table t1,t2;
#
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
diff --git a/mysql-test/main/type_timestamp.result b/mysql-test/main/type_timestamp.result
index 275d35ac476..0d54875df46 100644
--- a/mysql-test/main/type_timestamp.result
+++ b/mysql-test/main/type_timestamp.result
@@ -1230,6 +1230,8 @@ SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
c1
Warnings:
Warning 1292 Truncated incorrect datetime value: 'r'
+SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
+c1
DROP TABLE t1;
CREATE TABLE t1 (c1 timestamp);
INSERT INTO t1 VALUES ('2010-01-01 00:00:00');
diff --git a/mysql-test/main/type_timestamp.test b/mysql-test/main/type_timestamp.test
index bff33c030b5..14e865df918 100644
--- a/mysql-test/main/type_timestamp.test
+++ b/mysql-test/main/type_timestamp.test
@@ -810,6 +810,7 @@ DROP TABLE t1;
CREATE TABLE t1 (c1 timestamp);
SELECT MIN(t1.c1) AS k1 FROM t1 HAVING (k1 >= ALL(SELECT 'a' UNION SELECT 'r'));
SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
+SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
DROP TABLE t1;
CREATE TABLE t1 (c1 timestamp);
diff --git a/mysql-test/mariadb-test-run.pl b/mysql-test/mariadb-test-run.pl
index 4fc4d9f050e..9d554998953 100755
--- a/mysql-test/mariadb-test-run.pl
+++ b/mysql-test/mariadb-test-run.pl
@@ -408,8 +408,11 @@ sub main {
mark_time_used('collect');
- mysql_install_db(default_mysqld(), "$opt_vardir/install.db") unless using_extern();
-
+ if (!using_extern())
+ {
+ mysql_install_db(default_mysqld(), "$opt_vardir/install.db");
+ make_readonly("$opt_vardir/install.db");
+ }
if ($opt_dry_run)
{
for (@$tests) {
diff --git a/plugin/type_mysql_timestamp/CMakeLists.txt b/plugin/type_mysql_timestamp/CMakeLists.txt
new file mode 100644
index 00000000000..ca7bf1e7704
--- /dev/null
+++ b/plugin/type_mysql_timestamp/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (c) 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 Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(type_mysql_timestamp plugin.cc RECOMPILE_FOR_EMBEDDED
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/suite.opt b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/suite.opt
new file mode 100644
index 00000000000..e9e2a99b589
--- /dev/null
+++ b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$TYPE_MYSQL_TIMESTAMP_SO
diff --git a/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/suite.pm b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/suite.pm
new file mode 100644
index 00000000000..cbb8f1b097f
--- /dev/null
+++ b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/suite.pm
@@ -0,0 +1,10 @@
+package My::Suite::Type_test;
+
+@ISA = qw(My::Suite);
+
+return "No TYPE_TEST plugin" unless $ENV{TYPE_MYSQL_TIMESTAMP_SO};
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp.result b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp.result
new file mode 100644
index 00000000000..009b3a7c47c
--- /dev/null
+++ b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp.result
@@ -0,0 +1,45 @@
+#
+# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
+#
+SELECT
+PLUGIN_NAME,
+PLUGIN_VERSION,
+PLUGIN_STATUS,
+PLUGIN_TYPE,
+PLUGIN_AUTHOR,
+PLUGIN_DESCRIPTION,
+PLUGIN_LICENSE,
+PLUGIN_MATURITY,
+PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME LIKE 'type_mysql_timestamp';
+PLUGIN_NAME type_mysql_timestamp
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE DATA TYPE
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Data type TYPE_MYSQL_TIMESTAMP
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Experimental
+PLUGIN_AUTH_VERSION 1.0
+CREATE TABLE t1 (a TYPE_MYSQL_TIMESTAMP);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+DROP TABLE t1;
+CREATE TABLE t1 (a TIMESTAMP);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+ALTER TABLE t1 MODIFY a TYPE_MYSQL_TIMESTAMP;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+DROP TABLE t1;
diff --git a/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp.test b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp.test
new file mode 100644
index 00000000000..a7aaa5a3e4c
--- /dev/null
+++ b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp.test
@@ -0,0 +1,31 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
+--echo #
+
+--vertical_results
+SELECT
+ PLUGIN_NAME,
+ PLUGIN_VERSION,
+ PLUGIN_STATUS,
+ PLUGIN_TYPE,
+ PLUGIN_AUTHOR,
+ PLUGIN_DESCRIPTION,
+ PLUGIN_LICENSE,
+ PLUGIN_MATURITY,
+ PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+ WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME LIKE 'type_mysql_timestamp';
+--horizontal_results
+
+CREATE TABLE t1 (a TYPE_MYSQL_TIMESTAMP);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TIMESTAMP);
+SHOW CREATE TABLE t1;
+ALTER TABLE t1 MODIFY a TYPE_MYSQL_TIMESTAMP;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp_stat_tables.result b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp_stat_tables.result
new file mode 100644
index 00000000000..e48f29c9a26
--- /dev/null
+++ b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp_stat_tables.result
@@ -0,0 +1,73 @@
+#
+# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
+#
+SET @@global.innodb_stats_persistent=0;
+SHOW CREATE TABLE mysql.innodb_table_stats;
+Table Create Table
+innodb_table_stats CREATE TABLE `innodb_table_stats` (
+ `database_name` varchar(64) NOT NULL,
+ `table_name` varchar(199) NOT NULL,
+ `last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `n_rows` bigint(20) unsigned NOT NULL,
+ `clustered_index_size` bigint(20) unsigned NOT NULL,
+ `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
+ PRIMARY KEY (`database_name`,`table_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
+ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_table_stats;
+Table Create Table
+innodb_table_stats CREATE TABLE `innodb_table_stats` (
+ `database_name` varchar(64) NOT NULL,
+ `table_name` varchar(199) NOT NULL,
+ `last_update` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `n_rows` bigint(20) unsigned NOT NULL,
+ `clustered_index_size` bigint(20) unsigned NOT NULL,
+ `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
+ PRIMARY KEY (`database_name`,`table_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
+ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_index_stats;
+Table Create Table
+innodb_index_stats CREATE TABLE `innodb_index_stats` (
+ `database_name` varchar(64) NOT NULL,
+ `table_name` varchar(199) NOT NULL,
+ `index_name` varchar(64) NOT NULL,
+ `last_update` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `stat_name` varchar(64) NOT NULL,
+ `stat_value` bigint(20) unsigned NOT NULL,
+ `sample_size` bigint(20) unsigned DEFAULT NULL,
+ `stat_description` varchar(1024) NOT NULL,
+ PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
+SET @@global.innodb_stats_persistent=1;
+CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DROP TABLE t1;
+SET @@global.innodb_stats_persistent=0;
+ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_table_stats;
+Table Create Table
+innodb_table_stats CREATE TABLE `innodb_table_stats` (
+ `database_name` varchar(64) NOT NULL,
+ `table_name` varchar(199) NOT NULL,
+ `last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `n_rows` bigint(20) unsigned NOT NULL,
+ `clustered_index_size` bigint(20) unsigned NOT NULL,
+ `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
+ PRIMARY KEY (`database_name`,`table_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
+ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_index_stats;
+Table Create Table
+innodb_index_stats CREATE TABLE `innodb_index_stats` (
+ `database_name` varchar(64) NOT NULL,
+ `table_name` varchar(199) NOT NULL,
+ `index_name` varchar(64) NOT NULL,
+ `last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `stat_name` varchar(64) NOT NULL,
+ `stat_value` bigint(20) unsigned NOT NULL,
+ `sample_size` bigint(20) unsigned DEFAULT NULL,
+ `stat_description` varchar(1024) NOT NULL,
+ PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
+SET @@global.innodb_stats_persistent=1;
diff --git a/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp_stat_tables.test b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp_stat_tables.test
new file mode 100644
index 00000000000..d22c94c6f82
--- /dev/null
+++ b/plugin/type_mysql_timestamp/mysql-test/type_mysql_timestamp/type_mysql_timestamp_stat_tables.test
@@ -0,0 +1,24 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
+--echo #
+
+SET @@global.innodb_stats_persistent=0;
+SHOW CREATE TABLE mysql.innodb_table_stats;
+ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_table_stats;
+ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_index_stats;
+SET @@global.innodb_stats_persistent=1;
+
+CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (10);
+DROP TABLE t1;
+
+SET @@global.innodb_stats_persistent=0;
+ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_table_stats;
+ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP;
+SHOW CREATE TABLE mysql.innodb_index_stats;
+SET @@global.innodb_stats_persistent=1;
diff --git a/plugin/type_mysql_timestamp/plugin.cc b/plugin/type_mysql_timestamp/plugin.cc
new file mode 100644
index 00000000000..fd6ad896aa7
--- /dev/null
+++ b/plugin/type_mysql_timestamp/plugin.cc
@@ -0,0 +1,177 @@
+/*
+ Copyright (c) 2023, 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 Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include
+#include
+#include
+#include "sql_type.h"
+
+
+class Type_collection_local: public Type_collection
+{
+protected:
+ const Type_handler *aggregate_common(const Type_handler *h1,
+ const Type_handler *h2) const;
+public:
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+
+ const Type_handler *aggregate_for_result(const Type_handler *h1,
+ const Type_handler *h2)
+ const override
+ {
+ return aggregate_common(h1, h2);
+ }
+
+ const Type_handler *aggregate_for_comparison(const Type_handler *h1,
+ const Type_handler *h2)
+ const override
+ {
+ return aggregate_common(h1, h2);
+ }
+
+ const Type_handler *aggregate_for_min_max(const Type_handler *h1,
+ const Type_handler *h2)
+ const override
+ {
+ return aggregate_common(h1, h2);
+ }
+
+ const Type_handler *aggregate_for_num_op(const Type_handler *h1,
+ const Type_handler *h2)
+ const override
+ {
+ return aggregate_common(h1, h2);
+ }
+};
+
+
+static Type_collection_local type_collection_local;
+
+
+/*
+ A more MySQL compatible Field:
+ it does not set the UNSIGNED_FLAG.
+ This is how MySQL's Field_timestampf works.
+*/
+class Field_mysql_timestampf :public Field_timestampf
+{
+public:
+ Field_mysql_timestampf(const LEX_CSTRING &name,
+ const Record_addr &addr,
+ enum utype unireg_check_arg,
+ TABLE_SHARE *share, decimal_digits_t dec_arg)
+ :Field_timestampf(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ unireg_check_arg, &name, share, dec_arg)
+ {
+ flags&= ~UNSIGNED_FLAG; // MySQL compatibility
+ }
+ void sql_type(String &str) const override
+ {
+ sql_type_opt_dec_comment(str,
+ Field_mysql_timestampf::type_handler()->name(),
+ dec, type_version_mysql56());
+ }
+ const Type_handler *type_handler() const override;
+};
+
+
+class Type_handler_mysql_timestamp2: public Type_handler_timestamp2
+{
+public:
+ const Type_collection *type_collection() const override
+ {
+ return &type_collection_local;
+ }
+ Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override
+ {
+ return new (root)
+ Field_mysql_timestampf(*name, rec, attr->unireg_check, share,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+ }
+ void Column_definition_implicit_upgrade(Column_definition *c) const override
+ {
+ /*
+ Suppress the automatic upgrade depending on opt_mysql56_temporal_format,
+ derived from Type_handler_timestamp_common.
+ */
+ }
+};
+
+
+static Type_handler_mysql_timestamp2 type_handler_mysql_timestamp2;
+
+
+const Type_handler *Field_mysql_timestampf::type_handler() const
+{
+ return &type_handler_mysql_timestamp2;
+}
+
+
+const Type_handler *
+Type_collection_local::aggregate_common(const Type_handler *h1,
+ const Type_handler *h2) const
+{
+ if (h1 == h2)
+ return h1;
+
+ static const Type_aggregator::Pair agg[]=
+ {
+ {
+ &type_handler_timestamp2,
+ &type_handler_mysql_timestamp2,
+ &type_handler_mysql_timestamp2
+ },
+ {NULL,NULL,NULL}
+ };
+
+ return Type_aggregator::find_handler_in_array(agg, h1, h2, true);
+}
+
+
+static struct st_mariadb_data_type plugin_descriptor_type_mysql_timestamp=
+{
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ &type_handler_mysql_timestamp2
+};
+
+
+
+/*************************************************************************/
+
+maria_declare_plugin(type_mysql_timestamp)
+{
+ MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_type_mysql_timestamp, // pointer to type-specific plugin descriptor
+ "type_mysql_timestamp", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Data type TYPE_MYSQL_TIMESTAMP", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/
+}
+maria_declare_plugin_end;
diff --git a/sql/field.h b/sql/field.h
index 642456b9774..e57a93b6562 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -3354,7 +3354,7 @@ public:
/**
TIMESTAMP(0..6) - MySQL56 version
*/
-class Field_timestampf final :public Field_timestamp_with_dec {
+class Field_timestampf :public Field_timestamp_with_dec {
void store_TIMEVAL(const timeval &tv) override;
public:
Field_timestampf(uchar *ptr_arg,
diff --git a/sql/item_func.h b/sql/item_func.h
index 6e714814526..6df3b98276b 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -373,7 +373,7 @@ public:
{
for (uint i= 0; i < arg_count; i++)
{
- args[i]->no_rows_in_result();
+ args[i]->restore_to_before_no_rows_in_result();
}
}
void convert_const_compared_to_int_field(THD *thd);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 32392ab882e..d8f16405351 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1746,6 +1746,11 @@ static void close_connections(void)
(void) unlink(mysqld_unix_port);
}
}
+ /*
+ The following is needed to the threads stuck in
+ setup_connection_thread_globals()
+ to continue.
+ */
listen_sockets.free_memory();
mysql_mutex_unlock(&LOCK_start_thread);
@@ -2031,6 +2036,7 @@ static void clean_up(bool print_message)
end_ssl();
#ifndef EMBEDDED_LIBRARY
vio_end();
+ listen_sockets.free_memory();
#endif /*!EMBEDDED_LIBRARY*/
#if defined(ENABLED_DEBUG_SYNC)
/* End the debug sync facility. See debug_sync.cc. */
diff --git a/sql/sql_limit.h b/sql/sql_limit.h
index 41308bc12db..335aff9d215 100644
--- a/sql/sql_limit.h
+++ b/sql/sql_limit.h
@@ -61,6 +61,15 @@ class Select_limit_counters
with_ties= false;
}
+ /* Send the first row, still honoring offset_limit_cnt */
+ void send_first_row()
+ {
+ /* Guard against overflow */
+ if ((select_limit_cnt= offset_limit_cnt +1 ) == 0)
+ select_limit_cnt= offset_limit_cnt;
+ // with_ties= false; Remove // on merge to 10.6
+ }
+
bool is_unlimited() const
{ return select_limit_cnt == HA_POS_ERROR; }
/*
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2bb28e09ac2..363356eb385 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -149,10 +149,10 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order);
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
bool change_list, bool *simple_order);
static int return_zero_rows(JOIN *join, select_result *res,
- List &tables,
- List- &fields, bool send_row,
+ List *tables,
+ List
- *fields, bool send_row,
ulonglong select_options, const char *info,
- Item *having, List
- &all_fields);
+ Item *having, List
- *all_fields);
static COND *build_equal_items(JOIN *join, COND *cond,
COND_EQUAL *inherited,
List *join_list,
@@ -1299,11 +1299,40 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
DBUG_RETURN(0);
}
+
/*****************************************************************************
Check fields, find best join, do the select and output fields.
mysql_select assumes that all tables are already opened
*****************************************************************************/
+/*
+ Check if we have a field reference. If yes, we have to use
+ mixed_implicit_grouping.
+*/
+
+static bool check_list_for_field(List
- *items)
+{
+ List_iterator_fast
- select_it(*items);
+ Item *select_el;
+
+ while ((select_el= select_it++))
+ {
+ if (select_el->with_field())
+ return true;
+ }
+ return false;
+}
+
+static bool check_list_for_field(ORDER *order)
+{
+ for (; order; order= order->next)
+ {
+ if (order->item[0]->with_field())
+ return true;
+ }
+ return false;
+}
+
/**
Prepare of whole select (including sub queries in future).
@@ -1385,53 +1414,44 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
DBUG_RETURN(-1);
/*
- TRUE if the SELECT list mixes elements with and without grouping,
- and there is no GROUP BY clause. Mixing non-aggregated fields with
- aggregate functions in the SELECT list is a MySQL extenstion that
- is allowed only if the ONLY_FULL_GROUP_BY sql mode is not set.
+ mixed_implicit_grouping will be set to TRUE if the SELECT list
+ mixes elements with and without grouping, and there is no GROUP BY
+ clause.
+ Mixing non-aggregated fields with aggregate functions in the
+ SELECT list or HAVING is a MySQL extension that is allowed only if
+ the ONLY_FULL_GROUP_BY sql mode is not set.
*/
mixed_implicit_grouping= false;
if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
select_lex->with_sum_func && !group_list)
{
- List_iterator_fast
- select_it(fields_list);
- Item *select_el; /* Element of the SELECT clause, can be an expression. */
- bool found_field_elem= false;
- bool found_sum_func_elem= false;
-
- while ((select_el= select_it++))
+ if (check_list_for_field(&fields_list) ||
+ check_list_for_field(order))
{
- if (select_el->with_sum_func())
- found_sum_func_elem= true;
- if (select_el->with_field())
- found_field_elem= true;
- if (found_sum_func_elem && found_field_elem)
+ List_iterator_fast li(select_lex->leaf_tables);
+
+ mixed_implicit_grouping= true; // mark for future
+
+ while (TABLE_LIST *tbl= li++)
{
- mixed_implicit_grouping= true;
- break;
+ /*
+ If the query uses implicit grouping where the select list
+ contains both aggregate functions and non-aggregate fields,
+ any non-aggregated field may produce a NULL value. Set all
+ fields of each table as nullable before semantic analysis to
+ take into account this change of nullability.
+
+ Note: this loop doesn't touch tables inside merged
+ semi-joins, because subquery-to-semijoin conversion has not
+ been done yet. This is intended.
+ */
+ if (tbl->table)
+ tbl->table->maybe_null= 1;
}
}
}
-
table_count= select_lex->leaf_tables.elements;
- TABLE_LIST *tbl;
- List_iterator_fast li(select_lex->leaf_tables);
- while ((tbl= li++))
- {
- /*
- If the query uses implicit grouping where the select list contains both
- aggregate functions and non-aggregate fields, any non-aggregated field
- may produce a NULL value. Set all fields of each table as nullable before
- semantic analysis to take into account this change of nullability.
-
- Note: this loop doesn't touch tables inside merged semi-joins, because
- subquery-to-semijoin conversion has not been done yet. This is intended.
- */
- if (mixed_implicit_grouping && tbl->table)
- tbl->table->maybe_null= 1;
- }
-
uint real_og_num= og_num;
if (skip_order_by &&
select_lex != select_lex->master_unit()->global_parameters())
@@ -1444,14 +1464,14 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
DBUG_RETURN(-1);
ref_ptrs= ref_ptr_array_slice(0);
-
+
enum_parsing_place save_place=
thd->lex->current_select->context_analysis_place;
thd->lex->current_select->context_analysis_place= SELECT_LIST;
{
List_iterator_fast it(select_lex->leaf_tables);
- while ((tbl= it++))
+ while (TABLE_LIST *tbl= it++)
{
if (tbl->table_function &&
tbl->table_function->setup(thd, tbl, select_lex_arg))
@@ -4069,7 +4089,7 @@ bool JOIN::make_aggr_tables_info()
set_items_ref_array(items0);
if (join_tab)
join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
- setup_end_select_func(this, NULL);
+ setup_end_select_func(this);
group= has_group_by;
DBUG_RETURN(false);
@@ -4464,13 +4484,7 @@ JOIN::reinit()
}
}
- /* Reset of sum functions */
- if (sum_funcs)
- {
- Item_sum *func, **func_ptr= sum_funcs;
- while ((func= *(func_ptr++)))
- func->clear();
- }
+ clear_sum_funcs();
if (no_rows_in_result_called)
{
@@ -4753,12 +4767,12 @@ void JOIN::exec_inner()
}
else
{
- (void) return_zero_rows(this, result, select_lex->leaf_tables,
- *columns_list,
+ (void) return_zero_rows(this, result, &select_lex->leaf_tables,
+ columns_list,
send_row_on_empty_set(),
select_options,
zero_result_cause,
- having ? having : tmp_having, all_fields);
+ having ? having : tmp_having, &all_fields);
DBUG_VOID_RETURN;
}
}
@@ -15301,10 +15315,36 @@ ORDER *simple_remove_const(ORDER *order, COND *where)
}
+/*
+ Set all fields in the table to have a null value
+
+ @param tables Table list
+*/
+
+static void make_tables_null_complemented(List *tables)
+{
+ List_iterator ti(*tables);
+ TABLE_LIST *table;
+ while ((table= ti++))
+ {
+ /*
+ Don't touch semi-join materialization tables, as the a join_free()
+ call may have freed them (and HAVING clause can't have references to
+ them anyway).
+ */
+ if (!table->is_jtbm())
+ {
+ TABLE *tbl= table->table;
+ mark_as_null_row(tbl); // Set fields to NULL
+ }
+ }
+}
+
+
static int
-return_zero_rows(JOIN *join, select_result *result, List &tables,
- List
- &fields, bool send_row, ulonglong select_options,
- const char *info, Item *having, List
- &all_fields)
+return_zero_rows(JOIN *join, select_result *result, List *tables,
+ List
- *fields, bool send_row, ulonglong select_options,
+ const char *info, Item *having, List
- *all_fields)
{
DBUG_ENTER("return_zero_rows");
@@ -15320,24 +15360,15 @@ return_zero_rows(JOIN *join, select_result *result, List &tables,
Set all tables to have NULL row. This is needed as we will be evaluating
HAVING condition.
*/
- List_iterator ti(tables);
- TABLE_LIST *table;
- while ((table= ti++))
- {
- /*
- Don't touch semi-join materialization tables, as the above join_free()
- call has freed them (and HAVING clause can't have references to them
- anyway).
- */
- if (!table->is_jtbm())
- mark_as_null_row(table->table); // All fields are NULL
- }
- List_iterator_fast
- it(all_fields);
+ make_tables_null_complemented(tables);
+
+ List_iterator_fast
- it(*all_fields);
Item *item;
/*
Inform all items (especially aggregating) to calculate HAVING correctly,
also we will need it for sending results.
*/
+ join->no_rows_in_result_called= 1;
while ((item= it++))
item->no_rows_in_result();
if (having && having->val_int() == 0)
@@ -15351,12 +15382,12 @@ return_zero_rows(JOIN *join, select_result *result, List &tables,
join->thd->limit_found_rows= 0;
}
- if (!(result->send_result_set_metadata(fields,
+ if (!(result->send_result_set_metadata(*fields,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
{
bool send_error= FALSE;
if (send_row)
- send_error= result->send_data_with_check(fields, join->unit, 0) > 0;
+ send_error= result->send_data_with_check(*fields, join->unit, 0) > 0;
if (likely(!send_error))
result->send_eof(); // Should be safe
}
@@ -15372,49 +15403,42 @@ return_zero_rows(JOIN *join, select_result *result, List &tables,
}
/**
- used only in JOIN::clear (always) and in do_select()
- (if there where no matching rows)
+ Reset table rows to contain a null-complement row (all fields are null)
+
+ Used only in JOIN::clear() and in do_select() if there where no matching rows.
@param join JOIN
- @param cleared_tables If not null, clear also const tables and mark all
- cleared tables in the map. cleared_tables is only
- set when called from do_select() when there is a
- group function and there where no matching rows.
+ @param cleared_tables Used to mark all cleared tables in the map. Needed for
+ unclear_tables() to know which tables to restore to
+ their original state.
*/
static void clear_tables(JOIN *join, table_map *cleared_tables)
{
- /*
- must clear only the non-const tables as const tables are not re-calculated.
- */
+ DBUG_ASSERT(cleared_tables);
for (uint i= 0 ; i < join->table_count ; i++)
{
TABLE *table= join->table[i];
if (table->null_row)
continue; // Nothing more to do
- if (!(table->map & join->const_table_map) || cleared_tables)
+ (*cleared_tables)|= (((table_map) 1) << i);
+ if (table->s->null_bytes)
{
- if (cleared_tables)
- {
- (*cleared_tables)|= (((table_map) 1) << i);
- if (table->s->null_bytes)
- {
- /*
- Remember null bits for the record so that we can restore the
- original const record in unclear_tables()
- */
- memcpy(table->record[1], table->null_flags, table->s->null_bytes);
- }
- }
- mark_as_null_row(table); // All fields are NULL
+ /*
+ Remember null bits for the record so that we can restore the
+ original const record in unclear_tables()
+ */
+ memcpy(table->record[1], table->null_flags, table->s->null_bytes);
}
+ mark_as_null_row(table); // All fields are NULL
}
}
/**
Reverse null marking for tables and restore null bits.
+ This return the tables to the state of before clear_tables().
We have to do this because the tables may be re-used in a sub query
and the subquery will assume that the const tables contains the original
@@ -21043,9 +21067,9 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab)
end_select function to use. This function can't fail.
*/
-Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab)
+Next_select_func setup_end_select_func(JOIN *join)
{
- TMP_TABLE_PARAM *tmp_tbl= tab ? tab->tmp_table_param : &join->tmp_table_param;
+ TMP_TABLE_PARAM *tmp_tbl= &join->tmp_table_param;
/*
Choose method for presenting result to user. Use end_send_group
@@ -21115,7 +21139,7 @@ do_select(JOIN *join, Procedure *procedure)
join->duplicate_rows= join->send_records=0;
if (join->only_const_tables() && !join->need_tmp)
{
- Next_select_func end_select= setup_end_select_func(join, NULL);
+ Next_select_func end_select= setup_end_select_func(join);
/*
HAVING will be checked after processing aggregate functions,
@@ -21590,6 +21614,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
}
}
+ /* Restore state if mark_as_null_row() have been called */
if (join_tab->last_inner)
{
JOIN_TAB *last_inner_tab= join_tab->last_inner;
@@ -23002,11 +23027,18 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
{
int idx= -1;
enum_nested_loop_state ok_code= NESTED_LOOP_OK;
+ /*
+ join_tab can be 0 in the case all tables are const tables and we did not
+ need a temporary table to store the result.
+ In this case we use the original given fields, which is stored in
+ join->fields.
+ */
List
- *fields= join_tab ? (join_tab-1)->fields : join->fields;
DBUG_ENTER("end_send_group");
if (!join->items3.is_null() && !join->set_group_rpa)
{
+ /* Move ref_pointer_array to points to items3 */
join->set_group_rpa= true;
join->set_items_ref_array(join->items3);
}
@@ -23014,10 +23046,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
if (!join->first_record || end_of_records ||
(idx=test_if_group_changed(join->group_fields)) >= 0)
{
+
if (!join->group_sent &&
(join->first_record ||
(end_of_records && !join->group && !join->group_optimized_away)))
{
+ table_map cleared_tables= (table_map) 0;
if (join->procedure)
join->procedure->end_group();
/* Test if there was a group change. */
@@ -23042,11 +23076,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
/* Reset all sum functions on group change. */
if (!join->first_record)
{
- List_iterator_fast
- it(*join->fields);
- Item *item;
/* No matching rows for group function */
- join->clear();
+ List_iterator_fast
- it(*fields);
+ Item *item;
+ join->no_rows_in_result_called= 1;
+
+ join->clear(&cleared_tables);
while ((item= it++))
item->no_rows_in_result();
}
@@ -23074,7 +23110,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
if (join->rollup_send_data((uint) (idx+1)))
error= 1;
}
- }
+ if (join->no_rows_in_result_called)
+ {
+ /* Restore null tables to original state */
+ join->no_rows_in_result_called= 0;
+ if (cleared_tables)
+ unclear_tables(join, &cleared_tables);
+ }
+ }
if (unlikely(error > 0))
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if (end_of_records)
@@ -23391,6 +23434,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (join->first_record || (end_of_records && !join->group))
{
+ table_map cleared_tables= (table_map) 0;
if (join->procedure)
join->procedure->end_group();
int send_group_parts= join->send_group_parts;
@@ -23399,7 +23443,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!join->first_record)
{
/* No matching rows for group function */
- join->clear();
+ join->clear(&cleared_tables);
}
copy_sum_funcs(join->sum_funcs,
join->sum_funcs_end[send_group_parts]);
@@ -23422,6 +23466,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(NESTED_LOOP_ERROR);
}
}
+ if (cleared_tables)
+ unclear_tables(join, &cleared_tables);
if (end_of_records)
goto end;
}
@@ -25153,7 +25199,7 @@ JOIN_TAB::remove_duplicates()
!(join->select_options & OPTION_FOUND_ROWS))
{
// only const items with no OPTION_FOUND_ROWS
- join->unit->lim.set_single_row(); // Only send first row
+ join->unit->lim.send_first_row(); // Only send first row
my_free(sortorder);
DBUG_RETURN(false);
}
@@ -27557,11 +27603,8 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg,
(end_send_group/end_write_group)
*/
-void JOIN::clear()
+void inline JOIN::clear_sum_funcs()
{
- clear_tables(this, 0);
- copy_fields(&tmp_table_param);
-
if (sum_funcs)
{
Item_sum *func, **func_ptr= sum_funcs;
@@ -27571,6 +27614,22 @@ void JOIN::clear()
}
+/*
+ Prepare for returning 'empty row' when there is no matching row.
+
+ - Mark all tables with mark_as_null_row()
+ - Make a copy of of all simple SELECT items
+ - Reset all sum functions to NULL or 0.
+*/
+
+void JOIN::clear(table_map *cleared_tables)
+{
+ clear_tables(this, cleared_tables);
+ copy_fields(&tmp_table_param);
+ clear_sum_funcs();
+}
+
+
/**
Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
diff --git a/sql/sql_select.h b/sql/sql_select.h
index d5ca921d8d5..1dc16cb8b74 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -227,7 +227,7 @@ enum sj_strategy_enum
typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
-Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab);
+Next_select_func setup_end_select_func(JOIN *join);
int rr_sequential(READ_RECORD *info);
int read_record_func_for_rr_and_unpack(READ_RECORD *info);
Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
@@ -1701,7 +1701,8 @@ public:
void join_free();
/** Cleanup this JOIN, possibly for reuse */
void cleanup(bool full);
- void clear();
+ void clear(table_map *cleared_tables);
+ void inline clear_sum_funcs();
bool send_row_on_empty_set()
{
return (do_send_rows && implicit_grouping && !group_optimized_away &&
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 52c17d61d2e..8ebdb38db49 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -7574,8 +7574,9 @@ extern Named_type_handler type_handler_time;
extern Named_type_handler type_handler_time2;
extern Named_type_handler type_handler_datetime;
extern Named_type_handler type_handler_datetime2;
-extern Named_type_handler type_handler_timestamp;
-extern Named_type_handler type_handler_timestamp2;
+
+extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_timestamp;
+extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_timestamp2;
extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
diff --git a/sql/table.h b/sql/table.h
index 2cbe00e6910..e75905d4998 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -3366,10 +3366,16 @@ inline void mark_as_null_row(TABLE *table)
bfill(table->null_flags,table->s->null_bytes,255);
}
+/*
+ Restore table to state before mark_as_null_row() call.
+ This assumes that the caller has restored table->null_flags,
+ as is done in unclear_tables().
+*/
+
inline void unmark_as_null_row(TABLE *table)
{
- table->null_row=0;
- table->status= STATUS_NO_RECORD;
+ table->null_row= 0;
+ table->status&= ~STATUS_NULL_ROW;
}
bool is_simple_order(ORDER *order);
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 39f5943d5a4..2e8d87dad9e 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -204,7 +204,17 @@ static const dict_table_schema_t table_stats_schema =
{
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
- {"last_update", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 4},
+ /*
+ Don't check the DATA_UNSIGNED flag in last_update.
+ It presents if the server is running in a pure MariaDB installation,
+ because MariaDB's Field_timestampf::flags has UNSIGNED_FLAG.
+ But DATA_UNSIGNED misses when the server starts on a MySQL-5.7 directory
+ (during a migration), because MySQL's Field_timestampf::flags does not
+ have UNSIGNED_FLAG.
+ This is fine not to check DATA_UNSIGNED, because Field_timestampf
+ in both MariaDB and MySQL support only non-negative time_t values.
+ */
+ {"last_update", DATA_INT, DATA_NOT_NULL, 4},
{"n_rows", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
{"clustered_index_size", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
{"sum_of_other_index_sizes", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
@@ -218,7 +228,11 @@ static const dict_table_schema_t index_stats_schema =
{"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
{"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
{"index_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
- {"last_update", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 4},
+ /*
+ Don't check the DATA_UNSIGNED flag in last_update.
+ See comments about last_update in table_stats_schema above.
+ */
+ {"last_update", DATA_INT, DATA_NOT_NULL, 4},
{"stat_name", DATA_VARMYSQL, DATA_NOT_NULL, 64*3},
{"stat_value", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
{"sample_size", DATA_INT, DATA_UNSIGNED, 8},
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index c6044b201fe..48415f2a2dc 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -1284,23 +1284,20 @@ static dberr_t fsp_free_page(fil_space_t *space, page_no_t offset, mtr_t *mtr)
+ header->page.frame, frag_n_used - 1);
}
+ mtr->free(*space, static_cast(offset));
+ xdes_set_free(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
+ ut_ad(err == DB_SUCCESS);
+
if (!xdes_get_n_used(descr)) {
/* The extent has become free: move it to another list */
err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG,
xdes, xoffset, mtr);
- if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
- return err;
- }
- err = fsp_free_extent(space, offset, mtr);
- if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
- return err;
+ if (err == DB_SUCCESS) {
+ err = fsp_free_extent(space, offset, mtr);
}
}
- mtr->free(*space, static_cast(offset));
- xdes_set_free(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
-
- return DB_SUCCESS;
+ return err;
}
/** @return Number of segment inodes which fit on a single page */
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index 58bb6ab02a2..21e0491d6dd 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -399,12 +399,13 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr)
}
/** Remove unnecessary history data from a rollback segment.
-@param[in,out] rseg rollback segment
-@param[in] limit truncate anything before this
+@param rseg rollback segment
+@param limit truncate anything before this
+@param all whether everything can be truncated
@return error code */
static dberr_t
-trx_purge_truncate_rseg_history(trx_rseg_t& rseg,
- const purge_sys_t::iterator& limit)
+trx_purge_truncate_rseg_history(trx_rseg_t &rseg,
+ const purge_sys_t::iterator &limit, bool all)
{
fil_addr_t hdr_addr;
mtr_t mtr;
@@ -447,6 +448,9 @@ loop:
goto func_exit;
}
+ if (!all)
+ goto func_exit;
+
fil_addr_t prev_hdr_addr=
flst_get_prev_addr(b->page.frame + hdr_addr.boffset +
TRX_UNDO_HISTORY_NODE);
@@ -486,9 +490,9 @@ loop:
if (undo->hdr_page_no == hdr_addr.page)
goto found_cached;
ut_ad("inconsistent undo logs" == 0);
- break;
- found_cached:
- UT_LIST_REMOVE(rseg.undo_cached, undo);
+ if (false)
+ found_cached:
+ UT_LIST_REMOVE(rseg.undo_cached, undo);
static_assert(FIL_NULL == 0xffffffff, "");
if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT +
rseg_hdr->page.frame)))
@@ -584,9 +588,11 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
{
ut_ad(rseg.is_persistent());
rseg.latch.wr_lock(SRW_LOCK_CALL);
- if (!rseg.is_referenced() && rseg.needs_purge <= head.trx_no)
- if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head))
- err= e;
+ if (dberr_t e=
+ trx_purge_truncate_rseg_history(rseg, head,
+ !rseg.is_referenced() &&
+ rseg.needs_purge <= head.trx_no))
+ err= e;
rseg.latch.wr_unlock();
}
@@ -664,7 +670,8 @@ not_free:
}
ut_ad(rseg.curr_size > cached);
- if (rseg.curr_size > cached + 1)
+ if (rseg.curr_size > cached + 1 &&
+ (rseg.history_size || srv_fast_shutdown || srv_undo_sources))
goto not_free;
rseg.latch.rd_unlock();
diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c
index b80c2b69f16..8b82a71ff7c 100644
--- a/storage/myisam/mi_open.c
+++ b/storage/myisam/mi_open.c
@@ -518,6 +518,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share->kfile=kfile;
share->this_process=(ulong) getpid();
share->last_process= share->state.process;
+ share->base.base_key_parts= base_key_parts;
share->base.key_parts=key_parts;
share->base.all_key_parts=key_parts+unique_key_parts;
if (!(share->last_version=share->state.version))
diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index c90d989c975..f84ad6fa184 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/myisam/myisamdef.h
@@ -132,7 +132,7 @@ typedef struct st_mi_base_info
uint extra_alloc_bytes;
uint extra_alloc_procent;
/* The following are from the header */
- uint key_parts, all_key_parts;
+ uint key_parts, all_key_parts, base_key_parts;
} MI_BASE_INFO;
diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c
index d9ea4b754f2..4a983684394 100644
--- a/storage/myisammrg/myrg_open.c
+++ b/storage/myisammrg/myrg_open.c
@@ -432,17 +432,20 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
first_child= FALSE;
m_info->reclength= myisam->s->base.reclength;
min_keys= myisam->s->base.keys;
- key_parts= myisam->s->base.key_parts;
+ key_parts= myisam->s->base.base_key_parts;
if (*need_compat_check && m_info->rec_per_key_part)
{
my_free(m_info->rec_per_key_part);
m_info->rec_per_key_part= NULL;
}
- if (!m_info->rec_per_key_part)
+ if (!m_info->rec_per_key_part || m_info->key_parts != key_parts)
{
- if(!(m_info->rec_per_key_part= (ulong*)
- my_malloc(rg_key_memory_MYRG_INFO,
- key_parts * sizeof(long), MYF(MY_WME))))
+ m_info->key_parts= key_parts;
+ /* The +1 is because by my_realloc() don't allow zero length */
+ if (!(m_info->rec_per_key_part= (ulong*)
+ my_realloc(rg_key_memory_MYRG_INFO, m_info->rec_per_key_part,
+ key_parts * sizeof(long) +1,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
goto err; /* purecov: inspected */
errpos= 1;
}
@@ -457,7 +460,8 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
myisam->open_flag|= HA_OPEN_MERGE_TABLE;
/* Check table definition match. */
- if (m_info->reclength != myisam->s->base.reclength)
+ if (m_info->reclength != myisam->s->base.reclength ||
+ key_parts != myisam->s->base.base_key_parts)
{
DBUG_PRINT("error", ("definition mismatch table: '%s' repair: %d",
myisam->filename,
diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_30370.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_30370.test
index 788ea2323f7..99e56ab062a 100644
--- a/storage/spider/mysql-test/spider/bugfix/t/mdev_30370.test
+++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_30370.test
@@ -2,4 +2,7 @@
--echo # MDEV-30370 mariadbd hangs when running with --wsrep-recover and --plugin-load-add=ha_spider.so
--echo #
---exec $MYSQLD_BOOTSTRAP_CMD --wsrep-recover --plugin-load-add=ha_spider.so
+let $MYSQLD_DATADIR=$MYSQLTEST_VARDIR/mdev_30370;
+--mkdir $MYSQLD_DATADIR
+--exec $MYSQLD_BOOTSTRAP_CMD --wsrep-recover --plugin-load-add=ha_spider.so --datadir=$MYSQLD_DATADIR
+--rmdir $MYSQLD_DATADIR