developers
Threads by month
- ----- 2025 -----
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 7 participants
- 6852 discussions

[Maria-developers] bzr commit into MariaDB 5.1, with Maria 1.5:maria branch (knielsen:2716)
by knielsenīŧ knielsen-hq.org 07 Jul '09
by knielsenīŧ knielsen-hq.org 07 Jul '09
07 Jul '09
#At lp:maria
2716 knielsen(a)knielsen-hq.org 2009-07-07
Solaris 10 build script fixes by Toby Thain.
Added build scripts for 32 bit x86 architecture on Solaris.
Renamed some scripts for consistency.
Changed to dynamic linking of libgcc.
removed:
BUILD/compile-solaris-amd64-forte-debug
added:
BUILD/compile-solaris-amd64-debug-forte
BUILD/compile-solaris-x86-32
BUILD/compile-solaris-x86-32-debug
BUILD/compile-solaris-x86-32-debug-forte
BUILD/compile-solaris-x86-forte-32
modified:
BUILD/compile-solaris-amd64
BUILD/compile-solaris-amd64-debug
per-file messages:
BUILD/compile-solaris-amd64
Changed to dynamic linking of libgcc.
The -static-libgcc was a legacy of the original build scripts. -R
(analogous to -L link time search path) is a Solaris mechanism to
ensure a needed lib directory is searched at runtime.
In Solaris 10, gcc comes bundled, under /usr/sfw, allowing to use it without
creating dependency problems. This allows eg. benefiting from ordinary system
patch maintenance.
BUILD/compile-solaris-amd64-debug
Changed to dynamic linking of libgcc.
The -static-libgcc was a legacy of the original build scripts. -R
(analogous to -L link time search path) is a Solaris mechanism to
ensure a needed lib directory is searched at runtime.
In Solaris 10, gcc comes bundled, under /usr/sfw, allowing to use it without
creating dependency problems. This allows eg. benefiting from ordinary system
patch maintenance.
=== modified file 'BUILD/compile-solaris-amd64'
--- a/BUILD/compile-solaris-amd64 2009-05-09 04:01:53 +0000
+++ b/BUILD/compile-solaris-amd64 2009-07-07 11:19:24 +0000
@@ -26,7 +26,7 @@ path=`dirname $0`
extra_flags="$amd64_cflags -D__sun -m64 -mtune=athlon64"
extra_configs="$amd64_configs $max_configs --with-libevent"
-LDFLAGS="-lmtmalloc -static-libgcc"
+LDFLAGS="-lmtmalloc -R/usr/sfw/lib/64"
export LDFLAGS
. "$path/FINISH.sh"
=== modified file 'BUILD/compile-solaris-amd64-debug'
--- a/BUILD/compile-solaris-amd64-debug 2009-05-09 04:01:53 +0000
+++ b/BUILD/compile-solaris-amd64-debug 2009-07-07 11:19:24 +0000
@@ -5,7 +5,7 @@ path=`dirname $0`
extra_flags="$amd64_cflags -D__sun -m64 -mtune=athlon64 $debug_cflags"
extra_configs="$amd64_configs $debug_configs $max_configs --with-libevent"
-LDFLAGS="-lmtmalloc -static-libgcc"
+LDFLAGS="-lmtmalloc -R/usr/sfw/lib/64"
export LDFLAGS
. "$path/FINISH.sh"
=== added file 'BUILD/compile-solaris-amd64-debug-forte'
--- a/BUILD/compile-solaris-amd64-debug-forte 1970-01-01 00:00:00 +0000
+++ b/BUILD/compile-solaris-amd64-debug-forte 2009-07-07 11:19:24 +0000
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+# Take only #define options - the others are gcc specific.
+# (real fix is for SETUP.sh not to put gcc specific options in $debug_cflags)
+DEFS=""
+for F in $debug_cflags ; do
+ expr "$F" : "^-D" && DEFS="$DEFS $F"
+done
+debug_cflags="-O0 -g $DEFS"
+
+extra_flags="-m64 -mt -D_FORTEC_ -xlibmopt -fns=no $debug_cflags"
+extra_configs="$max_configs --with-libevent $debug_configs"
+
+warnings=""
+c_warnings=""
+cxx_warnings=""
+base_cxxflags="-noex"
+
+CC=cc
+CFLAGS="-xstrconst"
+CXX=CC
+LDFLAGS="-lmtmalloc"
+
+. "$path/FINISH.sh"
=== removed file 'BUILD/compile-solaris-amd64-forte-debug'
--- a/BUILD/compile-solaris-amd64-forte-debug 2009-05-09 04:01:53 +0000
+++ b/BUILD/compile-solaris-amd64-forte-debug 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-path=`dirname $0`
-. "$path/SETUP.sh"
-
-# Take only #define options - the others are gcc specific.
-# (real fix is for SETUP.sh not to put gcc specific options in $debug_cflags)
-DEFS=""
-for F in $debug_cflags ; do
- expr "$F" : "^-D" && DEFS="$DEFS $F"
-done
-debug_cflags="-O0 -g $DEFS"
-
-extra_flags="-m64 -mt -D_FORTEC_ -xlibmopt -fns=no $debug_cflags"
-extra_configs="$max_configs --with-libevent $debug_configs"
-
-warnings=""
-c_warnings=""
-cxx_warnings=""
-base_cxxflags="-noex"
-
-CC=cc
-CFLAGS="-xstrconst"
-CXX=CC
-LDFLAGS="-lmtmalloc"
-
-. "$path/FINISH.sh"
=== added file 'BUILD/compile-solaris-x86-32'
--- a/BUILD/compile-solaris-x86-32 1970-01-01 00:00:00 +0000
+++ b/BUILD/compile-solaris-x86-32 2009-07-07 11:19:24 +0000
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+extra_flags="-D__sun -m32"
+extra_configs="$max_configs --with-libevent"
+
+LDFLAGS="-lmtmalloc -R/usr/sfw/lib"
+export LDFLAGS
+
+. "$path/FINISH.sh"
=== added file 'BUILD/compile-solaris-x86-32-debug'
--- a/BUILD/compile-solaris-x86-32-debug 1970-01-01 00:00:00 +0000
+++ b/BUILD/compile-solaris-x86-32-debug 2009-07-07 11:19:24 +0000
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+extra_flags="-D__sun -m32 $debug_cflags"
+extra_configs="$max_configs --with-libevent $debug_configs"
+
+LDFLAGS="-lmtmalloc -R/usr/sfw/lib"
+export LDFLAGS
+
+. "$path/FINISH.sh"
=== added file 'BUILD/compile-solaris-x86-32-debug-forte'
--- a/BUILD/compile-solaris-x86-32-debug-forte 1970-01-01 00:00:00 +0000
+++ b/BUILD/compile-solaris-x86-32-debug-forte 2009-07-07 11:19:24 +0000
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+# Take only #define options - the others are gcc specific.
+# (real fix is for SETUP.sh not to put gcc specific options in $debug_cflags)
+DEFS=""
+for F in $debug_cflags ; do
+ expr "$F" : "^-D" && DEFS="$DEFS $F"
+done
+debug_cflags="-O0 -g $DEFS"
+
+extra_flags="-m32 -mt -D_FORTEC_ -xbuiltin=%all -xlibmil -xlibmopt -fns=no -xprefetch=auto -xprefetch_level=3 $debug_cflags"
+extra_configs="$max_configs --with-libevent $debug_configs"
+
+warnings=""
+c_warnings=""
+cxx_warnings=""
+base_cxxflags="-noex"
+
+CC=cc
+CFLAGS="-xstrconst"
+CXX=CC
+LDFLAGS="-lmtmalloc"
+
+. "$path/FINISH.sh"
=== added file 'BUILD/compile-solaris-x86-forte-32'
--- a/BUILD/compile-solaris-x86-forte-32 1970-01-01 00:00:00 +0000
+++ b/BUILD/compile-solaris-x86-forte-32 2009-07-07 11:19:24 +0000
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="-m32 -mt -D_FORTEC_ -xbuiltin=%all -xlibmil -xlibmopt -fns=no -xprefetch=auto -xprefetch_level=3"
+extra_configs="$max_configs --with-libevent"
+
+warnings=""
+c_warnings=""
+cxx_warnings=""
+base_cxxflags="-noex"
+
+CC=cc
+CFLAGS="-xstrconst"
+CXX=CC
+LDFLAGS="-lmtmalloc"
+
+. "$path/FINISH.sh"
1
0

