[Feat](Nereids) join hint support stage one (#27378)

support view as a independent unit of leading hint
add random test check of leading hint query
add more test with data of leading hint query
add random test check of distribute hint
This commit is contained in:
LiBinfeng
2023-11-29 21:08:08 +08:00
committed by GitHub
parent 6cdaf8ea32
commit 83ed8d3cba
52 changed files with 9019 additions and 1711 deletions

View File

@ -0,0 +1,622 @@
# join hint using document
In the database, "Hint" is an instruction that instructs the query optimizer to execute a plan. By embedding hints in SQL statements, you can influence the optimizer's decision to select the desired execution path. Here is a background example using Hint:
Suppose you have a table that contains a large amount of data, and you know that in some specific circumstances, the join order of the tables in a query may affect query performance. Leading Hint allows you to specify the order of table joins that you want the optimizer to follow.
For example, consider the following SQL query:
```sql
mysql> explain shape plan select * from t1 join t2 on t1.c1 = c2;
+-------------------------------------------+
| Explain String |
+-------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t1] |
+-------------------------------------------+
7 rows in set (0.06 sec)
```
In the above example, when the execution efficiency is not ideal, we want to adjust the join order without changing the original sql so as to avoid affecting the user's original scene and achieve the purpose of tuning. We can use leading to arbitrarily change the join order of tableA and tableB. For example, it could be written like:
```sql
mysql> explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;
+-----------------------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+-----------------------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() build RFs:RF0 c1->[c2] |
| --------PhysicalOlapScan[t2] apply RFs: RF0 |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(t2 t1) |
| UnUsed: |
| SyntaxError: |
+-----------------------------------------------------------------------------------------------------+
12 rows in set (0.06 sec)
```
In this example, the Hint /*+ leading(t2 t1) */ is used. This Hint tells the optimizer to use the specified table (t2) as the driver table in the execution plan, before (t1).
This document mainly describes how to use join related hints in Doris: leading hint, ordered hint and distribute hint
# Leading hint
Leading Hint is used to guide the optimizer in determining the join order of the query plan. In a query, the join order of the tables can affect query performance. Leading Hint allows you to specify the order of table joins that you want the optimizer to follow.
In doris, the syntax is /*+LEADING(tablespec [tablespec]... ) */,leading is surrounded by "/*+" and "*/" and placed directly behind the select in the select statement. Note that the '/' after leading and the selectlist need to be separated by at least one separator such as a space. At least two more tables need to be written before the leadinghint is justified. And any join can be bracketed to explicitly specify the shape of the joinTree. Example:
```sql
mysql> explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;
+------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(t2 t1) |
| UnUsed: |
| SyntaxError: |
+------------------------------------------------------------------------------+
12 rows in set (0.01 sec)
```
- If the leadinghint fails to take effect, the explain process will be used to generate the leadinghint. The EXPLAIN process will display whether the Leadinghint takes effect. There are three types of hints:
- Used: leading hint takes effect normally
- Unused: Unsupported cases include the feature that the leading specified join order is not equivalent to the original sql or is not supported in this version (see restrictions).
- SyntaxError: indicates leading hint syntax errors, such as failure to find the corresponding table
- The leading hint syntax creates a left deep tree by default. For example, select /*+ leading(t1 t2 t3) */ * from t1 join t2 on... Specify by default
```sql
join
/ \
join t3
/ \
t1 t2
mysql> explain shape plan select /*+ leading(t1 t2 t3) */ * from t1 join t2 on c1 = c2 join t3 on c2=c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: leading(t1 t2 t3) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------+
15 rows in set (0.00 sec)
```
The join tree shape is also allowed to be specified using braces. For example: /*+ leading(t1 {t2 t3}) */
```sql
join
/ \
t1 join
/ \
t2 t3
mysql> explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 join t2 on c1 = c2 join t3 on c2=c3;
+----------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| --------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ------------PhysicalOlapScan[t2] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: leading(t1 { t2 t3 }) |
| UnUsed: |
| SyntaxError: |
+----------------------------------------------------------------------------------+
15 rows in set (0.02 sec)
```
- When a view is used as an alias in joinReorder, the corresponding view can be specified as the leading parameter. Example:
```sql
mysql> explain shape plan select /*+ leading(alias t1) */ count(*) from t1 join (select c2 from t2 join t3 on t2.c2 = t3.c3) as alias on t1.c1 = alias.c2;
+--------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ----------------PhysicalProject |
| ------------------PhysicalOlapScan[t2] |
| ----------------PhysicalDistribute[DistributionSpecHash] |
| ------------------PhysicalProject |
| --------------------PhysicalOlapScan[t3] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(alias t1) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------------+
21 rows in set (0.06 sec)
```
## Basic cases
(Note that the column name is related to the table name, for example: only t1 has c1 field, the following example will write t1.c1 directly to c1 for simplicity)
```sql
CREATE DATABASE testleading;
USE testleading;
create table t1 (c1 int, c11 int) distributed by hash(c1) buckets 3 properties('replication_num' = '1');
create table t2 (c2 int, c22 int) distributed by hash(c2) buckets 3 properties('replication_num' = '1');
create table t3 (c3 int, c33 int) distributed by hash(c3) buckets 3 properties('replication_num' = '1');
create table t4 (c4 int, c44 int) distributed by hash(c4) buckets 3 properties('replication_num' = '1');
```
For a simple example, when we need to exchange the join order of t1 and t2, we only need to add leading(t2 t1) before it, which will be used in the explain
Shows whether the hint is used.
original plan
```sql
mysql> explain shape plan select * from t1 join t2 on t1.c1 = c2;
+-------------------------------------------+
| Explain String |
+-------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t1] |
+-------------------------------------------+
7 rows in set (0.06 sec)
```
Leading plan
```sql
mysql> explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;
+------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(t2 t1) |
| UnUsed: |
| SyntaxError: |
+------------------------------------------------------------------------------+
12 rows in set (0.00 sec)
```
hint effect display
Used unused
If the leading hint has a syntax error, the corresponding information is displayed in the syntax Error when explaining, but the plan is generated as usual, just without leading
```sql
mysql> explain shape plan select /*+ leading(t2 t3) */ * from t1 join t2 on t1.c1 = c2;
+--------------------------------------------------------+
| Explain String |
+--------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t1] |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t2] |
| |
| Used: |
| UnUsed: |
| SyntaxError: leading(t2 t3) Msg:can not find table: t3 |
+--------------------------------------------------------+
11 rows in set (0.01 sec)
```
## more cases
### Left deep tree
leading generates a left deep tree by default when we don't use any parentheses
```sql
mysql> explain shape plan select /*+ leading(t1 t2 t3) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: leading(t1 t2 t3) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------+
15 rows in set (0.10 sec)
```
### Right deep tree
When we want to make the shape of the plan into a right deep tree, bushy tree or zigzag tree, we only need to add curly brackets to limit the shape of the plan, instead of using swap to adjust from the left deep tree step by step like oracle.
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3;
+-----------------------------------------------+
| Explain String |
+-----------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t1] |
| --------PhysicalDistribute |
| ----------hashJoin[INNER_JOIN](t2.c2 = t3.c3) |
| ------------PhysicalOlapScan[t2] |
| ------------PhysicalDistribute |
| --------------PhysicalOlapScan[t3] |
| |
| Used: leading(t1 { t2 t3 }) |
| UnUsed: |
| SyntaxError: |
+-----------------------------------------------+
14 rows in set (0.02 sec)
```
### Bushy tree
```sql
mysql> explain shape plan select /*+ leading({t1 t2} {t3 t4}) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;
+-----------------------------------------------+
| Explain String |
+-----------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t2.c2 = t3.c3) |
| --------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute |
| ----------hashJoin[INNER_JOIN](t3.c3 = t4.c4) |
| ------------PhysicalOlapScan[t3] |
| ------------PhysicalDistribute |
| --------------PhysicalOlapScan[t4] |
| |
| Used: leading({ t1 t2 } { t3 t4 }) |
| UnUsed: |
| SyntaxError: |
+-----------------------------------------------+
17 rows in set (0.02 sec)
```
### zig-zag tree
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3} t4) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;
+--------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t3.c3 = t4.c4)) otherCondition=() |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ------------PhysicalOlapScan[t1] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ----------------PhysicalOlapScan[t2] |
| ----------------PhysicalDistribute[DistributionSpecHash] |
| ------------------PhysicalOlapScan[t3] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t4] |
| |
| Hint log: |
| Used: leading(t1 { t2 t3 } t4) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------------+
19 rows in set (0.02 sec)
```
## Non-inner join:
When non-inner-joins are encountered, such as Outer join or semi/anti join, leading hint automatically deduces the join mode of each join according to the original sql semantics. If leading hints that differ from the original sql semantics or cannot be generated, they are placed in unused, but do not affect the generation of the normal flow of the plan.
Here are examples of things that can't be exchanged:
-------- test outer join which can not swap
-- t1 leftjoin (t2 join t3 on (P23)) on (P12) != (t1 leftjoin t2 on (P12)) join t3 on (P23)
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: |
| UnUsed: leading(t1 { t2 t3 }) |
| SyntaxError: |
+--------------------------------------------------------------------------------+
15 rows in set (0.01 sec)
```
Below are some examples that can be exchanged and examples that cannot be exchanged, which readers can verify for themselves
```sql
-------- test outer join which can swap
-- (t1 leftjoin t2 on (P12)) innerjoin t3 on (P13) = (t1 innerjoin t3 on (P13)) leftjoin t2 on (P12)
explain shape plan select * from t1 left join t2 on c1 = c2 join t3 on c1 = c3;
explain shape plan select /*+ leading(t1 t3 t2) */ * from t1 left join t2 on c1 = c2 join t3 on c1 = c3;
-- (t1 leftjoin t2 on (P12)) leftjoin t3 on (P13) = (t1 leftjoin t3 on (P13)) leftjoin t2 on (P12)
explain shape plan select * from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;
explain shape plan select /*+ leading(t1 t3 t2) */ * from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;
-- (t1 leftjoin t2 on (P12)) leftjoin t3 on (P23) = t1 leftjoin (t2 leftjoin t3 on (P23)) on (P12)
select /*+ leading(t2 t3 t1) SWAP_INPUT(t1) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;
explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;
explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;
-------- test outer join which can not swap
-- t1 leftjoin (t2 join t3 on (P23)) on (P12) != (t1 leftjoin t2 on (P12)) join t3 on (P23)
-- eliminated to inner join
explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 join t3 on c2 = c3;
explain graph select /*+ leading(t1 t2 t3) */ * from t1 left join (select * from t2 join t3 on c2 = c3) on c1 = c2;
-- test semi join
explain shape plan select * from t1 where c1 in (select c2 from t2);
explain shape plan select /*+ leading(t2 t1) */ * from t1 where c1 in (select c2 from t2);
-- test anti join
explain shape plan select * from t1 where exists (select c2 from t2);
```
## View
In the case of aliases, you can specify the alias as a complete subtree with joinOrder generated from text order.
```sql
mysql> explain shape plan select /*+ leading(alias t1) */ count(*) from t1 join (select c2 from t2 join t3 on t2.c2 = t3.c3) as alias on t1.c1 = alias.c2;
+--------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ----------------PhysicalProject |
| ------------------PhysicalOlapScan[t2] |
| ----------------PhysicalDistribute[DistributionSpecHash] |
| ------------------PhysicalProject |
| --------------------PhysicalOlapScan[t3] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(alias t1) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------------+
21 rows in set (0.02 sec)
```
## mixed with ordered hint
When ordered hint is used together with ordered hint, ordered hint takes effect with a higher priority than leading hint. Example:
```sql
mysql> explain shape plan select /*+ ORDERED LEADING(t1 t2 t3) */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t2] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: leading(t1 t2 t3) |
| SyntaxError: |
+--------------------------------------------------------------------------------+
18 rows in set (0.02 sec)
```
## Limitation
- The current version supports only one leadingHint. If leadinghint is used with a subquery, the query will report an error. Example (This example explain will report an error, but will follow the normal path generation plan) :
```sql
mysql> explain shape plan select /*+ leading(alias t1) */ count(*) from t1 join (select /*+ leading(t3 t2) */ c2 from t2 join t3 on t2.c2 = t3.c3) as alias on t1.c1 = alias.c2;
+----------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ------------------PhysicalProject |
| --------------------PhysicalOlapScan[t2] |
| ------------------PhysicalDistribute[DistributionSpecHash] |
| --------------------PhysicalProject |
| ----------------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: |
| UnUsed: leading(alias t1) |
| SyntaxError: leading(t3 t2) Msg:one query block can only have one leading clause |
+----------------------------------------------------------------------------------------+
21 rows in set (0.01 sec)
```
# OrderedHint
- Using ordered hint causes the join tree to be fixed in shape and displayed in text order
- The syntax is /*+ ORDERED */,leading is surrounded by "/*+" and "*/" and placed directly behind the select in the select statement, for example:
```sql
explain shape plan select /*+ ORDERED */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
join
/ \
join t3
/ \
t2 t1
mysql> explain shape plan select /*+ ORDERED */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t2] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------+
18 rows in set (0.02 sec)
```
- When ordered hint and leading hint are used at the same time, the ordered hint prevails and the leading hint becomes invalid
```sql
mysql> explain shape plan select /*+ ORDERED LEADING(t1 t2 t3) */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t2] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: leading(t1 t2 t3) |
| SyntaxError: |
+--------------------------------------------------------------------------------+
18 rows in set (0.02 sec)
```
# DistributeHint
- Currently, only the distribute Type of the right table can be specified, and only two types are available: [shuffle] and [broadcast]. They are written before the right join table. Brackets and /*+ */ are allowed
- Currently you can use any DistributeHint
- When a DistributeHint whose plan cannot be correctly generated is not displayed, it takes effect based on maximum effort. Finally, the distribute mode that is displayed is mainly explained
- The current distribute version is not combined with leading. It takes effect only when the table specified in DISTRIBUTE is on the right of join.
- Mixed with ordered, the text order is used to set the join order and then specify the expected distribute mode in the corresponding join. Example:
Before use distribute hint:
```sql
mysql> explain shape plan select count(*) from t1 join t2 on t1.c1 = t2.c2;
+----------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t2] |
+----------------------------------------------------------------------------------+
11 rows in set (0.01 sec)
```
after use distribute hint:
```sql
mysql> explain shape plan select /*+ ordered */ count(*) from t2 join[broadcast] t1 on t1.c1 = t2.c2;
+----------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t2] |
| ------------PhysicalDistribute[DistributionSpecReplicated] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: |
| SyntaxError: |
+----------------------------------------------------------------------------------+
16 rows in set (0.01 sec)
```
- the Explain shape plan will display inside distribute operator related information, including DistributionSpecReplicated said the operator will be corresponding data into a copy of all be node, DistributionSpecGather indicates that data is gathered to fe nodes, and DistributionSpecHash indicates that data is dispersed to different be nodes according to a specific hashKey and algorithm.
# To be supported
- leadingHint indicates that the current query cannot be mixed with the subquery after it is promoted. A hint is required to control whether the subquery can be unnested
- A new distributeHint is needed for better and more complete control of the distribute operator
- Use leadingHint and distributeHint together to determine the shape of a join

View File

@ -39,6 +39,7 @@ grammar:
```sql
SELECT
[hint_statement, ...]
[ALL | DISTINCT | DISTINCTROW | ALL EXCEPT ( col_name1 [, col_name2, col_name3, ...] )]
select_expr [, select_expr ...]
[FROM table_references
@ -86,6 +87,8 @@ SELECT
11. SELECT supports explicit partition selection using PARTITION containing a list of partitions or subpartitions (or both) following the name of the table in `table_reference`
12. `[TABLET tids] TABLESAMPLE n [ROWS | PERCENT] [REPEATABLE seek]`: Limit the number of rows read from the table in the FROM clause, select a number of Tablets pseudo-randomly from the table according to the specified number of rows or percentages, and specify the number of seeds in REPEATABLE to return the selected samples again. In addition, you can also manually specify the TableID, Note that this can only be used for OLAP tables.
13. `hint_statement`: hint in front of the selectlist indicates that hints can be used to influence the behavior of the optimizer in order to obtain the desired execution plan. Details refer to [joinHint using document] (https://doris.apache.org/en/docs/query-acceleration/hint/joinHint.md)
**Syntax constraints:**

View File

@ -0,0 +1,607 @@
# join hint 使用文档
# 背景
在数据库中,"Hint" 是一种用于指导查询优化器执行计划的指令。通过在SQL语句中嵌入Hint,可以影响优化器的决策,以选中期望的执行路径。以下是一个使用Hint的背景示例:
假设有一个包含大量数据的表,而你知道在某些特定情况下,在一个查询中,表的连接顺序可能会影响查询性能。Leading Hint允许你指定希望优化器遵循的表连接的顺序。
例如,考虑以下SQL查询:
```sql
mysql> explain shape plan select * from t1 join t2 on t1.c1 = c2;
+-------------------------------------------+
| Explain String |
+-------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t1] |
+-------------------------------------------+
7 rows in set (0.06 sec)
```
在上述例子里面,在执行效率不理想的时候,我们希望调整下join顺序而不改变原始sql以免影响到用户原始场景且能达到调优的目的。我们可以使用leading任意改变tableA和tableB的join顺序。例如可以写成:
```sql
mysql> explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;
+-----------------------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+-----------------------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() build RFs:RF0 c1->[c2] |
| --------PhysicalOlapScan[t2] apply RFs: RF0 |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(t2 t1) |
| UnUsed: |
| SyntaxError: |
+-----------------------------------------------------------------------------------------------------+
12 rows in set (0.06 sec)
```
在这个例子中,使用了 /*+ leading(t2 t1) */ 这个Hint。这个Hint告诉优化器在执行计划中使用指定表(t2)作为驱动表,并置于(t1)之前。
本文主要阐述如何在Doris里面使用join相关的hint:leading hint、ordered hint 和 distribute hint
# Leading hint使用说明
Leading Hint 用于指导优化器确定查询计划的连接顺序。在一个查询中,表的连接顺序可能会影响查询性能。Leading Hint允许你指定希望优化器遵循的表连接的顺序。
在doris里面,其语法为 /*+LEADING( tablespec [ tablespec ]... ) */,leading由"/*+"和"*/"包围并置于select语句里面 select的正后方。注意,leading 后方的 '/' 和selectlist需要隔开至少一个分割符例如空格。至少需要写两个以上的表才认为这个leadinghint是合理的。且任意的join里面可以用大括号括号起来,来显式地指定joinTree的形状。例:
```sql
mysql> explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;
+------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(t2 t1) |
| UnUsed: |
| SyntaxError: |
+------------------------------------------------------------------------------+
12 rows in set (0.01 sec)
```
- 当leadinghint不生效的时候会走正常的流程生成计划,explain会显示使用的hint是否生效,主要分三种来显示:
- Used:leading hint正常生效
- Unused: 这里不支持的情况包含leading指定的join order与原sql不等价或本版本暂不支持特性(详见限制)
- SyntaxError: 指leading hint语法错误,如找不到对应的表等
- leading hint语法默认造出来左深树,例:select /*+ leading(t1 t2 t3) */ * from t1 join t2 on...默认指定出来
```sql
join
/ \
join t3
/ \
t1 t2
mysql> explain shape plan select /*+ leading(t1 t2 t3) */ * from t1 join t2 on c1 = c2 join t3 on c2=c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: leading(t1 t2 t3) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------+
15 rows in set (0.00 sec)
```
- 同时允许使用大括号指定join树形状。例:/*+ leading(t1 {t2 t3}) */
join
/ \
t1 join
/ \
t2 t3
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 join t2 on c1 = c2 join t3 on c2=c3;
+----------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| --------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ------------PhysicalOlapScan[t2] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: leading(t1 { t2 t3 }) |
| UnUsed: |
| SyntaxError: |
+----------------------------------------------------------------------------------+
15 rows in set (0.02 sec)
```
- 当有view作为别名参与joinReorder的时候可以指定对应的view作为leading的参数。例:
```sql
mysql> explain shape plan select /*+ leading(alias t1) */ count(*) from t1 join (select c2 from t2 join t3 on t2.c2 = t3.c3) as alias on t1.c1 = alias.c2;
+--------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ----------------PhysicalProject |
| ------------------PhysicalOlapScan[t2] |
| ----------------PhysicalDistribute[DistributionSpecHash] |
| ------------------PhysicalProject |
| --------------------PhysicalOlapScan[t3] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(alias t1) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------------+
21 rows in set (0.06 sec)
```
## 基本用例
(注意这里列命名和表命名相关,例:只有t1中有c1字段,后续例子为了简化会将 t1.c1 直接写成 c1)
```sql
CREATE DATABASE testleading;
USE testleading;
create table t1 (c1 int, c11 int) distributed by hash(c1) buckets 3 properties('replication_num' = '1');
create table t2 (c2 int, c22 int) distributed by hash(c2) buckets 3 properties('replication_num' = '1');
create table t3 (c3 int, c33 int) distributed by hash(c3) buckets 3 properties('replication_num' = '1');
create table t4 (c4 int, c44 int) distributed by hash(c4) buckets 3 properties('replication_num' = '1');
```
举个简单的例子,当我们需要交换t1和t2的join顺序的时候只需要在前面加上leading(t2 t1)即可,explain的时候会
显示是否用上了这个hint
原始plan
```sql
mysql> explain shape plan select * from t1 join t2 on t1.c1 = c2;
+-------------------------------------------+
| Explain String |
+-------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t1] |
+-------------------------------------------+
7 rows in set (0.06 sec)
```
Leading plan
```sql
mysql> explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;
+------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| --------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(t2 t1) |
| UnUsed: |
| SyntaxError: |
+------------------------------------------------------------------------------+
12 rows in set (0.00 sec)
```
hint 效果展示
Used unused
leading hint有语法错误explain的时候会在syntax error里面显示相应的信息,但是计划能照常生成,只不过没有使用leading而已
```sql
mysql> explain shape plan select /*+ leading(t2 t3) */ * from t1 join t2 on t1.c1 = c2;
+--------------------------------------------------------+
| Explain String |
+--------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t1] |
| --------PhysicalDistribute |
| ----------PhysicalOlapScan[t2] |
| |
| Used: |
| UnUsed: |
| SyntaxError: leading(t2 t3) Msg:can not find table: t3 |
+--------------------------------------------------------+
11 rows in set (0.01 sec)
```
## 扩展场景
### 左深树
当我们不使用任何括号的情况下leading会默认生成左深树
```sql
mysql> explain shape plan select /*+ leading(t1 t2 t3) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: leading(t1 t2 t3) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------+
15 rows in set (0.10 sec)
```
### 右深树
当我们想将计划的形状做成右深树或者bushy树或者zigzag树的时候,只需要加上大括号来限制plan的形状即可,不需要像oracle一样用swap从左深树一步步调整
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3;
+-----------------------------------------------+
| Explain String |
+-----------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| --------PhysicalOlapScan[t1] |
| --------PhysicalDistribute |
| ----------hashJoin[INNER_JOIN](t2.c2 = t3.c3) |
| ------------PhysicalOlapScan[t2] |
| ------------PhysicalDistribute |
| --------------PhysicalOlapScan[t3] |
| |
| Used: leading(t1 { t2 t3 }) |
| UnUsed: |
| SyntaxError: |
+-----------------------------------------------+
14 rows in set (0.02 sec)
```
### Bushy
```sql
mysql> explain shape plan select /*+ leading({t1 t2} {t3 t4}) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;
+-----------------------------------------------+
| Explain String |
+-----------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN](t2.c2 = t3.c3) |
| --------hashJoin[INNER_JOIN](t1.c1 = t2.c2) |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute |
| ----------hashJoin[INNER_JOIN](t3.c3 = t4.c4) |
| ------------PhysicalOlapScan[t3] |
| ------------PhysicalDistribute |
| --------------PhysicalOlapScan[t4] |
| |
| Used: leading({ t1 t2 } { t3 t4 }) |
| UnUsed: |
| SyntaxError: |
+-----------------------------------------------+
17 rows in set (0.02 sec)
```
### zig-zag
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3} t4) */ * from t1 join t2 on t1.c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;
+--------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t3.c3 = t4.c4)) otherCondition=() |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ------------PhysicalOlapScan[t1] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ----------------PhysicalOlapScan[t2] |
| ----------------PhysicalDistribute[DistributionSpecHash] |
| ------------------PhysicalOlapScan[t3] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t4] |
| |
| Hint log: |
| Used: leading(t1 { t2 t3 } t4) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------------+
19 rows in set (0.02 sec)
```
## Non-inner join
当遇到非inner-join的时候,例如Outer join或者semi/anti join的时候leading hint会根据原始sql语义自动推导各个join的join方式。若遇到与原始sql语义不同的leading hint或者生成不了的情况则会放到unused里面,但是不影响计划正常流程的生成。
下面是不能交换的例子:
-------- test outer join which can not swap
-- t1 leftjoin (t2 join t3 on (P23)) on (P12) != (t1 leftjoin t2 on (P12)) join t3 on (P23)
```sql
mysql> explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalOlapScan[t1] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalOlapScan[t2] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: |
| UnUsed: leading(t1 { t2 t3 }) |
| SyntaxError: |
+--------------------------------------------------------------------------------+
15 rows in set (0.01 sec)
```
下面是一些可以交换的例子和不能交换的例子,读者可自行验证
```sql
-------- test outer join which can swap
-- (t1 leftjoin t2 on (P12)) innerjoin t3 on (P13) = (t1 innerjoin t3 on (P13)) leftjoin t2 on (P12)
explain shape plan select * from t1 left join t2 on c1 = c2 join t3 on c1 = c3;
explain shape plan select /*+ leading(t1 t3 t2) */ * from t1 left join t2 on c1 = c2 join t3 on c1 = c3;
-- (t1 leftjoin t2 on (P12)) leftjoin t3 on (P13) = (t1 leftjoin t3 on (P13)) leftjoin t2 on (P12)
explain shape plan select * from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;
explain shape plan select /*+ leading(t1 t3 t2) */ * from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;
-- (t1 leftjoin t2 on (P12)) leftjoin t3 on (P23) = t1 leftjoin (t2 leftjoin t3 on (P23)) on (P12)
select /*+ leading(t2 t3 t1) SWAP_INPUT(t1) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;
explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;
explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;
-------- test outer join which can not swap
-- t1 leftjoin (t2 join t3 on (P23)) on (P12) != (t1 leftjoin t2 on (P12)) join t3 on (P23)
-- eliminated to inner join
explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 join t3 on c2 = c3;
explain graph select /*+ leading(t1 t2 t3) */ * from t1 left join (select * from t2 join t3 on c2 = c3) on c1 = c2;
-- test semi join
explain shape plan select * from t1 where c1 in (select c2 from t2);
explain shape plan select /*+ leading(t2 t1) */ * from t1 where c1 in (select c2 from t2);
-- test anti join
explain shape plan select * from t1 where exists (select c2 from t2);
```
## View
遇到别名的情况,可以将别名作为一个完整的子树进行指定,子树里面的joinOrder由文本序生成。
```sql
mysql> explain shape plan select /*+ leading(alias t1) */ count(*) from t1 join (select c2 from t2 join t3 on t2.c2 = t3.c3) as alias on t1.c1 = alias.c2;
+--------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ----------------PhysicalProject |
| ------------------PhysicalOlapScan[t2] |
| ----------------PhysicalDistribute[DistributionSpecHash] |
| ------------------PhysicalProject |
| --------------------PhysicalOlapScan[t3] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: leading(alias t1) |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------------+
21 rows in set (0.02 sec)
```
## ordered混合使用
当与ordered hint混合使用的时候以ordered hint为主,即ordered hint生效优先级高于leading hint。例:
```sql
mysql> explain shape plan select /*+ ORDERED LEADING(t1 t2 t3) */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t2] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: leading(t1 t2 t3) |
| SyntaxError: |
+--------------------------------------------------------------------------------+
18 rows in set (0.02 sec)
```
## 使用限制
- 当前版本只支持使用一个leadingHint。若和子查询同时使用leadinghint的话则查询会报错。例(这个例子explain会报错,但是会走正常的路径生成计划):
```sql
mysql> explain shape plan select /*+ leading(alias t1) */ count(*) from t1 join (select /*+ leading(t3 t2) */ c2 from t2 join t3 on t2.c2 = t3.c3) as alias on t1.c1 = alias.c2;
+----------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = alias.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| ------------------PhysicalProject |
| --------------------PhysicalOlapScan[t2] |
| ------------------PhysicalDistribute[DistributionSpecHash] |
| --------------------PhysicalProject |
| ----------------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: |
| UnUsed: leading(alias t1) |
| SyntaxError: leading(t3 t2) Msg:one query block can only have one leading clause |
+----------------------------------------------------------------------------------------+
21 rows in set (0.01 sec)
```
# OrderedHint 使用说明
- 使用ordered hint会让join tree的形状固定下来,按照文本序来显示
- 语法为 /*+ ORDERED */,leading由"/*+"和"*/"包围并置于select语句里面 select的正后方,例:
explain shape plan select /*+ ORDERED */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
join
/ \
join t3
/ \
t2 t1
```sql
mysql> explain shape plan select /*+ ORDERED */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t2] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: |
| SyntaxError: |
+--------------------------------------------------------------------------------+
18 rows in set (0.02 sec)
```
- 当ordered hint和leading hint同时使用时以ordered hint为准,leading hint会失效
```sql
mysql> explain shape plan select /*+ ORDERED LEADING(t1 t2 t3) */ t1.c1 from t2 join t1 on t1.c1 = t2.c2 join t3 on c2 = c3;
+--------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+--------------------------------------------------------------------------------+
| PhysicalResultSink |
| --PhysicalDistribute[DistributionSpecGather] |
| ----PhysicalProject |
| ------hashJoin[INNER_JOIN] hashCondition=((t2.c2 = t3.c3)) otherCondition=() |
| --------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t2] |
| ----------PhysicalDistribute[DistributionSpecHash] |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| --------PhysicalDistribute[DistributionSpecHash] |
| ----------PhysicalProject |
| ------------PhysicalOlapScan[t3] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: leading(t1 t2 t3) |
| SyntaxError: |
+--------------------------------------------------------------------------------+
18 rows in set (0.02 sec)
```
# DistributeHint 使用说明
- 目前只能指定右表的distribute Type 而且只有[shuffle] 和 [broadcast]两种,写在join右表前面且允许中括号和/*+ */两种写法
- 目前能使用任意个DistributeHint
- 当遇到无法正确生成计划的 DistributeHint,没有显示,按最大努力生效,最后以explain显示的distribute方式为主
- 当前版本暂不与leading混用,且当distribute指定的表位于join右边才可生效。
- 多与ordered混用,利用文本序把join顺序固定下来,然后再指定相应的join里面我们预期使用什么样的distribute方式。例:
使用前:
```sql
mysql> explain shape plan select count(*) from t1 join t2 on t1.c1 = t2.c2;
+----------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t1] |
| ------------PhysicalDistribute[DistributionSpecHash] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t2] |
+----------------------------------------------------------------------------------+
11 rows in set (0.01 sec)
```
使用后:
```sql
mysql> explain shape plan select /*+ ordered */ count(*) from t2 join[broadcast] t1 on t1.c1 = t2.c2;
+----------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+----------------------------------------------------------------------------------+
| PhysicalResultSink |
| --hashAgg[GLOBAL] |
| ----PhysicalDistribute[DistributionSpecGather] |
| ------hashAgg[LOCAL] |
| --------PhysicalProject |
| ----------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=() |
| ------------PhysicalProject |
| --------------PhysicalOlapScan[t2] |
| ------------PhysicalDistribute[DistributionSpecReplicated] |
| --------------PhysicalProject |
| ----------------PhysicalOlapScan[t1] |
| |
| Hint log: |
| Used: ORDERED |
| UnUsed: |
| SyntaxError: |
+----------------------------------------------------------------------------------+
16 rows in set (0.01 sec)
```
- Explain shape plan里面会显示distribute算子相关的信息,其中DistributionSpecReplicated表示该算子将对应的数据变成所有be节点复制一份,DistributionSpecGather表示将数据gather到fe节点,DistributionSpecHash表示将数据按照特定的hashKey以及算法打散到不同的be节点。
# 待支持
- leadingHint待支持子查询解嵌套指定,当前和子查询提升以后不能混用,需要有hint来控制是否可以解嵌套
- 需要新的distributeHint来更好且更全面地控制distribute算子
- 混合使用leadingHint与distributeHint来共同确定join的形状

View File

@ -39,6 +39,7 @@ SELECT
```sql
SELECT
[hint_statement, ...]
[ALL | DISTINCT | DISTINCTROW | ALL EXCEPT ( col_name1 [, col_name2, col_name3, ...] )]
select_expr [, select_expr ...]
[FROM table_references
@ -87,6 +88,8 @@ SELECT
12. `[TABLET tids] TABLESAMPLE n [ROWS | PERCENT] [REPEATABLE seek]`: 在FROM子句中限制表的读取行数,根据指定的行数或百分比从表中伪随机的选择数个Tablet,REPEATABLE指定种子数可使选择的样本再次返回,此外也可手动指定TableID,注意这只能用于OLAP表。
13. `hint_statement`: 在selectlist前面使用hint表示可以通过hint去影响优化器的行为以期得到想要的执行计划,详情可参考[joinHint 使用文档](https://doris.apache.org/zh-CN/docs/query-acceleration/hint/joinHint.md)
**语法约束:**
1. SELECT也可用于检索计算的行而不引用任何表。

View File

@ -27,6 +27,7 @@ import org.apache.doris.nereids.analyzer.UnboundOlapTableSink;
import org.apache.doris.nereids.analyzer.UnboundOneRowRelation;
import org.apache.doris.nereids.analyzer.UnboundRelation;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.jobs.Job;
import org.apache.doris.nereids.jobs.JobContext;
import org.apache.doris.nereids.jobs.executor.Analyzer;
@ -114,6 +115,9 @@ public class CascadesContext implements ScheduleContext {
private final Optional<CascadesContext> parent;
private final List<MaterializationContext> materializationContexts;
private boolean isLeadingJoin = false;
private final Map<String, Hint> hintMap = Maps.newLinkedHashMap();
/**
* Constructor of OptimizerContext.
@ -615,4 +619,16 @@ public class CascadesContext implements ScheduleContext {
p.value().setStatistics(updatedConsumerStats);
}
}
public boolean isLeadingJoin() {
return isLeadingJoin;
}
public void setLeadingJoin(boolean leadingJoin) {
isLeadingJoin = leadingJoin;
}
public Map<String, Hint> getHintMap() {
return hintMap;
}
}

View File

@ -68,7 +68,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@ -353,30 +352,30 @@ public class NereidsPlanner extends Planner {
/**
* getting hints explain string, which specified by enumerate and show in lists
* @param hintMap hint map recorded in statement context
* @param hints hint map recorded in statement context
* @return explain string shows using of hint
*/
public String getHintExplainString(Map<String, Hint> hintMap) {
public String getHintExplainString(List<Hint> hints) {
String used = "";
String unUsed = "";
String syntaxError = "";
for (Map.Entry<String, Hint> entry : hintMap.entrySet()) {
switch (entry.getValue().getStatus()) {
for (Hint hint : hints) {
switch (hint.getStatus()) {
case UNUSED:
unUsed = unUsed + " " + entry.getValue().getExplainString();
unUsed = unUsed + " " + hint.getExplainString();
break;
case SYNTAX_ERROR:
syntaxError = syntaxError + " " + entry.getValue().getExplainString()
+ " Msg:" + entry.getValue().getErrorMessage();
syntaxError = syntaxError + " " + hint.getExplainString()
+ " Msg:" + hint.getErrorMessage();
break;
case SUCCESS:
used = used + " " + entry.getValue().getExplainString();
used = used + " " + hint.getExplainString();
break;
default:
break;
}
}
return "\nUsed:" + used + "\nUnUsed:" + unUsed + "\nSyntaxError:" + syntaxError;
return "\nHint log:" + "\nUsed:" + used + "\nUnUsed:" + unUsed + "\nSyntaxError:" + syntaxError;
}
@Override
@ -417,8 +416,8 @@ public class NereidsPlanner extends Planner {
default:
plan = super.getExplainString(explainOptions);
}
if (!statementContext.getHintMap().isEmpty()) {
String hint = getHintExplainString(cascadesContext.getStatementContext().getHintMap());
if (statementContext != null && !statementContext.getHints().isEmpty()) {
String hint = getHintExplainString(statementContext.getHints());
return plan + hint;
}
return plan;

View File

@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -72,8 +73,6 @@ public class StatementContext {
private boolean isDpHyp = false;
private boolean isOtherJoinReorder = false;
private boolean isLeadingJoin = false;
private final IdGenerator<ExprId> exprIdGenerator = ExprId.createGenerator();
private final IdGenerator<ObjectId> objectIdGenerator = ObjectId.createGenerator();
private final IdGenerator<RelationId> relationIdGenerator = RelationId.createGenerator();
@ -87,9 +86,10 @@ public class StatementContext {
private final Map<CTEId, List<Pair<Map<Slot, Slot>, Group>>> cteIdToConsumerGroup = new HashMap<>();
private final Map<CTEId, LogicalPlan> rewrittenCteProducer = new HashMap<>();
private final Map<CTEId, LogicalPlan> rewrittenCteConsumer = new HashMap<>();
private final Map<String, Hint> hintMap = Maps.newLinkedHashMap();
private final Set<String> viewDdlSqlSet = Sets.newHashSet();
private final List<Hint> hints = new ArrayList<>();
public StatementContext() {
this.connectContext = ConnectContext.get();
}
@ -147,14 +147,6 @@ public class StatementContext {
isDpHyp = dpHyp;
}
public boolean isLeadingJoin() {
return isLeadingJoin;
}
public void setLeadingJoin(boolean leadingJoin) {
isLeadingJoin = leadingJoin;
}
public boolean isOtherJoinReorder() {
return isOtherJoinReorder;
}
@ -193,10 +185,6 @@ public class StatementContext {
return supplier.get();
}
public Map<String, Hint> getHintMap() {
return hintMap;
}
public ColumnAliasGenerator getColumnAliasGenerator() {
return columnAliasGenerator == null
? columnAliasGenerator = new ColumnAliasGenerator()
@ -246,4 +234,12 @@ public class StatementContext {
public List<String> getViewDdlSqls() {
return ImmutableList.copyOf(viewDdlSqlSet);
}
public void addHint(Hint hint) {
this.hints.add(hint);
}
public List<Hint> getHints() {
return ImmutableList.copyOf(hints);
}
}

View File

@ -31,6 +31,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
import org.apache.doris.nereids.util.JoinUtils;
import com.google.common.collect.Maps;
@ -61,10 +62,14 @@ public class LeadingHint extends Hint {
private final List<Pair<Long, Expression>> filters = new ArrayList<>();
private final Map<Expression, JoinType> conditionJoinType = Maps.newLinkedHashMap();
private final List<JoinConstraint> joinConstraintList = new ArrayList<>();
private Long innerJoinBitmap = 0L;
private Long totalBitmap = 0L;
public LeadingHint(String hintName) {
super(hintName);
}
@ -191,6 +196,30 @@ public class LeadingHint extends Hint {
return filters;
}
public void putConditionJoinType(Expression filter, JoinType joinType) {
conditionJoinType.put(filter, joinType);
}
/**
* find out whether conditions can match original joinType
* @param conditions conditions needs to put on this join
* @param joinType join type computed by join constraint
* @return can conditions matched
*/
public boolean isConditionJoinTypeMatched(List<Expression> conditions, JoinType joinType) {
for (Expression condition : conditions) {
JoinType originalJoinType = conditionJoinType.get(condition);
if (originalJoinType.equals(joinType)
|| originalJoinType.isOneSideOuterJoin() && joinType.isOneSideOuterJoin()
|| originalJoinType.isSemiJoin() && joinType.isSemiJoin()
|| originalJoinType.isAntiJoin() && joinType.isAntiJoin()) {
continue;
}
return false;
}
return true;
}
public List<JoinConstraint> getJoinConstraintList() {
return joinConstraintList;
}
@ -203,6 +232,31 @@ public class LeadingHint extends Hint {
this.innerJoinBitmap = innerJoinBitmap;
}
public Long getTotalBitmap() {
return totalBitmap;
}
/**
* set total bitmap used in leading before we get into leading join
*/
public void setTotalBitmap() {
Long totalBitmap = 0L;
if (hasSameName()) {
this.setStatus(HintStatus.SYNTAX_ERROR);
this.setErrorMessage("duplicated table");
}
for (int index = 0; index < getTablelist().size(); index++) {
RelationId id = findRelationIdAndTableName(getTablelist().get(index));
if (id == null) {
this.setStatus(HintStatus.SYNTAX_ERROR);
this.setErrorMessage("can not find table: " + getTablelist().get(index));
return;
}
totalBitmap = LongBitmap.set(totalBitmap, id.asInt());
}
this.totalBitmap = totalBitmap;
}
/**
* try to get join constraint, if can not get, it means join is inner join,
* @param joinTableBitmap table bitmap below this join
@ -218,6 +272,22 @@ public class LeadingHint extends Hint {
JoinConstraint matchedJoinConstraint = null;
for (JoinConstraint joinConstraint : joinConstraintList) {
if (joinConstraint.getJoinType().isFullOuterJoin()) {
if (leftTableBitmap.equals(joinConstraint.getLeftHand())
&& rightTableBitmap.equals(joinConstraint.getRightHand())
|| rightTableBitmap.equals(joinConstraint.getLeftHand())
&& leftTableBitmap.equals(joinConstraint.getRightHand())) {
if (matchedJoinConstraint != null) {
return Pair.of(null, false);
}
matchedJoinConstraint = joinConstraint;
reversed = false;
break;
} else {
continue;
}
}
if (!LongBitmap.isOverlap(joinConstraint.getMinRightHand(), joinTableBitmap)) {
continue;
}
@ -337,7 +407,6 @@ public class LeadingHint extends Hint {
* @return plan
*/
public Plan generateLeadingJoinPlan() {
this.setStatus(HintStatus.SUCCESS);
Stack<Pair<Integer, LogicalPlan>> stack = new Stack<>();
int index = 0;
LogicalPlan logicalPlan = getLogicalPlanByName(getTablelist().get(index));
@ -365,8 +434,16 @@ public class LeadingHint extends Hint {
getFilters(), newStackTop.second, logicalPlan);
Pair<List<Expression>, List<Expression>> pair = JoinUtils.extractExpressionForHashTable(
newStackTop.second.getOutput(), logicalPlan.getOutput(), conditions);
// leading hint would set status inside if not success
JoinType joinType = computeJoinType(getBitmap(newStackTop.second),
getBitmap(logicalPlan), conditions);
if (joinType == null) {
this.setStatus(HintStatus.SYNTAX_ERROR);
this.setErrorMessage("JoinType can not be null");
} else if (!isConditionJoinTypeMatched(conditions, joinType)) {
this.setStatus(HintStatus.UNUSED);
this.setErrorMessage("condition does not matched joinType");
}
if (!this.isSuccess()) {
return null;
}
@ -379,7 +456,13 @@ public class LeadingHint extends Hint {
logicalPlan);
logicalJoin.setBitmap(LongBitmap.or(getBitmap(newStackTop.second), getBitmap(logicalPlan)));
if (stackTopLevel > 0) {
stackTopLevel--;
if (index < getTablelist().size()) {
if (stackTopLevel > getLevellist().get(index)) {
stackTopLevel--;
}
} else {
stackTopLevel--;
}
}
if (!stack.isEmpty()) {
newStackTop = stack.peek();
@ -401,17 +484,7 @@ public class LeadingHint extends Hint {
LogicalJoin finalJoin = (LogicalJoin) stack.pop().second;
// we want all filters been remove
if (!getFilters().isEmpty()) {
List<Expression> conditions = getLastConditions(getFilters());
Pair<List<Expression>, List<Expression>> pair = JoinUtils.extractExpressionForHashTable(
finalJoin.left().getOutput(), finalJoin.right().getOutput(), conditions);
finalJoin = new LogicalJoin<>(finalJoin.getJoinType(), pair.first,
pair.second,
JoinHint.NONE,
Optional.empty(),
finalJoin.left(),
finalJoin.right());
}
assert (filters.isEmpty());
if (finalJoin != null) {
this.setStatus(HintStatus.SUCCESS);
}
@ -468,6 +541,8 @@ public class LeadingHint extends Hint {
return getBitmap((LogicalPlan) root.child(0));
} else if (root instanceof LogicalProject) {
return getBitmap((LogicalPlan) root.child(0));
} else if (root instanceof LogicalSubQueryAlias) {
return LongBitmap.set(0L, (((LogicalSubQueryAlias) root).getRelationId().asInt()));
} else {
return null;
}
@ -484,11 +559,6 @@ public class LeadingHint extends Hint {
this.setErrorMessage("duplicated table");
return totalBitmap;
}
if (tables != null && getTablelist().size() != tables.size()) {
this.setStatus(HintStatus.SYNTAX_ERROR);
this.setErrorMessage("tables should be same as join tables");
return totalBitmap;
}
for (int index = 0; index < getTablelist().size(); index++) {
RelationId id = findRelationIdAndTableName(getTablelist().get(index));
if (id == null) {

View File

@ -0,0 +1,35 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.hint;
/**
* ordered hint.
*/
public class OrderedHint extends Hint {
public OrderedHint(String hintName) {
super(hintName);
}
@Override
public String getExplainString() {
StringBuilder out = new StringBuilder();
out.append("ORDERED");
return out.toString();
}
}

View File

@ -19,8 +19,6 @@ package org.apache.doris.nereids.jobs.executor;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.jobs.rewrite.RewriteJob;
import org.apache.doris.nereids.processor.pre.EliminateLogicalSelectHint;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.analysis.AdjustAggregateNullableForEmptySet;
import org.apache.doris.nereids.rules.analysis.AnalyzeCTE;
import org.apache.doris.nereids.rules.analysis.BindExpression;
@ -30,8 +28,12 @@ import org.apache.doris.nereids.rules.analysis.BindSink;
import org.apache.doris.nereids.rules.analysis.CheckAfterBind;
import org.apache.doris.nereids.rules.analysis.CheckAnalysis;
import org.apache.doris.nereids.rules.analysis.CheckPolicy;
import org.apache.doris.nereids.rules.analysis.CollectJoinConstraint;
import org.apache.doris.nereids.rules.analysis.CollectSubQueryAlias;
import org.apache.doris.nereids.rules.analysis.EliminateGroupByConstant;
import org.apache.doris.nereids.rules.analysis.EliminateLogicalSelectHint;
import org.apache.doris.nereids.rules.analysis.FillUpMissingSlots;
import org.apache.doris.nereids.rules.analysis.LeadingJoin;
import org.apache.doris.nereids.rules.analysis.NormalizeAggregate;
import org.apache.doris.nereids.rules.analysis.NormalizeRepeat;
import org.apache.doris.nereids.rules.analysis.OneRowRelationExtractAggregate;
@ -41,6 +43,7 @@ import org.apache.doris.nereids.rules.analysis.ReplaceExpressionByChildOutput;
import org.apache.doris.nereids.rules.analysis.ResolveOrdinalInOrderByAndGroupBy;
import org.apache.doris.nereids.rules.analysis.SubqueryToApply;
import org.apache.doris.nereids.rules.analysis.UserAuthentication;
import org.apache.doris.nereids.rules.rewrite.JoinCommute;
import java.util.List;
import java.util.Objects;
@ -84,9 +87,9 @@ public class Analyzer extends AbstractBatchJobExecutor {
private static List<RewriteJob> buildAnalyzeJobs(Optional<CustomTableResolver> customTableResolver) {
return jobs(
// we should eliminate hint after "Subquery unnesting" because some hint maybe exist in the CTE or subquery.
custom(RuleType.ELIMINATE_HINT, EliminateLogicalSelectHint::new),
// we should eliminate hint before "Subquery unnesting".
topDown(new AnalyzeCTE()),
topDown(new EliminateLogicalSelectHint()),
bottomUp(
new BindRelation(customTableResolver),
new CheckPolicy(),
@ -121,6 +124,12 @@ public class Analyzer extends AbstractBatchJobExecutor {
bottomUp(new CheckAnalysis()),
topDown(new EliminateGroupByConstant()),
topDown(new NormalizeAggregate()),
bottomUp(new JoinCommute()),
bottomUp(
new CollectSubQueryAlias(),
new CollectJoinConstraint()
),
topDown(new LeadingJoin()),
bottomUp(new SubqueryToApply())
);
}

View File

@ -43,7 +43,6 @@ import org.apache.doris.nereids.rules.rewrite.CheckDataTypes;
import org.apache.doris.nereids.rules.rewrite.CheckMatchExpression;
import org.apache.doris.nereids.rules.rewrite.CheckMultiDistinct;
import org.apache.doris.nereids.rules.rewrite.CollectFilterAboveConsumer;
import org.apache.doris.nereids.rules.rewrite.CollectJoinConstraint;
import org.apache.doris.nereids.rules.rewrite.CollectProjectAboveConsumer;
import org.apache.doris.nereids.rules.rewrite.ColumnPruning;
import org.apache.doris.nereids.rules.rewrite.ConvertInnerOrCrossJoin;
@ -74,7 +73,7 @@ import org.apache.doris.nereids.rules.rewrite.InferFilterNotNull;
import org.apache.doris.nereids.rules.rewrite.InferJoinNotNull;
import org.apache.doris.nereids.rules.rewrite.InferPredicates;
import org.apache.doris.nereids.rules.rewrite.InferSetOperatorDistinct;
import org.apache.doris.nereids.rules.rewrite.LeadingJoin;
import org.apache.doris.nereids.rules.rewrite.JoinCommute;
import org.apache.doris.nereids.rules.rewrite.LimitSortToTopN;
import org.apache.doris.nereids.rules.rewrite.MergeFilters;
import org.apache.doris.nereids.rules.rewrite.MergeOneRowRelationIntoUnion;
@ -106,7 +105,6 @@ import org.apache.doris.nereids.rules.rewrite.PushProjectIntoOneRowRelation;
import org.apache.doris.nereids.rules.rewrite.PushProjectThroughUnion;
import org.apache.doris.nereids.rules.rewrite.ReorderJoin;
import org.apache.doris.nereids.rules.rewrite.RewriteCteChildren;
import org.apache.doris.nereids.rules.rewrite.SemiJoinCommute;
import org.apache.doris.nereids.rules.rewrite.SimplifyAggGroupBy;
import org.apache.doris.nereids.rules.rewrite.SplitLimit;
import org.apache.doris.nereids.rules.rewrite.TransposeSemiJoinAgg;
@ -226,7 +224,7 @@ public class Rewriter extends AbstractBatchJobExecutor {
),
// push down SEMI Join
bottomUp(
new SemiJoinCommute(),
new JoinCommute(),
new TransposeSemiJoinLogicalJoin(),
new TransposeSemiJoinLogicalJoinProject(),
new TransposeSemiJoinAgg(),
@ -240,15 +238,6 @@ public class Rewriter extends AbstractBatchJobExecutor {
bottomUp(new EliminateNotNull()),
topDown(new ConvertInnerOrCrossJoin())
),
topic("LEADING JOIN",
bottomUp(
new CollectJoinConstraint()
),
custom(RuleType.LEADING_JOIN, LeadingJoin::new),
bottomUp(
new ExpressionRewrite(CheckLegalityAfterRewrite.INSTANCE)
)
),
topic("Column pruning and infer predicate",
custom(RuleType.COLUMN_PRUNING, ColumnPruning::new),
custom(RuleType.INFER_PREDICATES, InferPredicates::new),

View File

@ -150,9 +150,17 @@ public class LongBitmap {
return Long.numberOfTrailingZeros(bitmap);
}
/**
* use to calculate table bitmap
* @param relationIdSet relationIds
* @return bitmap
*/
public static Long computeTableBitmap(Set<RelationId> relationIdSet) {
Long totalBitmap = 0L;
for (RelationId id : relationIdSet) {
if (id == null) {
continue;
}
totalBitmap = LongBitmap.set(totalBitmap, (id.asInt()));
}
return totalBitmap;

View File

@ -193,6 +193,7 @@ import org.apache.doris.nereids.exceptions.ParseException;
import org.apache.doris.nereids.properties.OrderKey;
import org.apache.doris.nereids.properties.SelectHint;
import org.apache.doris.nereids.properties.SelectHintLeading;
import org.apache.doris.nereids.properties.SelectHintOrdered;
import org.apache.doris.nereids.properties.SelectHintSetVar;
import org.apache.doris.nereids.trees.TableSample;
import org.apache.doris.nereids.trees.expressions.Add;
@ -2556,6 +2557,9 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
}
hints.put(hintName, new SelectHintLeading(hintName, leadingParameters));
break;
case "ordered":
hints.put(hintName, new SelectHintOrdered(hintName));
break;
default:
break;
}

View File

@ -46,7 +46,6 @@ public class PlanPreprocessors {
public List<PlanPreprocessor> getProcessors() {
// add processor if we need
return ImmutableList.of(
new EliminateLogicalSelectHint(),
new TurnOffPipelineForDml()
);
}

View File

@ -0,0 +1,32 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.properties;
/**
* select hint.
*/
public class SelectHintOrdered extends SelectHint {
public SelectHintOrdered(String hintName) {
super(hintName);
}
@Override
public String toString() {
return super.getHintName();
}
}

View File

@ -108,7 +108,10 @@ public enum RuleType {
SIMPLIFY_AGG_GROUP_BY(RuleTypeClass.REWRITE),
DISTINCT_AGGREGATE_DISASSEMBLE(RuleTypeClass.REWRITE),
LOGICAL_SUB_QUERY_ALIAS_TO_LOGICAL_PROJECT(RuleTypeClass.REWRITE),
COLLECT_SUB_QUERY_ALIAS(RuleTypeClass.REWRITE),
ELIMINATE_GROUP_BY_CONSTANT(RuleTypeClass.REWRITE),
ELIMINATE_LOGICAL_SELECT_HINT(RuleTypeClass.REWRITE),
ELIMINATE_ORDER_BY_CONSTANT(RuleTypeClass.REWRITE),
ELIMINATE_HINT(RuleTypeClass.REWRITE),
ELIMINATE_JOIN_ON_EMPTYRELATION(RuleTypeClass.REWRITE),

View File

@ -128,9 +128,8 @@ public class BindRelation extends OneAnalysisRuleFactory {
if (analyzedCte.isPresent()) {
LogicalCTEConsumer consumer = new LogicalCTEConsumer(unboundRelation.getRelationId(),
cteContext.getCteId(), tableName, analyzedCte.get());
if (cascadesContext.getStatementContext().isLeadingJoin()) {
LeadingHint leading = (LeadingHint) cascadesContext.getStatementContext()
.getHintMap().get("Leading");
if (cascadesContext.isLeadingJoin()) {
LeadingHint leading = (LeadingHint) cascadesContext.getHintMap().get("Leading");
leading.putRelationIdAndTableName(Pair.of(consumer.getRelationId(), tableName));
leading.getRelationIdToScanMap().put(consumer.getRelationId(), consumer);
}
@ -156,8 +155,8 @@ public class BindRelation extends OneAnalysisRuleFactory {
// TODO: should generate different Scan sub class according to table's type
LogicalPlan scan = getLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
if (cascadesContext.getStatementContext().isLeadingJoin()) {
LeadingHint leading = (LeadingHint) cascadesContext.getStatementContext().getHintMap().get("Leading");
if (cascadesContext.isLeadingJoin()) {
LeadingHint leading = (LeadingHint) cascadesContext.getHintMap().get("Leading");
leading.putRelationIdAndTableName(Pair.of(unboundRelation.getRelationId(), tableName));
leading.getRelationIdToScanMap().put(unboundRelation.getRelationId(), scan);
}

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.rewrite;
package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.common.Pair;
import org.apache.doris.nereids.hint.Hint;
@ -24,11 +24,11 @@ import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.LongBitmap;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.RelationId;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
@ -47,24 +47,17 @@ public class CollectJoinConstraint implements RewriteRuleFactory {
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
logicalRelation().thenApply(ctx -> {
LeadingHint leading = (LeadingHint) ctx.cascadesContext
.getStatementContext().getHintMap().get("Leading");
if (leading == null) {
return ctx.root;
} else if (leading.isSyntaxError()) {
return ctx.root;
}
return ctx.root;
}).toRule(RuleType.COLLECT_JOIN_CONSTRAINT),
logicalJoin().thenApply(ctx -> {
LeadingHint leading = (LeadingHint) ctx.cascadesContext
.getStatementContext().getHintMap().get("Leading");
if (leading == null) {
if (!ctx.cascadesContext.isLeadingJoin()) {
return ctx.root;
}
LeadingHint leading = (LeadingHint) ctx.cascadesContext
.getHintMap().get("Leading");
LogicalJoin join = ctx.root;
if (join.getJoinType().isNullAwareLeftAntiJoin()) {
leading.setStatus(Hint.HintStatus.UNUSED);
leading.setErrorMessage("condition does not matched joinType");
}
List<Expression> expressions = join.getHashJoinConjuncts();
Long totalFilterBitMap = 0L;
Long nonNullableSlotBitMap = 0L;
@ -74,6 +67,7 @@ public class CollectJoinConstraint implements RewriteRuleFactory {
Long filterBitMap = calSlotsTableBitMap(leading, expression.getInputSlots(), false);
totalFilterBitMap = LongBitmap.or(totalFilterBitMap, filterBitMap);
leading.getFilters().add(Pair.of(filterBitMap, expression));
leading.putConditionJoinType(expression, join.getJoinType());
}
expressions = join.getOtherJoinConjuncts();
for (Expression expression : expressions) {
@ -82,6 +76,7 @@ public class CollectJoinConstraint implements RewriteRuleFactory {
Long filterBitMap = calSlotsTableBitMap(leading, expression.getInputSlots(), false);
totalFilterBitMap = LongBitmap.or(totalFilterBitMap, filterBitMap);
leading.getFilters().add(Pair.of(filterBitMap, expression));
leading.putConditionJoinType(expression, join.getJoinType());
}
Long leftHand = LongBitmap.computeTableBitmap(join.left().getInputRelations());
Long rightHand = LongBitmap.computeTableBitmap(join.right().getInputRelations());
@ -91,28 +86,13 @@ public class CollectJoinConstraint implements RewriteRuleFactory {
return ctx.root;
}).toRule(RuleType.COLLECT_JOIN_CONSTRAINT),
logicalFilter().thenApply(ctx -> {
LeadingHint leading = (LeadingHint) ctx.cascadesContext
.getStatementContext().getHintMap().get("Leading");
if (leading == null) {
return ctx.root;
}
LogicalFilter filter = ctx.root;
Set<Expression> expressions = filter.getConjuncts();
for (Expression expression : expressions) {
Long filterBitMap = calSlotsTableBitMap(leading, expression.getInputSlots(), false);
leading.getFilters().add(Pair.of(filterBitMap, expression));
}
return ctx.root;
}).toRule(RuleType.COLLECT_JOIN_CONSTRAINT),
logicalProject(logicalOlapScan()).thenApply(
ctx -> {
LeadingHint leading = (LeadingHint) ctx.cascadesContext
.getStatementContext().getHintMap().get("Leading");
if (leading == null) {
if (!ctx.cascadesContext.isLeadingJoin()) {
return ctx.root;
}
LeadingHint leading = (LeadingHint) ctx.cascadesContext
.getHintMap().get("Leading");
LogicalProject<LogicalOlapScan> project = ctx.root;
LogicalOlapScan scan = project.child();
leading.getRelationIdToScanMap().put(scan.getRelationId(), project);
@ -195,15 +175,11 @@ public class CollectJoinConstraint implements RewriteRuleFactory {
if (getNotNullable && slot.nullable()) {
continue;
}
if (!slot.isColumnFromTable()) {
if (!slot.isColumnFromTable() && (slot.getQualifier() == null || slot.getQualifier().isEmpty())) {
// we can not get info from column not from table
continue;
}
String tableName = leading.getExprIdToTableNameMap().get(slot.getExprId());
if (tableName == null) {
tableName = slot.getQualifier().get(slot.getQualifier().size() - 1);
leading.getExprIdToTableNameMap().put(slot.getExprId(), tableName);
}
String tableName = slot.getQualifier().get(slot.getQualifier().size() - 1);
RelationId id = leading.findRelationIdAndTableName(tableName);
if (id == null) {
leading.setStatus(Hint.HintStatus.SYNTAX_ERROR);

View File

@ -0,0 +1,69 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.common.Pair;
import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
import org.apache.doris.nereids.trees.plans.RelationId;
import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
import com.google.common.collect.ImmutableList;
import java.util.List;
/**
* Eliminate the logical sub query and alias node after analyze and before rewrite
* If we match the alias node and return its child node, in the execute() of the job
* <p>
* TODO: refactor group merge strategy to support the feature above
*/
public class CollectSubQueryAlias implements RewriteRuleFactory {
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
logicalSubQueryAlias().thenApply(ctx -> {
if (ctx.cascadesContext.isLeadingJoin()) {
String aliasName = ctx.root.getAlias();
LeadingHint leading = (LeadingHint) ctx.cascadesContext.getHintMap().get("Leading");
RelationId newId = ctx.statementContext.getNextRelationId();
leading.putRelationIdAndTableName(Pair.of(newId, aliasName));
leading.getRelationIdToScanMap().put(newId, ctx.root);
ctx.root.setRelationId(newId);
}
return ctx.root;
}).toRule(RuleType.COLLECT_JOIN_CONSTRAINT),
logicalRelation().thenApply(ctx -> {
if (ctx.cascadesContext.isLeadingJoin()) {
LeadingHint leading = (LeadingHint) ctx.cascadesContext.getHintMap().get("Leading");
LogicalRelation relation = (LogicalRelation) ctx.root;
RelationId relationId = relation.getRelationId();
if (ctx.root instanceof LogicalCatalogRelation) {
String relationName = ((LogicalCatalogRelation) ctx.root).getTable().getName();
leading.putRelationIdAndTableName(Pair.of(relationId, relationName));
}
leading.getRelationIdToScanMap().put(relationId, ctx.root);
}
return ctx.root;
}).toRule(RuleType.COLLECT_JOIN_CONSTRAINT)
);
}
}

View File

@ -15,22 +15,25 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.processor.pre;
package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.analysis.SetVar;
import org.apache.doris.analysis.StringLiteral;
import org.apache.doris.common.DdlException;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.StatementContext;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.jobs.JobContext;
import org.apache.doris.nereids.hint.OrderedHint;
import org.apache.doris.nereids.properties.SelectHint;
import org.apache.doris.nereids.properties.SelectHintLeading;
import org.apache.doris.nereids.properties.SelectHintSetVar;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalSelectHint;
import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.SessionVariable;
import org.apache.doris.qe.VariableMgr;
@ -38,38 +41,44 @@ import org.apache.doris.qe.VariableMgr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
/**
* eliminate set var hint, and set var to session variables.
* eliminate logical select hint and set them to cascade context
*/
public class EliminateLogicalSelectHint extends PlanPreprocessor implements CustomRewriter {
public class EliminateLogicalSelectHint extends OneRewriteRuleFactory {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public Plan rewriteRoot(Plan plan, JobContext jobContext) {
return plan.accept(this, jobContext.getCascadesContext().getStatementContext());
}
@Override
public LogicalPlan visitLogicalSelectHint(
LogicalSelectHint<? extends Plan> selectHintPlan,
StatementContext context) {
for (Entry<String, SelectHint> hint : selectHintPlan.getHints().entrySet()) {
String hintName = hint.getKey();
if (hintName.equalsIgnoreCase("SET_VAR")) {
setVar((SelectHintSetVar) hint.getValue(), context);
} else if (hintName.equalsIgnoreCase("ORDERED")) {
ConnectContext.get().getSessionVariable().setDisableJoinReorder(true);
} else if (hintName.equalsIgnoreCase("LEADING")) {
extractLeading((SelectHintLeading) hint.getValue(), context);
} else {
logger.warn("Can not process select hint '{}' and skip it", hint.getKey());
public Rule build() {
return logicalSelectHint().thenApply(ctx -> {
LogicalSelectHint<Plan> selectHintPlan = ctx.root;
for (Entry<String, SelectHint> hint : selectHintPlan.getHints().entrySet()) {
String hintName = hint.getKey();
if (hintName.equalsIgnoreCase("SET_VAR")) {
setVar((SelectHintSetVar) hint.getValue(), ctx.statementContext);
} else if (hintName.equalsIgnoreCase("ORDERED")) {
try {
ctx.cascadesContext.getConnectContext().getSessionVariable()
.disableNereidsJoinReorderOnce();
} catch (DdlException e) {
throw new RuntimeException(e);
}
OrderedHint ordered = new OrderedHint("Ordered");
ordered.setStatus(Hint.HintStatus.SUCCESS);
ctx.cascadesContext.getHintMap().put("Ordered", ordered);
ctx.statementContext.addHint(ordered);
} else if (hintName.equalsIgnoreCase("LEADING")) {
extractLeading((SelectHintLeading) hint.getValue(), ctx.cascadesContext,
ctx.statementContext, selectHintPlan.getHints());
} else {
logger.warn("Can not process select hint '{}' and skip it", hint.getKey());
}
}
}
return (LogicalPlan) selectHintPlan.child();
return selectHintPlan.child();
}).toRule(RuleType.ELIMINATE_LOGICAL_SELECT_HINT);
}
private void setVar(SelectHintSetVar selectHint, StatementContext context) {
@ -84,7 +93,7 @@ public class EliminateLogicalSelectHint extends PlanPreprocessor implements Cust
VariableMgr.setVar(sessionVariable, new SetVar(key, new StringLiteral(value.get())));
} catch (Throwable t) {
throw new AnalysisException("Can not set session variable '"
+ key + "' = '" + value.get() + "'", t);
+ key + "' = '" + value.get() + "'", t);
}
}
}
@ -101,15 +110,28 @@ public class EliminateLogicalSelectHint extends PlanPreprocessor implements Cust
}
}
private void extractLeading(SelectHintLeading selectHint, StatementContext context) {
private void extractLeading(SelectHintLeading selectHint, CascadesContext context,
StatementContext statementContext, Map<String, SelectHint> hints) {
LeadingHint hint = new LeadingHint("Leading", selectHint.getParameters(), selectHint.toString());
if (context.getHintMap().get("Leading") != null) {
hint.setStatus(Hint.HintStatus.SYNTAX_ERROR);
hint.setErrorMessage("can only have one leading clause");
context.getHintMap().get("Leading").setStatus(Hint.HintStatus.UNUSED);
hint.setErrorMessage("one query block can only have one leading clause");
statementContext.addHint(hint);
context.setLeadingJoin(false);
return;
}
hint.setStatus(Hint.HintStatus.SUCCESS);
statementContext.addHint(hint);
context.getHintMap().put("Leading", hint);
context.setLeadingJoin(true);
if (hints.get("ordered") != null || ConnectContext.get().getSessionVariable().isDisableJoinReorder()) {
context.setLeadingJoin(false);
hint.setStatus(Hint.HintStatus.UNUSED);
} else {
context.setLeadingJoin(true);
}
assert (selectHint != null);
assert (context != null);
}
}

View File

@ -0,0 +1,69 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.common.DdlException;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.LongBitmap;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableList;
import java.util.List;
/**
* Leading join is used to generate leading join and replace original logical join
*/
public class LeadingJoin implements RewriteRuleFactory {
@Override
public List<Rule> buildRules() {
return ImmutableList.of(
logicalJoin()
.whenNot(join -> ConnectContext.get().getSessionVariable().isDisableJoinReorder())
.thenApply(ctx -> {
if (!ctx.cascadesContext.isLeadingJoin()) {
return ctx.root;
}
Hint leadingHint = ctx.cascadesContext.getHintMap().get("Leading");
((LeadingHint) leadingHint).setTotalBitmap();
Long currentBitMap = LongBitmap.computeTableBitmap(ctx.root.getInputRelations());
if (((LeadingHint) leadingHint).getTotalBitmap().equals(currentBitMap)
&& leadingHint.isSuccess()) {
Plan leadingJoin = ((LeadingHint) leadingHint).generateLeadingJoinPlan();
if (leadingHint.isSuccess() && leadingJoin != null) {
try {
ctx.cascadesContext.getConnectContext().getSessionVariable()
.disableNereidsJoinReorderOnce();
ctx.cascadesContext.setLeadingJoin(false);
} catch (DdlException e) {
throw new RuntimeException(e);
}
return leadingJoin;
}
}
return ctx.root;
}).toRule(RuleType.LEADING_JOIN)
);
}
}

View File

@ -17,15 +17,10 @@
package org.apache.doris.nereids.rules.analysis;
import org.apache.doris.common.Pair;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
import org.apache.doris.nereids.trees.plans.RelationId;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
import com.google.common.collect.ImmutableList;
@ -42,24 +37,6 @@ public class LogicalSubQueryAliasToLogicalProject extends OneRewriteRuleFactory
logicalSubQueryAlias().thenApply(ctx -> {
LogicalProject project = new LogicalProject<>(
ImmutableList.copyOf(ctx.root.getOutput()), ctx.root.child());
if (ctx.cascadesContext.getStatementContext().isLeadingJoin()) {
String aliasName = ctx.root.getAlias();
LeadingHint leading = (LeadingHint) ctx.cascadesContext.getStatementContext()
.getHintMap().get("Leading");
if (!(project.child() instanceof LogicalRelation)) {
if (leading.getTablelist().contains(aliasName)) {
leading.setStatus(Hint.HintStatus.SYNTAX_ERROR);
leading.setErrorMessage("Leading alias can only be table name alias");
}
} else {
RelationId id = leading.findRelationIdAndTableName(aliasName);
if (id == null) {
id = ((LogicalRelation) project.child()).getRelationId();
}
leading.putRelationIdAndTableName(Pair.of(id, aliasName));
leading.getRelationIdToScanMap().put(id, project);
}
}
return project;
})
);

View File

@ -24,8 +24,10 @@ import org.apache.doris.qe.ConnectContext;
/**
* RightSemiJoin -> LeftSemiJoin
* RightAntiJoin -> LeftAntiJoin
* RightOuterJoin -> LeftOuterJoin
*/
public class SemiJoinCommute extends OneRewriteRuleFactory {
public class JoinCommute extends OneRewriteRuleFactory {
@Override
public Rule build() {
return logicalJoin()

View File

@ -1,84 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.common.DdlException;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.jobs.JobContext;
import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.LongBitmap;
import org.apache.doris.nereids.rules.rewrite.LeadingJoin.LeadingContext;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter;
import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
/**
* Leading join is used to generate leading join and replace original logical join
*/
public class LeadingJoin extends DefaultPlanRewriter<LeadingContext> implements CustomRewriter {
@Override
public Plan rewriteRoot(Plan plan, JobContext jobContext) {
if (jobContext.getCascadesContext().getStatementContext().isLeadingJoin()) {
Hint leadingHint = jobContext.getCascadesContext().getStatementContext().getHintMap().get("Leading");
Plan leadingPlan = plan.accept(this, new LeadingContext(
(LeadingHint) leadingHint, ((LeadingHint) leadingHint)
.getLeadingTableBitmap(jobContext.getCascadesContext().getTables())));
if (leadingHint.isSuccess()) {
try {
jobContext.getCascadesContext().getConnectContext().getSessionVariable()
.disableNereidsJoinReorderOnce();
} catch (DdlException e) {
throw new RuntimeException(e);
}
} else {
return plan;
}
return leadingPlan;
}
return plan;
}
@Override
public Plan visit(Plan plan, LeadingContext context) {
Long currentBitMap = LongBitmap.computeTableBitmap(plan.getInputRelations());
if (LongBitmap.isSubset(currentBitMap, context.totalBitmap)
&& plan instanceof LogicalJoin && !context.leading.isSyntaxError()) {
Plan leadingJoin = context.leading.generateLeadingJoinPlan();
if (context.leading.isSuccess() && leadingJoin != null) {
return leadingJoin;
}
} else {
return (LogicalPlan) super.visit(plan, context);
}
return plan;
}
/** LeadingContext */
public static class LeadingContext {
public LeadingHint leading;
public Long totalBitmap;
public LeadingContext(LeadingHint leading, Long totalBitmap) {
this.leading = leading;
this.totalBitmap = totalBitmap;
}
}
}

View File

@ -17,10 +17,7 @@
package org.apache.doris.nereids.trees.copier;
import org.apache.doris.common.Pair;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.hint.LeadingHint;
import org.apache.doris.nereids.properties.OrderKey;
import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.expressions.Expression;
@ -33,7 +30,6 @@ import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
import org.apache.doris.nereids.trees.expressions.SubqueryExpr;
import org.apache.doris.nereids.trees.expressions.functions.Function;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.RelationId;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalApply;
import org.apache.doris.nereids.trees.plans.logical.LogicalAssertNumRows;
@ -67,7 +63,6 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalTopN;
import org.apache.doris.nereids.trees.plans.logical.LogicalUnion;
import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@ -173,7 +168,6 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
olapScan.getManuallySpecifiedPartitions(), olapScan.getSelectedTabletIds(),
olapScan.getHints(), olapScan.getTableSample());
}
updateLeadingRelationIdMap(newOlapScan.getRelationId(), newOlapScan.getTable().getName(), newOlapScan);
newOlapScan.getOutput();
context.putRelation(olapScan.getRelationId(), newOlapScan);
updateReplaceMapWithOutput(olapScan, newOlapScan, context.exprIdReplaceMap);
@ -200,7 +194,6 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
}
LogicalSchemaScan newSchemaScan = new LogicalSchemaScan(StatementScopeIdGenerator.newRelationId(),
schemaScan.getTable(), schemaScan.getQualifier());
updateLeadingRelationIdMap(newSchemaScan.getRelationId(), newSchemaScan.getTable().getName(), newSchemaScan);
updateReplaceMapWithOutput(schemaScan, newSchemaScan, context.exprIdReplaceMap);
context.putRelation(schemaScan.getRelationId(), newSchemaScan);
return newSchemaScan;
@ -213,7 +206,6 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
}
LogicalFileScan newFileScan = new LogicalFileScan(StatementScopeIdGenerator.newRelationId(),
fileScan.getTable(), fileScan.getQualifier(), fileScan.getTableSample());
updateLeadingRelationIdMap(newFileScan.getRelationId(), fileScan.getTable().getName(), newFileScan);
updateReplaceMapWithOutput(fileScan, newFileScan, context.exprIdReplaceMap);
context.putRelation(fileScan.getRelationId(), newFileScan);
Set<Expression> conjuncts = fileScan.getConjuncts().stream()
@ -241,7 +233,6 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
}
LogicalJdbcScan newJdbcScan = new LogicalJdbcScan(StatementScopeIdGenerator.newRelationId(),
jdbcScan.getTable(), jdbcScan.getQualifier());
updateLeadingRelationIdMap(newJdbcScan.getRelationId(), jdbcScan.getTable().getName(), newJdbcScan);
updateReplaceMapWithOutput(jdbcScan, newJdbcScan, context.exprIdReplaceMap);
context.putRelation(jdbcScan.getRelationId(), newJdbcScan);
return newJdbcScan;
@ -255,7 +246,6 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
LogicalEsScan newEsScan = new LogicalEsScan(StatementScopeIdGenerator.newRelationId(),
esScan.getTable(), esScan.getQualifier());
updateReplaceMapWithOutput(esScan, newEsScan, context.exprIdReplaceMap);
updateLeadingRelationIdMap(newEsScan.getRelationId(), esScan.getTable().getName(), newEsScan);
context.putRelation(esScan.getRelationId(), newEsScan);
return newEsScan;
}
@ -455,7 +445,6 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
StatementScopeIdGenerator.newRelationId(),
cteConsumer.getCteId(), cteConsumer.getName(),
consumerToProducerOutputMap, producerToConsumerOutputMap);
updateLeadingRelationIdMap(newCTEConsumer.getRelationId(), cteConsumer.getName(), newCTEConsumer);
context.putRelation(cteConsumer.getRelationId(), newCTEConsumer);
return newCTEConsumer;
}
@ -474,12 +463,4 @@ public class LogicalPlanDeepCopier extends DefaultPlanRewriter<DeepCopierContext
}
}
private void updateLeadingRelationIdMap(RelationId id, String tableName, LogicalPlan plan) {
if (!ConnectContext.get().getStatementContext().isLeadingJoin()) {
return;
}
Hint leading = ConnectContext.get().getStatementContext().getHintMap().get("Leading");
((LeadingHint) leading).updateRelationIdByTableName(Pair.of(id, tableName));
((LeadingHint) leading).getRelationIdToScanMap().put(id, plan);
}
}

View File

@ -185,10 +185,18 @@ public enum JoinType {
return this == LEFT_SEMI_JOIN || this == RIGHT_SEMI_JOIN;
}
public final boolean isAntiJoin() {
return this == LEFT_ANTI_JOIN || this == RIGHT_ANTI_JOIN;
}
public final boolean isOuterJoin() {
return this == LEFT_OUTER_JOIN || this == RIGHT_OUTER_JOIN || this == FULL_OUTER_JOIN;
}
public final boolean isOneSideOuterJoin() {
return this == LEFT_OUTER_JOIN || this == RIGHT_OUTER_JOIN;
}
public final boolean isRemainLeftJoin() {
return this != RIGHT_SEMI_JOIN && this != RIGHT_ANTI_JOIN;
}

View File

@ -64,7 +64,6 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
private final JoinType joinType;
private final List<Expression> otherJoinConjuncts;
private final List<Expression> hashJoinConjuncts;
private final JoinHint hint;
// When the predicate condition contains subqueries and disjunctions, the join will be marked as MarkJoin.
private final Optional<MarkJoinSlotReference> markJoinSlotReference;
@ -74,6 +73,8 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
// Table bitmap for tables below this join
private long bitmap = LongBitmap.newBitmap();
private JoinHint hint;
public LogicalJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
this(joinType, ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE,
Optional.empty(), Optional.empty(), Optional.empty(), leftChild, rightChild);
@ -216,6 +217,10 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
return hint;
}
public void setHint(JoinHint hint) {
this.hint = hint;
}
public boolean isMarkJoin() {
return markJoinSlotReference.isPresent();
}

View File

@ -24,11 +24,13 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.RelationId;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.nereids.util.Utils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
@ -36,6 +38,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
/**
@ -45,6 +48,7 @@ import java.util.function.Supplier;
*/
public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> {
protected RelationId relationId;
private final List<String> qualifier;
private final Optional<List<String>> columnAliases;
@ -170,4 +174,19 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends LogicalUnary<
builder.replace(replaceMap);
return builder.build();
}
public void setRelationId(RelationId relationId) {
this.relationId = relationId;
}
public RelationId getRelationId() {
return relationId;
}
@Override
public Set<RelationId> getInputRelations() {
Set<RelationId> relationIdSet = Sets.newHashSet();
relationIdSet.add(relationId);
return relationIdSet;
}
}

View File

@ -0,0 +1,153 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.jobs.joinorder.joinhint;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.datasets.tpch.TPCHTestBase;
import org.apache.doris.nereids.properties.SelectHint;
import org.apache.doris.nereids.properties.SelectHintLeading;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
import org.apache.doris.nereids.trees.plans.logical.LogicalSelectHint;
import org.apache.doris.nereids.util.HyperGraphBuilder;
import org.apache.doris.nereids.util.MemoTestUtils;
import org.apache.doris.nereids.util.PlanChecker;
import com.google.common.collect.Maps;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JoinHintTest extends TPCHTestBase {
private int used = 0;
private int unused = 0;
private int syntaxError = 0;
private int successCases = 0;
private int unsuccessCases = 0;
private List<String> failCases = new ArrayList<>();
@Test
public void testLeading() {
for (int t = 3; t < 10; t++) {
for (int e = t - 1; e <= (t * (t - 1)) / 2; e++) {
for (int i = 0; i < 10; i++) {
System.out.println("TableNumber: " + String.valueOf(t) + " EdgeNumber: " + e + " Iteration: " + i);
randomTest(t, e, false, true);
}
}
}
int totalCases = successCases + unsuccessCases;
System.out.println("TotalCases: " + totalCases + "\tSuccessCases: " + successCases + unsuccessCases + "\tUnSuccessCases: " + 0);
for (String treePlan : failCases) {
System.out.println(treePlan);
}
}
@Test
public void testHintJoin() {
for (int t = 3; t < 10; t++) {
for (int e = t - 1; e <= (t * (t - 1)) / 2; e++) {
for (int i = 0; i < 10; i++) {
System.out.println("TableNumber: " + String.valueOf(t) + " EdgeNumber: " + e + " Iteration: " + i);
randomTest(t, e, true, false);
}
}
}
int totalCases = successCases + unsuccessCases;
System.out.println("TotalCases: " + totalCases + "\tSuccessCases: " + successCases + "\tUnSuccessCases: " + unsuccessCases);
for (String treePlan : failCases) {
System.out.println(treePlan);
}
}
private Plan generateLeadingHintPlan(int tableNum, Plan childPlan) {
Map<String, SelectHint> hints = Maps.newLinkedHashMap();
List<String> leadingParameters = new ArrayList<String>();
for (int i = 0; i < tableNum; i++) {
leadingParameters.add(String.valueOf(i));
}
Collections.shuffle(leadingParameters);
System.out.println("LeadingHint: " + leadingParameters.toString());
hints.put("leading", new SelectHintLeading("leading", leadingParameters));
return new LogicalSelectHint<>(hints, childPlan);
}
private void randomTest(int tableNum, int edgeNum, boolean withJoinHint, boolean withLeading) {
HyperGraphBuilder hyperGraphBuilder = new HyperGraphBuilder();
Plan plan = withJoinHint ? hyperGraphBuilder.buildJoinPlanWithJoinHint(tableNum, edgeNum) :
hyperGraphBuilder.randomBuildPlanWith(tableNum, edgeNum);
plan = new LogicalProject(plan.getOutput(), plan);
Set<List<String>> res1 = hyperGraphBuilder.evaluate(plan);
if (!withLeading) {
CascadesContext cascadesContext = MemoTestUtils.createCascadesContext(connectContext, plan);
hyperGraphBuilder.initStats(cascadesContext);
Plan optimizedPlan = PlanChecker.from(cascadesContext)
.analyze()
.optimize()
.getBestPlanTree();
Set<List<String>> res2 = hyperGraphBuilder.evaluate(optimizedPlan);
if (!res1.equals(res2)) {
System.out.println(plan.treeString());
System.out.println(optimizedPlan.treeString());
cascadesContext = MemoTestUtils.createCascadesContext(connectContext, plan);
PlanChecker.from(cascadesContext).dpHypOptimize().getBestPlanTree();
System.out.println(res1);
System.out.println(res2);
unsuccessCases++;
failCases.add(plan.treeString());
failCases.add(optimizedPlan.treeString());
}
successCases++;
} else {
// generate select hint
for (int i = 0; i < (tableNum * tableNum - 1); i++) {
Plan leadingPlan = generateLeadingHintPlan(tableNum, plan);
CascadesContext cascadesContext = MemoTestUtils.createCascadesContext(connectContext, leadingPlan);
hyperGraphBuilder.initStats(cascadesContext);
Plan optimizedPlan = PlanChecker.from(cascadesContext)
.analyze()
.optimize()
.getBestPlanTree();
Set<List<String>> res2 = hyperGraphBuilder.evaluate(optimizedPlan);
if (!res1.equals(res2)) {
System.out.println(leadingPlan.treeString());
System.out.println(optimizedPlan.treeString());
cascadesContext = MemoTestUtils.createCascadesContext(connectContext, plan);
PlanChecker.from(cascadesContext).dpHypOptimize().getBestPlanTree();
System.out.println(res1);
System.out.println(res2);
unsuccessCases++;
failCases.add(leadingPlan.treeString());
failCases.add(optimizedPlan.treeString());
}
successCases++;
}
}
}
}

View File

@ -137,8 +137,10 @@ class PushDownLimitTest extends TestWithFeService implements MemoPatternMatchSup
@Test
void testPushLimitThroughRightJoin() {
ConnectContext context = MemoTestUtils.createConnectContext();
context.getSessionVariable().setDisableJoinReorder(true);
// after use RelationUtil to allocate relation id, the id will increase when getNextId() called.
test(JoinType.RIGHT_OUTER_JOIN, true,
testWithContext(context, JoinType.RIGHT_OUTER_JOIN, true,
logicalLimit(
logicalProject(
rightOuterLogicalJoin(
@ -148,7 +150,7 @@ class PushDownLimitTest extends TestWithFeService implements MemoPatternMatchSup
)
)
);
test(JoinType.RIGHT_OUTER_JOIN, false,
testWithContext(context, JoinType.RIGHT_OUTER_JOIN, false,
logicalLimit(
rightOuterLogicalJoin(
logicalOlapScan().when(s -> s.getTable().getName().equals("score")),
@ -355,6 +357,15 @@ class PushDownLimitTest extends TestWithFeService implements MemoPatternMatchSup
.matchesFromRoot(pattern);
}
private void testWithContext(ConnectContext context, JoinType joinType, boolean hasProject, PatternDescriptor<? extends Plan> pattern) {
Plan plan = generatePlan(joinType, hasProject);
PlanChecker.from(context)
.analyze(plan)
.applyTopDown(new ConvertInnerOrCrossJoin())
.applyTopDown(new PushDownLimit())
.matchesFromRoot(pattern);
}
private Plan generatePlan(JoinType joinType, boolean hasProject) {
ImmutableList<Expression> joinConditions =
joinType == JoinType.CROSS_JOIN || joinType == JoinType.INNER_JOIN

View File

@ -50,9 +50,9 @@ public class InferTest extends SqlTestBase {
.matches(
logicalProject(
innerLogicalJoin(
logicalOlapScan(),
logicalFilter().when(
f -> f.getPredicate().toString().equals("((id#0 = 4) OR (id#0 > 4))")),
logicalOlapScan()
f -> f.getPredicate().toString().equals("((id#0 = 4) OR (id#0 > 4))"))
)
)
);
@ -89,8 +89,8 @@ public class InferTest extends SqlTestBase {
.rewrite()
.matches(
innerLogicalJoin(
leftSemiLogicalJoin(),
logicalProject()
logicalProject(),
leftSemiLogicalJoin()
)
);
}

View File

@ -27,6 +27,7 @@ import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.JoinHint;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@ -50,6 +51,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -115,7 +117,7 @@ public class HyperGraphBuilder {
public Plan buildJoinPlan() {
assert plans.size() == 1 : "there are cross join";
Plan plan = plans.values().iterator().next();
return buildPlanWithJoinType(plan, new BitSet());
return buildPlanWithJoinType(plan, new BitSet(), false);
}
public Plan randomBuildPlanWith(int tableNum, int edgeNum) {
@ -128,6 +130,13 @@ public class HyperGraphBuilder {
return this.build();
}
public Plan buildJoinPlanWithJoinHint(int tableNum, int edgeNum) {
randomBuildInit(tableNum, edgeNum);
assert plans.size() == 1 : "there are cross join";
Plan plan = plans.values().iterator().next();
return buildPlanWithJoinType(plan, new BitSet(), true);
}
private void randomBuildInit(int tableNum, int edgeNum) {
Preconditions.checkArgument(edgeNum >= tableNum - 1,
"We can't build a connected graph with %s tables %s edges", tableNum, edgeNum);
@ -242,7 +251,7 @@ public class HyperGraphBuilder {
return this;
}
private Plan buildPlanWithJoinType(Plan plan, BitSet requireTable) {
private Plan buildPlanWithJoinType(Plan plan, BitSet requireTable, boolean withJoinHint) {
if (!(plan instanceof LogicalJoin)) {
return plan;
}
@ -269,11 +278,20 @@ public class HyperGraphBuilder {
}
}
Plan left = buildPlanWithJoinType(join.left(), requireTable);
Plan right = buildPlanWithJoinType(join.right(), requireTable);
Plan left = buildPlanWithJoinType(join.left(), requireTable, withJoinHint);
Plan right = buildPlanWithJoinType(join.right(), requireTable, withJoinHint);
Set<Slot> outputs = Stream.concat(left.getOutput().stream(), right.getOutput().stream())
.collect(Collectors.toSet());
assert outputs.containsAll(requireSlots);
if (withJoinHint) {
JoinHint[] values = JoinHint.values();
Random random = new Random();
int randomIndex = random.nextInt(values.length);
JoinHint hint = values[randomIndex];
Plan hintJoin = ((LogicalJoin) join.withChildren(left, right)).withJoinType(joinType);
((LogicalJoin) hintJoin).setHint(hint);
return hintJoin;
}
return ((LogicalJoin) join.withChildren(left, right)).withJoinType(joinType);
}
@ -528,6 +546,8 @@ public class HyperGraphBuilder {
matchPair.stream().map(p -> Pair.of(p.second, p.first)).collect(Collectors.toList()));
case NULL_AWARE_LEFT_ANTI_JOIN:
return calLNAAJ(left, right, matchPair);
case CROSS_JOIN:
return calFOJ(left, right, matchPair);
default:
assert false;
}

View File

@ -23,6 +23,7 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.memo.GroupId;
import org.apache.doris.nereids.memo.Memo;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalSelectHint;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Assertions;
@ -52,7 +53,7 @@ public class MemoValidator {
MemoValidator validator = validate(memo);
if (initPlan != null) {
if (initPlan instanceof UnboundResultSink) {
if (initPlan instanceof UnboundResultSink || initPlan instanceof LogicalSelectHint) {
return validator;
}
Assertions.assertEquals(initPlan, memo.getRoot().getLogicalExpression().getPlan());

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,223 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
suite("load") {
String database = context.config.getDbNameByFile(context.file)
sql "drop database if exists ${database}"
sql "create database ${database}"
sql "use ${database}"
sql """
drop table if exists lineitem;
"""
sql """
CREATE TABLE lineitem (
l_shipdate DATEV2 NOT NULL,
l_orderkey bigint NOT NULL,
l_linenumber int not null,
l_partkey int NOT NULL,
l_suppkey int not null,
l_quantity decimal(15, 2) NOT NULL,
l_extendedprice decimal(15, 2) NOT NULL,
l_discount decimal(15, 2) NOT NULL,
l_tax decimal(15, 2) NOT NULL,
l_returnflag VARCHAR(1) NOT NULL,
l_linestatus VARCHAR(1) NOT NULL,
l_commitdate DATEV2 NOT NULL,
l_receiptdate DATEV2 NOT NULL,
l_shipinstruct VARCHAR(25) NOT NULL,
l_shipmode VARCHAR(10) NOT NULL,
l_comment VARCHAR(44) NOT NULL
)ENGINE=OLAP
DUPLICATE KEY(`l_shipdate`, `l_orderkey`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`l_orderkey`) BUCKETS 96
PROPERTIES (
"replication_num" = "1",
"colocate_with" = "lineitem_orders"
);
"""
sql """
drop table if exists orders;
"""
sql '''
CREATE TABLE orders (
o_orderkey bigint NOT NULL,
o_orderdate DATEV2 NOT NULL,
o_custkey int NOT NULL,
o_orderstatus VARCHAR(1) NOT NULL,
o_totalprice decimal(15, 2) NOT NULL,
o_orderpriority VARCHAR(15) NOT NULL,
o_clerk VARCHAR(15) NOT NULL,
o_shippriority int NOT NULL,
o_comment VARCHAR(79) NOT NULL
)ENGINE=OLAP
DUPLICATE KEY(`o_orderkey`, `o_orderdate`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`o_orderkey`) BUCKETS 96
PROPERTIES (
"replication_num" = "1",
"colocate_with" = "lineitem_orders"
); '''
sql '''
drop table if exists partsupp;
'''
sql '''
CREATE TABLE partsupp (
ps_partkey int NOT NULL,
ps_suppkey int NOT NULL,
ps_availqty int NOT NULL,
ps_supplycost decimal(15, 2) NOT NULL,
ps_comment VARCHAR(199) NOT NULL
)ENGINE=OLAP
DUPLICATE KEY(`ps_partkey`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`ps_partkey`) BUCKETS 24
PROPERTIES (
"replication_num" = "1",
"colocate_with" = "part_partsupp"
);
'''
sql '''
drop table if exists part;
'''
sql '''
CREATE TABLE part (
p_partkey int NOT NULL,
p_name VARCHAR(55) NOT NULL,
p_mfgr VARCHAR(25) NOT NULL,
p_brand VARCHAR(10) NOT NULL,
p_type VARCHAR(25) NOT NULL,
p_size int NOT NULL,
p_container VARCHAR(10) NOT NULL,
p_retailprice decimal(15, 2) NOT NULL,
p_comment VARCHAR(23) NOT NULL
)ENGINE=OLAP
DUPLICATE KEY(`p_partkey`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`p_partkey`) BUCKETS 24
PROPERTIES (
"replication_num" = "1",
"colocate_with" = "part_partsupp"
);
'''
sql '''
drop table if exists customer;
'''
sql '''
CREATE TABLE customer (
c_custkey int NOT NULL,
c_name VARCHAR(25) NOT NULL,
c_address VARCHAR(40) NOT NULL,
c_nationkey int NOT NULL,
c_phone VARCHAR(15) NOT NULL,
c_acctbal decimal(15, 2) NOT NULL,
c_mktsegment VARCHAR(10) NOT NULL,
c_comment VARCHAR(117) NOT NULL
)ENGINE=OLAP
DUPLICATE KEY(`c_custkey`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`c_custkey`) BUCKETS 24
PROPERTIES (
"replication_num" = "1"
);
'''
sql '''
drop table if exists supplier
'''
sql '''
CREATE TABLE supplier (
s_suppkey int NOT NULL,
s_name VARCHAR(25) NOT NULL,
s_address VARCHAR(40) NOT NULL,
s_nationkey int NOT NULL,
s_phone VARCHAR(15) NOT NULL,
s_acctbal decimal(15, 2) NOT NULL,
s_comment VARCHAR(101) NOT NULL
)ENGINE=OLAP
DUPLICATE KEY(`s_suppkey`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`s_suppkey`) BUCKETS 12
PROPERTIES (
"replication_num" = "1"
);
'''
sql '''
drop table if exists nation;
'''
sql '''
CREATE TABLE `nation` (
`n_nationkey` int(11) NOT NULL,
`n_name` varchar(25) NOT NULL,
`n_regionkey` int(11) NOT NULL,
`n_comment` varchar(152) NULL
) ENGINE=OLAP
DUPLICATE KEY(`N_NATIONKEY`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`N_NATIONKEY`) BUCKETS 1
PROPERTIES (
"replication_num" = "1"
);
'''
sql '''
drop table if exists region;
'''
sql '''
CREATE TABLE region (
r_regionkey int NOT NULL,
r_name VARCHAR(25) NOT NULL,
r_comment VARCHAR(152)
)ENGINE=OLAP
DUPLICATE KEY(`r_regionkey`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`r_regionkey`) BUCKETS 1
PROPERTIES (
"replication_num" = "1"
);
'''
sql '''
drop view if exists revenue0;
'''
sql '''
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= date '1996-01-01'
and l_shipdate < date '1996-01-01' + interval '3' month
group by
l_suppkey;
'''
}

View File

@ -1,57 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q1") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set parallel_pipeline_task_num=8'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= date '1998-12-01' - interval '90' day
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus;
"""
}

View File

@ -1,72 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q10") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(lineitem {{customer orders} nation}) */
c_custkey,
c_name,
sum(l_extendedprice * (1 - l_discount)) as revenue,
c_acctbal,
n_name,
c_address,
c_phone,
c_comment
from
customer,
orders,
lineitem,
nation
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate >= date '1993-10-01'
and o_orderdate < date '1993-10-01' + interval '3' month
and l_returnflag = 'R'
and c_nationkey = n_nationkey
group by
c_custkey,
c_name,
c_acctbal,
c_phone,
n_name,
c_address,
c_comment
order by
revenue desc
limit 20;
"""
}

View File

@ -1,68 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q12") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(orders lineitem) */
l_shipmode,
sum(case
when o_orderpriority = '1-URGENT'
or o_orderpriority = '2-HIGH'
then 1
else 0
end) as high_line_count,
sum(case
when o_orderpriority <> '1-URGENT'
and o_orderpriority <> '2-HIGH'
then 1
else 0
end) as low_line_count
from
orders,
lineitem
where
o_orderkey = l_orderkey
and l_shipmode in ('MAIL', 'SHIP')
and l_commitdate < l_receiptdate
and l_shipdate < l_commitdate
and l_receiptdate >= date '1994-01-01'
and l_receiptdate < date '1994-01-01' + interval '1' year
group by
l_shipmode
order by
l_shipmode;
"""
}

View File

@ -1,57 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q13") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(orders customer) */
c_count,
count(*) as custdist
from
(
select
c_custkey,
count(o_orderkey) as c_count
from
customer left outer join orders on
c_custkey = o_custkey
and o_comment not like '%special%requests%'
group by
c_custkey
) as c_orders
group by
c_count
order by
custdist desc,
c_count desc;
"""
}

View File

@ -1,50 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q14") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(part lineitem) */
100.00 * sum(case
when p_type like 'PROMO%'
then l_extendedprice * (1 - l_discount)
else 0
end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue
from
lineitem,
part
where
l_partkey = p_partkey
and l_shipdate >= date '1995-09-01'
and l_shipdate < date '1995-09-01' + interval '1' month;
"""
}

View File

@ -1,70 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q16") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(partsupp part supplier) */
p_brand,
p_type,
p_size,
count(distinct ps_suppkey) as supplier_cnt
from
partsupp,
part
where
p_partkey = ps_partkey
and p_brand <> 'Brand#45'
and p_type not like 'MEDIUM POLISHED%'
and p_size in (49, 14, 23, 45, 19, 3, 36, 9)
and ps_suppkey not in (
select
s_suppkey
from
supplier
where
s_comment like '%Customer%Complaints%'
)
group by
p_brand,
p_type,
p_size
order by
supplier_cnt desc,
p_brand,
p_type,
p_size;
"""
}

View File

@ -1,77 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q19") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(lineitem part) */
sum(l_extendedprice* (1 - l_discount)) as revenue
from
lineitem,
part
where
(
p_partkey = l_partkey
and p_brand = 'Brand#12'
and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')
and l_quantity >= 1 and l_quantity <= 1 + 10
and p_size between 1 and 5
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
)
or
(
p_partkey = l_partkey
and p_brand = 'Brand#23'
and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')
and l_quantity >= 10 and l_quantity <= 10 + 10
and p_size between 1 and 10
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
)
or
(
p_partkey = l_partkey
and p_brand = 'Brand#34'
and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')
and l_quantity >= 20 and l_quantity <= 20 + 10
and p_size between 1 and 15
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
);
"""
}

View File

@ -1,67 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q3") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
// db = "tpch"
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set parallel_pipeline_task_num=8'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(lineitem {orders customer}) */
l_orderkey,
sum(l_extendedprice * (1 - l_discount)) as revenue,
o_orderdate,
o_shippriority
from
customer,
orders,
lineitem
where
c_mktsegment = 'BUILDING'
and c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate < date '1995-03-15'
and l_shipdate > date '1995-03-15'
group by
l_orderkey,
o_orderdate,
o_shippriority
order by
revenue desc,
o_orderdate
limit 10;
"""
}

View File

@ -1,63 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q4") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set parallel_pipeline_task_num=8'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(lineitem orders) */
o_orderpriority,
count(*) as order_count
from
orders
where
o_orderdate >= date '1993-07-01'
and o_orderdate < date '1993-07-01' + interval '3' month
and exists (
select
*
from
lineitem
where
l_orderkey = o_orderkey
and l_commitdate < l_receiptdate
)
group by
o_orderpriority
order by
o_orderpriority;
"""
}

View File

@ -1,63 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q5") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set parallel_pipeline_task_num=8'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
sql "set ignore_shape_nodes='PhysicalDistribute,PhysicalProject'"
qt_select """
explain shape plan
select
/*+ leading(lineitem {supplier {nation region}} orders customer) */
n_name,
sum(l_extendedprice * (1 - l_discount)) as revenue
from
customer,
orders,
lineitem,
supplier,
nation,
region
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and l_suppkey = s_suppkey
and c_nationkey = s_nationkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'ASIA'
and o_orderdate >= date '1994-01-01'
and o_orderdate < date '1994-01-01' + interval '1' year
group by
n_name
order by
revenue desc;
"""
}

View File

@ -1,45 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q6") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set global exec_mem_limit = 21G'
sql 'SET enable_pipeline_engine = true'
sql 'set parallel_pipeline_task_num=8'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
sum(l_extendedprice * l_discount) as revenue
from
lineitem
where
l_shipdate >= date '1994-01-01'
and l_shipdate < date '1994-01-01' + interval '1' year
and l_discount between .06 - 0.01 and .06 + 0.01
and l_quantity < 24;
"""
}

View File

@ -1,69 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
suite("q9") {
String db = context.config.getDbNameByFile(new File(context.file.parent))
sql "use ${db}"
sql 'set enable_nereids_planner=true'
sql 'set enable_fallback_to_original_planner=false'
sql "set runtime_filter_mode='GLOBAL'"
sql 'set parallel_pipeline_task_num=8'
sql 'set exec_mem_limit=21G'
sql 'SET enable_pipeline_engine = true'
sql 'set be_number_for_test=3'
sql "set enable_runtime_filter_prune=false"
qt_select """
explain shape plan
select
/*+ leading(orders {{lineitem part} {supplier nation}} partsupp) */
nation,
o_year,
sum(amount) as sum_profit
from
(
select
n_name as nation,
extract(year from o_orderdate) as o_year,
l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount
from
part,
supplier,
lineitem,
partsupp,
orders,
nation
where
s_suppkey = l_suppkey
and ps_suppkey = l_suppkey
and ps_partkey = l_partkey
and p_partkey = l_partkey
and o_orderkey = l_orderkey
and s_nationkey = n_nationkey
and p_name like '%green%'
) as profit
group by
nation,
o_year
order by
nation,
o_year desc;
"""
}

View File

@ -38,80 +38,895 @@ suite("test_leading") {
sql """create table t3 (c3 int, c33 int) distributed by hash(c3) buckets 3 properties('replication_num' = '1');"""
sql """create table t4 (c4 int, c44 int) distributed by hash(c4) buckets 3 properties('replication_num' = '1');"""
sql '''
alter table t1 modify column c1 set stats ('ndv'='1', 'avg_size'='1', 'max_size'='1', 'num_nulls'='0', 'min_value'='1', 'max_value'='1', 'row_count'='10000')
'''
sql '''
alter table t2 modify column c2 set stats ('ndv'='1', 'avg_size'='1', 'max_size'='1', 'num_nulls'='0', 'min_value'='1', 'max_value'='1', 'row_count'='10000')
'''
sql '''
alter table t3 modify column c3 set stats ('ndv'='1', 'avg_size'='1', 'max_size'='1', 'num_nulls'='0', 'min_value'='1', 'max_value'='1', 'row_count'='10000')
'''
sql '''
alter table t4 modify column c4 set stats ('ndv'='1', 'avg_size'='1', 'max_size'='1', 'num_nulls'='0', 'min_value'='1', 'max_value'='1', 'row_count'='10000')
'''
streamLoad {
table "t1"
db "test_leading"
set 'column_separator', '|'
set 'format', 'csv'
file 't1.csv'
time 10000
}
streamLoad {
table "t2"
db "test_leading"
set 'column_separator', '|'
set 'format', 'csv'
file 't2.csv'
time 10000
}
streamLoad {
table "t3"
db "test_leading"
set 'column_separator', '|'
set 'format', 'csv'
file 't3.csv'
time 10000
}
streamLoad {
table "t4"
db "test_leading"
set 'column_separator', '|'
set 'format', 'csv'
file 't4.csv'
time 10000
}
//// check table count
qt_select1_1 """select count(*) from t1;"""
qt_select1_2 """select count(*) from t2;"""
qt_select1_3 """select count(*) from t3;"""
qt_select1_4 """select count(*) from t4;"""
//// test inner join with all edge and vertax is complete and equal predicates
qt_select1 """explain shape plan select /*+ leading(t2 t1) */ * from t1 join t2 on c1 = c2;"""
qt_select2 """explain shape plan select /*+ leading(t1 t2) */ * from t1 join t2 on c1 = c2;"""
qt_select3 """explain shape plan select /*+ leading(t1 t2 t3) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select4 """explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select5 """explain shape plan select /*+ leading(t1 {t2 t3} t4) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select6 """explain shape plan select /*+ leading({t1 t2} {t3 t4}) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select2_1 """select count(*) from t1 join t2 on c1 = c2;"""
qt_select2_2 """select /*+ leading(t2 t1) */ count(*) from t1 join t2 on c1 = c2;"""
qt_select2_3 """select /*+ leading(t1 t2) */ count(*) from t1 join t2 on c1 = c2;"""
// test inner join with part of edge and need cross join
qt_select7 """explain shape plan select /*+ leading({t1 t2} {t3 t4}) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select3_1 """select count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_5 """select /*+ leading(t1 {t3 t2}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_6 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_7 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_8 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_9 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select3_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
//// test outer join which can swap
// (A leftjoin B on (Pab)) innerjoin C on (Pac) = (A innerjoin C on (Pac)) leftjoin B on (Pab)
qt_select8 """explain shape plan select * from t1 left join t2 on c1 = c2 join t3 on c1 = c3;"""
qt_select9 """explain shape plan select /*+ leading(t1 t3 t2) */ * from t1 left join t2 on c1 = c2 join t3 on c1 = c3;"""
// (A leftjoin B on (Pab)) leftjoin C on (Pac) = (A leftjoin C on (Pac)) leftjoin B on (Pab)
qt_select10 """explain shape plan select * from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;"""
qt_select11 """explain shape plan select /*+ leading(t1 t3 t2) */ * from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;"""
qt_select4_1 """select count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select4_2 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select4_3 """select /*+ leading({t1 t2} {t3 t4}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select4_4 """select /*+ leading(t1 {t2 t3 t4}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select4_5 """select /*+ leading(t1 {t2 {t3 t4}}) */ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select5_1 """select count(*) from t1 join t2 on c1 > c2;"""
qt_select5_2 """select /*+ leading(t2 t1) */ count(*) from t1 join t2 on c1 > c2;"""
qt_select6_1 """select count(*) from t1 join t2 on c1 > c2 join t3 on c2 > c3 where c1 < 100;"""
qt_select6_2 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 > c2 join t3 on c2 > c3 where c1 < 100;"""
// (A leftjoin B on (Pab)) leftjoin C on (Pac) = (A leftjoin C on (Pac)) leftjoin B on (Pab)
qt_select7_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;"""
qt_select7_2 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3;"""
qt_select8_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3 where c1 between 100 and 300;"""
qt_select8_2 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3 where c1 between 100 and 300;"""
qt_select9_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3 where c3 between 100 and 300;"""
qt_select9_2 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3 where c3 between 100 and 300;"""
qt_select10_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3 where c2 between 100 and 300;"""
qt_select10_2 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 = c3 where c2 between 100 and 300;"""
qt_select11_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 > c3 where c3 between 100 and 300;"""
qt_select11_2 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c1 > c3 where c3 between 100 and 300;"""
// (A leftjoin B on (Pab)) leftjoin C on (Pbc) = A leftjoin (B leftjoin C on (Pbc)) on (Pab)
qt_select12 """explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
//// test outer join which can not swap
qt_select12_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select12_2 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select13_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 between 100 and 300;"""
qt_select13_2 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 between 100 and 300;"""
qt_select14_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c2 between 100 and 300;"""
qt_select14_2 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c2 between 100 and 300;"""
qt_select15_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c3 between 100 and 300;"""
qt_select15_2 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c3 between 100 and 300;"""
//// test outer join which can not swap
// A leftjoin (B join C on (Pbc)) on (Pab) != (A leftjoin B on (Pab)) join C on (Pbc) output should be unused when explain
// this can be done because left join can be eliminated to inner join
qt_select13 """explain shape plan select /*+ leading(t1 {t2 t3}) */ * from t1 left join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select16_1 """select count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3;"""
qt_select16_2 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3;"""
// this can not be done, expect not success but return right deep tree
qt_select14 """explain shape plan select * from t1 left join (select * from t2 join t3 on c2 = c3) as tmp on c1 = c2;"""
qt_select15 """explain shape plan select /*+ leading(t1 t2 t3) */ * from t1 left join (select * from t2 join t3 on c2 = c3) as tmp on c1 = c2;"""
// inner join + full outer join
qt_select17_1 """select count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
qt_select17_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 full join t3 on c2 = c3;"""
//// test semi join
qt_select16 """explain shape plan select * from t1 where c1 in (select c2 from t2);"""
qt_select17 """explain shape plan select /*+ leading(t2 t1) */ * from t1 where c1 in (select c2 from t2);"""
// inner join + left outer join
qt_select18_1 """select count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select18_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 left join t3 on c2 = c3;"""
//// test anti join
qt_select18 """explain shape plan select * from t1 where exists (select 1 from t2);"""
qt_select19 """explain shape plan select /*+ leading (t2 t1) */ * from t1 where exists (select 1 from t2);"""
// inner join + right outer join
qt_select19_1 """select count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select19_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 right join t3 on c2 = c3;"""
//// test cte
// inline cte, change join order of tables inside cte
qt_select20 """explain shape plan with cte as (select * from t1 join t2 on c1 = c2) select * from cte, t2;"""
qt_select21 """explain shape plan with cte as (select * from t1 join t2 on c1 = c2) select /*+ leading(t2 t1 t3) */ * from cte, t3;"""
// outside cte
// inside and outside together (after unnest subquery)
// inner join + semi join
qt_select20_1 """select count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select20_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
//// test syntax error and unsupported feature
// not exist tables in leading: syntax error
qt_select22 """explain shape plan select /*+ leading(t66 t1) */ * from t1 join t2 on c1 = c2;"""
qt_select23 """explain shape plan select /*+ leading(t3 t1) */ * from t1 join t2 on c1 = c2;"""
// subquery alias as leading table
qt_select24 """explain shape plan with cte as (select * from t1 join t2 on c1 = c2) select /*+ leading(t2 cte t1) */ * from cte, t2;"""
// do not have all tables inside hint
qt_select25 """explain shape plan select /*+ leading(t1 t2) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
// duplicated table
qt_select26 """explain shape plan select /*+ leading(t1 t1 t2 t3) */ * from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
// inner join + anti join
qt_select21_1 """select count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select21_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
//// test table alias
qt_select27 """explain shape plan select /*+ leading(t1 t_2) */ * from t1 join t2 t_2 on c1 = c2;"""
qt_select28 """explain shape plan select /*+ leading(t1 t2) */ * from t1 join t2 t_2 on c1 = c2;"""
qt_select29 """explain shape plan select /*+ leading(t1 t_1) */ * from t1 join t1 t_1 on t1.c1 = t_1.c1;"""
// left join + left join
qt_select22_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
qt_select22_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3;"""
// left join + right join
qt_select23_1 """select count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
qt_select23_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3;"""
// left join + semi join
qt_select24_1 """select count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select24_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
// left join + anti join
qt_select25_1 """select count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select25_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
// right join + semi join
qt_select26_1 """select count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
qt_select26_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3;"""
// right join + anti join
qt_select27_1 """select count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
qt_select27_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3;"""
// semi join + anti join
qt_select28_1 """select count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
qt_select28_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3;"""
// left join + left join + inner join
qt_select32_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select32_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
// left join + right join + inner join
qt_select33_1 """select count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select33_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
// left join + semi join + inner join
qt_select34_1 """select count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select34_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
// left join + anti join + inner join
qt_select35_1 """select count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select35_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
// right join + semi join + inner join
qt_select36_1 """select count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select36_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
// right join + anti join + inner join
qt_select37_1 """select count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select37_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
// semi join + anti join + inner join
qt_select38_1 """select count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_2 """select /*+ leading(t1 t2 t3 t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_3 """select /*+ leading(t1 {t2 t3} t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_4 """select /*+ leading(t1 t3 t2 t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_5 """select /*+ leading(t1 {t2 t2} t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_6 """select /*+ leading(t2 t1 t3 t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_7 """select /*+ leading(t2 {t1 t3} t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_8 """select /*+ leading(t2 t3 t1 t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_9 """select /*+ leading(t2 {t3 t1} t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_10 """select /*+ leading(t3 t1 t2 t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_11 """select /*+ leading(t3 {t1 t2} t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_12 """select /*+ leading(t3 t2 t1 t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select38_13 """select /*+ leading(t3 {t2 t1} t4) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
// left join + left join + inner join
qt_select42_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select42_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 join t4 on c3 = c4;"""
// left join + right join + inner join
qt_select43_1 """select count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
qt_select43_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 join t4 on c3 = c4;"""
// left join + semi join + inner join
qt_select44_1 """select count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select44_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
// left join + anti join + inner join
qt_select45_1 """select count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select45_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
// right join + semi join + inner join
qt_select46_1 """select count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select46_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 join t4 on c1 = c4;"""
// right join + anti join + inner join
qt_select47_1 """select count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
qt_select47_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 join t4 on c1 = c4;"""
// semi join + anti join + inner join
qt_select48_1 """select count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_2 """select /*+ leading(t1 t2 t4 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_3 """select /*+ leading(t1 {t2 t4} t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_4 """select /*+ leading(t1 t4 t2 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_5 """select /*+ leading(t1 {t4 t2} t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_6 """select /*+ leading(t2 t1 t4 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_7 """select /*+ leading(t2 {t1 t4} t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_8 """select /*+ leading(t2 t4 t1 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_9 """select /*+ leading(t2 {t4 t1} t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_10 """select /*+ leading(t4 t1 t2 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_11 """select /*+ leading(t4 {t1 t2} t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_12 """select /*+ leading(t4 t2 t1 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
qt_select48_13 """select /*+ leading(t4 {t2 t1} t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 join t4 on c1 = c4;"""
// left join + left join + inner join
qt_select49_1 """select count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3 left join t4 on t3.c3 = t4.c4;"""
qt_select49_2 """select /*+ leading(t1 t2 {t3 t4}) */ count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3 left join t4 on t3.c3 = t4.c4;"""
qt_select49_3 """select /*+ leading({t1 t2} t3 t4) */ count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3 left join t4 on t3.c3 = t4.c4;"""
qt_select49_4 """select /*+ leading({t1 t3} t2 t4) */ count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3 left join t4 on t3.c3 = t4.c4;"""
qt_select49_5 """select /*+ leading(t1 {t3 t4} t2) */ count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3 left join t4 on t3.c3 = t4.c4;"""
qt_select49_6 """select /*+ leading({t1 t3} t4 t2) */ count(*) from t1 left join t2 on c1 = c2 join t3 on c2 = c3 left join t4 on t3.c3 = t4.c4;"""
// cte
qt_select50_1 """with cte as (select * from t1 join t2 on c1 = c2) select count(*) from cte, t2;"""
qt_select50_2 """with cte as (select /*+ leading(t2 t1) */* from t1 join t2 on c1 = c2) select /*+ leading(cte t3) */ count(*) from cte, t3;"""
qt_select50_3 """with cte as (select /*+ leading(t2 t1) */* from t1 join t2 on c1 = c2) select count(*) from cte, t3;"""
qt_select50_4 """with cte as (select * from t1 join t2 on c1 = c2) select /*+ leading(cte t3) */ count(*) from cte, t3;"""
// in subquery +
// inner join + anti join
qt_select51_1 """select count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select51_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// left join + left join
qt_select52_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select52_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// left join + right join
qt_select53_1 """select count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select53_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// left join + semi join
qt_select54_1 """select count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select54_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// left join + anti join
qt_select55_1 """select count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select55_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// right join + semi join
qt_select56_1 """select count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select56_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// right join + anti join
qt_select57_1 """select count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
qt_select57_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where c1 in (select c4 from t4);"""
// semi join + anti join
qt_select58_1 """select count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
qt_select58_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where c1 in (select c4 from t4);"""
// exists subquery +
// inner join + anti join
qt_select61_1 """select count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select61_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + left join
qt_select62_1 """select count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select62_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + right join
qt_select63_1 """select count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select63_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + semi join
qt_select64_1 """select count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select64_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + anti join
qt_select65_1 """select count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select65_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// right join + semi join
qt_select66_1 """select count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select66_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 right join t2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// right join + anti join
qt_select67_1 """select count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select67_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 right join t2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// semi join + anti join
qt_select68_1 """select count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_2 """select /*+ leading(t1 t2 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_3 """select /*+ leading(t1 {t2 t3}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_5 """select /*+ leading(t1 {t2 t2}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_6 """select /*+ leading(t2 t1 t3) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_7 """select /*+ leading(t2 {t1 t3}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_8 """select /*+ leading(t2 t3 t1) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_9 """select /*+ leading(t2 {t3 t1}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_12 """select /*+ leading(t3 t2 t1) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select68_13 """select /*+ leading(t3 {t2 t1}) */ count(*) from t1 left semi join t2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// wrong table name
qt_select70_1 """explain shape plan select /*+ leading(t1 t3) */ count(*) from t1 join t2 on c1 = c2;"""
qt_select70_2 """explain shape plan select /*+ leading(t1 t5) */ count(*) from t1 join t2 on c1 = c2;"""
// duplicate table name
qt_select71_1 """explain shape plan select /*+ leading(t1 t1 t2) */ count(*) from t1 join t2 on c1 = c2;"""
qt_select71_2 """explain shape plan select /*+ leading(t1 t2 t2) */ count(*) from t1 join t2 on c1 = c2;"""
// different scope
qt_select72_1 """explain shape plan select count(*) from t1 join t2 on c1 = c2 where c2 in (select /*+ leading(t4 t3) */ c3 from t3 join t4 on c3 = c4);"""
qt_select72_2 """explain shape plan select /*+ leading(t1 t2) */ count(*) from t1 join t2 on c1 = c2 where c2 in (select c3 from t3 join t4 on c3 = c4);"""
// multi leading hint
qt_select73_1 """explain shape plan select /*+ leading(t1 t2) */ count(*) from t1 join t2 on c1 = c2 where c2 in (select /*+ leading(t4 t3) */ c3 from t3 join t4 on c3 = c4);"""
// alias
// inner join + anti join
qt_select81_1 """select count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select81_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + left join
qt_select82_1 """select count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select82_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + right join
qt_select83_1 """select count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select83_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 right join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + semi join
qt_select84_1 """select count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select84_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// left join + anti join
qt_select85_1 """select count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select85_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 left join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// right join + semi join
qt_select86_1 """select count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select86_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left semi join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// right join + anti join
qt_select87_1 """select count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select87_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 right join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c2 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
// semi join + anti join
qt_select88_1 """select count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_2 """select /*+ leading(t1 alias2 t3) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_3 """select /*+ leading(t1 {alias2 t3}) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_4 """select /*+ leading(t1 t3 t2) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_5 """select /*+ leading(t1 {alias2 t2}) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_6 """select /*+ leading(alias2 t1 t3) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_7 """select /*+ leading(alias2 {t1 t3}) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_8 """select /*+ leading(alias2 t3 t1) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_9 """select /*+ leading(alias2 {t3 t1}) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_10 """select /*+ leading(t3 t1 t2) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_11 """select /*+ leading(t3 {t1 t2}) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_12 """select /*+ leading(t3 alias2 t1) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
qt_select88_13 """select /*+ leading(t3 {alias2 t1}) */ count(*) from t1 left semi join (select c2 from t2) as alias2 on c1 = c2 left anti join t3 on c1 = c3 where exists (select 1 from t3 join t4 on c3 = c4);"""
sql """drop table if exists t1;"""
sql """drop table if exists t2;"""