mirror of
https://github.com/MariaDB/server.git
synced 2025-11-09 11:41:36 +03:00
MDEV-13817 add support for oracle left join syntax - the ( + )
Parser changes made by Alexander Barkov <bar@mariadb.com>. Part of the tests made by Iqbal Hassan <iqbal@hasprime.com>. Initially marking with ORA_JOIN flag made also by Iqbal Hassan <iqbal@hasprime.com>. Main idea is that parser mark fields with (+) with a flag (ORA_JOIN). During Prepare the flag bring to the new created items if needed. Later after preparing (fix_firlds()) WHERE confition the relations betweel the tables analyzed and tables reordered so to make JOIN/LEFT JOIN operators in chain equivalent to the query with oracle outer join operator (+). Then the flags of (+) removed.
This commit is contained in:
@@ -92,6 +92,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
|||||||
../sql/sql_lex.cc ../sql/keycaches.cc
|
../sql/sql_lex.cc ../sql/keycaches.cc
|
||||||
../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc
|
../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc
|
||||||
../sql/sql_binlog.cc ../sql/sql_manager.cc
|
../sql/sql_binlog.cc ../sql/sql_manager.cc
|
||||||
|
../sql/sql_oracle_outer_join.cc
|
||||||
../sql/sql_parse.cc ../sql/sql_bootstrap.cc
|
../sql/sql_parse.cc ../sql/sql_bootstrap.cc
|
||||||
../sql/sql_partition.cc ../sql/sql_plugin.cc
|
../sql/sql_partition.cc ../sql/sql_plugin.cc
|
||||||
../sql/debug_sync.cc ../sql/debug.cc
|
../sql/debug_sync.cc ../sql/debug.cc
|
||||||
|
|||||||
951
mysql-test/suite/compat/oracle/r/ora_outer_join.result
Normal file
951
mysql-test/suite/compat/oracle/r/ora_outer_join.result
Normal file
@@ -0,0 +1,951 @@
|
|||||||
|
set SQL_MODE= oracle;
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create table t3 (c int, e int);
|
||||||
|
insert into t3 values (3,2),(10,3),(2,20);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (3),(1),(20);
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t1, t2, t3, t4
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
3 3 NULL 3
|
||||||
|
1 1 1 NULL
|
||||||
|
1 3 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t1, t2, t3, t4
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
1 SIMPLE t4 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t4"."d" AS "d","test"."t2"."b" AS "b","test"."t3"."c" AS "c" from "test"."t1" join "test"."t4" left join "test"."t2" on("test"."t4"."d" = "test"."t1"."a" and "test"."t2"."b" = "test"."t1"."a") left join "test"."t3" on("test"."t4"."d" = "test"."t1"."a" and "test"."t3"."c" = "test"."t1"."a") where 1
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t4, t3, t2, t1
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
1 1 1 NULL
|
||||||
|
3 3 NULL 3
|
||||||
|
1 3 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t4, t3, t2, t1
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t4 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
|
||||||
|
1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t4"."d" AS "d","test"."t2"."b" AS "b","test"."t3"."c" AS "c" from "test"."t4" join "test"."t1" left join "test"."t3" on("test"."t1"."a" = "test"."t4"."d" and "test"."t3"."c" = "test"."t4"."d") left join "test"."t2" on("test"."t1"."a" = "test"."t4"."d" and "test"."t2"."b" = "test"."t4"."d") where 1
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t2, t1, t4, t3
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
3 3 NULL 3
|
||||||
|
1 1 1 NULL
|
||||||
|
1 3 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t2, t1, t4, t3
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
1 SIMPLE t4 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t4"."d" AS "d","test"."t2"."b" AS "b","test"."t3"."c" AS "c" from "test"."t1" join "test"."t4" left join "test"."t2" on("test"."t4"."d" = "test"."t1"."a" and "test"."t2"."b" = "test"."t1"."a") left join "test"."t3" on("test"."t4"."d" = "test"."t1"."a" and "test"."t3"."c" = "test"."t1"."a") where 1
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t3, t4, t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
1 1 1 NULL
|
||||||
|
3 3 NULL 3
|
||||||
|
1 3 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t3, t4, t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t4 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
|
||||||
|
1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t4"."d" AS "d","test"."t2"."b" AS "b","test"."t3"."c" AS "c" from "test"."t4" join "test"."t1" left join "test"."t3" on("test"."t1"."a" = "test"."t4"."d" and "test"."t3"."c" = "test"."t4"."d") left join "test"."t2" on("test"."t1"."a" = "test"."t4"."d" and "test"."t2"."b" = "test"."t4"."d") where 1
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
#
|
||||||
|
# tests of Iqbal Hassan <iqbal@hasprime.com>
|
||||||
|
# (with 2 fixes)
|
||||||
|
#
|
||||||
|
CREATE TABLE tj1(a int, b int);
|
||||||
|
CREATE TABLE tj2(c int, d int);
|
||||||
|
CREATE TABLE tj3(e int, f int);
|
||||||
|
CREATE TABLE tj4(b int, c int);
|
||||||
|
INSERT INTO tj1 VALUES (1, 1);
|
||||||
|
INSERT INTO tj1 VALUES (2, 2);
|
||||||
|
INSERT INTO tj2 VALUES (2, 3);
|
||||||
|
INSERT INTO tj3 VALUES (1, 4);
|
||||||
|
#
|
||||||
|
# Basic test
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
a b c d
|
||||||
|
2 2 2 3
|
||||||
|
1 1 NULL NULL
|
||||||
|
#
|
||||||
|
# Compare marked with literal
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND tj2.d(+) > 4;
|
||||||
|
a b c d
|
||||||
|
1 1 NULL NULL
|
||||||
|
2 2 NULL NULL
|
||||||
|
explain extended
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND tj2.d(+) > 4;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE tj1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 SIMPLE tj2 ALL NULL NULL NULL NULL 1 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."tj1"."a" AS "a","test"."tj1"."b" AS "b","test"."tj2"."c" AS "c","test"."tj2"."d" AS "d" from "test"."tj1" left join "test"."tj2" on("test"."tj2"."c" = "test"."tj1"."a" and "test"."tj2"."d" > 4) where 1
|
||||||
|
#
|
||||||
|
# Use both marked and unmarked field in the same condition
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND tj2.d = 3;
|
||||||
|
a b c d
|
||||||
|
2 2 2 3
|
||||||
|
#
|
||||||
|
# Use both marked and unmarked field in OR condition
|
||||||
|
#
|
||||||
|
SELECT * FROM tj2,tj1 WHERE tj1.a = tj2.c(+) OR tj2.d=4;
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj3.e(+) AND (tj1.a = tj2.c(+) OR tj2.d=4);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
#
|
||||||
|
# Use unmarked fields in OR condition
|
||||||
|
#
|
||||||
|
SELECT * FROM tj2,tj1 WHERE tj1.a = tj2.c(+) AND (tj2.d=3 OR tj2.d * 2=3);
|
||||||
|
c d a b
|
||||||
|
2 3 2 2
|
||||||
|
#
|
||||||
|
# Use marked fields in OR condition when all fields are marked
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND (tj2.d(+)=3 OR tj2.c(+)=1);
|
||||||
|
a b c d
|
||||||
|
2 2 2 3
|
||||||
|
1 1 NULL NULL
|
||||||
|
#
|
||||||
|
# Use more than one marked table per condition
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) + tj3.e(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: both tables tj2 and tj3 are of INNER type in the relation
|
||||||
|
#
|
||||||
|
# Use different tables per `AND` operand
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) AND tj1.a = tj3.e(+);
|
||||||
|
a b c d e f
|
||||||
|
1 1 NULL NULL 1 4
|
||||||
|
2 2 2 3 NULL NULL
|
||||||
|
#
|
||||||
|
# Ensure table dependencies are properly resolved
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj3.e AND tj1.a + 1 = tj2.c(+);
|
||||||
|
a b c d e f
|
||||||
|
1 1 2 3 1 4
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) AND tj2.c = tj3.e(+) + 1;
|
||||||
|
a b c d e f
|
||||||
|
2 2 2 3 1 4
|
||||||
|
1 1 NULL NULL NULL NULL
|
||||||
|
SELECT * FROM tj1, tj2, tj3 WHERE tj1.a + tj3.e = tj2.c(+);
|
||||||
|
a b c d e f
|
||||||
|
1 1 2 3 1 4
|
||||||
|
2 2 NULL NULL 1 4
|
||||||
|
#
|
||||||
|
# Cyclic dependency of tables
|
||||||
|
# ORA-01416 two tables cannot be outer-joined to each other
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) AND tj2.c = tj3.e(+) + 1 AND tj3.e = tj1.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
#
|
||||||
|
# Table not referenced in where condition (must be cross-joined)
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2, tj3 WHERE tj1.a + 1 = tj2.c(+);
|
||||||
|
a b c d e f
|
||||||
|
1 1 2 3 1 4
|
||||||
|
2 2 NULL NULL 1 4
|
||||||
|
#
|
||||||
|
# Alias
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 b WHERE tj1.a + 1 = b.c(+);
|
||||||
|
a b c d
|
||||||
|
1 1 2 3
|
||||||
|
2 2 NULL NULL
|
||||||
|
#
|
||||||
|
# Subselect
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, (SELECT * from tj2) b WHERE tj1.a + 1 = b.c(+);
|
||||||
|
a b c d
|
||||||
|
1 1 2 3
|
||||||
|
2 2 NULL NULL
|
||||||
|
SELECT * FROM tj1, (SELECT * FROM tj1, tj2 d WHERE tj1.a = d.c(+)) b WHERE tj1.a + 1 = b.c(+);
|
||||||
|
a b a b c d
|
||||||
|
1 1 2 2 2 3
|
||||||
|
2 2 NULL NULL NULL NULL
|
||||||
|
#
|
||||||
|
# Single table
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1 WHERE tj1.a(+) = 1;
|
||||||
|
a b
|
||||||
|
1 1
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '"test"."tj1"."a" = 1'
|
||||||
|
#
|
||||||
|
# Self outer join
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1 a, tj1 b WHERE a.a + 1 = b.a(+);
|
||||||
|
a b a b
|
||||||
|
1 1 2 2
|
||||||
|
2 2 NULL NULL
|
||||||
|
#
|
||||||
|
# Self outer join without alias
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a + 1 = tj1.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
#
|
||||||
|
# Outer join condition is independent of other tables
|
||||||
|
# In this case we need to restrict the marked table(s) to appear
|
||||||
|
# after the unmarked table(s) during topological sort. This test
|
||||||
|
# ensures that the topological sort is working correctly.
|
||||||
|
#
|
||||||
|
# correct result in is empty result set (tj2.c = 1 filters all out)
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj2.c(+) = 1;
|
||||||
|
a b c d
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '"test"."tj2"."c" = 1'
|
||||||
|
# one row (there is tj1.a = 1)
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a(+) = 1;
|
||||||
|
a b c d
|
||||||
|
1 1 2 3
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '"test"."tj1"."a" = 1'
|
||||||
|
#
|
||||||
|
# Outer join in 'IN' condition
|
||||||
|
# ORA-01719
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a IN (tj2.c(+), tj2.d(+));
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a NOT IN (tj2.c(+), tj2.d(+));
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
#
|
||||||
|
# Outer join in 'IN' condition with a single expression
|
||||||
|
# This is also allowed in oracle since the expression is
|
||||||
|
# can be simplified to 'equal' or 'not equal' condition
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a IN (tj2.c(+));
|
||||||
|
a b c d
|
||||||
|
2 2 2 3
|
||||||
|
1 1 NULL NULL
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a NOT IN (tj2.c(+));
|
||||||
|
a b c d
|
||||||
|
1 1 2 3
|
||||||
|
2 2 NULL NULL
|
||||||
|
#
|
||||||
|
# Oracle outer join not in WHERE clause
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c GROUP BY tj2.c(+);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ')' at line 1
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c GROUP BY tj2.c HAVING tj2.c(+) > 1;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') > 1' at line 1
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c ORDER BY tj2.c(+);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ')' at line 1
|
||||||
|
SELECT tj2.c(+) FROM tj2;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') FROM tj2' at line 1
|
||||||
|
#
|
||||||
|
# Mix ANSI and Oracle outer join
|
||||||
|
# ORA-25156
|
||||||
|
SELECT * FROM tj1 LEFT JOIN tj2 ON tj2.c = 1 WHERE tj1.a = tj2.c(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
SELECT * FROM tj1 INNER JOIN tj2 ON tj2.c = 1 WHERE tj1.a = tj2.c(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
SELECT * FROM tj1 NATURAL JOIN tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
#
|
||||||
|
# View with oracle outer join
|
||||||
|
#
|
||||||
|
CREATE VIEW v1 AS SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
SELECT * FROM v1;
|
||||||
|
a b c d
|
||||||
|
2 2 2 3
|
||||||
|
1 1 NULL NULL
|
||||||
|
#
|
||||||
|
# Cursor with oracle outer join
|
||||||
|
#
|
||||||
|
DECLARE
|
||||||
|
CURSOR c1 IS SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
BEGIN
|
||||||
|
FOR r1 IN c1 LOOP
|
||||||
|
SELECT r1.a || ' ' || r1.c;
|
||||||
|
END LOOP;
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
r1.a || ' ' || r1.c
|
||||||
|
2 2
|
||||||
|
r1.a || ' ' || r1.c
|
||||||
|
1
|
||||||
|
#
|
||||||
|
# Marking ROW type
|
||||||
|
#
|
||||||
|
DECLARE
|
||||||
|
v1 ROW (a INT, b INT);
|
||||||
|
BEGIN
|
||||||
|
SELECT * FROM tj1 WHERE tj1.a = v1.a(+);
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ');
|
||||||
|
END' at line 4
|
||||||
|
#
|
||||||
|
# Unspecified table used in WHERE clause that contains (+)
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj3.c(+);
|
||||||
|
ERROR 42S22: Unknown column 'tj3.c' in 'WHERE'
|
||||||
|
#
|
||||||
|
# '.' prefixed table name
|
||||||
|
#
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = .tj2.c(+);
|
||||||
|
a b c d
|
||||||
|
2 2 2 3
|
||||||
|
1 1 NULL NULL
|
||||||
|
CREATE DATABASE db1;
|
||||||
|
USE db1;
|
||||||
|
CREATE TABLE tj1(a int, b int);
|
||||||
|
INSERT INTO tj1 VALUES (3, 3);
|
||||||
|
INSERT INTO tj1 VALUES (4, 4);
|
||||||
|
#
|
||||||
|
# DB qualifed ident with oracle outer join (aliased)
|
||||||
|
#
|
||||||
|
SELECT * FROM test.tj2 a, tj1 WHERE a.c(+) = tj1.a - 1;
|
||||||
|
c d a b
|
||||||
|
2 3 3 3
|
||||||
|
NULL NULL 4 4
|
||||||
|
#
|
||||||
|
# DB qualifed ident with oracle outer join (non-aliased)
|
||||||
|
#
|
||||||
|
SELECT * FROM test.tj2, tj1 WHERE test.tj2.c(+) = tj1.a - 1;
|
||||||
|
c d a b
|
||||||
|
2 3 3 3
|
||||||
|
NULL NULL 4 4
|
||||||
|
#
|
||||||
|
# DB qualifed ident with oracle outer join (aliased but use table name)
|
||||||
|
#
|
||||||
|
SELECT * FROM test.tj2 a, tj1 WHERE test.tj2.c(+) = tj1.a - 1;
|
||||||
|
ERROR 42S22: Unknown column 'test.tj2.c' in 'WHERE'
|
||||||
|
USE test;
|
||||||
|
#
|
||||||
|
# UPDATE with oracle outer join
|
||||||
|
#
|
||||||
|
UPDATE tj1, tj2 SET tj1.a = tj2.c WHERE tj1.a = tj2.c(+);
|
||||||
|
SELECT * FROM tj1;
|
||||||
|
a b
|
||||||
|
NULL 1
|
||||||
|
2 2
|
||||||
|
#
|
||||||
|
# DELETE with oracle outer join
|
||||||
|
#
|
||||||
|
DELETE tj1 FROM tj1, tj2 WHERE tj1.b(+) = tj2.c;
|
||||||
|
SELECT * FROM tj1;
|
||||||
|
a b
|
||||||
|
NULL 1
|
||||||
|
DROP DATABASE db1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE tj4;
|
||||||
|
DROP TABLE tj3;
|
||||||
|
DROP TABLE tj2;
|
||||||
|
DROP TABLE tj1;
|
||||||
|
#
|
||||||
|
# End of iqbal-rsec tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Test from the MDEV comments
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create table t3 (c int, e int);
|
||||||
|
insert into t3 values (3,2),(10,3),(2,20);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (3),(1),(20);
|
||||||
|
select t1.a, t4.d, t2.b, t3.c from t1, t2, t3, t4 where t1.a = t2.b(+) and t1.a = t3.c(+) and t4.d = t2.b(+) and t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
3 3 NULL 3
|
||||||
|
1 1 1 NULL
|
||||||
|
1 3 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
select t1.a, t4.d, t2.b, t3.c from t1, t2, t3, t4 where t1.a + t3.c = t2.b(+) and t1.a = t3.c(+) and t4.d = t2.b(+) and t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
3 3 NULL 3
|
||||||
|
1 3 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
1 1 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
select t1.a, t4.d, t2.b, t3.c from t1, t2, t3, t4 where (t2.b(+) in (t1.a, t1.a+1)) and t1.a = t3.c(+) and t4.d = t2.b(+) and t4.d = t3.c(+);
|
||||||
|
a d b c
|
||||||
|
3 3 NULL 3
|
||||||
|
1 1 1 NULL
|
||||||
|
1 3 NULL NULL
|
||||||
|
2 3 NULL NULL
|
||||||
|
2 1 NULL NULL
|
||||||
|
3 1 NULL NULL
|
||||||
|
1 20 NULL NULL
|
||||||
|
2 20 NULL NULL
|
||||||
|
3 20 NULL NULL
|
||||||
|
drop tables t1, t2, t3, t4;
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create table t3 (c int, f int);
|
||||||
|
insert into t3 values (3,2),(10,3),(2,20);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (3),(1),(20);
|
||||||
|
create table t5 (e int);
|
||||||
|
insert into t5 values (3),(2),(20);
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, t2, t3, t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and t3.c=t5.e(+);
|
||||||
|
a b c d e
|
||||||
|
2 2 2 NULL NULL
|
||||||
|
3 NULL NULL 3 NULL
|
||||||
|
1 1 NULL 1 NULL
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, t2, t3, t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and 1=t5.e(+);
|
||||||
|
a b c d e
|
||||||
|
3 NULL NULL 3 NULL
|
||||||
|
1 1 NULL 1 NULL
|
||||||
|
2 2 2 NULL NULL
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, t2, t3, t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and 3=t5.e(+);
|
||||||
|
a b c d e
|
||||||
|
3 NULL NULL 3 3
|
||||||
|
1 1 NULL 1 NULL
|
||||||
|
2 2 2 NULL NULL
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, (t2, t3), t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and 3=t5.e(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
drop tables t1, t2, t3, t4, t5;
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
select t1.a, t2.b from t1, t2 where 1 = t2.b(+);
|
||||||
|
a b
|
||||||
|
1 1
|
||||||
|
2 1
|
||||||
|
3 1
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '1 = "test"."t2"."b"'
|
||||||
|
select t1.a, t2.b from t2, t1 where 1 = t2.b(+);
|
||||||
|
a b
|
||||||
|
1 1
|
||||||
|
2 1
|
||||||
|
3 1
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '1 = "test"."t2"."b"'
|
||||||
|
select t1.a,t2.b from t2,t1 where t2.b(+) in (1,2);
|
||||||
|
a b
|
||||||
|
1 2
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
2 1
|
||||||
|
3 2
|
||||||
|
3 1
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '"test"."t2"."b" in (1,2)'
|
||||||
|
select t2.b from t2 where 1 = t2.b(+);
|
||||||
|
b
|
||||||
|
1
|
||||||
|
Warnings:
|
||||||
|
Warning 4237 Oracle outer join operator (+) ignored in '1 = "test"."t2"."b"'
|
||||||
|
drop tables t1, t2;
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(4),(5),(20),(21),(23);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (1),(4),(6),(7),(8),(23);
|
||||||
|
create table t3 (c int);
|
||||||
|
insert into t3 values (4),(7),(9),(4),(6),(10),(11),(1);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (1),(4),(10),(12),(20),(21),(23);
|
||||||
|
SELECT * FROM t1,t2,t3,t4 WHERE t1.a = t2.b(+) AND t1.a = t3.c(+) AND t2.b=t4.d(+) AND t3.c=t4.d(+);
|
||||||
|
a b c d
|
||||||
|
1 1 1 1
|
||||||
|
4 4 4 4
|
||||||
|
4 4 4 4
|
||||||
|
23 23 NULL NULL
|
||||||
|
2 NULL NULL NULL
|
||||||
|
5 NULL NULL NULL
|
||||||
|
20 NULL NULL NULL
|
||||||
|
21 NULL NULL NULL
|
||||||
|
select * from t1, t2, t3 where (t1.a + t2.b = t3.c(+));
|
||||||
|
a b c
|
||||||
|
1 6 7
|
||||||
|
1 8 9
|
||||||
|
2 7 9
|
||||||
|
5 4 9
|
||||||
|
2 4 6
|
||||||
|
5 1 6
|
||||||
|
2 8 10
|
||||||
|
4 6 10
|
||||||
|
4 7 11
|
||||||
|
5 6 11
|
||||||
|
1 1 NULL
|
||||||
|
1 4 NULL
|
||||||
|
1 7 NULL
|
||||||
|
1 23 NULL
|
||||||
|
2 1 NULL
|
||||||
|
2 6 NULL
|
||||||
|
2 23 NULL
|
||||||
|
4 1 NULL
|
||||||
|
4 4 NULL
|
||||||
|
4 8 NULL
|
||||||
|
4 23 NULL
|
||||||
|
5 7 NULL
|
||||||
|
5 8 NULL
|
||||||
|
5 23 NULL
|
||||||
|
20 1 NULL
|
||||||
|
20 4 NULL
|
||||||
|
20 6 NULL
|
||||||
|
20 7 NULL
|
||||||
|
20 8 NULL
|
||||||
|
20 23 NULL
|
||||||
|
21 1 NULL
|
||||||
|
21 4 NULL
|
||||||
|
21 6 NULL
|
||||||
|
21 7 NULL
|
||||||
|
21 8 NULL
|
||||||
|
21 23 NULL
|
||||||
|
23 1 NULL
|
||||||
|
23 4 NULL
|
||||||
|
23 6 NULL
|
||||||
|
23 7 NULL
|
||||||
|
23 8 NULL
|
||||||
|
23 23 NULL
|
||||||
|
# no tables mentioned
|
||||||
|
select * from t2, t3 where b = c(+);
|
||||||
|
b c
|
||||||
|
4 4
|
||||||
|
7 7
|
||||||
|
4 4
|
||||||
|
6 6
|
||||||
|
1 1
|
||||||
|
8 NULL
|
||||||
|
23 NULL
|
||||||
|
# should be the same as above
|
||||||
|
select * from t2, t3 where t2.b = t3.c(+);
|
||||||
|
b c
|
||||||
|
4 4
|
||||||
|
7 7
|
||||||
|
4 4
|
||||||
|
6 6
|
||||||
|
1 1
|
||||||
|
8 NULL
|
||||||
|
23 NULL
|
||||||
|
drop tables t1, t2, t3, t4;
|
||||||
|
#
|
||||||
|
# View creation and usage
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create view v1 as
|
||||||
|
select t1.a, t2.b from t1, t2 where t1.a = t2.b(+);
|
||||||
|
show create view v1;
|
||||||
|
View Create View character_set_client collation_connection
|
||||||
|
v1 CREATE VIEW "v1" AS select "t1"."a" AS "a","t2"."b" AS "b" from ("t1" left join "t2" on("t1"."a" = "t2"."b")) latin1 latin1_swedish_ci
|
||||||
|
select * from v1;
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
select t1.a, t2.b from t1, t2 where t1.a = t2.b(+);
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
usage without oracle sql mode
|
||||||
|
set SQL_MODE= '';
|
||||||
|
select * from v1;
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
select t1.a, t2.b from t1, t2 where t1.a = t2.b(+);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ')' at line 1
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
drop view v1;
|
||||||
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# MDEV-36830: Oracle outer join syntax (+): outer join not converted to inner
|
||||||
|
#
|
||||||
|
create table t1 (
|
||||||
|
a int not null,
|
||||||
|
b int not null
|
||||||
|
);
|
||||||
|
insert into t1 select seq,seq from seq_1_to_10;
|
||||||
|
create table t2 (
|
||||||
|
a int not null,
|
||||||
|
b int not null
|
||||||
|
);
|
||||||
|
insert into t2 select seq,seq from seq_1_to_3;
|
||||||
|
# Must be converted to inner join:
|
||||||
|
explain extended
|
||||||
|
select * from t1, t2
|
||||||
|
where
|
||||||
|
t1.a=1 and
|
||||||
|
t1.b=t2.b(+) and
|
||||||
|
t2.b=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b","test"."t2"."a" AS "a","test"."t2"."b" AS "b" from "test"."t1" join "test"."t2" where "test"."t1"."a" = 1 and "test"."t2"."b" = 1 and "test"."t1"."b" = 1
|
||||||
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# MDEV-36838: Oracle outer join syntax (+): server crash on derived tables
|
||||||
|
#
|
||||||
|
select a.a
|
||||||
|
from (select 1 as a) a,
|
||||||
|
(select 2 as b) b
|
||||||
|
where a.a=b.b(+);
|
||||||
|
a
|
||||||
|
1
|
||||||
|
#
|
||||||
|
# MDEV-36866: Oracle outer join syntax (+): query with checking for
|
||||||
|
# null of non-null column uses wrong query plan and returns wrong
|
||||||
|
# result
|
||||||
|
#
|
||||||
|
create table t1 (a int default NULL);
|
||||||
|
create table t2 (a int not null);
|
||||||
|
insert into t1 values (1), (2), (3), (4), (5), (6), (NULL);
|
||||||
|
insert into t2 values (1), (4), (5), (6), (7);
|
||||||
|
select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1;
|
||||||
|
a a
|
||||||
|
explain select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1;
|
||||||
|
a a
|
||||||
|
2 NULL
|
||||||
|
3 NULL
|
||||||
|
NULL NULL
|
||||||
|
explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 7
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join)
|
||||||
|
select t1.*,t2.* from t1,t2 where t1.a=t2.a(+) and isnull(t2.a)=1;
|
||||||
|
a a
|
||||||
|
2 NULL
|
||||||
|
3 NULL
|
||||||
|
NULL NULL
|
||||||
|
explain extended select t1.*,t2.* from t1,t2 where t1.a=t2.a(+) and isnull(t2.a)=1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t2"."a" AS "a" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where "test"."t2"."a" is null = 1
|
||||||
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# Correct nullability test
|
||||||
|
#
|
||||||
|
create table t1 (a int not null, s varchar(10) not null);
|
||||||
|
create table t2 (a int not null, s varchar(10) not null);
|
||||||
|
insert into t1 values (1, 'one');
|
||||||
|
insert into t1 values (2, 'two');
|
||||||
|
insert into t2 values (2, 'two');
|
||||||
|
insert into t2 values (3, 'three');
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t2.a);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Not exists; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where "test"."t2"."a" is null
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t1.a+t2.a);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where "test"."t1"."a" + "test"."t2"."a" is null
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(coalesce(t2.s, 'null'));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on(multiple equal("test"."t1"."a", "test"."t2"."a")) where 0
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(ifnull(t2.s, 'null'));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on(multiple equal("test"."t1"."a", "test"."t2"."a")) where 0
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(coalesce(t2.s, null));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where coalesce("test"."t2"."s",NULL) is null
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(ifnull(t2.s, null));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where ifnull("test"."t2"."s",NULL) is null
|
||||||
|
# Our optimizer does not optimize out never-null-subselects under
|
||||||
|
# isnull() so we do not test it. The following test is to make
|
||||||
|
# sure that nullable one stay in the WHERE.
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t2.a in (select a from t1));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
2 MATERIALIZED t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
Warnings:
|
||||||
|
Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where <expr_cache><"test"."t2"."a">(<in_optimizer>("test"."t2"."a","test"."t2"."a" in ( <materialize> (/* select#2 */ select "test"."t1"."a" from "test"."t1" ), <primary_index_lookup>("test"."t2"."a" in <temporary table> on distinct_key where "test"."t2"."a" = "<subquery2>"."a")))) is null
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t2.a in (1, 2, 3));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on("test"."t2"."a" = "test"."t1"."a") where "test"."t2"."a" in (1,2,3) is null
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t1.a in (1, 2, 3));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on(multiple equal("test"."t1"."a", "test"."t2"."a")) where 0
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(isnull(t2.a));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on(multiple equal("test"."t1"."a", "test"."t2"."a")) where 0
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(field(t2.a, 2, 23));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on(multiple equal("test"."t1"."a", "test"."t2"."a")) where 0
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(benchmark(10, t2.a));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."s" AS "s","test"."t2"."a" AS "a","test"."t2"."s" AS "s" from "test"."t1" left join "test"."t2" on(multiple equal("test"."t1"."a", "test"."t2"."a")) where 0
|
||||||
|
drop table t1, t2;
|
||||||
|
#
|
||||||
|
# MDEV-36895: Oracle outer join syntax (+): some NULLs missing from
|
||||||
|
# result of the query with derived tables and limit
|
||||||
|
#
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (3),(7),(1);
|
||||||
|
create table t3 (c int);
|
||||||
|
insert into t3 values (3),(1);
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(7),(1);
|
||||||
|
select * from
|
||||||
|
(
|
||||||
|
select * from
|
||||||
|
(select 'Z' as z, t1.a from t1) dt1
|
||||||
|
left join
|
||||||
|
(select 'Y' as y, t2.b from t2) dt2
|
||||||
|
left join
|
||||||
|
(select 'X' as x, t3.c from t3) dt3
|
||||||
|
on dt2.b=dt3.c
|
||||||
|
on dt1.a=dt2.b
|
||||||
|
order by z, a, y, b, x, c
|
||||||
|
limit 9
|
||||||
|
) dt;
|
||||||
|
z a y b x c
|
||||||
|
Z 1 Y 1 X 1
|
||||||
|
Z 1 Y 1 X 1
|
||||||
|
Z 2 NULL NULL NULL NULL
|
||||||
|
Z 7 Y 7 NULL NULL
|
||||||
|
select * from
|
||||||
|
(
|
||||||
|
select * from
|
||||||
|
(select 'Z' as z, t1.a from t1) dt1
|
||||||
|
,(select * from
|
||||||
|
(select 'Y' as y, t2.b from t2) dt2
|
||||||
|
,
|
||||||
|
(select 'X' as x, t3.c from t3) dt3
|
||||||
|
where dt2.b=dt3.c(+)
|
||||||
|
) tdt2
|
||||||
|
where dt1.a=tdt2.b(+)
|
||||||
|
order by z, a, y, b, x, c
|
||||||
|
limit 9
|
||||||
|
) dt;
|
||||||
|
z a y b x c
|
||||||
|
Z 1 Y 1 X 1
|
||||||
|
Z 1 Y 1 X 1
|
||||||
|
Z 2 NULL NULL NULL NULL
|
||||||
|
Z 7 Y 7 NULL NULL
|
||||||
|
drop table t1, t2, t3;
|
||||||
|
#
|
||||||
|
# MDEV-37337: Oracle outer join syntax (+): IN equal to = allow (+) on right side
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+);
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
explain extended
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t2"."b" AS "b" from "test"."t1" left join "test"."t2" on("test"."t2"."b" = "test"."t1"."a") where 1
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+), 29);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+);
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
a b
|
||||||
|
2 2
|
||||||
|
1 1
|
||||||
|
3 NULL
|
||||||
|
explain extended
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00
|
||||||
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select "test"."t1"."a" AS "a","test"."t2"."b" AS "b" from "test"."t1" left join "test"."t2" on("test"."t2"."b" = "test"."t1"."a") where 1
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+), 29);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
# End of 12.1 tests
|
||||||
107
mysql-test/suite/compat/oracle/r/ora_outer_join_err.result
Normal file
107
mysql-test/suite/compat/oracle/r/ora_outer_join_err.result
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
SET sql_mode=ORACLE;
|
||||||
|
#
|
||||||
|
# Cycles
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (b int);
|
||||||
|
create table t3 (c int);
|
||||||
|
# b - cyrcle
|
||||||
|
select * from t1, t2, t3
|
||||||
|
where t1.a = t2.b(+) AND t2.b = t3.c(+) AND
|
||||||
|
t3.c = t2.b(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
# O - cyrcle
|
||||||
|
select * from t1, t2, t3
|
||||||
|
where t1.a = t2.b(+) AND t2.b = t3.c(+) AND
|
||||||
|
t3.c = t1.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
# self-reference cyrcle
|
||||||
|
select * from t1, t2, t3
|
||||||
|
where t1.a = t2.b(+) AND t2.b = t3.c(+) AND
|
||||||
|
t3.c = t3.c(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (b int);
|
||||||
|
create table t3 (c int);
|
||||||
|
create table t4 (d int);
|
||||||
|
create table t5 (e int);
|
||||||
|
# complex case
|
||||||
|
select * from t1, t2, t3, t4, t5
|
||||||
|
where
|
||||||
|
t3.c = t4.d(+) AND t4.d = t3.c(+) AND
|
||||||
|
t1.a = t5.e(+) AND t2.b = t5.e(+) AND
|
||||||
|
t2.b = t3.c(+)
|
||||||
|
;
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: cycle dependencies
|
||||||
|
DROP TABLE t1,t2,t3,t4,t5;
|
||||||
|
#
|
||||||
|
# mix with other join operatirs
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
create table t3 (a int);
|
||||||
|
# mixing with left join
|
||||||
|
select * from t1, t2 left join t3 on (t2.a = t3.a)
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
# mixing with right join
|
||||||
|
select * from t1, t2 right join t3 on (t2.a = t3.a)
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
# mixing with natural join
|
||||||
|
select * from t1, t2 natural join t3
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
# mixing with nested join
|
||||||
|
select * from t1, t2 join t3
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
# mixing with nested join
|
||||||
|
select * from t1, (t2, t3)
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: mixed with other type of join
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
#
|
||||||
|
# misplaced usage of (+)
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
select t1.a(+), t2.a from t1,t2;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '), t2.a from t1,t2' at line 1
|
||||||
|
select t1.a, t2.a from t1,t2 HAVING t1.a(+) = t2.a;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') = t2.a' at line 1
|
||||||
|
select t1.a, t2.a from t1 join t2 on (t1.a(+) = t2.a);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') = t2.a)' at line 1
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
#
|
||||||
|
# outer reference
|
||||||
|
#
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
select u2.a, (select t1.a, t2.a from t1,t2 where u1.a(+) = t2.a)
|
||||||
|
from t1 as u1, t2 as u2 where u1.a(+) = u2.a;
|
||||||
|
ERROR HY000: Invalid usage of (+) operator with outer reference a
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
#
|
||||||
|
# MDEV-36883: Oracle outer join syntax (+): operator (+) is not
|
||||||
|
# processed in condition like "(t2.b(+) , t1.b) in (select ...)"
|
||||||
|
#
|
||||||
|
create table t1 ( c int, b char(1));
|
||||||
|
insert into t1 values (1,'b');
|
||||||
|
create table t2 ( a int , b char(1));
|
||||||
|
insert into t2 values (1,'a');
|
||||||
|
create table t3 (c1 char(1), c2 char(2));
|
||||||
|
insert into t3 values ('c','d');
|
||||||
|
insert into t3 values ('c','d');
|
||||||
|
SELECT t2.b
|
||||||
|
FROM t1, t2 WHERE t1.c = t2.a(+) AND (t2.b(+), t1.b) IN (SELECT * from t3);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
SELECT t2.b
|
||||||
|
FROM t1, t2 WHERE t1.c = t2.a(+) AND (t2.b(+), t1.b) IN (('a','a'),('b','b'));
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
SELECT t2.b
|
||||||
|
FROM t1, t2 WHERE t1.c = t2.a(+) AND (t2.b(+), t1.b) = (SELECT * from t3
|
||||||
|
ORDER BY a LIMIT 1);
|
||||||
|
ERROR HY000: Invalid usage of (+) operator: used in OR, IN or ROW operation
|
||||||
|
drop tables t1,t2,t3;
|
||||||
667
mysql-test/suite/compat/oracle/t/ora_outer_join.test
Normal file
667
mysql-test/suite/compat/oracle/t/ora_outer_join.test
Normal file
@@ -0,0 +1,667 @@
|
|||||||
|
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create table t3 (c int, e int);
|
||||||
|
insert into t3 values (3,2),(10,3),(2,20);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (3),(1),(20);
|
||||||
|
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t1, t2, t3, t4
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t1, t2, t3, t4
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t4, t3, t2, t1
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t4, t3, t2, t1
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t2, t1, t4, t3
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t2, t1, t4, t3
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t3, t4, t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select t1.a, t4.d, t2.b, t3.c
|
||||||
|
from t3, t4, t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+) and
|
||||||
|
t1.a = t3.c(+) and
|
||||||
|
t4.d = t2.b(+) and
|
||||||
|
t4.d = t3.c(+);
|
||||||
|
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # tests of Iqbal Hassan <iqbal@hasprime.com>
|
||||||
|
--echo # (with 2 fixes)
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE tj1(a int, b int);
|
||||||
|
CREATE TABLE tj2(c int, d int);
|
||||||
|
CREATE TABLE tj3(e int, f int);
|
||||||
|
CREATE TABLE tj4(b int, c int);
|
||||||
|
INSERT INTO tj1 VALUES (1, 1);
|
||||||
|
INSERT INTO tj1 VALUES (2, 2);
|
||||||
|
INSERT INTO tj2 VALUES (2, 3);
|
||||||
|
INSERT INTO tj3 VALUES (1, 4);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Basic test
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Compare marked with literal
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND tj2.d(+) > 4;
|
||||||
|
explain extended
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND tj2.d(+) > 4;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Use both marked and unmarked field in the same condition
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND tj2.d = 3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Use both marked and unmarked field in OR condition
|
||||||
|
--echo #
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
SELECT * FROM tj2,tj1 WHERE tj1.a = tj2.c(+) OR tj2.d=4;
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj3.e(+) AND (tj1.a = tj2.c(+) OR tj2.d=4);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Use unmarked fields in OR condition
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj2,tj1 WHERE tj1.a = tj2.c(+) AND (tj2.d=3 OR tj2.d * 2=3);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Use marked fields in OR condition when all fields are marked
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1,tj2 WHERE tj1.a = tj2.c(+) AND (tj2.d(+)=3 OR tj2.c(+)=1);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Use more than one marked table per condition
|
||||||
|
--echo #
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_ONE_TABLE
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) + tj3.e(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Use different tables per `AND` operand
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) AND tj1.a = tj3.e(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Ensure table dependencies are properly resolved
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj3.e AND tj1.a + 1 = tj2.c(+);
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) AND tj2.c = tj3.e(+) + 1;
|
||||||
|
SELECT * FROM tj1, tj2, tj3 WHERE tj1.a + tj3.e = tj2.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Cyclic dependency of tables
|
||||||
|
--echo # ORA-01416 two tables cannot be outer-joined to each other
|
||||||
|
--echo #
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
SELECT * FROM tj1,tj2,tj3 WHERE tj1.a = tj2.c(+) AND tj2.c = tj3.e(+) + 1 AND tj3.e = tj1.a(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Table not referenced in where condition (must be cross-joined)
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1, tj2, tj3 WHERE tj1.a + 1 = tj2.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Alias
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1, tj2 b WHERE tj1.a + 1 = b.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Subselect
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1, (SELECT * from tj2) b WHERE tj1.a + 1 = b.c(+);
|
||||||
|
SELECT * FROM tj1, (SELECT * FROM tj1, tj2 d WHERE tj1.a = d.c(+)) b WHERE tj1.a + 1 = b.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Single table
|
||||||
|
--echo #
|
||||||
|
# --error ER_INVALID_USE_OF_ORA_JOIN
|
||||||
|
# it is legal, Oracle just ignore the operator if it is applied to all tabes
|
||||||
|
|
||||||
|
# The WARN_ORA_JOIN_IGNORED is emitted only on PREPARE:
|
||||||
|
--disable_ps_protocol
|
||||||
|
SELECT * FROM tj1 WHERE tj1.a(+) = 1;
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Self outer join
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1 a, tj1 b WHERE a.a + 1 = b.a(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Self outer join without alias
|
||||||
|
--echo #
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a + 1 = tj1.a(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Outer join condition is independent of other tables
|
||||||
|
--echo # In this case we need to restrict the marked table(s) to appear
|
||||||
|
--echo # after the unmarked table(s) during topological sort. This test
|
||||||
|
--echo # ensures that the topological sort is working correctly.
|
||||||
|
--echo #
|
||||||
|
--echo # correct result in is empty result set (tj2.c = 1 filters all out)
|
||||||
|
|
||||||
|
# The WARN_ORA_JOIN_IGNORED is emitted only on PREPARE:
|
||||||
|
--disable_ps_protocol
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj2.c(+) = 1;
|
||||||
|
--echo # one row (there is tj1.a = 1)
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a(+) = 1;
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Outer join in 'IN' condition
|
||||||
|
--echo # ORA-01719
|
||||||
|
--echo #
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a IN (tj2.c(+), tj2.d(+));
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a NOT IN (tj2.c(+), tj2.d(+));
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Outer join in 'IN' condition with a single expression
|
||||||
|
--echo # This is also allowed in oracle since the expression is
|
||||||
|
--echo # can be simplified to 'equal' or 'not equal' condition
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a IN (tj2.c(+));
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a NOT IN (tj2.c(+));
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Oracle outer join not in WHERE clause
|
||||||
|
--echo #
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c GROUP BY tj2.c(+);
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c GROUP BY tj2.c HAVING tj2.c(+) > 1;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c ORDER BY tj2.c(+);
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
SELECT tj2.c(+) FROM tj2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Mix ANSI and Oracle outer join
|
||||||
|
--echo # ORA-25156
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
SELECT * FROM tj1 LEFT JOIN tj2 ON tj2.c = 1 WHERE tj1.a = tj2.c(+);
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
SELECT * FROM tj1 INNER JOIN tj2 ON tj2.c = 1 WHERE tj1.a = tj2.c(+);
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
SELECT * FROM tj1 NATURAL JOIN tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # View with oracle outer join
|
||||||
|
--echo #
|
||||||
|
CREATE VIEW v1 AS SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
SELECT * FROM v1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Cursor with oracle outer join
|
||||||
|
--echo #
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
CURSOR c1 IS SELECT * FROM tj1, tj2 WHERE tj1.a = tj2.c(+);
|
||||||
|
BEGIN
|
||||||
|
FOR r1 IN c1 LOOP
|
||||||
|
SELECT r1.a || ' ' || r1.c;
|
||||||
|
END LOOP;
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Marking ROW type
|
||||||
|
--echo #
|
||||||
|
DELIMITER $$;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
DECLARE
|
||||||
|
v1 ROW (a INT, b INT);
|
||||||
|
BEGIN
|
||||||
|
SELECT * FROM tj1 WHERE tj1.a = v1.a(+);
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Unspecified table used in WHERE clause that contains (+)
|
||||||
|
--echo #
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = tj3.c(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # '.' prefixed table name
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM tj1, tj2 WHERE tj1.a = .tj2.c(+);
|
||||||
|
|
||||||
|
CREATE DATABASE db1;
|
||||||
|
USE db1;
|
||||||
|
CREATE TABLE tj1(a int, b int);
|
||||||
|
INSERT INTO tj1 VALUES (3, 3);
|
||||||
|
INSERT INTO tj1 VALUES (4, 4);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # DB qualifed ident with oracle outer join (aliased)
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM test.tj2 a, tj1 WHERE a.c(+) = tj1.a - 1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # DB qualifed ident with oracle outer join (non-aliased)
|
||||||
|
--echo #
|
||||||
|
SELECT * FROM test.tj2, tj1 WHERE test.tj2.c(+) = tj1.a - 1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # DB qualifed ident with oracle outer join (aliased but use table name)
|
||||||
|
--echo #
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
SELECT * FROM test.tj2 a, tj1 WHERE test.tj2.c(+) = tj1.a - 1;
|
||||||
|
|
||||||
|
USE test;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # UPDATE with oracle outer join
|
||||||
|
--echo #
|
||||||
|
UPDATE tj1, tj2 SET tj1.a = tj2.c WHERE tj1.a = tj2.c(+);
|
||||||
|
SELECT * FROM tj1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # DELETE with oracle outer join
|
||||||
|
--echo #
|
||||||
|
DELETE tj1 FROM tj1, tj2 WHERE tj1.b(+) = tj2.c;
|
||||||
|
SELECT * FROM tj1;
|
||||||
|
|
||||||
|
DROP DATABASE db1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE tj4;
|
||||||
|
DROP TABLE tj3;
|
||||||
|
DROP TABLE tj2;
|
||||||
|
DROP TABLE tj1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of iqbal-rsec tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test from the MDEV comments
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create table t3 (c int, e int);
|
||||||
|
insert into t3 values (3,2),(10,3),(2,20);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (3),(1),(20);
|
||||||
|
select t1.a, t4.d, t2.b, t3.c from t1, t2, t3, t4 where t1.a = t2.b(+) and t1.a = t3.c(+) and t4.d = t2.b(+) and t4.d = t3.c(+);
|
||||||
|
select t1.a, t4.d, t2.b, t3.c from t1, t2, t3, t4 where t1.a + t3.c = t2.b(+) and t1.a = t3.c(+) and t4.d = t2.b(+) and t4.d = t3.c(+);
|
||||||
|
select t1.a, t4.d, t2.b, t3.c from t1, t2, t3, t4 where (t2.b(+) in (t1.a, t1.a+1)) and t1.a = t3.c(+) and t4.d = t2.b(+) and t4.d = t3.c(+);
|
||||||
|
|
||||||
|
drop tables t1, t2, t3, t4;
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
create table t3 (c int, f int);
|
||||||
|
insert into t3 values (3,2),(10,3),(2,20);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (3),(1),(20);
|
||||||
|
create table t5 (e int);
|
||||||
|
insert into t5 values (3),(2),(20);
|
||||||
|
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, t2, t3, t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and t3.c=t5.e(+);
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, t2, t3, t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and 1=t5.e(+);
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, t2, t3, t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and 3=t5.e(+);
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
select t1.a, t2.b, t3.c, t4.d, t5.e from t1, (t2, t3), t4, t5 where t1.a = t2.b(+) and t2.b = t3.c(+) and t1.a = t4.d(+) and t4.d=t5.e(+) and 3=t5.e(+);
|
||||||
|
|
||||||
|
drop tables t1, t2, t3, t4, t5;
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
|
||||||
|
# The WARN_ORA_JOIN_IGNORED is emitted only on PREPARE:
|
||||||
|
--disable_ps_protocol
|
||||||
|
select t1.a, t2.b from t1, t2 where 1 = t2.b(+);
|
||||||
|
select t1.a, t2.b from t2, t1 where 1 = t2.b(+);
|
||||||
|
select t1.a,t2.b from t2,t1 where t2.b(+) in (1,2);
|
||||||
|
select t2.b from t2 where 1 = t2.b(+);
|
||||||
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
drop tables t1, t2;
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(4),(5),(20),(21),(23);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (1),(4),(6),(7),(8),(23);
|
||||||
|
create table t3 (c int);
|
||||||
|
insert into t3 values (4),(7),(9),(4),(6),(10),(11),(1);
|
||||||
|
create table t4 (d int);
|
||||||
|
insert into t4 values (1),(4),(10),(12),(20),(21),(23);
|
||||||
|
|
||||||
|
SELECT * FROM t1,t2,t3,t4 WHERE t1.a = t2.b(+) AND t1.a = t3.c(+) AND t2.b=t4.d(+) AND t3.c=t4.d(+);
|
||||||
|
select * from t1, t2, t3 where (t1.a + t2.b = t3.c(+));
|
||||||
|
|
||||||
|
--echo # no tables mentioned
|
||||||
|
select * from t2, t3 where b = c(+);
|
||||||
|
--echo # should be the same as above
|
||||||
|
select * from t2, t3 where t2.b = t3.c(+);
|
||||||
|
|
||||||
|
drop tables t1, t2, t3, t4;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # View creation and usage
|
||||||
|
--echo #
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
|
||||||
|
create view v1 as
|
||||||
|
select t1.a, t2.b from t1, t2 where t1.a = t2.b(+);
|
||||||
|
show create view v1;
|
||||||
|
select * from v1;
|
||||||
|
select t1.a, t2.b from t1, t2 where t1.a = t2.b(+);
|
||||||
|
|
||||||
|
--echo usage without oracle sql mode
|
||||||
|
set SQL_MODE= '';
|
||||||
|
select * from v1;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
select t1.a, t2.b from t1, t2 where t1.a = t2.b(+);
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
|
||||||
|
drop view v1;
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-36830: Oracle outer join syntax (+): outer join not converted to inner
|
||||||
|
--echo #
|
||||||
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
|
create table t1 (
|
||||||
|
a int not null,
|
||||||
|
b int not null
|
||||||
|
);
|
||||||
|
insert into t1 select seq,seq from seq_1_to_10;
|
||||||
|
|
||||||
|
create table t2 (
|
||||||
|
a int not null,
|
||||||
|
b int not null
|
||||||
|
);
|
||||||
|
insert into t2 select seq,seq from seq_1_to_3;
|
||||||
|
|
||||||
|
--echo # Must be converted to inner join:
|
||||||
|
explain extended
|
||||||
|
select * from t1, t2
|
||||||
|
where
|
||||||
|
t1.a=1 and
|
||||||
|
t1.b=t2.b(+) and
|
||||||
|
t2.b=1;
|
||||||
|
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-36838: Oracle outer join syntax (+): server crash on derived tables
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
select a.a
|
||||||
|
from (select 1 as a) a,
|
||||||
|
(select 2 as b) b
|
||||||
|
where a.a=b.b(+);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-36866: Oracle outer join syntax (+): query with checking for
|
||||||
|
--echo # null of non-null column uses wrong query plan and returns wrong
|
||||||
|
--echo # result
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int default NULL);
|
||||||
|
create table t2 (a int not null);
|
||||||
|
insert into t1 values (1), (2), (3), (4), (5), (6), (NULL);
|
||||||
|
insert into t2 values (1), (4), (5), (6), (7);
|
||||||
|
|
||||||
|
select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1;
|
||||||
|
explain select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1;
|
||||||
|
|
||||||
|
select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1;
|
||||||
|
explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1;
|
||||||
|
|
||||||
|
select t1.*,t2.* from t1,t2 where t1.a=t2.a(+) and isnull(t2.a)=1;
|
||||||
|
explain extended select t1.*,t2.* from t1,t2 where t1.a=t2.a(+) and isnull(t2.a)=1;
|
||||||
|
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Correct nullability test
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int not null, s varchar(10) not null);
|
||||||
|
create table t2 (a int not null, s varchar(10) not null);
|
||||||
|
insert into t1 values (1, 'one');
|
||||||
|
insert into t1 values (2, 'two');
|
||||||
|
insert into t2 values (2, 'two');
|
||||||
|
insert into t2 values (3, 'three');
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t2.a);
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t1.a+t2.a);
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(coalesce(t2.s, 'null'));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(ifnull(t2.s, 'null'));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(coalesce(t2.s, null));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(ifnull(t2.s, null));
|
||||||
|
|
||||||
|
--echo # Our optimizer does not optimize out never-null-subselects under
|
||||||
|
--echo # isnull() so we do not test it. The following test is to make
|
||||||
|
--echo # sure that nullable one stay in the WHERE.
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t2.a in (select a from t1));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t2.a in (1, 2, 3));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(t1.a in (1, 2, 3));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(isnull(t2.a));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(field(t2.a, 2, 23));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select * from t1,t2 where t1.a = t2.a (+) and
|
||||||
|
isnull(benchmark(10, t2.a));
|
||||||
|
|
||||||
|
|
||||||
|
drop table t1, t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-36895: Oracle outer join syntax (+): some NULLs missing from
|
||||||
|
--echo # result of the query with derived tables and limit
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (3),(7),(1);
|
||||||
|
create table t3 (c int);
|
||||||
|
insert into t3 values (3),(1);
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(7),(1);
|
||||||
|
|
||||||
|
select * from
|
||||||
|
(
|
||||||
|
select * from
|
||||||
|
(select 'Z' as z, t1.a from t1) dt1
|
||||||
|
left join
|
||||||
|
(select 'Y' as y, t2.b from t2) dt2
|
||||||
|
left join
|
||||||
|
(select 'X' as x, t3.c from t3) dt3
|
||||||
|
on dt2.b=dt3.c
|
||||||
|
on dt1.a=dt2.b
|
||||||
|
order by z, a, y, b, x, c
|
||||||
|
limit 9
|
||||||
|
) dt;
|
||||||
|
|
||||||
|
|
||||||
|
select * from
|
||||||
|
(
|
||||||
|
select * from
|
||||||
|
(select 'Z' as z, t1.a from t1) dt1
|
||||||
|
,(select * from
|
||||||
|
(select 'Y' as y, t2.b from t2) dt2
|
||||||
|
,
|
||||||
|
(select 'X' as x, t3.c from t3) dt3
|
||||||
|
where dt2.b=dt3.c(+)
|
||||||
|
) tdt2
|
||||||
|
where dt1.a=tdt2.b(+)
|
||||||
|
order by z, a, y, b, x, c
|
||||||
|
limit 9
|
||||||
|
) dt;
|
||||||
|
|
||||||
|
drop table t1, t2, t3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-37337: Oracle outer join syntax (+): IN equal to = allow (+) on right side
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+);
|
||||||
|
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
explain extended
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+), 29);
|
||||||
|
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
create table t1 (a int);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
create table t2 (b int);
|
||||||
|
insert into t2 values (2),(1),(20);
|
||||||
|
|
||||||
|
set SQL_MODE= oracle;
|
||||||
|
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a = t2.b(+);
|
||||||
|
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
|
||||||
|
explain extended
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+));
|
||||||
|
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
select t1.a, t2.b
|
||||||
|
from t1, t2
|
||||||
|
where
|
||||||
|
t1.a IN (t2.b(+), 29);
|
||||||
|
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
|
--echo # End of 12.1 tests
|
||||||
138
mysql-test/suite/compat/oracle/t/ora_outer_join_err.test
Normal file
138
mysql-test/suite/compat/oracle/t/ora_outer_join_err.test
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
SET sql_mode=ORACLE;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Cycles
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (b int);
|
||||||
|
create table t3 (c int);
|
||||||
|
|
||||||
|
--echo # b - cyrcle
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
select * from t1, t2, t3
|
||||||
|
where t1.a = t2.b(+) AND t2.b = t3.c(+) AND
|
||||||
|
t3.c = t2.b(+);
|
||||||
|
--echo # O - cyrcle
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
select * from t1, t2, t3
|
||||||
|
where t1.a = t2.b(+) AND t2.b = t3.c(+) AND
|
||||||
|
t3.c = t1.a(+);
|
||||||
|
--echo # self-reference cyrcle
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
select * from t1, t2, t3
|
||||||
|
where t1.a = t2.b(+) AND t2.b = t3.c(+) AND
|
||||||
|
t3.c = t3.c(+);
|
||||||
|
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (b int);
|
||||||
|
create table t3 (c int);
|
||||||
|
create table t4 (d int);
|
||||||
|
create table t5 (e int);
|
||||||
|
|
||||||
|
--echo # complex case
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
select * from t1, t2, t3, t4, t5
|
||||||
|
where
|
||||||
|
t3.c = t4.d(+) AND t4.d = t3.c(+) AND
|
||||||
|
t1.a = t5.e(+) AND t2.b = t5.e(+) AND
|
||||||
|
t2.b = t3.c(+)
|
||||||
|
;
|
||||||
|
|
||||||
|
DROP TABLE t1,t2,t3,t4,t5;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # mix with other join operatirs
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
create table t3 (a int);
|
||||||
|
|
||||||
|
--echo # mixing with left join
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
select * from t1, t2 left join t3 on (t2.a = t3.a)
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
|
||||||
|
--echo # mixing with right join
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
select * from t1, t2 right join t3 on (t2.a = t3.a)
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
|
||||||
|
--echo # mixing with natural join
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
select * from t1, t2 natural join t3
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
|
||||||
|
--echo # mixing with nested join
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
select * from t1, t2 join t3
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
|
||||||
|
--echo # mixing with nested join
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
select * from t1, (t2, t3)
|
||||||
|
where t1.a = t2.a(+);
|
||||||
|
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # misplaced usage of (+)
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
select t1.a(+), t2.a from t1,t2;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
select t1.a, t2.a from t1,t2 HAVING t1.a(+) = t2.a;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
select t1.a, t2.a from t1 join t2 on (t1.a(+) = t2.a);
|
||||||
|
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # outer reference
|
||||||
|
--echo #
|
||||||
|
create table t1 (a int);
|
||||||
|
create table t2 (a int);
|
||||||
|
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_OUTER_REF
|
||||||
|
select u2.a, (select t1.a, t2.a from t1,t2 where u1.a(+) = t2.a)
|
||||||
|
from t1 as u1, t2 as u2 where u1.a(+) = u2.a;
|
||||||
|
|
||||||
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-36883: Oracle outer join syntax (+): operator (+) is not
|
||||||
|
--echo # processed in condition like "(t2.b(+) , t1.b) in (select ...)"
|
||||||
|
--echo #
|
||||||
|
create table t1 ( c int, b char(1));
|
||||||
|
insert into t1 values (1,'b');
|
||||||
|
|
||||||
|
create table t2 ( a int , b char(1));
|
||||||
|
insert into t2 values (1,'a');
|
||||||
|
|
||||||
|
create table t3 (c1 char(1), c2 char(2));
|
||||||
|
insert into t3 values ('c','d');
|
||||||
|
insert into t3 values ('c','d');
|
||||||
|
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
SELECT t2.b
|
||||||
|
FROM t1, t2 WHERE t1.c = t2.a(+) AND (t2.b(+), t1.b) IN (SELECT * from t3);
|
||||||
|
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
SELECT t2.b
|
||||||
|
FROM t1, t2 WHERE t1.c = t2.a(+) AND (t2.b(+), t1.b) IN (('a','a'),('b','b'));
|
||||||
|
|
||||||
|
--error ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
SELECT t2.b
|
||||||
|
FROM t1, t2 WHERE t1.c = t2.a(+) AND (t2.b(+), t1.b) = (SELECT * from t3
|
||||||
|
ORDER BY a LIMIT 1);
|
||||||
|
|
||||||
|
drop tables t1,t2,t3;
|
||||||
@@ -132,6 +132,7 @@ SET (SQL_SOURCE
|
|||||||
sql_error.cc sql_handler.cc sql_get_diagnostics.cc
|
sql_error.cc sql_handler.cc sql_get_diagnostics.cc
|
||||||
sql_help.cc sql_insert.cc sql_lex.cc
|
sql_help.cc sql_insert.cc sql_lex.cc
|
||||||
sql_list.cc sql_load.cc sql_manager.cc
|
sql_list.cc sql_load.cc sql_manager.cc
|
||||||
|
sql_oracle_outer_join.cc
|
||||||
sql_parse.cc sql_bootstrap.cc
|
sql_parse.cc sql_bootstrap.cc
|
||||||
sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
|
sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
|
||||||
debug_sync.cc debug.cc
|
debug_sync.cc debug.cc
|
||||||
|
|||||||
159
sql/item.cc
159
sql/item.cc
@@ -3512,6 +3512,11 @@ void Item_ident::print(String *str, enum_query_type query_type)
|
|||||||
str->append('.');
|
str->append('.');
|
||||||
}
|
}
|
||||||
append_identifier(thd, str, &field_name);
|
append_identifier(thd, str, &field_name);
|
||||||
|
|
||||||
|
if (with_ora_join())
|
||||||
|
{
|
||||||
|
str->append(STRING_WITH_LEN(" (+)"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
@@ -6332,6 +6337,22 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Item_field::check_ora_join(Item **reference, bool outer_ref_fixed)
|
||||||
|
{
|
||||||
|
if(with_ora_join())
|
||||||
|
{
|
||||||
|
if (outer_ref_fixed) // Oracle join operator is local
|
||||||
|
{
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_OUTER_REF, MYF(0), name.str);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
// Keep flag about oracle join if view fied was resolved
|
||||||
|
if (reference[0] != this) // resolved to a new field
|
||||||
|
reference[0]->copy_flags(this, item_with_t::ORA_JOIN);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Resolve the name of a column reference.
|
Resolve the name of a column reference.
|
||||||
@@ -6466,7 +6487,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
set_max_sum_func_level(thd, select);
|
set_max_sum_func_level(thd, select);
|
||||||
set_field(new_field);
|
set_field(new_field);
|
||||||
depended_from= (*((Item_field**)res))->depended_from;
|
depended_from= (*((Item_field**)res))->depended_from;
|
||||||
return 0;
|
return check_ora_join(reference, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -6493,7 +6514,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
its arguments are not defined.
|
its arguments are not defined.
|
||||||
*/
|
*/
|
||||||
set_max_sum_func_level(thd, select);
|
set_max_sum_func_level(thd, select);
|
||||||
return FALSE;
|
return check_ora_join(reference, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6548,7 +6569,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
Also we suppose that view can't be changed during PS/SP life.
|
Also we suppose that view can't be changed during PS/SP life.
|
||||||
*/
|
*/
|
||||||
if (from_field == view_ref_found)
|
if (from_field == view_ref_found)
|
||||||
return FALSE;
|
return check_ora_join(reference, outer_fixed);
|
||||||
|
|
||||||
set_field(from_field);
|
set_field(from_field);
|
||||||
}
|
}
|
||||||
@@ -6596,6 +6617,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
base_flags|= item_base_t::FIXED;
|
base_flags|= item_base_t::FIXED;
|
||||||
|
if (check_ora_join(reference, outer_fixed))
|
||||||
|
goto error;
|
||||||
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
||||||
!outer_fixed && !thd->lex->in_sum_func &&
|
!outer_fixed && !thd->lex->in_sum_func &&
|
||||||
select &&
|
select &&
|
||||||
@@ -6644,7 +6667,7 @@ mark_non_agg_field:
|
|||||||
select_lex->set_non_agg_field_used(true);
|
select_lex->set_non_agg_field_used(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FALSE;
|
return check_ora_join(reference, outer_fixed);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
context->process_error(thd);
|
context->process_error(thd);
|
||||||
@@ -7806,6 +7829,17 @@ bool Item_null::send(Protocol *protocol, st_value *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a List<Item> consisting of one element -
|
||||||
|
a single Item_join_operator_plus instance.
|
||||||
|
*/
|
||||||
|
List<Item> *Item_join_operator_plus::make_as_item_list(THD *thd)
|
||||||
|
{
|
||||||
|
Item *item= new (thd->mem_root) Item_join_operator_plus(thd);
|
||||||
|
return item ? List<Item>::make(thd->mem_root, item) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check if an item is a constant one and can be cached.
|
Check if an item is a constant one and can be cached.
|
||||||
|
|
||||||
@@ -9666,6 +9700,14 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_direct_view_ref::add_maybe_null_after_ora_join_processor(void *arg)
|
||||||
|
{
|
||||||
|
if (!maybe_null() && view->table && view->table->maybe_null)
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Prepare referenced outer field then call usual Item_direct_ref::fix_fields
|
Prepare referenced outer field then call usual Item_direct_ref::fix_fields
|
||||||
|
|
||||||
@@ -10175,6 +10217,115 @@ bool Item_default_value::val_native_result(THD *thd, Native *to)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
We're processing an expression with a (+) operator somewhere.
|
||||||
|
We encounter reference to 'table.column' (with the(+) or not).
|
||||||
|
Add table to the oracle outer join structure we're building
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool Item_ident::ora_join_add_table_ref(ora_join_processor_param *arg,
|
||||||
|
TABLE_LIST *table)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed());
|
||||||
|
TABLE_LIST *err_table= NULL;
|
||||||
|
|
||||||
|
if (with_ora_join())
|
||||||
|
{
|
||||||
|
// This an item with (+) operator, the referred table is INNER.
|
||||||
|
if (arg->inner == NULL)
|
||||||
|
{
|
||||||
|
arg->inner= table;
|
||||||
|
// Make sure this table is not also in the list of OUTER tables.
|
||||||
|
List_iterator_fast<TABLE_LIST> it(arg->outer);
|
||||||
|
TABLE_LIST *t;
|
||||||
|
while ((t= it++))
|
||||||
|
{
|
||||||
|
if (t == table)
|
||||||
|
{
|
||||||
|
err_table= t;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cannot have two INNER tables, like t1.col=t2.col(+) + t3.col(+)
|
||||||
|
if (arg->inner != table)
|
||||||
|
{
|
||||||
|
err_table= arg->inner;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No (+) operator, this is an outer table.
|
||||||
|
List_iterator_fast<TABLE_LIST> it(arg->outer);
|
||||||
|
TABLE_LIST *t;
|
||||||
|
|
||||||
|
// Check if this table is already in the list of outer tables
|
||||||
|
while ((t= it++))
|
||||||
|
{
|
||||||
|
if (t == table)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (t == NULL)
|
||||||
|
{
|
||||||
|
// Check that this table is also used as INNER by this condition
|
||||||
|
if (table == arg->inner)
|
||||||
|
{
|
||||||
|
err_table= arg->inner;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
arg->outer.push_back(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
err:
|
||||||
|
// it is not marked all tables as outer or several inner or outer tables
|
||||||
|
if (table == err_table)
|
||||||
|
{
|
||||||
|
// self reference (simple case of cyclic reference)
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_CYCLE, MYF(0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_ONE_TABLE, MYF(0),
|
||||||
|
err_table->alias.str,
|
||||||
|
table->alias.str,
|
||||||
|
(with_ora_join()?"INNER":"OUTER"));
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_field::ora_join_processor(void *arg)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(field->table->pos_in_table_list);
|
||||||
|
return Item_ident::ora_join_add_table_ref((ora_join_processor_param *)arg,
|
||||||
|
field->table->pos_in_table_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_direct_view_ref::ora_join_processor(void *arg)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(view);
|
||||||
|
return Item_ident::ora_join_add_table_ref((ora_join_processor_param *)arg,
|
||||||
|
view);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_ref::ora_join_processor(void *arg)
|
||||||
|
{
|
||||||
|
if (with_ora_join())
|
||||||
|
{
|
||||||
|
// It should not happened
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN, MYF(0));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
table_map Item_default_value::used_tables() const
|
table_map Item_default_value::used_tables() const
|
||||||
{
|
{
|
||||||
if (!field || !field->default_value)
|
if (!field || !field->default_value)
|
||||||
|
|||||||
115
sql/item.h
115
sql/item.h
@@ -97,6 +97,15 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ora_join_processor_param
|
||||||
|
{
|
||||||
|
TABLE_LIST *inner;
|
||||||
|
List<TABLE_LIST> outer;
|
||||||
|
/* TRUE means Oracle join operator was used inside some OR clause */
|
||||||
|
bool or_present;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef DBUG_OFF
|
#ifdef DBUG_OFF
|
||||||
static inline const char *dbug_print_item(Item *item) { return NULL; }
|
static inline const char *dbug_print_item(Item *item) { return NULL; }
|
||||||
#else
|
#else
|
||||||
@@ -709,7 +718,7 @@ struct subselect_table_finder_param
|
|||||||
|
|
||||||
/* Base flags (including IN) for an item */
|
/* Base flags (including IN) for an item */
|
||||||
|
|
||||||
typedef uint8 item_flags_t;
|
typedef uint16 item_flags_t;
|
||||||
|
|
||||||
enum class item_base_t : item_flags_t
|
enum class item_base_t : item_flags_t
|
||||||
{
|
{
|
||||||
@@ -742,8 +751,9 @@ enum class item_with_t : item_flags_t
|
|||||||
SUBQUERY= (1<<4), // If item contains a subquery
|
SUBQUERY= (1<<4), // If item contains a subquery
|
||||||
ROWNUM_FUNC= (1<<5), // If ROWNUM function was used
|
ROWNUM_FUNC= (1<<5), // If ROWNUM function was used
|
||||||
PARAM= (1<<6), // If user parameter was used
|
PARAM= (1<<6), // If user parameter was used
|
||||||
COMPLEX_DATA_TYPE= (1<<7) // If the expression is of a complex data type which
|
COMPLEX_DATA_TYPE= (1<<7),// If the expression is of a complex data type which
|
||||||
// requires special handling on destruction
|
// requires special handling on destruction
|
||||||
|
ORA_JOIN= (1<<8), // If Oracle join syntax was used
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -809,6 +819,7 @@ static inline item_with_t operator~(const item_with_t a)
|
|||||||
typedef uint8 item_walk_flags;
|
typedef uint8 item_walk_flags;
|
||||||
const item_walk_flags WALK_SUBQUERY= 1;
|
const item_walk_flags WALK_SUBQUERY= 1;
|
||||||
const item_walk_flags WALK_NO_CACHE_PROCESS= (1<<1);
|
const item_walk_flags WALK_NO_CACHE_PROCESS= (1<<1);
|
||||||
|
const item_walk_flags WALK_NO_REF= (1<<2);
|
||||||
|
|
||||||
|
|
||||||
class Item :public Value_source,
|
class Item :public Value_source,
|
||||||
@@ -1070,6 +1081,8 @@ public:
|
|||||||
{ return (bool) (with_flags & item_with_t::PARAM); }
|
{ return (bool) (with_flags & item_with_t::PARAM); }
|
||||||
inline bool with_complex_data_types() const
|
inline bool with_complex_data_types() const
|
||||||
{ return (bool) (with_flags & item_with_t::COMPLEX_DATA_TYPE); }
|
{ return (bool) (with_flags & item_with_t::COMPLEX_DATA_TYPE); }
|
||||||
|
inline bool with_ora_join() const
|
||||||
|
{ return (bool) (with_flags & item_with_t::ORA_JOIN); }
|
||||||
inline void copy_flags(const Item *org, item_base_t mask)
|
inline void copy_flags(const Item *org, item_base_t mask)
|
||||||
{
|
{
|
||||||
base_flags= (item_base_t) (((item_flags_t) base_flags &
|
base_flags= (item_base_t) (((item_flags_t) base_flags &
|
||||||
@@ -2283,6 +2296,19 @@ public:
|
|||||||
is_expensive_cache= (int8)(-1);
|
is_expensive_cache= (int8)(-1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
virtual bool ora_join_processor(void *arg) { return 0; }
|
||||||
|
/*
|
||||||
|
This marks the item as nullable. Note that if we'd want a method that
|
||||||
|
marks the item as not nullable (maybe_null=false) we'd need to process
|
||||||
|
carefully functions (e.g. json*) that can always return null even with
|
||||||
|
non-null arguments
|
||||||
|
*/
|
||||||
|
virtual bool add_maybe_null_after_ora_join_processor(void *arg) { return 0; }
|
||||||
|
virtual bool remove_ora_join_processor(void *arg)
|
||||||
|
{
|
||||||
|
with_flags&= ~item_with_t::ORA_JOIN;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool set_extraction_flag_processor(void *arg)
|
virtual bool set_extraction_flag_processor(void *arg)
|
||||||
{
|
{
|
||||||
@@ -2892,6 +2918,24 @@ protected:
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool is_any_arg_maybe_null()
|
||||||
|
{
|
||||||
|
for (uint i= 0; i < arg_count; i++)
|
||||||
|
{
|
||||||
|
if (args[i]->maybe_null())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool is_all_arg_maybe_null()
|
||||||
|
{
|
||||||
|
for (uint i= 0; i < arg_count; i++)
|
||||||
|
{
|
||||||
|
if (!args[i]->maybe_null())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool transform_args(THD *thd, Item_transformer transformer, uchar *arg);
|
bool transform_args(THD *thd, Item_transformer transformer, uchar *arg);
|
||||||
void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *);
|
void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *);
|
||||||
bool excl_dep_on_table(table_map tab_map)
|
bool excl_dep_on_table(table_map tab_map)
|
||||||
@@ -3701,6 +3745,10 @@ public:
|
|||||||
Collect outer references
|
Collect outer references
|
||||||
*/
|
*/
|
||||||
bool collect_outer_ref_processor(void *arg) override;
|
bool collect_outer_ref_processor(void *arg) override;
|
||||||
|
|
||||||
|
bool ora_join_add_table_ref(ora_join_processor_param *arg,
|
||||||
|
TABLE_LIST *table);
|
||||||
|
|
||||||
friend bool insert_fields(THD *thd, Name_resolution_context *context,
|
friend bool insert_fields(THD *thd, Name_resolution_context *context,
|
||||||
const LEX_CSTRING &db_name,
|
const LEX_CSTRING &db_name,
|
||||||
const LEX_CSTRING &table_name,
|
const LEX_CSTRING &table_name,
|
||||||
@@ -3933,6 +3981,20 @@ public:
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
bool ora_join_processor(void *arg) override;
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Before this operation field nullability can not be removed
|
||||||
|
(only can be set).
|
||||||
|
maybe_null() store the old nullability state, and
|
||||||
|
field->maybe_null() is the current state.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(!maybe_null() || field->maybe_null());
|
||||||
|
set_maybe_null(field->maybe_null());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool check_ora_join(Item **reference, bool outer_ref_fixed);
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
Item_equal *get_item_equal() override { return item_equal; }
|
Item_equal *get_item_equal() override { return item_equal; }
|
||||||
void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; }
|
void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; }
|
||||||
@@ -4064,6 +4126,27 @@ public:
|
|||||||
Item *do_build_clone(THD *thd) const override { return get_copy(thd); }
|
Item *do_build_clone(THD *thd) const override { return get_copy(thd); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
A pseudo-Item to parse Oracle style outer join operator:
|
||||||
|
WHERE t1.a = t2.b (+);
|
||||||
|
*/
|
||||||
|
class Item_join_operator_plus: public Item_null
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Item_null::Item_null;
|
||||||
|
/*
|
||||||
|
Need to override as least one method to have an unique vtable,
|
||||||
|
to make dynamic_cast work.
|
||||||
|
*/
|
||||||
|
void print(String *str, enum_query_type) override
|
||||||
|
{
|
||||||
|
str->append("(+)"_LEX_CSTRING);
|
||||||
|
}
|
||||||
|
static List<Item> *make_as_item_list(THD *thd);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Item_null_result :public Item_null
|
class Item_null_result :public Item_null
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -5853,6 +5936,13 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
return (this->*processor)(arg);
|
return (this->*processor)(arg);
|
||||||
}
|
}
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
// see Item::add_maybe_null_after_ora_join_processor
|
||||||
|
if (!maybe_null() && is_any_arg_maybe_null())
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Built-in schema, e.g. mariadb_schema, oracle_schema, maxdb_schema
|
Built-in schema, e.g. mariadb_schema, oracle_schema, maxdb_schema
|
||||||
*/
|
*/
|
||||||
@@ -6074,6 +6164,8 @@ public:
|
|||||||
bool walk(Item_processor processor, void *arg,
|
bool walk(Item_processor processor, void *arg,
|
||||||
item_walk_flags flags) override
|
item_walk_flags flags) override
|
||||||
{
|
{
|
||||||
|
if (flags & WALK_NO_REF)
|
||||||
|
return (this->*processor)(arg);
|
||||||
if (ref && *ref)
|
if (ref && *ref)
|
||||||
return (*ref)->walk(processor, arg, flags) ||
|
return (*ref)->walk(processor, arg, flags) ||
|
||||||
(this->*processor)(arg);
|
(this->*processor)(arg);
|
||||||
@@ -6179,6 +6271,13 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
return cleanup_processor(arg);
|
return cleanup_processor(arg);
|
||||||
}
|
}
|
||||||
|
bool ora_join_processor(void *arg) override;
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if ((*ref)->maybe_null())
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) override
|
Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) override
|
||||||
{ return (*ref)->field_transformer_for_having_pushdown(thd, arg); }
|
{ return (*ref)->field_transformer_for_having_pushdown(thd, arg); }
|
||||||
};
|
};
|
||||||
@@ -6397,6 +6496,12 @@ public:
|
|||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_cache_wrapper>(thd, this); }
|
{ return get_item_copy<Item_cache_wrapper>(thd, this); }
|
||||||
Item *do_build_clone(THD *) const override { return nullptr; }
|
Item *do_build_clone(THD *) const override { return nullptr; }
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (orig_item->maybe_null())
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -6473,6 +6578,8 @@ public:
|
|||||||
bool walk(Item_processor processor, void *arg,
|
bool walk(Item_processor processor, void *arg,
|
||||||
item_walk_flags flags) override
|
item_walk_flags flags) override
|
||||||
{
|
{
|
||||||
|
if (flags & WALK_NO_REF)
|
||||||
|
return (this->*processor)(arg);
|
||||||
return (*ref)->walk(processor, arg, flags) ||
|
return (*ref)->walk(processor, arg, flags) ||
|
||||||
(this->*processor)(arg);
|
(this->*processor)(arg);
|
||||||
}
|
}
|
||||||
@@ -6483,6 +6590,7 @@ public:
|
|||||||
view_arg->view_used_tables|= (*ref)->used_tables();
|
view_arg->view_used_tables|= (*ref)->used_tables();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
bool ora_join_processor(void *arg) override;
|
||||||
bool excl_dep_on_table(table_map tab_map) override;
|
bool excl_dep_on_table(table_map tab_map) override;
|
||||||
bool excl_dep_on_grouping_fields(st_select_lex *sel) override;
|
bool excl_dep_on_grouping_fields(st_select_lex *sel) override;
|
||||||
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override;
|
bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override;
|
||||||
@@ -6627,6 +6735,7 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
void print(String *str, enum_query_type query_type) override;
|
void print(String *str, enum_query_type query_type) override;
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -8417,6 +8526,8 @@ public:
|
|||||||
bool walk(Item_processor processor, void *arg,
|
bool walk(Item_processor processor, void *arg,
|
||||||
item_walk_flags flags) override
|
item_walk_flags flags) override
|
||||||
{
|
{
|
||||||
|
if (flags & WALK_NO_REF)
|
||||||
|
return (this->*processor)(arg);
|
||||||
return m_item->walk(processor, arg, flags) ||
|
return m_item->walk(processor, arg, flags) ||
|
||||||
(this->*processor)(arg);
|
(this->*processor)(arg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5034,6 +5034,33 @@ void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_func_in::ora_join_processor(void *arg)
|
||||||
|
{
|
||||||
|
if (with_ora_join())
|
||||||
|
{
|
||||||
|
if (args[0]->cols() > 1 && args[0]->with_ora_join())
|
||||||
|
{
|
||||||
|
// used in ROW operaton
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC, MYF(0));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
uint n= argument_count();
|
||||||
|
DBUG_ASSERT(n >= 2);
|
||||||
|
// first argument (0) is right part of IN where oracle joins are allowed
|
||||||
|
for (uint i= 1; i < n; i++)
|
||||||
|
{
|
||||||
|
if (args[i]->with_ora_join())
|
||||||
|
{
|
||||||
|
// used in right part of IN
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC, MYF(0));
|
||||||
|
return TRUE ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Func_handler_bit_or_int_to_ulonglong:
|
class Func_handler_bit_or_int_to_ulonglong:
|
||||||
public Item_handled_func::Handler_ulonglong
|
public Item_handled_func::Handler_ulonglong
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -279,6 +279,9 @@ public:
|
|||||||
{
|
{
|
||||||
return negated_item(thd);
|
return negated_item(thd);
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Item_func_truth(THD *thd, Item *a, bool a_value, bool a_affirmative):
|
Item_func_truth(THD *thd, Item *a, bool a_value, bool a_affirmative):
|
||||||
@@ -887,6 +890,9 @@ public:
|
|||||||
}
|
}
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_func_equal>(thd, this); }
|
{ return get_item_copy<Item_func_equal>(thd, this); }
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1191,6 +1197,9 @@ public:
|
|||||||
}
|
}
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_func_interval>(thd, this); }
|
{ return get_item_copy<Item_func_interval>(thd, this); }
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1217,6 +1226,12 @@ public:
|
|||||||
fix_attributes(args, arg_count);
|
fix_attributes(args, arg_count);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (!maybe_null() && is_all_arg_maybe_null())
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
LEX_CSTRING func_name_cstring() const override
|
LEX_CSTRING func_name_cstring() const override
|
||||||
{
|
{
|
||||||
static LEX_CSTRING name= {STRING_WITH_LEN("coalesce") };
|
static LEX_CSTRING name= {STRING_WITH_LEN("coalesce") };
|
||||||
@@ -1309,6 +1324,12 @@ public:
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (!maybe_null() && is_all_arg_maybe_null())
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
LEX_CSTRING func_name_cstring() const override
|
LEX_CSTRING func_name_cstring() const override
|
||||||
{
|
{
|
||||||
static LEX_CSTRING name= {STRING_WITH_LEN("ifnull") };
|
static LEX_CSTRING name= {STRING_WITH_LEN("ifnull") };
|
||||||
@@ -2745,6 +2766,7 @@ public:
|
|||||||
Item* varchar_upper_cmp_transformer(THD *thd, uchar *arg) override;
|
Item* varchar_upper_cmp_transformer(THD *thd, uchar *arg) override;
|
||||||
|
|
||||||
Item* vcol_subst_transformer(THD *thd, uchar *arg) override;
|
Item* vcol_subst_transformer(THD *thd, uchar *arg) override;
|
||||||
|
bool ora_join_processor(void *arg) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class cmp_item_row :public cmp_item
|
class cmp_item_row :public cmp_item
|
||||||
@@ -2827,6 +2849,9 @@ public:
|
|||||||
base_flags&= ~item_base_t::MAYBE_NULL;
|
base_flags&= ~item_base_t::MAYBE_NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
bool count_sargable_conds(void *arg) override;
|
bool count_sargable_conds(void *arg) override;
|
||||||
|
|
||||||
Item* vcol_subst_transformer(THD *thd, uchar *arg) override;
|
Item* vcol_subst_transformer(THD *thd, uchar *arg) override;
|
||||||
@@ -3321,7 +3346,7 @@ public:
|
|||||||
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
|
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
|
||||||
List<Item> &fields, uint flags) override;
|
List<Item> &fields, uint flags) override;
|
||||||
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
||||||
COND **conds);
|
COND **conds, List<Item> *all_fields);
|
||||||
void copy_andor_arguments(THD *thd, Item_cond *item);
|
void copy_andor_arguments(THD *thd, Item_cond *item);
|
||||||
bool walk(Item_processor processor, void *arg,
|
bool walk(Item_processor processor, void *arg,
|
||||||
item_walk_flags flags) override;
|
item_walk_flags flags) override;
|
||||||
@@ -3742,6 +3767,15 @@ public:
|
|||||||
table_map not_null_tables() const override { return and_tables_cache; }
|
table_map not_null_tables() const override { return and_tables_cache; }
|
||||||
Item *copy_andor_structure(THD *thd) override;
|
Item *copy_andor_structure(THD *thd) override;
|
||||||
Item *neg_transformer(THD *thd) override;
|
Item *neg_transformer(THD *thd) override;
|
||||||
|
bool ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (with_ora_join())
|
||||||
|
{
|
||||||
|
// Oracle join operator is used in this OR clause.
|
||||||
|
((ora_join_processor_param *) arg)->or_present= true;
|
||||||
|
}
|
||||||
|
return (FALSE);
|
||||||
|
}
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_cond_or>(thd, this); }
|
{ return get_item_copy<Item_cond_or>(thd, this); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2624,6 +2624,9 @@ public:
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
bool fix_length_and_dec(THD *thd) override;
|
bool fix_length_and_dec(THD *thd) override;
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
bool eval_not_null_tables(void *) override
|
bool eval_not_null_tables(void *) override
|
||||||
{
|
{
|
||||||
not_null_tables_cache= 0;
|
not_null_tables_cache= 0;
|
||||||
@@ -2696,6 +2699,9 @@ public:
|
|||||||
bool fix_length_and_dec(THD *thd) override;
|
bool fix_length_and_dec(THD *thd) override;
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_func_field>(thd, this); }
|
{ return get_item_copy<Item_func_field>(thd, this); }
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2941,6 +2947,9 @@ public:
|
|||||||
base_flags&= ~item_base_t::MAYBE_NULL;
|
base_flags&= ~item_base_t::MAYBE_NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
void print(String *str, enum_query_type query_type) override;
|
void print(String *str, enum_query_type query_type) override;
|
||||||
bool check_vcol_func_processor(void *arg) override
|
bool check_vcol_func_processor(void *arg) override
|
||||||
{
|
{
|
||||||
@@ -3980,6 +3989,9 @@ public:
|
|||||||
base_flags&= ~item_base_t::MAYBE_NULL;
|
base_flags&= ~item_base_t::MAYBE_NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
bool check_vcol_func_processor(void *arg) override
|
bool check_vcol_func_processor(void *arg) override
|
||||||
{
|
{
|
||||||
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
|
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
|
||||||
@@ -4288,6 +4300,9 @@ public:
|
|||||||
base_flags&= ~item_base_t::MAYBE_NULL;
|
base_flags&= ~item_base_t::MAYBE_NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
bool check_vcol_func_processor(void *arg) override
|
bool check_vcol_func_processor(void *arg) override
|
||||||
{
|
{
|
||||||
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
|
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
|
||||||
@@ -4345,6 +4360,9 @@ public:
|
|||||||
max_length= 11;
|
max_length= 11;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_func_sqlcode>(thd, this); }
|
{ return get_item_copy<Item_func_sqlcode>(thd, this); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -122,6 +122,17 @@ public:
|
|||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_row>(thd, this); }
|
{ return get_item_copy<Item_row>(thd, this); }
|
||||||
Item *do_build_clone(THD *thd) const override;
|
Item *do_build_clone(THD *thd) const override;
|
||||||
|
|
||||||
|
bool ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (with_ora_join())
|
||||||
|
{
|
||||||
|
// Oracle join operator is used inside rows.
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC, MYF(0));
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
return (FALSE);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ITEM_ROW_INCLUDED */
|
#endif /* ITEM_ROW_INCLUDED */
|
||||||
|
|||||||
@@ -1223,6 +1223,9 @@ public:
|
|||||||
base_flags&= ~item_base_t::MAYBE_NULL;
|
base_flags&= ~item_base_t::MAYBE_NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_func_sqlerrm>(thd, this); }
|
{ return get_item_copy<Item_func_sqlerrm>(thd, this); }
|
||||||
};
|
};
|
||||||
@@ -1344,6 +1347,9 @@ public:
|
|||||||
}
|
}
|
||||||
Item *do_get_copy(THD *thd) const override
|
Item *do_get_copy(THD *thd) const override
|
||||||
{ return get_item_copy<Item_func_current_role>(thd, this); }
|
{ return get_item_copy<Item_func_current_role>(thd, this); }
|
||||||
|
// null do not depend on nullability of the argument
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2058,6 +2064,9 @@ public:
|
|||||||
base_flags&= ~item_base_t::MAYBE_NULL;
|
base_flags&= ~item_base_t::MAYBE_NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
};
|
};
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
table_map not_null_tables() const override { return 0; }
|
table_map not_null_tables() const override { return 0; }
|
||||||
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
|
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
|
||||||
override
|
override
|
||||||
|
|||||||
@@ -3614,11 +3614,13 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left_expr && left_expr->fix_fields_if_needed(thd_arg, &left_expr))
|
if (!left_expr || left_expr->fix_fields_if_needed(thd_arg, &left_expr))
|
||||||
goto err;
|
goto err;
|
||||||
else
|
else
|
||||||
if (Item_subselect::fix_fields(thd_arg, ref))
|
if (Item_subselect::fix_fields(thd_arg, ref))
|
||||||
goto err;
|
goto err;
|
||||||
|
if (left_expr->with_ora_join())
|
||||||
|
copy_flags(left_expr, item_with_t::ORA_JOIN);
|
||||||
base_flags|= item_base_t::FIXED;
|
base_flags|= item_base_t::FIXED;
|
||||||
thd->where= save_where;
|
thd->where= save_where;
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
|
|||||||
@@ -791,6 +791,22 @@ public:
|
|||||||
Subq_materialization_tracker *get_materialization_tracker() const
|
Subq_materialization_tracker *get_materialization_tracker() const
|
||||||
{ return materialization_tracker; }
|
{ return materialization_tracker; }
|
||||||
|
|
||||||
|
bool ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (left_expr->with_ora_join() && left_expr->cols() > 1)
|
||||||
|
{
|
||||||
|
// used in ROW operaton
|
||||||
|
my_error(ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC, MYF(0));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{
|
||||||
|
if (!maybe_null() && left_expr->maybe_null())
|
||||||
|
set_maybe_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
friend class Item_ref_null_helper;
|
friend class Item_ref_null_helper;
|
||||||
friend class Item_is_not_null_test;
|
friend class Item_is_not_null_test;
|
||||||
friend class Item_in_optimizer;
|
friend class Item_in_optimizer;
|
||||||
|
|||||||
@@ -807,6 +807,9 @@ public:
|
|||||||
null_value=0;
|
null_value=0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1271,6 +1274,9 @@ public:
|
|||||||
null_value= 0;
|
null_value= 0;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
// block standard processor for never null
|
||||||
|
bool add_maybe_null_after_ora_join_processor(void *arg) override
|
||||||
|
{ return 0; }
|
||||||
void cleanup() override
|
void cleanup() override
|
||||||
{
|
{
|
||||||
bits= reset_bits;
|
bits= reset_bits;
|
||||||
|
|||||||
@@ -12338,3 +12338,17 @@ ER_NULL_FOR_ASSOC_ARRAY_INDEX
|
|||||||
eng "NULL key used for associative array '%s'"
|
eng "NULL key used for associative array '%s'"
|
||||||
ER_NEED_NAMED_ASSOCIATION
|
ER_NEED_NAMED_ASSOCIATION
|
||||||
eng "Initializing %s requires named association"
|
eng "Initializing %s requires named association"
|
||||||
|
ER_INVALID_USE_OF_ORA_JOIN
|
||||||
|
eng "Invalid usage of (+) operator"
|
||||||
|
ER_INVALID_USE_OF_ORA_JOIN_CYCLE
|
||||||
|
eng "Invalid usage of (+) operator: cycle dependencies"
|
||||||
|
ER_INVALID_USE_OF_ORA_JOIN_OUTER_REF
|
||||||
|
eng "Invalid usage of (+) operator with outer reference %s"
|
||||||
|
ER_INVALID_USE_OF_ORA_JOIN_ONE_TABLE
|
||||||
|
eng "Invalid usage of (+) operator: both tables %s and %s are of %s type in the relation"
|
||||||
|
ER_INVALID_USE_OF_ORA_JOIN_WRONG_FUNC
|
||||||
|
eng "Invalid usage of (+) operator: used in OR, IN or ROW operation"
|
||||||
|
ER_INVALID_USE_OF_ORA_JOIN_MIX
|
||||||
|
eng "Invalid usage of (+) operator: mixed with other type of join"
|
||||||
|
WARN_ORA_JOIN_IGNORED
|
||||||
|
eng "Oracle outer join operator (+) ignored in '%-.100s'"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
/* Basic functions needed by many modules */
|
/* Basic functions needed by many modules */
|
||||||
|
|
||||||
|
#include "lex_ident_sys.h"
|
||||||
#include "mariadb.h"
|
#include "mariadb.h"
|
||||||
#include "sql_base.h" // setup_table_map
|
#include "sql_base.h" // setup_table_map
|
||||||
#include "sql_list.h"
|
#include "sql_list.h"
|
||||||
@@ -8903,15 +8904,17 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fix all conditions and outer join expressions.
|
Fix all conditions and outer join expressions.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
setup_conds()
|
setup_conds()
|
||||||
thd thread handler
|
thd thread handler
|
||||||
tables list of tables for name resolving (select_lex->table_list)
|
tables list of tables for name resolving (select_lex->table_list)
|
||||||
leaves list of leaves of join table tree (select_lex->leaf_tables)
|
leaves list of leaves of join table tree (select_lex->leaf_tables)
|
||||||
conds WHERE clause
|
conds WHERE clause
|
||||||
|
all_fields SELECT list + hidden fields
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
TODO
|
TODO
|
||||||
@@ -8922,7 +8925,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
|
int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
|
||||||
COND **conds)
|
COND **conds, List<Item> *all_fields)
|
||||||
{
|
{
|
||||||
SELECT_LEX *select_lex= thd->lex->current_select;
|
SELECT_LEX *select_lex= thd->lex->current_select;
|
||||||
TABLE_LIST *table= NULL; // For HP compilers
|
TABLE_LIST *table= NULL; // For HP compilers
|
||||||
@@ -8975,6 +8978,10 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
|
|||||||
(*conds)->mark_as_condition_AND_part(NO_JOIN_NEST);
|
(*conds)->mark_as_condition_AND_part(NO_JOIN_NEST);
|
||||||
if ((*conds)->fix_fields_if_needed_for_bool(thd, conds))
|
if ((*conds)->fix_fields_if_needed_for_bool(thd, conds))
|
||||||
goto err_no_arena;
|
goto err_no_arena;
|
||||||
|
|
||||||
|
if (setup_oracle_join(thd, conds, tables, select_lex->table_list,
|
||||||
|
&select_lex->top_join_list, all_fields))
|
||||||
|
goto err_no_arena;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ void update_non_unique_table_error(TABLE_LIST *update,
|
|||||||
const char *operation,
|
const char *operation,
|
||||||
TABLE_LIST *duplicate);
|
TABLE_LIST *duplicate);
|
||||||
int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
|
int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
|
||||||
COND **conds);
|
COND **conds, List<Item> *all_fields);
|
||||||
void wrap_ident(THD *thd, Item **conds);
|
void wrap_ident(THD *thd, Item **conds);
|
||||||
int setup_ftfuncs(SELECT_LEX* select);
|
int setup_ftfuncs(SELECT_LEX* select);
|
||||||
void cleanup_ftfuncs(SELECT_LEX *select_lex);
|
void cleanup_ftfuncs(SELECT_LEX *select_lex);
|
||||||
@@ -694,4 +694,11 @@ private:
|
|||||||
int m_unhandled_errors;
|
int m_unhandled_errors;
|
||||||
uint first_error;
|
uint first_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool setup_oracle_join(THD *thd, Item **conds,
|
||||||
|
TABLE_LIST *tables,
|
||||||
|
SQL_I_List<TABLE_LIST> &select_table_list,
|
||||||
|
List<TABLE_LIST> *select_join_list,
|
||||||
|
List<Item> *all_fields);
|
||||||
|
|
||||||
#endif /* SQL_BASE_INCLUDED */
|
#endif /* SQL_BASE_INCLUDED */
|
||||||
|
|||||||
@@ -9092,6 +9092,34 @@ Item *LEX::create_item_ident_trigger_specific(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
@detail
|
||||||
|
This is called when we've parsed Oracle's outer join syntax, that is
|
||||||
|
|
||||||
|
[[db_name.]table_name.]column_name(+)
|
||||||
|
|
||||||
|
Check if the parse context allows it, if yes, mark the Item_field with
|
||||||
|
ORA_JOIN flag and return it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool LEX::mark_item_ident_for_ora_join(THD *thd, Item *item)
|
||||||
|
{
|
||||||
|
Item_field *item_field;
|
||||||
|
DBUG_ASSERT(item);
|
||||||
|
|
||||||
|
if ((thd->variables.sql_mode & MODE_ORACLE) &&
|
||||||
|
current_select && current_select->parsing_place == IN_WHERE &&
|
||||||
|
(item_field= dynamic_cast<Item_field*>(item)))
|
||||||
|
{
|
||||||
|
item_field->with_flags|= item_with_t::ORA_JOIN;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
thd->parse_error(ER_SYNTAX_ERROR);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Item *LEX::create_item_limit(THD *thd, const Lex_ident_cli_st *ca)
|
Item *LEX::create_item_limit(THD *thd, const Lex_ident_cli_st *ca)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(thd->m_parser_state->m_lip.get_buf() <= ca->pos());
|
DBUG_ASSERT(thd->m_parser_state->m_lip.get_buf() <= ca->pos());
|
||||||
@@ -10566,6 +10594,15 @@ Item *LEX::make_item_func_call_generic(THD *thd,
|
|||||||
const Lex_ident_cli_st *cname,
|
const Lex_ident_cli_st *cname,
|
||||||
List<Item> *args)
|
List<Item> *args)
|
||||||
{
|
{
|
||||||
|
if (args && args->elements == 1 &&
|
||||||
|
dynamic_cast<Item_join_operator_plus*>(args->head()))
|
||||||
|
{
|
||||||
|
Item *item= create_item_ident(thd, cdb, cname);
|
||||||
|
if (!item || mark_item_ident_for_ora_join(thd, item))
|
||||||
|
return nullptr;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
Lex_ident_sys db(thd, cdb), name(thd, cname);
|
Lex_ident_sys db(thd, cdb), name(thd, cname);
|
||||||
if (db.is_null() || name.is_null())
|
if (db.is_null() || name.is_null())
|
||||||
return NULL; // EOM
|
return NULL; // EOM
|
||||||
@@ -10661,6 +10698,15 @@ Item *LEX::make_item_func_call_generic(THD *thd,
|
|||||||
Lex_ident_cli_st *cfunc,
|
Lex_ident_cli_st *cfunc,
|
||||||
List<Item> *args)
|
List<Item> *args)
|
||||||
{
|
{
|
||||||
|
if (args && args->elements == 1 &&
|
||||||
|
dynamic_cast<Item_join_operator_plus*>(args->head()))
|
||||||
|
{
|
||||||
|
Item *item= create_item_ident(thd, cdb, cpkg, cfunc);
|
||||||
|
if (!item || mark_item_ident_for_ora_join(thd, item))
|
||||||
|
return nullptr;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
Lex_ident_sys db(thd, cdb), pkg(thd, cpkg), func(thd, cfunc);
|
Lex_ident_sys db(thd, cdb), pkg(thd, cpkg), func(thd, cfunc);
|
||||||
Identifier_chain2 q_pkg_func(pkg, func);
|
Identifier_chain2 q_pkg_func(pkg, func);
|
||||||
sp_name *qname;
|
sp_name *qname;
|
||||||
|
|||||||
@@ -4061,13 +4061,13 @@ public:
|
|||||||
const Lex_ident_sys_st &db,
|
const Lex_ident_sys_st &db,
|
||||||
const Lex_ident_sys_st &table,
|
const Lex_ident_sys_st &table,
|
||||||
const Lex_ident_sys_st &name);
|
const Lex_ident_sys_st &name);
|
||||||
Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name)
|
Item *create_item_ident_nosp(THD *thd, const Lex_ident_sys_st *name)
|
||||||
{
|
{
|
||||||
return create_item_ident_field(thd, Lex_ident_sys(), Lex_ident_sys(), *name);
|
return create_item_ident_field(thd, Lex_ident_sys(), Lex_ident_sys(), *name);
|
||||||
}
|
}
|
||||||
Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
|
Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
|
||||||
const char *start, const char *end);
|
const char *start, const char *end);
|
||||||
Item *create_item_ident(THD *thd, Lex_ident_cli_st *cname)
|
Item *create_item_ident(THD *thd, const Lex_ident_cli_st *cname)
|
||||||
{
|
{
|
||||||
Lex_ident_sys name(thd, cname);
|
Lex_ident_sys name(thd, cname);
|
||||||
if (name.is_null())
|
if (name.is_null())
|
||||||
@@ -4195,6 +4195,8 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mark_item_ident_for_ora_join(THD *thd, Item *item);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create items of this kind:
|
Create items of this kind:
|
||||||
SELECT name(args); -- e.g. spvar_assoc_array('key')
|
SELECT name(args); -- e.g. spvar_assoc_array('key')
|
||||||
|
|||||||
1147
sql/sql_oracle_outer_join.cc
Normal file
1147
sql/sql_oracle_outer_join.cc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -954,7 +954,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
|
|||||||
DBUG_ENTER("setup_without_group");
|
DBUG_ENTER("setup_without_group");
|
||||||
|
|
||||||
thd->lex->allow_sum_func.clear_bit(select->nest_level);
|
thd->lex->allow_sum_func.clear_bit(select->nest_level);
|
||||||
res= setup_conds(thd, tables, leaves, conds);
|
res= setup_conds(thd, tables, leaves, conds, &all_fields);
|
||||||
|
|
||||||
/* it's not wrong to have non-aggregated columns in a WHERE */
|
/* it's not wrong to have non-aggregated columns in a WHERE */
|
||||||
select->set_non_agg_field_used(saved_non_agg_field_used);
|
select->set_non_agg_field_used(saved_non_agg_field_used);
|
||||||
|
|||||||
@@ -1594,6 +1594,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
%type <item_list>
|
%type <item_list>
|
||||||
expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
|
expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
|
||||||
ident_list ident_list_arg opt_expr_list
|
ident_list ident_list_arg opt_expr_list
|
||||||
|
opt_udf_expr_list_or_join_operator
|
||||||
|
opt_expr_list_or_join_operator
|
||||||
execute_using
|
execute_using
|
||||||
execute_params
|
execute_params
|
||||||
opt_sp_cparam_list
|
opt_sp_cparam_list
|
||||||
@@ -11015,23 +11017,28 @@ function_call_generic:
|
|||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
udf_func *udf= 0;
|
udf_func *udf= 0;
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
Lex_ident_sys ident(thd, &$1);
|
if (using_udf_functions)
|
||||||
|
|
||||||
if (using_udf_functions &&
|
|
||||||
(udf= find_udf(ident.str, ident.length)) &&
|
|
||||||
udf->type == UDFTYPE_AGGREGATE)
|
|
||||||
{
|
{
|
||||||
if (unlikely(lex->current_select->inc_in_sum_expr()))
|
// find_udf expectes a 0-terminated string
|
||||||
|
const Lex_ident_sys sysname(thd, &$1);
|
||||||
|
if (sysname.is_null())
|
||||||
|
MYSQL_YYABORT; // EOM
|
||||||
|
if ((udf= find_udf(sysname.str, sysname.length)) &&
|
||||||
|
udf->type == UDFTYPE_AGGREGATE)
|
||||||
{
|
{
|
||||||
thd->parse_error();
|
if (unlikely(lex->current_select->inc_in_sum_expr()))
|
||||||
MYSQL_YYABORT;
|
{
|
||||||
|
thd->parse_error();
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Temporary placing the result of find_udf in $3 */
|
/* Temporary placing the result of find_udf in $3 */
|
||||||
$<udf>$= udf;
|
$<udf>$= udf;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
opt_udf_expr_list ')' opt_object_member_access
|
|
||||||
|
opt_udf_expr_list_or_join_operator ')' opt_object_member_access
|
||||||
{
|
{
|
||||||
const Type_handler *h;
|
const Type_handler *h;
|
||||||
Create_func *builder;
|
Create_func *builder;
|
||||||
@@ -11055,9 +11062,19 @@ function_call_generic:
|
|||||||
|
|
||||||
This will be revised with WL#2128 (SQL PATH)
|
This will be revised with WL#2128 (SQL PATH)
|
||||||
*/
|
*/
|
||||||
builder= Schema::find_implied(thd)->
|
if ($4 && $4->elements == 1 &&
|
||||||
find_native_function_builder(thd, ident);
|
dynamic_cast<Item_join_operator_plus*>($4->head()))
|
||||||
if (builder)
|
{
|
||||||
|
if ($6.str)
|
||||||
|
{
|
||||||
|
thd->parse_error();
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
item= Lex->create_item_ident(thd, &$1);
|
||||||
|
if (!item || Lex->mark_item_ident_for_ora_join(thd, item))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
} else if ((builder= Schema::find_implied(thd)->
|
||||||
|
find_native_function_builder(thd, ident)))
|
||||||
{
|
{
|
||||||
item= builder->create_func(thd, &ident, $4);
|
item= builder->create_func(thd, &ident, $4);
|
||||||
}
|
}
|
||||||
@@ -11139,7 +11156,7 @@ function_call_generic:
|
|||||||
$1, $3)))
|
$1, $3)))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| ident_cli '.' ident_cli '(' opt_expr_list ')'
|
| ident_cli '.' ident_cli '(' opt_expr_list_or_join_operator ')'
|
||||||
{
|
{
|
||||||
const Lex_ident_cli pos($1.pos(), $6.pos() - $1.pos() + 1);
|
const Lex_ident_cli pos($1.pos(), $6.pos() - $1.pos() + 1);
|
||||||
if (unlikely(!($$= Lex->make_item_func_or_method_call(thd, $1,
|
if (unlikely(!($$= Lex->make_item_func_or_method_call(thd, $1,
|
||||||
@@ -11147,7 +11164,21 @@ function_call_generic:
|
|||||||
pos))))
|
pos))))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| ident_cli '.' ident_cli '.' ident_cli '(' opt_expr_list ')'
|
| '.' ident_cli '.' ident_cli '(' '+' ')'
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This grammar branch is needed for symmetry with simple_ident,
|
||||||
|
to handle Oracle style outer join:
|
||||||
|
WHERE t1.a = .t2.a(+)
|
||||||
|
*/
|
||||||
|
Lex_ident_cli empty($2.pos(), 0);
|
||||||
|
List<Item> *list= Item_join_operator_plus::make_as_item_list(thd);
|
||||||
|
if (unlikely(
|
||||||
|
!list ||
|
||||||
|
!($$= Lex->make_item_func_call_generic(thd, &empty, &$2, &$4, list))))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| ident_cli '.' ident_cli '.' ident_cli '(' opt_expr_list_or_join_operator ')'
|
||||||
{
|
{
|
||||||
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, &$5, $7))))
|
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, &$5, $7))))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
@@ -11221,6 +11252,19 @@ opt_udf_expr_list:
|
|||||||
%endif
|
%endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
opt_udf_expr_list_or_join_operator:
|
||||||
|
opt_udf_expr_list
|
||||||
|
| remember_name '+' remember_end
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
remember_name and remember_end are needed here
|
||||||
|
to avoid a shift/reduce conflict with the rule udf_expr.
|
||||||
|
*/
|
||||||
|
if (!($$= Item_join_operator_plus::make_as_item_list(thd)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
udf_expr_list:
|
udf_expr_list:
|
||||||
udf_expr
|
udf_expr
|
||||||
{
|
{
|
||||||
@@ -11865,6 +11909,15 @@ opt_expr_list:
|
|||||||
| expr_list { $$= $1;}
|
| expr_list { $$= $1;}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
opt_expr_list_or_join_operator:
|
||||||
|
opt_expr_list
|
||||||
|
| '+'
|
||||||
|
{
|
||||||
|
if (!($$= Item_join_operator_plus::make_as_item_list(thd)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
expr_list:
|
expr_list:
|
||||||
expr
|
expr
|
||||||
{
|
{
|
||||||
@@ -16006,7 +16059,6 @@ order_ident:
|
|||||||
expr { $$=$1; }
|
expr { $$=$1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
simple_ident:
|
simple_ident:
|
||||||
ident_cli
|
ident_cli
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10643,7 +10643,7 @@ bool TR_table::query(ulonglong trx_id)
|
|||||||
Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]);
|
Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]);
|
||||||
Item *value= newx Item_int(thd, trx_id);
|
Item *value= newx Item_int(thd, trx_id);
|
||||||
COND *conds= newx Item_func_eq(thd, field, value);
|
COND *conds= newx Item_func_eq(thd, field, value);
|
||||||
if (unlikely((error= setup_conds(thd, this, dummy, &conds))))
|
if (unlikely((error= setup_conds(thd, this, dummy, &conds, NULL))))
|
||||||
return false;
|
return false;
|
||||||
select= make_select(table, 0, 0, conds, NULL, 0, &error);
|
select= make_select(table, 0, 0, conds, NULL, 0, &error);
|
||||||
if (unlikely(error || !select))
|
if (unlikely(error || !select))
|
||||||
@@ -10682,7 +10682,7 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards)
|
|||||||
conds= newx Item_func_ge(thd, field, value);
|
conds= newx Item_func_ge(thd, field, value);
|
||||||
else
|
else
|
||||||
conds= newx Item_func_le(thd, field, value);
|
conds= newx Item_func_le(thd, field, value);
|
||||||
if (unlikely((error= setup_conds(thd, this, dummy, &conds))))
|
if (unlikely((error= setup_conds(thd, this, dummy, &conds, NULL))))
|
||||||
return false;
|
return false;
|
||||||
// FIXME: (performance) force index 'commit_timestamp'
|
// FIXME: (performance) force index 'commit_timestamp'
|
||||||
select= make_select(table, 0, 0, conds, NULL, 0, &error);
|
select= make_select(table, 0, 0, conds, NULL, 0, &error);
|
||||||
|
|||||||
@@ -2608,6 +2608,7 @@ struct TABLE_LIST
|
|||||||
Item_in_subselect *jtbm_subselect;
|
Item_in_subselect *jtbm_subselect;
|
||||||
/* TODO: check if this can be joined with tablenr_exec */
|
/* TODO: check if this can be joined with tablenr_exec */
|
||||||
uint jtbm_table_no;
|
uint jtbm_table_no;
|
||||||
|
uint ora_join_table_no;
|
||||||
|
|
||||||
SJ_MATERIALIZATION_INFO *sj_mat_info;
|
SJ_MATERIALIZATION_INFO *sj_mat_info;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user