[Maria-developers] Rev 2817: BUG#42742: crash in setup_sj_materialization, Copy_field::set in file:///home/psergey/dev/mysql-next-fix-subq/
by Sergey Petrunya 06 Jul '09
by Sergey Petrunya 06 Jul '09
06 Jul '09
At file:///home/psergey/dev/mysql-next-fix-subq/
------------------------------------------------------------
revno: 2817
revision-id: psergey(a)askmonty.org-20090706143329-72s3e73rov2f5tml
parent: psergey(a)askmonty.org-20090706142603-z3z8ku4fdah6ntwv
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: mysql-next-fix-subq
timestamp: Mon 2009-07-06 18:33:29 +0400
message:
BUG#42742: crash in setup_sj_materialization, Copy_field::set
- If a semi-join strategy covers certain [first_table; last_table]
range in join order, do reset the sj_strategy member for all tables
within the range, except the first one.
Failure to do so caused EXPLAIN/execution code to try applying two
strategies at once which would cause all kinds of undesired effects.
=== modified file 'mysql-test/r/subselect_sj2.result'
--- a/mysql-test/r/subselect_sj2.result 2009-03-21 15:31:38 +0000
+++ b/mysql-test/r/subselect_sj2.result 2009-07-06 14:33:29 +0000
@@ -689,3 +689,19 @@
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
drop table t1, t2;
+#
+# BUG#42742: crash in setup_sj_materialization, Copy_field::set
+#
+create table t3 ( c1 year) engine=innodb;
+insert into t3 values (2135),(2142);
+create table t2 (c1 tinytext,c2 text,c6 timestamp) engine=innodb;
+# The following must not crash, EXPLAIN should show one SJ strategy, not a mix:
+explain select 1 from t2 where
+c2 in (select 1 from t3, t2) and
+c1 in (select convert(c6,char(1)) from t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where
+1 PRIMARY t2 ALL NULL NULL NULL NULL 1
+1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; Using join buffer
+1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2); Using join buffer
+drop table t2, t3;
=== modified file 'mysql-test/r/subselect_sj2_jcl6.result'
--- a/mysql-test/r/subselect_sj2_jcl6.result 2009-06-19 09:12:06 +0000
+++ b/mysql-test/r/subselect_sj2_jcl6.result 2009-07-06 14:33:29 +0000
@@ -693,6 +693,22 @@
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
drop table t1, t2;
+#
+# BUG#42742: crash in setup_sj_materialization, Copy_field::set
+#
+create table t3 ( c1 year) engine=innodb;
+insert into t3 values (2135),(2142);
+create table t2 (c1 tinytext,c2 text,c6 timestamp) engine=innodb;
+# The following must not crash, EXPLAIN should show one SJ strategy, not a mix:
+explain select 1 from t2 where
+c2 in (select 1 from t3, t2) and
+c1 in (select convert(c6,char(1)) from t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where
+1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using join buffer
+1 PRIMARY t2 ALL NULL NULL NULL NULL 1 Using where; Using join buffer
+1 PRIMARY t3 ALL NULL NULL NULL NULL 2 FirstMatch(t2); Using join buffer
+drop table t2, t3;
set join_cache_level=default;
show variables like 'join_cache_level';
Variable_name Value
=== modified file 'mysql-test/t/subselect_sj2.test'
--- a/mysql-test/t/subselect_sj2.test 2009-03-21 15:31:38 +0000
+++ b/mysql-test/t/subselect_sj2.test 2009-07-06 14:33:29 +0000
@@ -872,3 +872,15 @@
explain select 1 from t2 where c2 = any (select log10(null) from t1 where c6 <null) ;
drop table t1, t2;
+--echo #
+--echo # BUG#42742: crash in setup_sj_materialization, Copy_field::set
+--echo #
+create table t3 ( c1 year) engine=innodb;
+insert into t3 values (2135),(2142);
+create table t2 (c1 tinytext,c2 text,c6 timestamp) engine=innodb;
+-- echo # The following must not crash, EXPLAIN should show one SJ strategy, not a mix:
+explain select 1 from t2 where
+ c2 in (select 1 from t3, t2) and
+ c1 in (select convert(c6,char(1)) from t2);
+drop table t2, t3;
+
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-07-06 07:57:39 +0000
+++ b/sql/sql_select.cc 2009-07-06 14:33:29 +0000
@@ -7916,7 +7916,11 @@
uint i_end= first + join->best_positions[first].n_sj_tables;
for (uint i= first; i < i_end; i++)
+ {
+ if (i != first)
+ join->best_positions[i].sj_strategy= SJ_OPT_NONE;
handled_tabs |= join->best_positions[i].table->table->map;
+ }
if (tablenr != first)
pos->sj_strategy= SJ_OPT_NONE;
1
0

[Maria-developers] Rev 2816: BUG#31480: Incorrect result for nested subquery when executed via semi join in file:///home/psergey/dev/mysql-next/
by Sergey Petrunya 06 Jul '09
by Sergey Petrunya 06 Jul '09
06 Jul '09
At file:///home/psergey/dev/mysql-next/
------------------------------------------------------------
revno: 2816
revision-id: psergey(a)askmonty.org-20090706142603-z3z8ku4fdah6ntwv
parent: psergey(a)askmonty.org-20090706075739-ay9m392esf31wx0s
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: mysql-next
timestamp: Mon 2009-07-06 18:26:03 +0400
message:
BUG#31480: Incorrect result for nested subquery when executed via semi join
- Post-push valgrind fix
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2009-07-06 07:57:39 +0000
+++ b/sql/item_subselect.cc 2009-07-06 14:26:03 +0000
@@ -289,8 +289,12 @@
used_tables_cache &= ~OUTER_REF_TABLE_BIT;
if (furthest_correlated_ancestor > 1)
used_tables_cache |= OUTER_REF_TABLE_BIT;
- const_item_cache &= test(!(used_tables_cache &
- ~new_parent->join->const_table_map));
+
+ /*
+ Don't update const_tables_cache yet as we don't yet know which of the
+ parent's tables are constant. Parent will call update_used_tables() anyway,
+ and that will be our chance to update.
+ */
}
1
0

[Maria-developers] Rev 2816: BUG#31480: Incorrect result for nested subquery when executed via semi join in file:///home/psergey/dev/mysql-next-look-vg/
by Sergey Petrunya 06 Jul '09
by Sergey Petrunya 06 Jul '09
06 Jul '09
At file:///home/psergey/dev/mysql-next-look-vg/
------------------------------------------------------------
revno: 2816
revision-id: psergey(a)askmonty.org-20090706141824-4u0m7arubaadks6w
parent: psergey(a)askmonty.org-20090706081826-4bvmp429ikj9aptw
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: mysql-next-look-vg
timestamp: Mon 2009-07-06 18:18:24 +0400
message:
BUG#31480: Incorrect result for nested subquery when executed via semi join
- Post-push valgrind fix
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2009-07-06 08:18:26 +0000
+++ b/sql/item_subselect.cc 2009-07-06 14:18:24 +0000
@@ -289,8 +289,12 @@
used_tables_cache &= ~OUTER_REF_TABLE_BIT;
if (furthest_correlated_ancestor > 1)
used_tables_cache |= OUTER_REF_TABLE_BIT;
- const_item_cache &= test(!(used_tables_cache &
- ~new_parent->join->const_table_map));
+
+ /*
+ Don't update const_tables_cache yet as we don't yet know which of the
+ parent's tables are constant. Parent will call update_used_tables() anyway,
+ and that will be our chance to update.
+ */
}
1
0
Test, please ignore
1
0
Test, please ignore.
1
0
Test, please ignore
1
0

