Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
1ce37bf3
Commit
1ce37bf3
authored
Nov 03, 2005
by
unknown
Browse files
Options
Browse Files
Download
Plain Diff
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/psergey/mysql-5.0-oct03-push
parents
0f69754c
8c72f9bd
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
522 additions
and
29 deletions
+522
-29
mysql-test/r/bigint.result
mysql-test/r/bigint.result
+1
-1
mysql-test/r/join_nested.result
mysql-test/r/join_nested.result
+64
-0
mysql-test/r/view.result
mysql-test/r/view.result
+22
-1
mysql-test/t/bigint.test
mysql-test/t/bigint.test
+1
-1
mysql-test/t/join_nested.test
mysql-test/t/join_nested.test
+68
-0
mysql-test/t/view.test
mysql-test/t/view.test
+25
-1
sql/mysql_priv.h
sql/mysql_priv.h
+6
-0
sql/sql_lex.cc
sql/sql_lex.cc
+30
-10
sql/sql_prepare.cc
sql/sql_prepare.cc
+0
-2
sql/sql_select.cc
sql/sql_select.cc
+286
-11
sql/sql_select.h
sql/sql_select.h
+10
-1
sql/table.h
sql/table.h
+9
-1
No files found.
mysql-test/r/bigint.result
View file @
1ce37bf3
drop table if exists t1;
drop table if exists t1
, t2
;
select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296;
0 256 00000000000000065536 2147483647 -2147483648 2147483648 4294967296
0 256 65536 2147483647 -2147483648 2147483648 4294967296
...
...
mysql-test/r/join_nested.result
View file @
1ce37bf3
...
...
@@ -1403,3 +1403,67 @@ SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d);
ERROR 42S22: Unknown column 'v2.x' in 'field list'
DROP VIEW v1, v2;
DROP TABLE t1, t2, t3, t4, t5, t6;
create table t1 (id1 int(11) not null);
insert into t1 values (1),(2);
create table t2 (id2 int(11) not null);
insert into t2 values (1),(2),(3),(4);
create table t3 (id3 char(16) not null);
insert into t3 values ('100');
create table t4 (id2 int(11) not null, id3 char(16));
create table t5 (id1 int(11) not null, key (id1));
insert into t5 values (1),(2),(1);
create view v1 as
select t4.id3 from t4 join t2 on t4.id2 = t2.id2;
select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3);
id1
1
2
drop view v1;
drop table t1, t2, t3, t4, t5;
create table t0 (a int);
insert into t0 values (0),(1),(2),(3);
create table t1(a int);
insert into t1 select A.a + 10*(B.a) from t0 A, t0 B;
create table t2 (a int, b int);
insert into t2 values (1,1), (2,2), (3,3);
create table t3(a int, b int, filler char(200), key(a));
insert into t3 select a,a,'filler' from t1;
insert into t3 select a,a,'filler' from t1;
create table t4 like t3;
insert into t4 select * from t3;
insert into t4 select * from t3;
create table t5 like t4;
insert into t5 select * from t4;
insert into t5 select * from t4;
create table t6 like t5;
insert into t6 select * from t5;
insert into t6 select * from t5;
create table t7 like t6;
insert into t7 select * from t6;
insert into t7 select * from t6;
explain select * from t4 join
t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL X
1 SIMPLE t3 ref a a 5 test.t2.b X
1 SIMPLE t5 ref a a 5 test.t3.b X
1 SIMPLE t4 ref a a 5 test.t3.b X Using where
explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b
join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL X
1 SIMPLE t3 ref a a 5 test.t2.b X Using where
1 SIMPLE t4 ref a a 5 test.t3.b X
1 SIMPLE t6 ref a a 5 test.t4.b X
1 SIMPLE t5 ref a a 5 test.t2.b X
1 SIMPLE t7 ref a a 5 test.t5.b X
explain select * from t2 left join
(t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b
join t5 on t5.a=t3.b) on t3.a=t2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL X
1 SIMPLE t3 ref a a 5 test.t2.b X
1 SIMPLE t4 ref a a 5 test.t3.b X
1 SIMPLE t6 ref a a 5 test.t4.b X
1 SIMPLE t5 ref a a 5 test.t3.b X
drop table t0, t1, t2, t4, t5, t6;
mysql-test/r/view.result
View file @
1ce37bf3
drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6;
drop table if exists t1,t2,t
3,t4,t
9,`t1a``b`,v1,v2,v3,v4,v5,v6;
drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6;
drop database if exists mysqltest;
use test;
...
...
@@ -2335,3 +2335,24 @@ f1 group_concat(f2 order by f2 desc)
1 3,2,1
drop view v1,v2;
drop table t1;
create table t1 (x int, y int);
create table t2 (x int, y int, z int);
create table t3 (x int, y int, z int);
create table t4 (x int, y int, z int);
create view v1 as
select t1.x
from (
(t1 join t2 on ((t1.y = t2.y)))
join
(t3 left join t4 on (t3.y = t4.y) and (t3.z = t4.z))
);
prepare stmt1 from "select count(*) from v1 where x = ?";
set @parm1=1;
execute stmt1 using @parm1;
count(*)
0
execute stmt1 using @parm1;
count(*)
0
drop view v1;
drop table t1,t2,t3,t4;
mysql-test/t/bigint.test
View file @
1ce37bf3
...
...
@@ -2,7 +2,7 @@
# Initialize
--
disable_warnings
drop
table
if
exists
t1
;
drop
table
if
exists
t1
,
t2
;
--
enable_warnings
#
...
...
mysql-test/t/join_nested.test
View file @
1ce37bf3
...
...
@@ -832,3 +832,71 @@ SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d);
DROP
VIEW
v1
,
v2
;
DROP
TABLE
t1
,
t2
,
t3
,
t4
,
t5
,
t6
;
#
# BUG#13126 -test case from bug report
#
create
table
t1
(
id1
int
(
11
)
not
null
);
insert
into
t1
values
(
1
),(
2
);
create
table
t2
(
id2
int
(
11
)
not
null
);
insert
into
t2
values
(
1
),(
2
),(
3
),(
4
);
create
table
t3
(
id3
char
(
16
)
not
null
);
insert
into
t3
values
(
'100'
);
create
table
t4
(
id2
int
(
11
)
not
null
,
id3
char
(
16
));
create
table
t5
(
id1
int
(
11
)
not
null
,
key
(
id1
));
insert
into
t5
values
(
1
),(
2
),(
1
);
create
view
v1
as
select
t4
.
id3
from
t4
join
t2
on
t4
.
id2
=
t2
.
id2
;
select
t1
.
id1
from
t1
inner
join
(
t3
left
join
v1
on
t3
.
id3
=
v1
.
id3
);
drop
view
v1
;
drop
table
t1
,
t2
,
t3
,
t4
,
t5
;
create
table
t0
(
a
int
);
insert
into
t0
values
(
0
),(
1
),(
2
),(
3
);
create
table
t1
(
a
int
);
insert
into
t1
select
A
.
a
+
10
*
(
B
.
a
)
from
t0
A
,
t0
B
;
create
table
t2
(
a
int
,
b
int
);
insert
into
t2
values
(
1
,
1
),
(
2
,
2
),
(
3
,
3
);
create
table
t3
(
a
int
,
b
int
,
filler
char
(
200
),
key
(
a
));
insert
into
t3
select
a
,
a
,
'filler'
from
t1
;
insert
into
t3
select
a
,
a
,
'filler'
from
t1
;
create
table
t4
like
t3
;
insert
into
t4
select
*
from
t3
;
insert
into
t4
select
*
from
t3
;
create
table
t5
like
t4
;
insert
into
t5
select
*
from
t4
;
insert
into
t5
select
*
from
t4
;
create
table
t6
like
t5
;
insert
into
t6
select
*
from
t5
;
insert
into
t6
select
*
from
t5
;
create
table
t7
like
t6
;
insert
into
t7
select
*
from
t6
;
insert
into
t7
select
*
from
t6
;
--
replace_column
9
X
explain
select
*
from
t4
join
t2
left
join
(
t3
join
t5
on
t5
.
a
=
t3
.
b
)
on
t3
.
a
=
t2
.
b
where
t4
.
a
<=>
t3
.
b
;
--
replace_column
9
X
explain
select
*
from
(
t4
join
t6
on
t6
.
a
=
t4
.
b
)
right
join
t3
on
t4
.
a
=
t3
.
b
join
t2
left
join
(
t5
join
t7
on
t7
.
a
=
t5
.
b
)
on
t5
.
a
=
t2
.
b
where
t3
.
a
<=>
t2
.
b
;
--
replace_column
9
X
explain
select
*
from
t2
left
join
(
t3
left
join
(
t4
join
t6
on
t6
.
a
=
t4
.
b
)
on
t4
.
a
=
t3
.
b
join
t5
on
t5
.
a
=
t3
.
b
)
on
t3
.
a
=
t2
.
b
;
drop
table
t0
,
t1
,
t2
,
t4
,
t5
,
t6
;
mysql-test/t/view.test
View file @
1ce37bf3
--
disable_warnings
drop
table
if
exists
t1
,
t2
,
t9
,
`t1a``b`
,
v1
,
v2
,
v3
,
v4
,
v5
,
v6
;
drop
table
if
exists
t1
,
t2
,
t
3
,
t4
,
t
9
,
`t1a``b`
,
v1
,
v2
,
v3
,
v4
,
v5
,
v6
;
drop
view
if
exists
t1
,
t2
,
`t1a``b`
,
v1
,
v2
,
v3
,
v4
,
v5
,
v6
;
drop
database
if
exists
mysqltest
;
--
enable_warnings
...
...
@@ -2200,3 +2200,27 @@ select * from v1;
select
*
from
v2
;
drop
view
v1
,
v2
;
drop
table
t1
;
#
# BUG#14026 Crash on second PS execution when using views
#
create
table
t1
(
x
int
,
y
int
);
create
table
t2
(
x
int
,
y
int
,
z
int
);
create
table
t3
(
x
int
,
y
int
,
z
int
);
create
table
t4
(
x
int
,
y
int
,
z
int
);
create
view
v1
as
select
t1
.
x
from
(
(
t1
join
t2
on
((
t1
.
y
=
t2
.
y
)))
join
(
t3
left
join
t4
on
(
t3
.
y
=
t4
.
y
)
and
(
t3
.
z
=
t4
.
z
))
);
prepare
stmt1
from
"select count(*) from v1 where x = ?"
;
set
@
parm1
=
1
;
execute
stmt1
using
@
parm1
;
execute
stmt1
using
@
parm1
;
drop
view
v1
;
drop
table
t1
,
t2
,
t3
,
t4
;
sql/mysql_priv.h
View file @
1ce37bf3
...
...
@@ -44,6 +44,12 @@
typedef
ulonglong
table_map
;
/* Used for table bits in join */
typedef
Bitmap
<
64
>
key_map
;
/* Used for finding keys */
typedef
ulong
key_part_map
;
/* Used for finding key parts */
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
structures that have not been simplified away and embed more the one
element)
*/
typedef
ulonglong
nested_join_map
;
/* query_id */
typedef
ulonglong
query_id_t
;
...
...
sql/sql_lex.cc
View file @
1ce37bf3
...
...
@@ -2037,6 +2037,35 @@ void st_lex::cleanup_after_one_table_open()
}
/*
Do end-of-prepare fixup for list of tables and their merge-VIEWed tables
SYNOPSIS
fix_prepare_info_in_table_list()
thd Thread handle
tbl List of tables to process
DESCRIPTION
Perform end-end-of prepare fixup for list of tables, if any of the tables
is a merge-algorithm VIEW, recursively fix up its underlying tables as
well.
*/
static
void
fix_prepare_info_in_table_list
(
THD
*
thd
,
TABLE_LIST
*
tbl
)
{
for
(;
tbl
;
tbl
=
tbl
->
next_local
)
{
if
(
tbl
->
on_expr
)
{
tbl
->
prep_on_expr
=
tbl
->
on_expr
;
tbl
->
on_expr
=
tbl
->
on_expr
->
copy_andor_structure
(
thd
);
}
fix_prepare_info_in_table_list
(
thd
,
tbl
->
merge_underlying_list
);
}
}
/*
fix some structures at the end of preparation
...
...
@@ -2056,16 +2085,7 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
prep_where
=
*
conds
;
*
conds
=
where
=
prep_where
->
copy_andor_structure
(
thd
);
}
for
(
TABLE_LIST
*
tbl
=
(
TABLE_LIST
*
)
table_list
.
first
;
tbl
;
tbl
=
tbl
->
next_local
)
{
if
(
tbl
->
on_expr
)
{
tbl
->
prep_on_expr
=
tbl
->
on_expr
;
tbl
->
on_expr
=
tbl
->
on_expr
->
copy_andor_structure
(
thd
);
}
}
fix_prepare_info_in_table_list
(
thd
,
(
TABLE_LIST
*
)
table_list
.
first
);
}
}
...
...
sql/sql_prepare.cc
View file @
1ce37bf3
...
...
@@ -2109,8 +2109,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
were closed in the end of previous prepare or execute call.
*/
tables
->
table
=
0
;
if
(
tables
->
nested_join
)
tables
->
nested_join
->
counter
=
0
;
if
(
tables
->
prep_on_expr
)
{
...
...
sql/sql_select.cc
View file @
1ce37bf3
...
...
@@ -98,6 +98,12 @@ static COND* substitute_for_best_equal_field(COND *cond,
void
*
table_join_idx
);
static
COND
*
simplify_joins
(
JOIN
*
join
,
List
<
TABLE_LIST
>
*
join_list
,
COND
*
conds
,
bool
top
);
static
bool
check_interleaving_with_nj
(
JOIN_TAB
*
last
,
JOIN_TAB
*
next
);
static
void
restore_prev_nj_state
(
JOIN_TAB
*
last
);
static
void
reset_nj_counters
(
List
<
TABLE_LIST
>
*
join_list
);
static
uint
build_bitmap_for_nested_joins
(
List
<
TABLE_LIST
>
*
join_list
,
uint
first_unused
);
static
COND
*
optimize_cond
(
JOIN
*
join
,
COND
*
conds
,
List
<
TABLE_LIST
>
*
join_list
,
Item
::
cond_result
*
cond_value
);
...
...
@@ -520,12 +526,14 @@ bool JOIN::test_in_subselect(Item **where)
return
0
;
}
/*
global select optimisation.
return 0 - success
1 - error
error code saved in field 'error'
*/
int
JOIN
::
optimize
()
{
...
...
@@ -588,6 +596,7 @@ JOIN::optimize()
/* Convert all outer joins to inner joins if possible */
conds
=
simplify_joins
(
this
,
join_list
,
conds
,
TRUE
);
build_bitmap_for_nested_joins
(
join_list
,
0
);
sel
->
prep_where
=
conds
?
conds
->
copy_andor_structure
(
thd
)
:
0
;
...
...
@@ -700,7 +709,8 @@ JOIN::optimize()
DBUG_PRINT
(
"error"
,(
"Error: make_select() failed"
));
DBUG_RETURN
(
1
);
}
reset_nj_counters
(
join_list
);
make_outerjoin_info
(
this
);
/*
...
...
@@ -1968,14 +1978,19 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
continue
;
}
outer_join
|=
table
->
map
;
s
->
embedding_map
=
0
;
for
(;
embedding
;
embedding
=
embedding
->
embedding
)
s
->
embedding_map
|=
embedding
->
nested_join
->
nj_map
;
continue
;
}
if
(
embedding
)
{
/* s belongs to a nested join, maybe to several embedded joins */
s
->
embedding_map
=
0
;
do
{
NESTED_JOIN
*
nested_join
=
embedding
->
nested_join
;
s
->
embedding_map
|=
nested_join
->
nj_map
;
s
->
dependent
|=
embedding
->
dep_tables
;
embedding
=
embedding
->
embedding
;
outer_join
|=
nested_join
->
used_tables
;
...
...
@@ -3549,6 +3564,8 @@ choose_plan(JOIN *join, table_map join_tables)
bool
straight_join
=
join
->
select_options
&
SELECT_STRAIGHT_JOIN
;
DBUG_ENTER
(
"choose_plan"
);
join
->
cur_embedding_map
=
0
;
reset_nj_counters
(
join
->
join_list
);
/*
if (SELECT_STRAIGHT_JOIN option is set)
reorder tables so dependent tables come after tables they depend
...
...
@@ -4029,7 +4046,9 @@ best_extension_by_limited_search(JOIN *join,
for
(
JOIN_TAB
**
pos
=
join
->
best_ref
+
idx
;
(
s
=
*
pos
)
;
pos
++
)
{
table_map
real_table_bit
=
s
->
table
->
map
;
if
((
remaining_tables
&
real_table_bit
)
&&
!
(
remaining_tables
&
s
->
dependent
))
if
((
remaining_tables
&
real_table_bit
)
&&
!
(
remaining_tables
&
s
->
dependent
)
&&
(
!
idx
||
!
check_interleaving_with_nj
(
join
->
positions
[
idx
-
1
].
table
,
s
)))
{
double
current_record_count
,
current_read_time
;
...
...
@@ -4045,6 +4064,7 @@ best_extension_by_limited_search(JOIN *join,
{
DBUG_EXECUTE
(
"opt"
,
print_plan
(
join
,
read_time
,
record_count
,
idx
,
"prune_by_cost"
););
restore_prev_nj_state
(
s
);
continue
;
}
...
...
@@ -4073,6 +4093,7 @@ best_extension_by_limited_search(JOIN *join,
{
DBUG_EXECUTE
(
"opt"
,
print_plan
(
join
,
read_time
,
record_count
,
idx
,
"pruned_by_heuristic"
););
restore_prev_nj_state
(
s
);
continue
;
}
}
...
...
@@ -4107,9 +4128,11 @@ best_extension_by_limited_search(JOIN *join,
sizeof
(
POSITION
)
*
(
idx
+
1
));
join
->
best_read
=
current_read_time
-
0.001
;
}
DBUG_EXECUTE
(
"opt"
,
print_plan
(
join
,
current_read_time
,
current_record_count
,
idx
,
"full_plan"
););
DBUG_EXECUTE
(
"opt"
,
print_plan
(
join
,
current_read_time
,
current_record_count
,
idx
,
"full_plan"
););
}
restore_prev_nj_state
(
s
);
}
}
DBUG_VOID_RETURN
;
...
...
@@ -4154,7 +4177,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
for
(
JOIN_TAB
**
pos
=
join
->
best_ref
+
idx
;
(
s
=*
pos
)
;
pos
++
)
{
table_map
real_table_bit
=
s
->
table
->
map
;
if
((
rest_tables
&
real_table_bit
)
&&
!
(
rest_tables
&
s
->
dependent
))
if
((
rest_tables
&
real_table_bit
)
&&
!
(
rest_tables
&
s
->
dependent
)
&&
(
!
idx
||
!
check_interleaving_with_nj
(
join
->
positions
[
idx
-
1
].
table
,
s
)))
{
double
best
,
best_time
,
records
;
best
=
best_time
=
records
=
DBL_MAX
;
...
...
@@ -4492,10 +4516,10 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
join
->
unit
->
select_limit_cnt
>=
records
)
join
->
sort_by_table
=
(
TABLE
*
)
1
;
// Must use temporary table
/*
/*
Go to the next level only if there hasn't been a better key on
this level! This will cut down the search for a lot simple cases!
*/
*/
double
current_record_count
=
record_count
*
records
;
double
current_read_time
=
read_time
+
best
;
if
(
best_record_count
>
current_record_count
||
...
...
@@ -4516,6 +4540,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
return
;
swap_variables
(
JOIN_TAB
*
,
join
->
best_ref
[
idx
],
*
pos
);
}
restore_prev_nj_state
(
s
);
if
(
join
->
select_options
&
SELECT_STRAIGHT_JOIN
)
break
;
// Don't test all combinations
}
...
...
@@ -5101,7 +5126,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
This function can be called only after the execution plan
has been chosen.
*/
static
void
make_outerjoin_info
(
JOIN
*
join
)
{
...
...
@@ -7262,11 +7287,11 @@ propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list,
ascent all attributes are calculated, all outer joins that can be
converted are replaced and then all unnecessary braces are removed.
As join list contains join tables in the reverse order sequential
elimination of outer joins does not requi
t
e extra recursive calls.
elimination of outer joins does not requi
r
e extra recursive calls.
EXAMPLES
Here is an example of a join query with invalid cross references:
SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN
ON
t3.b=t1.b
SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN
t3 ON
t3.b=t1.b
RETURN VALUE
The new condition, if success
...
...
@@ -7423,7 +7448,257 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
DBUG_RETURN
(
conds
);
}
/*
Assign each nested join structure a bit in nested_join_map
SYNOPSIS
build_bitmap_for_nested_joins()
join Join being processed
join_list List of tables
first_unused Number of first unused bit in nested_join_map before the
call
DESCRIPTION
Assign each nested join structure (except "confluent" ones - those that
embed only one element) a bit in nested_join_map.
NOTE
This function is called after simplify_joins(), when there are no
redundant nested joins, #non_confluent_nested_joins <= #tables_in_join so
we will not run out of bits in nested_join_map.
RETURN
First unused bit in nested_join_map after the call.
*/
static
uint
build_bitmap_for_nested_joins
(
List
<
TABLE_LIST
>
*
join_list
,
uint
first_unused
)
{
List_iterator
<
TABLE_LIST
>
li
(
*
join_list
);
TABLE_LIST
*
table
;
DBUG_ENTER
(
"build_bitmap_for_nested_joins"
);
while
((
table
=
li
++
))
{
NESTED_JOIN
*
nested_join
;
if
((
nested_join
=
table
->
nested_join
))
{
/*
It is guaranteed by simplify_joins() function that a nested join
that has only one child represents a single table VIEW (and the child
is an underlying table). We don't assign bits to such nested join
structures because
1. it is redundant (a "sequence" of one table cannot be interleaved
with anything)
2. we could run out bits in nested_join_map otherwise.
*/
if
(
nested_join
->
join_list
.
elements
!=
1
)
{
nested_join
->
nj_map
=
1
<<
first_unused
++
;
first_unused
=
build_bitmap_for_nested_joins
(
&
nested_join
->
join_list
,
first_unused
);
}
}
}
DBUG_RETURN
(
first_unused
);
}
/*
Set NESTED_JOIN::counter=0 in all nested joins in passed list
SYNOPSIS
reset_nj_counters()
join_list List of nested joins to process. It may also contain base
tables which will be ignored.
DESCRIPTION
Recursively set NESTED_JOIN::counter=0 for all nested joins contained in
the passed join_list.
*/
static
void
reset_nj_counters
(
List
<
TABLE_LIST
>
*
join_list
)
{
List_iterator
<
TABLE_LIST
>
li
(
*
join_list
);
TABLE_LIST
*
table
;
DBUG_ENTER
(
"reset_nj_counters"
);
while
((
table
=
li
++
))
{
NESTED_JOIN
*
nested_join
;
if
((
nested_join
=
table
->
nested_join
))
{
nested_join
->
counter
=
0
;
reset_nj_counters
(
&
nested_join
->
join_list
);
}
}
DBUG_VOID_RETURN
;
}
/*
Check interleaving with an inner tables of an outer join for extension table
SYNOPSIS
check_interleaving_with_nj()
join Join being processed
last_tab Last table in current partial join order (this function is
not called for empty partial join orders)
next_tab Table we're going to extend the current partial join with
DESCRIPTION
Check if table next_tab can be added to current partial join order, and
if yes, record that it has been added.
The function assumes that both current partial join order and its
extension with next_tab are valid wrt table dependencies.
IMPLEMENTATION
LIMITATIONS ON JOIN ORDER
The nested [outer] joins executioner algorithm imposes these limitations
on join order:
1. "Outer tables first" - any "outer" table must be before any
corresponding "inner" table.
2. "No interleaving" - tables inside a nested join must form a continuous
sequence in join order (i.e. the sequence must not be interrupted by
tables that are outside of this nested join).
#1 is checked elsewhere, this function checks #2 provided that #1 has
been already checked.
WHY NEED NON-INTERLEAVING
Consider an example:
select * from t0 join t1 left join (t2 join t3) on cond1
The join order "t1 t2 t0 t3" is invalid:
table t0 is outside of the nested join, so WHERE condition for t0 is
attached directly to t0 (without triggers, and it may be used to access
t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss
combinations of (t1, t2, t3) that satisfy condition cond1, and produce a
null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have
been produced.
If table t0 is not between t2 and t3, the problem doesn't exist:
* If t0 is located after (t2,t3), WHERE(t0) is applied after nested join
processing has finished.
* If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are
wrapped into condition triggers, which takes care of correct nested
join processing.
HOW IT IS IMPLEMENTED
The limitations on join order can be rephrased as follows: for valid
join order one must be able to:
1. write down the used tables in the join order on one line.
2. for each nested join, put one '(' and one ')' on the said line
3. write "LEFT JOIN" and "ON (...)" where appropriate
4. get a query equivalent to the query we're trying to execute.
Calls to check_interleaving_with_nj() are equivalent to writing the
above described line from left to right.
A single check_interleaving_with_nj(A,B) call is equivalent to writing
table B and appropriate brackets on condition that table A and
appropriate brackets is the last what was written. Graphically the
transition is as follows:
+---- current position
|
... last_tab ))) | ( next_tab ) )..) | ...
X Y Z |
+- need to move to this
position.
Notes about the position:
The caller guarantees that there is no more then one X-bracket by
checking "!(remaining_tables & s->dependent)" before calling this
function. X-bracket may have a pair in Y-bracket.
When "writing" we store/update this auxilary info about the current
position:
1. join->cur_embedding_map - bitmap of pairs of brackets (aka nested
joins) we've opened but didn't close.
2. {each NESTED_JOIN structure not simplified away}->counter - number
of this nested join's children that have already been added to to
the partial join order.
RETURN
FALSE Join order extended, nested joins info about current join order
(see NOTE section) updated.
TRUE Requested join order extension not allowed.
*/
static
bool
check_interleaving_with_nj
(
JOIN_TAB
*
last_tab
,
JOIN_TAB
*
next_tab
)
{
TABLE_LIST
*
next_emb
=
next_tab
->
table
->
pos_in_table_list
->
embedding
;
JOIN
*
join
=
last_tab
->
join
;
if
(
join
->
cur_embedding_map
&
~
next_tab
->
embedding_map
)
{
/*
next_tab is outside of the "pair of brackets" we're currently in.
Cannot add it.
*/
return
TRUE
;
}
/*
Do update counters for "pairs of brackets" that we've left (marked as
X,Y,Z in the above picture)
*/
for
(;
next_emb
;
next_emb
=
next_emb
->
embedding
)
{
next_emb
->
nested_join
->
counter
++
;
if
(
next_emb
->
nested_join
->
counter
==
1
)
{
/*
next_emb is the first table inside a nested join we've "entered". In
the picture above, we're looking at the 'X' bracket. Don't exit yet as
X bracket might have Y pair bracket.
*/
join
->
cur_embedding_map
|=
next_emb
->
nested_join
->
nj_map
;
}
if
(
next_emb
->
nested_join
->
join_list
.
elements
!=
next_emb
->
nested_join
->
counter
)
break
;
/*
We're currently at Y or Z-bracket as depicted in the above picture.
Mark that we've left it and continue walking up the brackets hierarchy.
*/
join
->
cur_embedding_map
&=
~
next_emb
->
nested_join
->
nj_map
;
}
return
FALSE
;
}
/*
Nested joins perspective: Remove the last table from the join order
SYNOPSIS
restore_prev_nj_state()
last join table to remove, it is assumed to be the last in current
partial join order.
DESCRIPTION
Remove the last table from the partial join order and update the nested
joins counters and join->cur_embedding_map. It is ok to call this
function for the first table in join order (for which
check_interleaving_with_nj has not been called)
*/
static
void
restore_prev_nj_state
(
JOIN_TAB
*
last
)
{
TABLE_LIST
*
last_emb
=
last
->
table
->
pos_in_table_list
->
embedding
;
JOIN
*
join
=
last
->
join
;
while
(
last_emb
&&
!
(
--
last_emb
->
nested_join
->
counter
))
{
join
->
cur_embedding_map
&=
last_emb
->
nested_join
->
nj_map
;
last_emb
=
last_emb
->
embedding
;
}
}
static
COND
*
optimize_cond
(
JOIN
*
join
,
COND
*
conds
,
List
<
TABLE_LIST
>
*
join_list
,
...
...
sql/sql_select.h
View file @
1ce37bf3
...
...
@@ -136,7 +136,9 @@ typedef struct st_join_table {
TABLE_REF
ref
;
JOIN_CACHE
cache
;
JOIN
*
join
;
/* Bitmap of nested joins this table is part of */
nested_join_map
embedding_map
;
void
cleanup
();
}
JOIN_TAB
;
...
...
@@ -193,6 +195,13 @@ class JOIN :public Sql_alloc
*/
ha_rows
fetch_limit
;
POSITION
positions
[
MAX_TABLES
+
1
],
best_positions
[
MAX_TABLES
+
1
];
/*
Bitmap of nested joins embedding the position at the end of the current
partial join (valid only during join optimizer run).
*/
nested_join_map
cur_embedding_map
;
double
best_read
;
List
<
Item
>
*
fields
;
List
<
Cached_item
>
group_fields
,
group_fields_cache
;
...
...
sql/table.h
View file @
1ce37bf3
...
...
@@ -795,7 +795,15 @@ typedef struct st_nested_join
table_map
used_tables
;
/* bitmap of tables in the nested join */
table_map
not_null_tables
;
/* tables that rejects nulls */
struct
st_join_table
*
first_nested
;
/* the first nested table in the plan */
uint
counter
;
/* to count tables in the nested join */
/*
Used to count tables in the nested join in 2 isolated places:
1. In make_outerjoin_info().
2. check_interleaving_with_nj/restore_prev_nj_state (these are called
by the join optimizer.
Before each use the counters are zeroed by reset_nj_counters.
*/
uint
counter
;
nested_join_map
nj_map
;
/* Bit used to identify this nested join*/
}
NESTED_JOIN
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment