Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions core/translate/planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,10 @@ pub fn parse_where(
end,
} = e
{
if expr_contains_subquery(lhs) {
return Ok(WalkControl::Continue);
}

let lhs_expr = std::mem::take(lhs.as_mut());
let start_expr = std::mem::take(start.as_mut());
let end_expr = std::mem::take(end.as_mut());
Expand Down Expand Up @@ -1544,6 +1548,21 @@ pub fn parse_where(
}
}

fn expr_contains_subquery(expr: &Expr) -> bool {
let mut found_subquery = false;
let _ = walk_expr(expr, &mut |e| {
if matches!(
e,
Expr::Subquery(_) | Expr::InSelect { .. } | Expr::Exists(_)
) {
found_subquery = true;
return Ok(WalkControl::SkipChildren);
}
Ok(WalkControl::Continue)
});
found_subquery
}

/**
Returns the earliest point at which a WHERE term can be evaluated.
For expressions referencing tables, this is the innermost loop that contains a row for each
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
source: subqueries.sqltest
expression: SELECT id FROM products WHERE ((SELECT max(id) FROM products) + 1) BETWEEN 2 AND 4;
info:
statement_type: SELECT
tables:
- products
setup_blocks:
- schema
database: ':memory:'
---
QUERY PLAN
|--SCALAR SUBQUERY 1
| `--SCAN products
`--SCAN products

BYTECODE
addr opcode p1 p2 p3 p4 p5 comment
0 Init 0 36 0 0 Start at 36
1 Once 18 0 0 0 goto 18
2 BeginSubrtn 2 0 0 0 r[2]=NULL
3 Null 0 1 0 0 r[1]=NULL
4 Null 0 4 0 0 r[4]=NULL
5 Integer 1 5 0 0 r[5]=1; LIMIT counter
6 IfNot 5 14 0 0 if !r[5] goto 14
7 OpenRead 0 2 0 k(5,B,B,B,B,B) 0 table=products, root=2, iDb=0
8 Last 0 14 0 0
9 RowId 0 6 0 0 r[6]=products.rowid
10 CollSeq 0 0 0 Binary 0 collation=Binary
11 AggStep 0 6 4 max 0 accum=r[4] step(r[6])
12 Goto 0 14 0 0
13 Prev 0 9 0 0
14 AggFinal 0 4 0 max 0 accum=r[4]
15 Copy 4 3 0 0 r[3]=r[4]
16 Copy 3 1 0 0 r[1]=r[3]
17 Return 2 0 1 0
18 OpenRead 1 2 0 k(5,B,B,B,B,B) 0 table=products, root=2, iDb=0
19 Copy 1 10 0 0 r[10]=r[1]
20 Add 10 11 9 0 r[9]=r[10]+r[11]
21 Copy 9 13 0 0 r[13]=r[9]
22 Integer 1 12 0 0 r[12]=1
23 Ge 13 14 25 0 if r[13]>=r[14] goto 25
24 ZeroOrNull 13 12 14 0 ((r[13]=NULL)|(r[14]=NULL)) ? r[12]=NULL : r[12]=0
25 Copy 9 16 0 0 r[16]=r[9]
26 Integer 1 15 0 0 r[15]=1
27 Le 16 17 29 0 if r[16]<=r[17] goto 29
28 ZeroOrNull 16 15 17 0 ((r[16]=NULL)|(r[17]=NULL)) ? r[15]=NULL : r[15]=0
29 And 15 12 8 0 r[8]=(r[12] && r[15])
30 IfNot 8 35 1 0 if !r[8] goto 35
31 Rewind 1 35 0 0 Rewind table products
32 RowId 1 7 0 0 r[7]=products.rowid
33 ResultRow 7 1 0 0 output=r[7]
34 Next 1 32 0 0
35 Halt 0 0 0 0
36 Transaction 0 1 11 0 iDb=0 tx_mode=Read
37 Integer 1 11 0 0 r[11]=1
38 Integer 2 14 0 0 r[14]=2
39 Integer 4 17 0 0 r[17]=4
40 Goto 0 1 0 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
source: subqueries.sqltest
expression: SELECT id FROM products WHERE (SELECT max(id) FROM products) BETWEEN 1 AND 3;
info:
statement_type: SELECT
tables:
- products
setup_blocks:
- schema
database: ':memory:'
---
QUERY PLAN
|--SCALAR SUBQUERY 1
| `--SCAN products
`--SCAN products

BYTECODE
addr opcode p1 p2 p3 p4 p5 comment
0 Init 0 35 0 0 Start at 35
1 Once 18 0 0 0 goto 18
2 BeginSubrtn 2 0 0 0 r[2]=NULL
3 Null 0 1 0 0 r[1]=NULL
4 Null 0 4 0 0 r[4]=NULL
5 Integer 1 5 0 0 r[5]=1; LIMIT counter
6 IfNot 5 14 0 0 if !r[5] goto 14
7 OpenRead 0 2 0 k(5,B,B,B,B,B) 0 table=products, root=2, iDb=0
8 Last 0 14 0 0
9 RowId 0 6 0 0 r[6]=products.rowid
10 CollSeq 0 0 0 Binary 0 collation=Binary
11 AggStep 0 6 4 max 0 accum=r[4] step(r[6])
12 Goto 0 14 0 0
13 Prev 0 9 0 0
14 AggFinal 0 4 0 max 0 accum=r[4]
15 Copy 4 3 0 0 r[3]=r[4]
16 Copy 3 1 0 0 r[1]=r[3]
17 Return 2 0 1 0
18 OpenRead 1 2 0 k(5,B,B,B,B,B) 0 table=products, root=2, iDb=0
19 Copy 1 9 0 0 r[9]=r[1]
20 Copy 9 11 0 0 r[11]=r[9]
21 Integer 1 10 0 0 r[10]=1
22 Ge 11 12 24 0 if r[11]>=r[12] goto 24
23 ZeroOrNull 11 10 12 0 ((r[11]=NULL)|(r[12]=NULL)) ? r[10]=NULL : r[10]=0
24 Copy 9 14 0 0 r[14]=r[9]
25 Integer 1 13 0 0 r[13]=1
26 Le 14 15 28 0 if r[14]<=r[15] goto 28
27 ZeroOrNull 14 13 15 0 ((r[14]=NULL)|(r[15]=NULL)) ? r[13]=NULL : r[13]=0
28 And 13 10 8 0 r[8]=(r[10] && r[13])
29 IfNot 8 34 1 0 if !r[8] goto 34
30 Rewind 1 34 0 0 Rewind table products
31 RowId 1 7 0 0 r[7]=products.rowid
32 ResultRow 7 1 0 0 output=r[7]
33 Next 1 31 0 0
34 Halt 0 0 0 0
35 Transaction 0 1 11 0 iDb=0 tx_mode=Read
36 Integer 1 12 0 0 r[12]=1
37 Integer 3 15 0 0 r[15]=3
38 Goto 0 1 0 0
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ setup schema {
# SCALAR SUBQUERIES
# =============================================================================

# BETWEEN in WHERE should not duplicate a scalar subquery on the left-hand side.
@setup schema
snapshot between-lhs-scalar-subquery {
SELECT id FROM products WHERE (SELECT max(id) FROM products) BETWEEN 1 AND 3;
}

# BETWEEN in WHERE should not duplicate a nested scalar subquery on the left-hand side.
@setup schema
snapshot between-lhs-nested-scalar-subquery {
SELECT id FROM products WHERE ((SELECT max(id) FROM products) + 1) BETWEEN 2 AND 4;
}

# Scalar subquery in SELECT - returns single value from aggregation
@setup schema
snapshot scalar-subquery-max-price {
Expand Down
Loading