[Maria-developers] Rev 2815: BUG#31480: Incorrect result for nested subquery when executed via semi join in file:///home/psergey/dev/mysql-next-fix-subq/
by Sergey Petrunya 06 Jul '09
by Sergey Petrunya 06 Jul '09
06 Jul '09
At file:///home/psergey/dev/mysql-next-fix-subq/
------------------------------------------------------------
revno: 2815
revision-id: psergey(a)askmonty.org-20090706081826-4bvmp429ikj9aptw
parent: psergey(a)askmonty.org-20090704004450-4pqbx9pm50bzky0l
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: mysql-next-fix-subq
timestamp: Mon 2009-07-06 12:18:26 +0400
message:
BUG#31480: Incorrect result for nested subquery when executed via semi join
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result 2009-03-19 17:03:58 +0000
+++ b/mysql-test/r/subselect_sj.result 2009-07-06 08:18:26 +0000
@@ -327,3 +327,48 @@
HAVING X > '2012-12-12';
X
drop table t1, t2;
+#
+# BUG#31480: Incorrect result for nested subquery when executed via semi join
+#
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
+3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+show warnings;
+Level Code Message
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+a
+2
+2
+3
+2
+drop table t1, t2, t3;
=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result 2009-03-19 17:03:58 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result 2009-07-06 08:18:26 +0000
@@ -331,6 +331,51 @@
HAVING X > '2012-12-12';
X
drop table t1, t2;
+#
+# BUG#31480: Incorrect result for nested subquery when executed via semi join
+#
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
+3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+show warnings;
+Level Code Message
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+a
+2
+2
+3
+2
+drop table t1, t2, t3;
set join_cache_level=default;
show variables like 'join_cache_level';
Variable_name Value
=== modified file 'mysql-test/t/subselect_sj.test'
--- a/mysql-test/t/subselect_sj.test 2009-03-19 17:03:58 +0000
+++ b/mysql-test/t/subselect_sj.test 2009-07-06 08:18:26 +0000
@@ -216,4 +216,39 @@
HAVING X > '2012-12-12';
drop table t1, t2;
-
+--echo #
+--echo # BUG#31480: Incorrect result for nested subquery when executed via semi join
+--echo #
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+show warnings;
+
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+
+drop table t1, t2, t3;
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item.cc 2009-07-06 08:18:26 +0000
@@ -2212,7 +2212,8 @@
}
-void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_field::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
if (new_parent == depended_from)
depended_from= NULL;
@@ -3797,16 +3798,17 @@
static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *resolved_item,
- Item_ident *mark_item)
+ Item_ident *mark_item, table_map dep_map)
{
const char *db_name= (resolved_item->db_name ?
resolved_item->db_name : "");
const char *table_name= (resolved_item->table_name ?
resolved_item->table_name : "");
+ //table_map dep_map = resolved_item->used_tables();
/* store pointer on SELECT_LEX from which item is dependent */
if (mark_item)
mark_item->depended_from= last;
- current->mark_as_dependent(last);
+ current->mark_as_dependent(last, dep_map);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -3864,21 +3866,26 @@
Item_subselect *prev_subselect_item=
previous_select->master_unit()->item;
Item_ident *dependent= resolved_item;
+ table_map found_used_tables;
if (found_field == view_ref_found)
{
Item::Type type= found_item->type();
+ found_used_tables= found_item->used_tables();
prev_subselect_item->used_tables_cache|=
- found_item->used_tables();
+ found_used_tables;
dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ?
(Item_ident*) found_item :
0);
}
else
+ {
+ found_used_tables= found_field->table->map;
prev_subselect_item->used_tables_cache|=
found_field->table->map;
+ }
prev_subselect_item->const_item_cache= 0;
mark_as_dependent(thd, last_select, current_sel, resolved_item,
- dependent);
+ dependent, found_used_tables);
}
}
@@ -4159,6 +4166,7 @@
SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
Name_resolution_context *outer_context= 0;
SELECT_LEX *select= 0;
+ uint n_levels= 0;
/* Currently derived tables cannot be correlated */
if (current_sel->master_unit()->first_select()->linkage !=
DERIVED_TABLE_TYPE)
@@ -4251,7 +4259,8 @@
context->select_lex, this,
((ref_type == REF_ITEM ||
ref_type == FIELD_ITEM) ?
- (Item_ident*) (*reference) : 0));
+ (Item_ident*) (*reference) : 0),
+ (*from_field)->table->map);
return 0;
}
}
@@ -4266,7 +4275,8 @@
context->select_lex, this,
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
- 0));
+ 0),
+ (*reference)->used_tables());
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
@@ -4300,6 +4310,7 @@
*/
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
prev_subselect_item->const_item_cache= 0;
+ n_levels++;
}
DBUG_ASSERT(ref != 0);
@@ -4367,14 +4378,15 @@
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- rf);
+ rf, rf->used_tables());
return 0;
}
else
{
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
- this, (Item_ident*)*reference);
+ this, (Item_ident*)*reference,
+ (*reference)->used_tables());
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -6084,7 +6096,8 @@
((refer_type == REF_ITEM ||
refer_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
- 0));
+ 0),
+ (*reference)->used_tables());
/*
view reference found, we substituted it instead of this
Item, so can quit
@@ -6134,7 +6147,8 @@
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
- thd->lex->current_select, this, fld);
+ thd->lex->current_select, this, fld,
+ from_field->table->map);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6157,7 +6171,8 @@
/* Should be checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last_checked_context->select_lex,
- context->select_lex, this, this);
+ context->select_lex, this, this,
+ (*ref)->used_tables());
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6568,20 +6583,22 @@
return err;
}
-void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
if (depended_from == new_parent)
{
*ref= outer_ref;
- outer_ref->fix_after_pullout(new_parent, ref);
+ outer_ref->fix_after_pullout(new_parent, parent_tables, ref);
}
}
-void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
+void Item_ref::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **refptr)
{
if (depended_from == new_parent)
{
- (*ref)->fix_after_pullout(new_parent, ref);
+ (*ref)->fix_after_pullout(new_parent, parent_tables, ref);
depended_from= NULL;
}
}
=== modified file 'sql/item.h'
--- a/sql/item.h 2009-05-25 10:10:18 +0000
+++ b/sql/item.h 2009-07-06 08:18:26 +0000
@@ -557,7 +557,8 @@
Fix after some tables has been pulled out. Basically re-calculate all
attributes that are dependent on the tables.
*/
- virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref) {};
+ virtual void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref) {};
/*
should be used in case where we are sure that we do not need
@@ -1486,7 +1487,8 @@
bool send(Protocol *protocol, String *str_arg);
void reset_field(Field *f);
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
void make_field(Send_field *tmp_field);
int save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
@@ -2278,7 +2280,8 @@
bool send(Protocol *prot, String *tmp);
void make_field(Send_field *field);
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
int save_in_field(Field *field, bool no_conversions);
void save_org_in_field(Field *field);
enum Item_result result_type () const { return (*ref)->result_type(); }
@@ -2448,7 +2451,8 @@
outer_ref->save_org_in_field(result_field);
}
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
table_map used_tables() const
{
return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT;
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item_cmpfunc.cc 2009-07-06 08:18:26 +0000
@@ -4004,7 +4004,8 @@
}
-void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_cond::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
List_iterator<Item> li(list);
Item *item;
@@ -4018,7 +4019,7 @@
while ((item=li++))
{
table_map tmp_table_map;
- item->fix_after_pullout(new_parent, li.ref());
+ item->fix_after_pullout(new_parent, parent_tables, li.ref());
item= *li.ref();
used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item();
=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h 2009-01-26 16:03:39 +0000
+++ b/sql/item_cmpfunc.h 2009-07-06 08:18:26 +0000
@@ -1475,7 +1475,8 @@
bool add_at_head(Item *item) { return list.push_front(item); }
void add_at_head(List<Item> *nlist) { list.prepand(nlist); }
bool fix_fields(THD *, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
enum Type type() const { return COND_ITEM; }
List<Item>* argument_list() { return &list; }
=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item_func.cc 2009-07-06 08:18:26 +0000
@@ -206,7 +206,8 @@
}
-void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_func::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
Item **arg,**arg_end;
@@ -217,7 +218,7 @@
{
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- (*arg)->fix_after_pullout(new_parent, arg);
+ (*arg)->fix_after_pullout(new_parent, parent_tables, arg);
Item *item= *arg;
used_tables_cache|= item->used_tables();
=== modified file 'sql/item_func.h'
--- a/sql/item_func.h 2009-05-21 20:27:17 +0000
+++ b/sql/item_func.h 2009-07-06 08:18:26 +0000
@@ -117,7 +117,8 @@
// Constructor used for Item_cond_and/or (see Item comment)
Item_func(THD *thd, Item_func *item);
bool fix_fields(THD *, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
table_map used_tables() const;
table_map not_null_tables() const;
void update_used_tables();
=== modified file 'sql/item_row.cc'
--- a/sql/item_row.cc 2008-02-22 11:11:25 +0000
+++ b/sql/item_row.cc 2009-07-06 08:18:26 +0000
@@ -124,13 +124,14 @@
}
}
-void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_row::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
used_tables_cache= 0;
const_item_cache= 1;
for (uint i= 0; i < arg_count; i++)
{
- items[i]->fix_after_pullout(new_parent, &items[i]);
+ items[i]->fix_after_pullout(new_parent, parent_tables, &items[i]);
used_tables_cache|= items[i]->used_tables();
const_item_cache&= items[i]->const_item();
}
=== modified file 'sql/item_row.h'
--- a/sql/item_row.h 2008-02-22 11:11:25 +0000
+++ b/sql/item_row.h 2009-07-06 08:18:26 +0000
@@ -59,7 +59,8 @@
return 0;
};
bool fix_fields(THD *thd, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
void cleanup();
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
table_map used_tables() const { return used_tables_cache; };
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2009-06-30 08:03:05 +0000
+++ b/sql/item_subselect.cc 2009-07-06 08:18:26 +0000
@@ -39,7 +39,7 @@
Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
- const_item_cache(1), engine_changed(0), changed(0),
+ const_item_cache(1), inside_fix_fields(0), engine_changed(0), changed(0),
is_correlated(FALSE)
{
with_subselect= 1;
@@ -158,6 +158,13 @@
DBUG_RETURN(RES_OK);
}
+void Item_subselect::set_depth()
+{
+ uint n= 0;
+ for (SELECT_LEX *s= unit->first_select(); s; s= s->outer_select())
+ n++;
+ this->depth= n - 1;
+}
bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
{
@@ -168,9 +175,19 @@
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
+ if (!inside_fix_fields)
+ {
+ set_depth();
+ if (!(ancestor_used_tables= (table_map*)thd->calloc((1+depth) *
+ sizeof(table_map))))
+ return TRUE;
+ furthest_correlated_ancestor= 0;
+ }
+
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE;
+ inside_fix_fields++;
res= engine->prepare();
// all transformation is done (used by prepared statements)
@@ -203,12 +220,14 @@
if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where;
+ inside_fix_fields--;
return ret;
}
// Is it one field subselect?
if (engine->cols() > max_columns)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
+ inside_fix_fields--;
return TRUE;
}
fix_length_and_dec();
@@ -225,11 +244,56 @@
fixed= 1;
err:
+ inside_fix_fields--;
thd->where= save_where;
return res;
}
+/*
+ Adjust attributes after our parent select has been merged into grandparent
+
+ DESCRIPTION
+ Subquery is a composite object which may be correlated, that is, it may
+ have
+ 1. references to tables of the parent select (i.e. one that has the clause
+ with the subquery predicate)
+ 2. references to tables of the grandparent select
+ 3. references to tables of further ancestors.
+
+ Before the pullout, this item indicates:
+ - #1 with table bits in used_tables()
+ - #2 and #3 with OUTER_REF_TABLE_BIT.
+
+ After parent has been merged with grandparent:
+ - references to parent and grandparent tables should be indicated with
+ table bits.
+ - references to greatgrandparent and further ancestors - with
+ OUTER_REF_TABLE_BIT.
+
+ This is exactly what this function does, based on pre-collected info in
+ ancestor_used_tables and furthest_correlated_ancestor.
+*/
+
+void Item_subselect::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
+{
+ used_tables_cache= (used_tables_cache << parent_tables) |
+ ancestor_used_tables[0];
+ for (uint i=0; i < depth; i++)
+ ancestor_used_tables[i]= ancestor_used_tables[i+1];
+ depth--;
+
+ if (furthest_correlated_ancestor)
+ furthest_correlated_ancestor--;
+ used_tables_cache &= ~OUTER_REF_TABLE_BIT;
+ if (furthest_correlated_ancestor > 1)
+ used_tables_cache |= OUTER_REF_TABLE_BIT;
+ const_item_cache &= test(!(used_tables_cache &
+ ~new_parent->join->const_table_map));
+}
+
+
bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument)
{
=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h 2008-11-10 18:36:50 +0000
+++ b/sql/item_subselect.h 2009-07-06 08:18:26 +0000
@@ -66,9 +66,39 @@
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constant state */
+
bool const_item_cache;
+ int inside_fix_fields;
+public:
+ /*
+ Depth of the subquery predicate.
+ If the subquery predicate is attatched to some clause of the top-level
+ select, depth will be 1
+ If it is attached to a clause in a subquery of the top-level select, depth
+ will be 2 and so forth.
+ */
+ uint depth;
+
+ /*
+ Maximum correlation level of the select
+ - select that has no references to outside will have 0,
+ - select that references tables in the select it is located will have 1,
+ - select that has references to tables of its parent select will have 2,
+ - select that has references to tables of grandparent will have 3
+ and so forth.
+ */
+ uint furthest_correlated_ancestor;
+ /*
+ This is used_tables() for non-direct ancestors. That is,
+ - used_tables() shows which tables of the parent select are referred to
+ from within the subquery,
+ - ancestor_used_tables[0] shows which tables of the grandparent select are
+ referred to from within the subquery,
+ - ancestor_used_tables[1] shows which tables of the great grand parent
+ select... and so forth.
+ */
+ table_map *ancestor_used_tables;
-public:
/* changed engine indicator */
bool engine_changed;
/* subquery is transformed */
@@ -84,6 +114,7 @@
Item_subselect();
virtual subs_type substype() { return UNKNOWN_SUBS; }
+ void set_depth();
/*
We need this method, because some compilers do not allow 'this'
@@ -109,6 +140,8 @@
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item_sum.cc 2009-07-06 08:18:26 +0000
@@ -350,7 +350,7 @@
sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1;
}
- thd->lex->current_select->mark_as_dependent(aggr_sel);
+ thd->lex->current_select->mark_as_dependent(aggr_sel, NULL);
return FALSE;
}
=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc 2009-06-04 06:27:44 +0000
+++ b/sql/sql_lex.cc 2009-07-06 08:18:26 +0000
@@ -1901,8 +1901,9 @@
'last' should be reachable from this st_select_lex_node
*/
-void st_select_lex::mark_as_dependent(st_select_lex *last)
+void st_select_lex::mark_as_dependent(st_select_lex *last, table_map dep_map)
{
+ uint n_levels= master_unit()->item->depth;
/*
Mark all selects from resolved to 1 before select where was
found table as depended (of select where was found table)
@@ -1928,7 +1929,14 @@
}
Item_subselect *subquery_predicate= s->master_unit()->item;
if (subquery_predicate)
+ {
subquery_predicate->is_correlated= TRUE;
+ subquery_predicate->furthest_correlated_ancestor=
+ max(subquery_predicate->furthest_correlated_ancestor, n_levels);
+ if (n_levels > 1)
+ subquery_predicate->ancestor_used_tables[n_levels - 2]= dep_map;
+ }
+ n_levels--;
}
}
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2009-06-12 02:01:08 +0000
+++ b/sql/sql_lex.h 2009-07-06 08:18:26 +0000
@@ -755,7 +755,7 @@
return master_unit()->return_after_parsing();
}
- void mark_as_dependent(st_select_lex *last);
+ void mark_as_dependent(st_select_lex *last, table_map dep_map);
bool set_braces(bool value);
bool inc_in_sum_expr();
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-07-04 00:44:50 +0000
+++ b/sql/sql_select.cc 2009-07-06 08:18:26 +0000
@@ -3122,16 +3122,23 @@
}
-void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist)
+void fix_list_after_tbl_changes(SELECT_LEX *new_parent, uint parent_tables,
+ List<TABLE_LIST> *tlist)
{
List_iterator<TABLE_LIST> it(*tlist);
TABLE_LIST *table;
while ((table= it++))
{
if (table->on_expr)
- table->on_expr->fix_after_pullout(new_parent, &table->on_expr);
+ {
+ table->on_expr->fix_after_pullout(new_parent, parent_tables,
+ &table->on_expr);
+ }
if (table->nested_join)
- fix_list_after_tbl_changes(new_parent, &table->nested_join->join_list);
+ {
+ fix_list_after_tbl_changes(new_parent, parent_tables,
+ &table->nested_join->join_list);
+ }
}
}
@@ -3334,6 +3341,7 @@
/*TODO: also reset the 'with_subselect' there. */
/* n. Adjust the parent_join->tables counter */
+ uint parent_tables= parent_join->tables;
uint table_no= parent_join->tables;
/* n. Walk through child's tables and adjust table->map */
for (tl= subq_lex->leaf_tables; tl; tl= tl->next_leaf, table_no++)
@@ -3410,8 +3418,10 @@
Fix attributes (mainly item->table_map()) for sj-nest's WHERE and ON
expressions.
*/
- sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr);
- fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list);
+ sj_nest->sj_on_expr->fix_after_pullout(parent_lex, parent_join->tables,
+ &sj_nest->sj_on_expr);
+ fix_list_after_tbl_changes(parent_lex, parent_join->tables,
+ &sj_nest->nested_join->join_list);
/* Unlink the child select_lex so it doesn't show up in EXPLAIN: */
1
0

