mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
Merge 10.5 into 10.6
This commit is contained in:
commit
270eeeb523
26 changed files with 601 additions and 154 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(<dir>])"
|
||||
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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 <subquery2> 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
|
||||
#
|
||||
|
|
|
@ -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 #
|
||||
|
|
|
@ -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
|
||||
#
|
||||
#
|
||||
|
|
|
@ -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 #
|
||||
|
|
|
@ -3919,3 +3919,15 @@ ERROR HY000: Unable to open underlying table which is differently defined or of
|
|||
DROP TRIGGER trg1;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE m1;
|
||||
#
|
||||
# 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
|
||||
|
|
|
@ -2923,3 +2923,15 @@ set global default_storage_engine=@save_default_storage_engine;
|
|||
# Check that all connections opened by test cases in this file are really
|
||||
# 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 #
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
/*
|
||||
|
|
|
@ -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<TABLE_LIST> &tables,
|
||||
List<Item> &fields, bool send_row,
|
||||
List<TABLE_LIST> *tables,
|
||||
List<Item> *fields, bool send_row,
|
||||
ulonglong select_options, const char *info,
|
||||
Item *having, List<Item> &all_fields);
|
||||
Item *having, List<Item> *all_fields);
|
||||
static COND *build_equal_items(JOIN *join, COND *cond,
|
||||
COND_EQUAL *inherited,
|
||||
List<TABLE_LIST> *join_list,
|
||||
|
@ -1274,11 +1274,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<Item> *items)
|
||||
{
|
||||
List_iterator_fast <Item> 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).
|
||||
|
@ -1360,53 +1389,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 <Item> 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<TABLE_LIST> 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<TABLE_LIST> 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())
|
||||
|
@ -1419,14 +1439,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<TABLE_LIST> 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))
|
||||
|
@ -4046,7 +4066,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);
|
||||
|
@ -4441,13 +4461,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)
|
||||
{
|
||||
|
@ -4730,12 +4744,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;
|
||||
}
|
||||
}
|
||||
|
@ -15278,10 +15292,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<TABLE_LIST> *tables)
|
||||
{
|
||||
List_iterator<TABLE_LIST> 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<TABLE_LIST> &tables,
|
||||
List<Item> &fields, bool send_row, ulonglong select_options,
|
||||
const char *info, Item *having, List<Item> &all_fields)
|
||||
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> *tables,
|
||||
List<Item> *fields, bool send_row, ulonglong select_options,
|
||||
const char *info, Item *having, List<Item> *all_fields)
|
||||
{
|
||||
DBUG_ENTER("return_zero_rows");
|
||||
|
||||
|
@ -15297,24 +15337,15 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
|||
Set all tables to have NULL row. This is needed as we will be evaluating
|
||||
HAVING condition.
|
||||
*/
|
||||
List_iterator<TABLE_LIST> 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<Item> it(all_fields);
|
||||
make_tables_null_complemented(tables);
|
||||
|
||||
List_iterator_fast<Item> 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)
|
||||
|
@ -15328,12 +15359,12 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_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
|
||||
}
|
||||
|
@ -15349,49 +15380,42 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_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
|
||||
|
@ -21020,9 +21044,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
|
||||
|
@ -21092,7 +21116,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,
|
||||
|
@ -21567,6 +21591,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;
|
||||
|
@ -22979,11 +23004,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<Item> *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);
|
||||
}
|
||||
|
@ -22991,10 +23023,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. */
|
||||
|
@ -23019,11 +23053,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<Item> it(*join->fields);
|
||||
Item *item;
|
||||
/* No matching rows for group function */
|
||||
join->clear();
|
||||
|
||||
List_iterator_fast<Item> it(*fields);
|
||||
Item *item;
|
||||
join->no_rows_in_result_called= 1;
|
||||
|
||||
join->clear(&cleared_tables);
|
||||
while ((item= it++))
|
||||
item->no_rows_in_result();
|
||||
}
|
||||
|
@ -23051,7 +23087,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)
|
||||
|
@ -23368,6 +23411,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;
|
||||
|
@ -23376,7 +23420,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]);
|
||||
|
@ -23399,6 +23443,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;
|
||||
}
|
||||
|
@ -25130,7 +25176,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);
|
||||
}
|
||||
|
@ -27527,11 +27573,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;
|
||||
|
@ -27541,6 +27584,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
|
||||
|
||||
|
|
|
@ -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 &&
|
||||
|
|
10
sql/table.h
10
sql/table.h
|
@ -3318,10 +3318,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);
|
||||
|
|
|
@ -664,7 +664,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();
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue