1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use toasty_core::stmt;
use crate::engine::simplify::Simplify;
impl Simplify<'_> {
pub(super) fn simplify_stmt_query_when_empty(&mut self, stmt: &mut stmt::Query) {
if stmt.with.is_some() {
// Just skip if there are any CTEs for now
return;
}
if self.stmt_query_is_empty(stmt) {
stmt.body = stmt::ExprSet::Values(Default::default());
stmt.order_by = None;
stmt.limit = None;
}
}
pub(super) fn stmt_query_is_empty(&self, query: &stmt::Query) -> bool {
match &query.body {
stmt::ExprSet::Values(values) => values.is_empty(),
stmt::ExprSet::Select(select) => self.stmt_select_is_empty(select),
_ => false,
}
}
pub(super) fn stmt_select_is_empty(&self, select: &stmt::Select) -> bool {
// Only check table sources (lowered queries)
let stmt::Source::Table(source_table) = &select.source else {
return false;
};
if select.filter.is_false() {
return true;
}
// Check if the source guarantees empty results
self.source_table_is_empty(source_table)
}
fn source_table_is_empty(&self, source_table: &stmt::SourceTable) -> bool {
if source_table.from.is_empty() {
todo!(
"this case is not handled yet at this level; \
Do we want to handle this or transform the statement \
to something different first?"
);
}
// Get the primary relation from the first table
let stmt::TableFactor::Table(primary_table_id) = &source_table.from[0].relation;
// Check if primary source is empty VALUES
if self.table_ref_is_empty_values(&source_table.tables[primary_table_id.0]) {
// Primary source is empty - result will be empty unless there are
// LEFT JOINs that could still produce results
return !source_table
.from
.iter()
.flat_map(|twj| &twj.joins)
.any(|join| matches!(join.constraint, stmt::JoinOp::Left(_)));
}
// Check if any non-optional join has empty VALUES
// Currently only LEFT joins exist, so any other join would be INNER
// For now, this is conservative - we'd add INNER/CROSS join detection here
false
}
fn table_ref_is_empty_values(&self, table_ref: &stmt::TableRef) -> bool {
match table_ref {
stmt::TableRef::Derived(derived) => {
// Check if the derived table is empty VALUES. Inner queries
// would have already been simplified, so we only need to check
// for empty values here.
matches!(&derived.subquery.body,
stmt::ExprSet::Values(values) if values.is_empty()
)
}
_ => false,
}
}
}