[Maria-developers] Rev 2815: BUG#31480: Incorrect result for nested subquery when executed via semi join in file:///home/psergey/dev/mysql-next-fix-subq/
by Sergey Petrunya 06 Jul '09
by Sergey Petrunya 06 Jul '09
06 Jul '09
At file:///home/psergey/dev/mysql-next-fix-subq/
------------------------------------------------------------
revno: 2815
revision-id: psergey(a)askmonty.org-20090706075739-ay9m392esf31wx0s
parent: psergey(a)askmonty.org-20090704004450-4pqbx9pm50bzky0l
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: mysql-next-fix-subq
timestamp: Mon 2009-07-06 11:57:39 +0400
message:
BUG#31480: Incorrect result for nested subquery when executed via semi join
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result 2009-03-19 17:03:58 +0000
+++ b/mysql-test/r/subselect_sj.result 2009-07-06 07:57:39 +0000
@@ -327,3 +327,48 @@
HAVING X > '2012-12-12';
X
drop table t1, t2;
+#
+# BUG#31480: Incorrect result for nested subquery when executed via semi join
+#
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
+3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+show warnings;
+Level Code Message
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+a
+2
+2
+3
+2
+drop table t1, t2, t3;
=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result 2009-03-19 17:03:58 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result 2009-07-06 07:57:39 +0000
@@ -331,6 +331,51 @@
HAVING X > '2012-12-12';
X
drop table t1, t2;
+#
+# BUG#31480: Incorrect result for nested subquery when executed via semi join
+#
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
+3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+show warnings;
+Level Code Message
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+a
+2
+2
+3
+2
+drop table t1, t2, t3;
set join_cache_level=default;
show variables like 'join_cache_level';
Variable_name Value
=== modified file 'mysql-test/t/subselect_sj.test'
--- a/mysql-test/t/subselect_sj.test 2009-03-19 17:03:58 +0000
+++ b/mysql-test/t/subselect_sj.test 2009-07-06 07:57:39 +0000
@@ -216,4 +216,39 @@
HAVING X > '2012-12-12';
drop table t1, t2;
-
+--echo #
+--echo # BUG#31480: Incorrect result for nested subquery when executed via semi join
+--echo #
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+show warnings;
+
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+
+drop table t1, t2, t3;
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item.cc 2009-07-06 07:57:39 +0000
@@ -2212,7 +2212,8 @@
}
-void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_field::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
if (new_parent == depended_from)
depended_from= NULL;
@@ -3797,16 +3798,17 @@
static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *resolved_item,
- Item_ident *mark_item)
+ Item_ident *mark_item, table_map dep_map)
{
const char *db_name= (resolved_item->db_name ?
resolved_item->db_name : "");
const char *table_name= (resolved_item->table_name ?
resolved_item->table_name : "");
+ //table_map dep_map = resolved_item->used_tables();
/* store pointer on SELECT_LEX from which item is dependent */
if (mark_item)
mark_item->depended_from= last;
- current->mark_as_dependent(last);
+ current->mark_as_dependent(last, dep_map);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -3864,21 +3866,26 @@
Item_subselect *prev_subselect_item=
previous_select->master_unit()->item;
Item_ident *dependent= resolved_item;
+ table_map found_used_tables;
if (found_field == view_ref_found)
{
Item::Type type= found_item->type();
+ found_used_tables= found_item->used_tables();
prev_subselect_item->used_tables_cache|=
- found_item->used_tables();
+ found_used_tables;
dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ?
(Item_ident*) found_item :
0);
}
else
+ {
+ found_used_tables= found_field->table->map;
prev_subselect_item->used_tables_cache|=
found_field->table->map;
+ }
prev_subselect_item->const_item_cache= 0;
mark_as_dependent(thd, last_select, current_sel, resolved_item,
- dependent);
+ dependent, found_used_tables);
}
}
@@ -4159,6 +4166,7 @@
SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
Name_resolution_context *outer_context= 0;
SELECT_LEX *select= 0;
+ uint n_levels= 0;
/* Currently derived tables cannot be correlated */
if (current_sel->master_unit()->first_select()->linkage !=
DERIVED_TABLE_TYPE)
@@ -4251,7 +4259,8 @@
context->select_lex, this,
((ref_type == REF_ITEM ||
ref_type == FIELD_ITEM) ?
- (Item_ident*) (*reference) : 0));
+ (Item_ident*) (*reference) : 0),
+ (*from_field)->table->map);
return 0;
}
}
@@ -4266,7 +4275,8 @@
context->select_lex, this,
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
- 0));
+ 0),
+ (*reference)->used_tables());
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
@@ -4300,6 +4310,7 @@
*/
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
prev_subselect_item->const_item_cache= 0;
+ n_levels++;
}
DBUG_ASSERT(ref != 0);
@@ -4367,14 +4378,15 @@
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- rf);
+ rf, rf->used_tables());
return 0;
}
else
{
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
- this, (Item_ident*)*reference);
+ this, (Item_ident*)*reference,
+ (*reference)->used_tables());
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -6084,7 +6096,8 @@
((refer_type == REF_ITEM ||
refer_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
- 0));
+ 0),
+ (*reference)->used_tables());
/*
view reference found, we substituted it instead of this
Item, so can quit
@@ -6134,7 +6147,8 @@
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
- thd->lex->current_select, this, fld);
+ thd->lex->current_select, this, fld,
+ from_field->table->map);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6157,7 +6171,8 @@
/* Should be checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last_checked_context->select_lex,
- context->select_lex, this, this);
+ context->select_lex, this, this,
+ (*ref)->used_tables());
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6568,20 +6583,22 @@
return err;
}
-void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
if (depended_from == new_parent)
{
*ref= outer_ref;
- outer_ref->fix_after_pullout(new_parent, ref);
+ outer_ref->fix_after_pullout(new_parent, parent_tables, ref);
}
}
-void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
+void Item_ref::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **refptr)
{
if (depended_from == new_parent)
{
- (*ref)->fix_after_pullout(new_parent, ref);
+ (*ref)->fix_after_pullout(new_parent, parent_tables, ref);
depended_from= NULL;
}
}
=== modified file 'sql/item.h'
--- a/sql/item.h 2009-05-25 10:10:18 +0000
+++ b/sql/item.h 2009-07-06 07:57:39 +0000
@@ -557,7 +557,8 @@
Fix after some tables has been pulled out. Basically re-calculate all
attributes that are dependent on the tables.
*/
- virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref) {};
+ virtual void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref) {};
/*
should be used in case where we are sure that we do not need
@@ -1486,7 +1487,8 @@
bool send(Protocol *protocol, String *str_arg);
void reset_field(Field *f);
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
void make_field(Send_field *tmp_field);
int save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
@@ -2278,7 +2280,8 @@
bool send(Protocol *prot, String *tmp);
void make_field(Send_field *field);
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
int save_in_field(Field *field, bool no_conversions);
void save_org_in_field(Field *field);
enum Item_result result_type () const { return (*ref)->result_type(); }
@@ -2448,7 +2451,8 @@
outer_ref->save_org_in_field(result_field);
}
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
table_map used_tables() const
{
return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT;
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item_cmpfunc.cc 2009-07-06 07:57:39 +0000
@@ -4004,7 +4004,8 @@
}
-void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_cond::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
List_iterator<Item> li(list);
Item *item;
@@ -4018,7 +4019,7 @@
while ((item=li++))
{
table_map tmp_table_map;
- item->fix_after_pullout(new_parent, li.ref());
+ item->fix_after_pullout(new_parent, parent_tables, li.ref());
item= *li.ref();
used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item();
=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h 2009-01-26 16:03:39 +0000
+++ b/sql/item_cmpfunc.h 2009-07-06 07:57:39 +0000
@@ -1475,7 +1475,8 @@
bool add_at_head(Item *item) { return list.push_front(item); }
void add_at_head(List<Item> *nlist) { list.prepand(nlist); }
bool fix_fields(THD *, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
enum Type type() const { return COND_ITEM; }
List<Item>* argument_list() { return &list; }
=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item_func.cc 2009-07-06 07:57:39 +0000
@@ -206,7 +206,8 @@
}
-void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_func::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
Item **arg,**arg_end;
@@ -217,7 +218,7 @@
{
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- (*arg)->fix_after_pullout(new_parent, arg);
+ (*arg)->fix_after_pullout(new_parent, parent_tables, arg);
Item *item= *arg;
used_tables_cache|= item->used_tables();
=== modified file 'sql/item_func.h'
--- a/sql/item_func.h 2009-05-21 20:27:17 +0000
+++ b/sql/item_func.h 2009-07-06 07:57:39 +0000
@@ -117,7 +117,8 @@
// Constructor used for Item_cond_and/or (see Item comment)
Item_func(THD *thd, Item_func *item);
bool fix_fields(THD *, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
table_map used_tables() const;
table_map not_null_tables() const;
void update_used_tables();
=== modified file 'sql/item_row.cc'
--- a/sql/item_row.cc 2008-02-22 11:11:25 +0000
+++ b/sql/item_row.cc 2009-07-06 07:57:39 +0000
@@ -124,13 +124,14 @@
}
}
-void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_row::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
used_tables_cache= 0;
const_item_cache= 1;
for (uint i= 0; i < arg_count; i++)
{
- items[i]->fix_after_pullout(new_parent, &items[i]);
+ items[i]->fix_after_pullout(new_parent, parent_tables, &items[i]);
used_tables_cache|= items[i]->used_tables();
const_item_cache&= items[i]->const_item();
}
=== modified file 'sql/item_row.h'
--- a/sql/item_row.h 2008-02-22 11:11:25 +0000
+++ b/sql/item_row.h 2009-07-06 07:57:39 +0000
@@ -59,7 +59,8 @@
return 0;
};
bool fix_fields(THD *thd, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
void cleanup();
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
table_map used_tables() const { return used_tables_cache; };
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2009-06-30 08:03:05 +0000
+++ b/sql/item_subselect.cc 2009-07-06 07:57:39 +0000
@@ -39,7 +39,7 @@
Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
- const_item_cache(1), engine_changed(0), changed(0),
+ const_item_cache(1), inside_fix_fields(0), engine_changed(0), changed(0),
is_correlated(FALSE)
{
with_subselect= 1;
@@ -158,6 +158,13 @@
DBUG_RETURN(RES_OK);
}
+void Item_subselect::set_depth()
+{
+ uint n= 0;
+ for (SELECT_LEX *s= unit->first_select(); s; s= s->outer_select())
+ n++;
+ this->depth= n - 1;
+}
bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
{
@@ -168,9 +175,19 @@
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
+ if (!inside_fix_fields)
+ {
+ set_depth();
+ if (!(ancestor_used_tables= (table_map*)thd->calloc((1+depth) *
+ sizeof(table_map))))
+ return TRUE;
+ furthest_correlated_ancestor= 0;
+ }
+
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE;
+ inside_fix_fields++;
res= engine->prepare();
// all transformation is done (used by prepared statements)
@@ -203,12 +220,14 @@
if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where;
+ inside_fix_fields--;
return ret;
}
// Is it one field subselect?
if (engine->cols() > max_columns)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
+ inside_fix_fields--;
return TRUE;
}
fix_length_and_dec();
@@ -225,11 +244,56 @@
fixed= 1;
err:
+ inside_fix_fields--;
thd->where= save_where;
return res;
}
+/*
+ Adjust attributes after our parent select has been merged into grandparent
+
+ DESCRIPTION
+ Subquery is a composite object which may be correlated, that is, it may
+ have
+ 1. references to tables of the parent select (i.e. one that has the clause
+ with the subquery predicate)
+ 2. references to tables of the grandparent select
+ 3. references to tables of further ancestors.
+
+ Before the pullout, this item indicates:
+ - #1 with table bits in used_tables()
+ - #2 and #3 with OUTER_REF_TABLE_BIT.
+
+ After parent has been merged with grandparent:
+ - references to parent and grandparent tables should be indicated with
+ table bits.
+ - references to greatgrandparent and further ancestors - with
+ OUTER_REF_TABLE_BIT.
+
+ This is exactly what this function does, based on pre-collected info in
+ ancestor_used_tables and furthest_correlated_ancestor.
+*/
+
+void Item_subselect::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
+{
+ used_tables_cache= (used_tables_cache << parent_tables) |
+ ancestor_used_tables[0];
+ for (uint i=0; i < depth; i++)
+ ancestor_used_tables[i]= ancestor_used_tables[i+1];
+ depth--;
+
+ if (furthest_correlated_ancestor)
+ furthest_correlated_ancestor--;
+ used_tables_cache &= ~OUTER_REF_TABLE_BIT;
+ if (furthest_correlated_ancestor > 1)
+ used_tables_cache |= OUTER_REF_TABLE_BIT;
+ const_item_cache &= test(!(used_tables_cache &
+ ~new_parent->join->const_table_map));
+}
+
+
bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument)
{
=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h 2008-11-10 18:36:50 +0000
+++ b/sql/item_subselect.h 2009-07-06 07:57:39 +0000
@@ -66,9 +66,39 @@
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constant state */
+
bool const_item_cache;
+ int inside_fix_fields;
+public:
+ /*
+ Depth of the subquery predicate.
+ If the subquery predicate is attatched to some clause of the top-level
+ select, depth will be 1
+ If it is attached to a clause in a subquery of the top-level select, depth
+ will be 2 and so forth.
+ */
+ uint depth;
+
+ /*
+ Maximum correlation level of the select
+ - select that has no references to outside will have 0,
+ - select that references tables in the select it is located will have 1,
+ - select that has references to tables of its parent select will have 2,
+ - select that has references to tables of grandparent will have 3
+ and so forth.
+ */
+ uint furthest_correlated_ancestor;
+ /*
+ This is used_tables() for non-direct ancestors. That is,
+ - used_tables() shows which tables of the parent select are referred to
+ from within the subquery,
+ - ancestor_used_tables[0] shows which tables of the grandparent select are
+ referred to from within the subquery,
+ - ancestor_used_tables[1] shows which tables of the great grand parent
+ select... and so forth.
+ */
+ table_map *ancestor_used_tables;
-public:
/* changed engine indicator */
bool engine_changed;
/* subquery is transformed */
@@ -84,6 +114,7 @@
Item_subselect();
virtual subs_type substype() { return UNKNOWN_SUBS; }
+ void set_depth();
/*
We need this method, because some compilers do not allow 'this'
@@ -109,6 +140,8 @@
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc 2009-06-09 16:53:34 +0000
+++ b/sql/item_sum.cc 2009-07-06 07:57:39 +0000
@@ -350,7 +350,7 @@
sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1;
}
- thd->lex->current_select->mark_as_dependent(aggr_sel);
+ thd->lex->current_select->mark_as_dependent(aggr_sel, NULL);
return FALSE;
}
=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc 2009-06-04 06:27:44 +0000
+++ b/sql/sql_lex.cc 2009-07-06 07:57:39 +0000
@@ -1901,8 +1901,9 @@
'last' should be reachable from this st_select_lex_node
*/
-void st_select_lex::mark_as_dependent(st_select_lex *last)
+void st_select_lex::mark_as_dependent(st_select_lex *last, table_map dep_map)
{
+ uint n_levels= master_unit()->item->depth;
/*
Mark all selects from resolved to 1 before select where was
found table as depended (of select where was found table)
@@ -1928,7 +1929,14 @@
}
Item_subselect *subquery_predicate= s->master_unit()->item;
if (subquery_predicate)
+ {
subquery_predicate->is_correlated= TRUE;
+ subquery_predicate->furthest_correlated_ancestor=
+ max(subquery_predicate->furthest_correlated_ancestor, n_levels);
+ if (n_levels > 1)
+ subquery_predicate->ancestor_used_tables[n_levels - 2]= dep_map;
+ }
+ n_levels--;
}
}
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2009-06-12 02:01:08 +0000
+++ b/sql/sql_lex.h 2009-07-06 07:57:39 +0000
@@ -755,7 +755,7 @@
return master_unit()->return_after_parsing();
}
- void mark_as_dependent(st_select_lex *last);
+ void mark_as_dependent(st_select_lex *last, table_map dep_map);
bool set_braces(bool value);
bool inc_in_sum_expr();
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-07-04 00:44:50 +0000
+++ b/sql/sql_select.cc 2009-07-06 07:57:39 +0000
@@ -3122,16 +3122,23 @@
}
-void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist)
+void fix_list_after_tbl_changes(SELECT_LEX *new_parent, uint parent_tables,
+ List<TABLE_LIST> *tlist)
{
List_iterator<TABLE_LIST> it(*tlist);
TABLE_LIST *table;
while ((table= it++))
{
if (table->on_expr)
- table->on_expr->fix_after_pullout(new_parent, &table->on_expr);
+ {
+ table->on_expr->fix_after_pullout(new_parent, parent_tables,
+ &table->on_expr);
+ }
if (table->nested_join)
- fix_list_after_tbl_changes(new_parent, &table->nested_join->join_list);
+ {
+ fix_list_after_tbl_changes(new_parent, parent_tables,
+ &table->nested_join->join_list);
+ }
}
}
@@ -3334,6 +3341,7 @@
/*TODO: also reset the 'with_subselect' there. */
/* n. Adjust the parent_join->tables counter */
+ uint parent_tables= parent_join->tables;
uint table_no= parent_join->tables;
/* n. Walk through child's tables and adjust table->map */
for (tl= subq_lex->leaf_tables; tl; tl= tl->next_leaf, table_no++)
@@ -3410,8 +3418,10 @@
Fix attributes (mainly item->table_map()) for sj-nest's WHERE and ON
expressions.
*/
- sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr);
- fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list);
+ sj_nest->sj_on_expr->fix_after_pullout(parent_lex, parent_join->tables,
+ &sj_nest->sj_on_expr);
+ fix_list_after_tbl_changes(parent_lex, parent_join->tables,
+ &sj_nest->nested_join->join_list);
/* Unlink the child select_lex so it doesn't show up in EXPLAIN: */
1
0

[Maria-developers] Rev 2697: BUG#31480: Incorrect result for nested subquery when executed via semi join in file:///home/psergey/dev/mysql-6.0-look/
by Sergey Petrunya 04 Jul '09
by Sergey Petrunya 04 Jul '09
04 Jul '09
At file:///home/psergey/dev/mysql-6.0-look/
------------------------------------------------------------
revno: 2697
revision-id: psergey(a)askmonty.org-20090704040131-bzcjcds3siutn6sc
parent: jperkin(a)sun.com-20090423215644-h7ssug9w1hdgzn39
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: mysql-6.0-look
timestamp: Sat 2009-07-04 08:01:31 +0400
message:
BUG#31480: Incorrect result for nested subquery when executed via semi join
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result 2009-03-19 17:03:58 +0000
+++ b/mysql-test/r/subselect_sj.result 2009-07-04 04:01:31 +0000
@@ -327,3 +327,48 @@
HAVING X > '2012-12-12';
X
drop table t1, t2;
+#
+# BUG#31480: Incorrect result for nested subquery when executed via semi join
+#
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
+3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+show warnings;
+Level Code Message
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+a
+2
+2
+3
+2
+drop table t1, t2, t3;
=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result 2009-03-19 17:03:58 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result 2009-07-04 04:01:31 +0000
@@ -331,6 +331,51 @@
HAVING X > '2012-12-12';
X
drop table t1, t2;
+#
+# BUG#31480: Incorrect result for nested subquery when executed via semi join
+#
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Start temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where; End temporary; Using join buffer
+3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
+Warnings:
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+show warnings;
+Level Code Message
+Note 1276 Field or reference 'test.t1.b' of SELECT #3 was resolved in SELECT #1
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t1`.`a` = `test`.`t2`.`c`) and <nop>(<in_optimizer>(`test`.`t2`.`d`,<exists>(select 1 AS `Not_used` from `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`e`) and (<cache>(`test`.`t2`.`d`) >= `test`.`t3`.`e`))))))
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+a
+2
+2
+3
+2
+drop table t1, t2, t3;
set join_cache_level=default;
show variables like 'join_cache_level';
Variable_name Value
=== modified file 'mysql-test/t/subselect_sj.test'
--- a/mysql-test/t/subselect_sj.test 2009-03-19 17:03:58 +0000
+++ b/mysql-test/t/subselect_sj.test 2009-07-04 04:01:31 +0000
@@ -216,4 +216,39 @@
HAVING X > '2012-12-12';
drop table t1, t2;
-
+--echo #
+--echo # BUG#31480: Incorrect result for nested subquery when executed via semi join
+--echo #
+create table t1 (a int not null, b int not null);
+create table t2 (c int not null, d int not null);
+create table t3 (e int not null);
+
+insert into t1 values (1,10);
+insert into t1 values (2,10);
+insert into t1 values (1,20);
+insert into t1 values (2,20);
+insert into t1 values (3,20);
+insert into t1 values (2,30);
+insert into t1 values (4,40);
+
+insert into t2 values (2,10);
+insert into t2 values (2,20);
+insert into t2 values (4,10);
+insert into t2 values (5,10);
+insert into t2 values (3,20);
+insert into t2 values (2,40);
+
+insert into t3 values (10);
+insert into t3 values (30);
+insert into t3 values (10);
+insert into t3 values (20);
+
+explain extended
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+show warnings;
+
+select a from t1
+where a in (select c from t2 where d >= some(select e from t3 where b=e));
+
+drop table t1, t2, t3;
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2009-04-03 15:14:49 +0000
+++ b/sql/item.cc 2009-07-04 04:01:31 +0000
@@ -2174,7 +2174,8 @@
}
-void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_field::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
if (new_parent == depended_from)
depended_from= NULL;
@@ -3559,16 +3560,17 @@
static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *resolved_item,
- Item_ident *mark_item)
+ Item_ident *mark_item, table_map dep_map)
{
const char *db_name= (resolved_item->db_name ?
resolved_item->db_name : "");
const char *table_name= (resolved_item->table_name ?
resolved_item->table_name : "");
+ //table_map dep_map = resolved_item->used_tables();
/* store pointer on SELECT_LEX from which item is dependent */
if (mark_item)
mark_item->depended_from= last;
- current->mark_as_dependent(last);
+ current->mark_as_dependent(last, dep_map);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
@@ -3628,21 +3630,26 @@
Item_subselect *prev_subselect_item=
previous_select->master_unit()->item;
Item_ident *dependent= resolved_item;
+ table_map found_used_tables;
if (found_field == view_ref_found)
{
Item::Type type= found_item->type();
+ found_used_tables= found_item->used_tables();
prev_subselect_item->used_tables_cache|=
- found_item->used_tables();
+ found_used_tables;
dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ?
(Item_ident*) found_item :
0);
}
else
+ {
+ found_used_tables= found_field->table->map;
prev_subselect_item->used_tables_cache|=
found_field->table->map;
+ }
prev_subselect_item->const_item_cache= 0;
mark_as_dependent(thd, last_select, current_sel, resolved_item,
- dependent);
+ dependent, found_used_tables);
}
}
@@ -3923,6 +3930,7 @@
SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
Name_resolution_context *outer_context= 0;
SELECT_LEX *select= 0;
+ uint n_levels= 0;
/* Currently derived tables cannot be correlated */
if (current_sel->master_unit()->first_select()->linkage !=
DERIVED_TABLE_TYPE)
@@ -4015,7 +4023,8 @@
context->select_lex, this,
((ref_type == REF_ITEM ||
ref_type == FIELD_ITEM) ?
- (Item_ident*) (*reference) : 0));
+ (Item_ident*) (*reference) : 0),
+ (*from_field)->table->map);
return 0;
}
}
@@ -4030,7 +4039,8 @@
context->select_lex, this,
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
- 0));
+ 0),
+ (*reference)->used_tables());
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
@@ -4064,6 +4074,7 @@
*/
prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
prev_subselect_item->const_item_cache= 0;
+ n_levels++;
}
DBUG_ASSERT(ref != 0);
@@ -4131,14 +4142,15 @@
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- rf);
+ rf, rf->used_tables());
return 0;
}
else
{
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
- this, (Item_ident*)*reference);
+ this, (Item_ident*)*reference,
+ (*reference)->used_tables());
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -5840,7 +5852,8 @@
((refer_type == REF_ITEM ||
refer_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
- 0));
+ 0),
+ (*reference)->used_tables());
/*
view reference found, we substituted it instead of this
Item, so can quit
@@ -5890,7 +5903,8 @@
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
- thd->lex->current_select, this, fld);
+ thd->lex->current_select, this, fld,
+ from_field->table->map);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -5913,7 +5927,8 @@
/* Should be checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last_checked_context->select_lex,
- context->select_lex, this, this);
+ context->select_lex, this, this,
+ (*ref)->used_tables());
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6323,20 +6338,22 @@
return err;
}
-void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
if (depended_from == new_parent)
{
*ref= outer_ref;
- outer_ref->fix_after_pullout(new_parent, ref);
+ outer_ref->fix_after_pullout(new_parent, parent_tables, ref);
}
}
-void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
+void Item_ref::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **refptr)
{
if (depended_from == new_parent)
{
- (*ref)->fix_after_pullout(new_parent, ref);
+ (*ref)->fix_after_pullout(new_parent, parent_tables, ref);
depended_from= NULL;
}
}
=== modified file 'sql/item.h'
--- a/sql/item.h 2009-04-03 15:14:49 +0000
+++ b/sql/item.h 2009-07-04 04:01:31 +0000
@@ -557,7 +557,8 @@
Fix after some tables has been pulled out. Basically re-calculate all
attributes that are dependent on the tables.
*/
- virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref) {};
+ virtual void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref) {};
/*
should be used in case where we are sure that we do not need
@@ -1486,7 +1487,8 @@
bool send(Protocol *protocol, String *str_arg);
void reset_field(Field *f);
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
void make_field(Send_field *tmp_field);
int save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
@@ -2278,7 +2280,8 @@
bool send(Protocol *prot, String *tmp);
void make_field(Send_field *field);
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
int save_in_field(Field *field, bool no_conversions);
void save_org_in_field(Field *field);
enum Item_result result_type () const { return (*ref)->result_type(); }
@@ -2448,7 +2451,8 @@
outer_ref->save_org_in_field(result_field);
}
bool fix_fields(THD *, Item **);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
table_map used_tables() const
{
return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT;
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2009-04-01 21:36:07 +0000
+++ b/sql/item_cmpfunc.cc 2009-07-04 04:01:31 +0000
@@ -4013,7 +4013,8 @@
}
-void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_cond::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
List_iterator<Item> li(list);
Item *item;
@@ -4027,7 +4028,7 @@
while ((item=li++))
{
table_map tmp_table_map;
- item->fix_after_pullout(new_parent, li.ref());
+ item->fix_after_pullout(new_parent, parent_tables, li.ref());
item= *li.ref();
used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item();
=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h 2009-01-26 16:03:39 +0000
+++ b/sql/item_cmpfunc.h 2009-07-04 04:01:31 +0000
@@ -1475,7 +1475,8 @@
bool add_at_head(Item *item) { return list.push_front(item); }
void add_at_head(List<Item> *nlist) { list.prepand(nlist); }
bool fix_fields(THD *, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
enum Type type() const { return COND_ITEM; }
List<Item>* argument_list() { return &list; }
=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc 2009-04-13 13:24:28 +0000
+++ b/sql/item_func.cc 2009-07-04 04:01:31 +0000
@@ -206,7 +206,8 @@
}
-void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_func::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
Item **arg,**arg_end;
@@ -217,7 +218,7 @@
{
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- (*arg)->fix_after_pullout(new_parent, arg);
+ (*arg)->fix_after_pullout(new_parent, parent_tables, arg);
Item *item= *arg;
used_tables_cache|= item->used_tables();
=== modified file 'sql/item_func.h'
--- a/sql/item_func.h 2009-02-13 16:30:54 +0000
+++ b/sql/item_func.h 2009-07-04 04:01:31 +0000
@@ -117,7 +117,8 @@
// Constructor used for Item_cond_and/or (see Item comment)
Item_func(THD *thd, Item_func *item);
bool fix_fields(THD *, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
table_map used_tables() const;
table_map not_null_tables() const;
void update_used_tables();
=== modified file 'sql/item_row.cc'
--- a/sql/item_row.cc 2008-02-22 11:11:25 +0000
+++ b/sql/item_row.cc 2009-07-04 04:01:31 +0000
@@ -124,13 +124,14 @@
}
}
-void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_row::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
{
used_tables_cache= 0;
const_item_cache= 1;
for (uint i= 0; i < arg_count; i++)
{
- items[i]->fix_after_pullout(new_parent, &items[i]);
+ items[i]->fix_after_pullout(new_parent, parent_tables, &items[i]);
used_tables_cache|= items[i]->used_tables();
const_item_cache&= items[i]->const_item();
}
=== modified file 'sql/item_row.h'
--- a/sql/item_row.h 2008-02-22 11:11:25 +0000
+++ b/sql/item_row.h 2009-07-04 04:01:31 +0000
@@ -59,7 +59,8 @@
return 0;
};
bool fix_fields(THD *thd, Item **ref);
- void fix_after_pullout(st_select_lex *new_parent, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
void cleanup();
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
table_map used_tables() const { return used_tables_cache; };
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2009-01-08 19:06:44 +0000
+++ b/sql/item_subselect.cc 2009-07-04 04:01:31 +0000
@@ -39,7 +39,7 @@
Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
- const_item_cache(1), engine_changed(0), changed(0),
+ const_item_cache(1), inside_fix_fields(0), engine_changed(0), changed(0),
is_correlated(FALSE)
{
with_subselect= 1;
@@ -158,6 +158,13 @@
DBUG_RETURN(RES_OK);
}
+void Item_subselect::set_depth()
+{
+ uint n= 0;
+ for (SELECT_LEX *s= unit->first_select(); s; s= s->outer_select())
+ n++;
+ this->depth= n - 1;
+}
bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
{
@@ -168,9 +175,19 @@
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
+ if (!inside_fix_fields)
+ {
+ set_depth();
+ if (!(ancestor_used_tables= (table_map*)thd->calloc((1+depth) *
+ sizeof(table_map))))
+ return TRUE;
+ furthest_correlated_ancestor= 0;
+ }
+
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE;
+ inside_fix_fields++;
res= engine->prepare();
// all transformation is done (used by prepared statements)
@@ -203,12 +220,14 @@
if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where;
+ inside_fix_fields--;
return ret;
}
// Is it one field subselect?
if (engine->cols() > max_columns)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
+ inside_fix_fields--;
return TRUE;
}
fix_length_and_dec();
@@ -225,11 +244,56 @@
fixed= 1;
err:
+ inside_fix_fields--;
thd->where= save_where;
return res;
}
+/*
+ Adjust attributes after our parent select has been merged into grandparent
+
+ DESCRIPTION
+ Subquery is a composite object which may be correlated, that is, it may
+ have
+ 1. references to tables of the parent select (i.e. one that has the clause
+ with the subquery predicate)
+ 2. references to tables of the grandparent select
+ 3. references to tables of further ancestors.
+
+ Before the pullout, this item indicates:
+ - #1 with table bits in used_tables()
+ - #2 and #3 with OUTER_REF_TABLE_BIT.
+
+ After parent has been merged with grandparent:
+ - references to parent and grandparent tables should be indicated with
+ table bits.
+ - references to greatgrandparent and further ancestors - with
+ OUTER_REF_TABLE_BIT.
+
+ This is exactly what this function does, based on pre-collected info in
+ ancestor_used_tables and furthest_correlated_ancestor.
+*/
+
+void Item_subselect::fix_after_pullout(st_select_lex *new_parent,
+ uint parent_tables, Item **ref)
+{
+ used_tables_cache= (used_tables_cache << parent_tables) |
+ ancestor_used_tables[0];
+ for (uint i=0; i < depth; i++)
+ ancestor_used_tables[i]= ancestor_used_tables[i+1];
+ depth--;
+
+ if (furthest_correlated_ancestor)
+ furthest_correlated_ancestor--;
+ used_tables_cache &= ~OUTER_REF_TABLE_BIT;
+ if (furthest_correlated_ancestor > 1)
+ used_tables_cache |= OUTER_REF_TABLE_BIT;
+ const_item_cache &= test(!(used_tables_cache &
+ ~new_parent->join->const_table_map));
+}
+
+
bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument)
{
=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h 2008-11-10 18:36:50 +0000
+++ b/sql/item_subselect.h 2009-07-04 04:01:31 +0000
@@ -66,9 +66,39 @@
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constant state */
+
bool const_item_cache;
+ int inside_fix_fields;
+public:
+ /*
+ Depth of the subquery predicate.
+ If the subquery predicate is attatched to some clause of the top-level
+ select, depth will be 1
+ If it is attached to a clause in a subquery of the top-level select, depth
+ will be 2 and so forth.
+ */
+ uint depth;
+
+ /*
+ Maximum correlation level of the select
+ - select that has no references to outside will have 0,
+ - select that references tables in the select it is located will have 1,
+ - select that has references to tables of its parent select will have 2,
+ - select that has references to tables of grandparent will have 3
+ and so forth.
+ */
+ uint furthest_correlated_ancestor;
+ /*
+ This is used_tables() for non-direct ancestors. That is,
+ - used_tables() shows which tables of the parent select are referred to
+ from within the subquery,
+ - ancestor_used_tables[0] shows which tables of the grandparent select are
+ referred to from within the subquery,
+ - ancestor_used_tables[1] shows which tables of the great grand parent
+ select... and so forth.
+ */
+ table_map *ancestor_used_tables;
-public:
/* changed engine indicator */
bool engine_changed;
/* subquery is transformed */
@@ -84,6 +114,7 @@
Item_subselect();
virtual subs_type substype() { return UNKNOWN_SUBS; }
+ void set_depth();
/*
We need this method, because some compilers do not allow 'this'
@@ -109,6 +140,8 @@
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
+ void fix_after_pullout(st_select_lex *new_parent, uint parent_tables,
+ Item **ref);
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc 2009-03-11 12:52:04 +0000
+++ b/sql/item_sum.cc 2009-07-04 04:01:31 +0000
@@ -350,7 +350,7 @@
sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1;
}
- thd->lex->current_select->mark_as_dependent(aggr_sel);
+ thd->lex->current_select->mark_as_dependent(aggr_sel, NULL);
return FALSE;
}
=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc 2009-04-01 09:34:34 +0000
+++ b/sql/sql_lex.cc 2009-07-04 04:01:31 +0000
@@ -1835,8 +1835,9 @@
'last' should be reachable from this st_select_lex_node
*/
-void st_select_lex::mark_as_dependent(st_select_lex *last)
+void st_select_lex::mark_as_dependent(st_select_lex *last, table_map dep_map)
{
+ uint n_levels= master_unit()->item->depth;
/*
Mark all selects from resolved to 1 before select where was
found table as depended (of select where was found table)
@@ -1862,7 +1863,14 @@
}
Item_subselect *subquery_predicate= s->master_unit()->item;
if (subquery_predicate)
+ {
subquery_predicate->is_correlated= TRUE;
+ subquery_predicate->furthest_correlated_ancestor=
+ max(subquery_predicate->furthest_correlated_ancestor, n_levels);
+ if (n_levels > 1)
+ subquery_predicate->ancestor_used_tables[n_levels - 2]= dep_map;
+ }
+ n_levels--;
}
}
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2009-03-19 16:42:23 +0000
+++ b/sql/sql_lex.h 2009-07-04 04:01:31 +0000
@@ -754,7 +754,7 @@
return master_unit()->return_after_parsing();
}
- void mark_as_dependent(st_select_lex *last);
+ void mark_as_dependent(st_select_lex *last, table_map dep_map);
bool set_braces(bool value);
bool inc_in_sum_expr();
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-04-13 09:51:24 +0000
+++ b/sql/sql_select.cc 2009-07-04 04:01:31 +0000
@@ -3119,16 +3119,23 @@
}
-void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist)
+void fix_list_after_tbl_changes(SELECT_LEX *new_parent, uint parent_tables,
+ List<TABLE_LIST> *tlist)
{
List_iterator<TABLE_LIST> it(*tlist);
TABLE_LIST *table;
while ((table= it++))
{
if (table->on_expr)
- table->on_expr->fix_after_pullout(new_parent, &table->on_expr);
+ {
+ table->on_expr->fix_after_pullout(new_parent, parent_tables,
+ &table->on_expr);
+ }
if (table->nested_join)
- fix_list_after_tbl_changes(new_parent, &table->nested_join->join_list);
+ {
+ fix_list_after_tbl_changes(new_parent, parent_tables,
+ &table->nested_join->join_list);
+ }
}
}
@@ -3331,6 +3338,7 @@
/*TODO: also reset the 'with_subselect' there. */
/* n. Adjust the parent_join->tables counter */
+ uint parent_tables= parent_join->tables;
uint table_no= parent_join->tables;
/* n. Walk through child's tables and adjust table->map */
for (tl= subq_lex->leaf_tables; tl; tl= tl->next_leaf, table_no++)
@@ -3407,8 +3415,10 @@
Walk through sj nest's WHERE and ON expressions and call
item->fix_table_changes() for all items.
*/
- sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr);
- fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list);
+ sj_nest->sj_on_expr->fix_after_pullout(parent_lex, parent_join->tables,
+ &sj_nest->sj_on_expr);
+ fix_list_after_tbl_changes(parent_lex, parent_join->tables,
+ &sj_nest->nested_join->join_list);
/* Unlink the child select_lex so it doesn't show up in EXPLAIN: */
1
0