Skip to content

Commit b6700ac

Browse files
authored
implement Subquery (#86)
* feat: implement table aliases * feat: implement subquery * fix: the corresponding TableName cannot be found when binding Table is allowed (e.g. when there is a join in the subquery and no alias is declared) * style: code fmt
1 parent 8786f0f commit b6700ac

File tree

13 files changed

+170
-55
lines changed

13 files changed

+170
-55
lines changed

src/binder/copy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl<'a, T: Transaction> Binder<'a, T> {
6969
}
7070
};
7171

72-
if let Some(table) = self.context.transaction.table(&table_name.to_string()) {
72+
if let Some(table) = self.context.table(&table_name.to_string()) {
7373
let cols = table.all_columns();
7474
let ext_source = ExtSource {
7575
path: match target {

src/binder/delete.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ impl<'a, T: Transaction> Binder<'a, T> {
1111
from: &TableWithJoins,
1212
selection: &Option<Expr>,
1313
) -> Result<LogicalPlan, BindError> {
14-
if let TableFactor::Table { name, .. } = &from.relation {
14+
if let TableFactor::Table { name, alias, .. } = &from.relation {
1515
let name = lower_case_name(name);
1616
let (_, name) = split_name(&name)?;
17-
let (table_name, mut plan) = self._bind_single_table_ref(None, name)?;
17+
let (table_name, mut plan) =
18+
self._bind_single_table_ref(None, name, Self::trans_alias(alias))?;
1819

1920
if let Some(predicate) = selection {
2021
plan = self.bind_where(plan, predicate)?;

src/binder/expr.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ impl<'a, T: Transaction> Binder<'a, T> {
5959
if let Some(table) = table_name.or(bind_table_name) {
6060
let table_catalog = self
6161
.context
62-
.transaction
6362
.table(table)
6463
.ok_or_else(|| BindError::InvalidTable(table.to_string()))?;
6564

src/binder/insert.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl<'a, T: Transaction> Binder<'a, T> {
2424
let (_, name) = split_name(&name)?;
2525
let table_name = Arc::new(name.to_string());
2626

27-
if let Some(table) = self.context.transaction.table(&table_name) {
27+
if let Some(table) = self.context.table(&table_name) {
2828
let mut columns = Vec::new();
2929

3030
if idents.is_empty() {

src/binder/mod.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ pub enum InputRefType {
2828

2929
#[derive(Clone)]
3030
pub struct BinderContext<'a, T: Transaction> {
31-
pub(crate) transaction: &'a T,
31+
transaction: &'a T,
3232
pub(crate) bind_table: BTreeMap<TableName, (TableCatalog, Option<JoinType>)>,
3333
aliases: BTreeMap<String, ScalarExpression>,
34+
table_aliases: BTreeMap<String, TableName>,
3435
group_by_exprs: Vec<ScalarExpression>,
3536
pub(crate) agg_calls: Vec<ScalarExpression>,
3637
}
@@ -41,11 +42,20 @@ impl<'a, T: Transaction> BinderContext<'a, T> {
4142
transaction,
4243
bind_table: Default::default(),
4344
aliases: Default::default(),
45+
table_aliases: Default::default(),
4446
group_by_exprs: vec![],
4547
agg_calls: Default::default(),
4648
}
4749
}
4850

51+
pub fn table(&self, table_name: &String) -> Option<&TableCatalog> {
52+
if let Some(real_name) = self.table_aliases.get(table_name) {
53+
self.transaction.table(real_name)
54+
} else {
55+
self.transaction.table(table_name)
56+
}
57+
}
58+
4959
// Tips: The order of this index is based on Aggregate being bound first.
5060
pub fn input_ref_index(&self, ty: InputRefType) -> usize {
5161
match ty {
@@ -54,12 +64,42 @@ impl<'a, T: Transaction> BinderContext<'a, T> {
5464
}
5565
}
5666

57-
pub fn add_alias(&mut self, alias: String, expr: ScalarExpression) {
58-
if self.aliases.contains_key(&alias) {
59-
return;
67+
pub fn add_alias(&mut self, alias: String, expr: ScalarExpression) -> Result<(), BindError> {
68+
let is_exist = self.aliases.insert(alias.clone(), expr).is_some();
69+
if is_exist {
70+
return Err(BindError::InvalidColumn(format!("{} duplicated", alias)));
71+
}
72+
73+
Ok(())
74+
}
75+
76+
pub fn add_table_alias(&mut self, alias: String, table: TableName) -> Result<(), BindError> {
77+
let is_alias_exist = self
78+
.table_aliases
79+
.insert(alias.clone(), table.clone())
80+
.is_some();
81+
if is_alias_exist {
82+
return Err(BindError::InvalidTable(format!("{} duplicated", alias)));
83+
}
84+
85+
Ok(())
86+
}
87+
88+
pub fn add_bind_table(
89+
&mut self,
90+
table: TableName,
91+
table_catalog: TableCatalog,
92+
join_type: Option<JoinType>,
93+
) -> Result<(), BindError> {
94+
let is_bound = self
95+
.bind_table
96+
.insert(table.clone(), (table_catalog.clone(), join_type))
97+
.is_some();
98+
if is_bound {
99+
return Err(BindError::InvalidTable(format!("{} duplicated", table)));
60100
}
61101

62-
self.aliases.insert(alias, expr);
102+
Ok(())
63103
}
64104

65105
pub fn has_agg_call(&self, expr: &ScalarExpression) -> bool {
@@ -175,8 +215,8 @@ pub enum BindError {
175215
AmbiguousColumn(String),
176216
#[error("binary operator types mismatch: {0} != {1}")]
177217
BinaryOpTypeMismatch(String, String),
178-
#[error("subquery in FROM must have an alias")]
179-
SubqueryMustHaveAlias,
218+
#[error("subquery error: {0}")]
219+
Subquery(String),
180220
#[error("agg miss: {0}")]
181221
AggMiss(String),
182222
#[error("catalog error: {0}")]

src/binder/select.rs

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use itertools::Itertools;
3131
use sqlparser::ast;
3232
use sqlparser::ast::{
3333
Distinct, Expr, Ident, Join, JoinConstraint, JoinOperator, Offset, OrderByExpr, Query, Select,
34-
SelectItem, SetExpr, TableFactor, TableWithJoins,
34+
SelectItem, SetExpr, TableAlias, TableFactor, TableWithJoins,
3535
};
3636

3737
impl<'a, T: Transaction> Binder<'a, T> {
@@ -128,18 +128,25 @@ impl<'a, T: Transaction> Binder<'a, T> {
128128
let (left_name, mut plan) = self.bind_single_table_ref(relation, None)?;
129129

130130
if !joins.is_empty() {
131+
let left_name = Self::unpack_name(left_name, true);
132+
131133
for join in joins {
132-
plan = self.bind_join(left_name.clone(), plan, join)?;
134+
plan = self.bind_join(&left_name, plan, join)?;
133135
}
134136
}
135137
Ok(plan)
136138
}
137139

140+
fn unpack_name(table_name: Option<TableName>, is_left: bool) -> TableName {
141+
let title = if is_left { "Left" } else { "Right" };
142+
table_name.expect(&format!("{}: Table is not named", title))
143+
}
144+
138145
fn bind_single_table_ref(
139146
&mut self,
140147
table: &TableFactor,
141148
joint_type: Option<JoinType>,
142-
) -> Result<(TableName, LogicalPlan), BindError> {
149+
) -> Result<(Option<TableName>, LogicalPlan), BindError> {
143150
let plan_with_name = match table {
144151
TableFactor::Table { name, alias, .. } => {
145152
let obj_name = name
@@ -148,45 +155,69 @@ impl<'a, T: Transaction> Binder<'a, T> {
148155
.map(|ident| Ident::new(ident.value.to_lowercase()))
149156
.collect_vec();
150157

151-
let (_database, _schema, mut table): (&str, &str, &str) = match obj_name.as_slice()
152-
{
158+
let (_database, _schema, table): (&str, &str, &str) = match obj_name.as_slice() {
153159
[table] => (DEFAULT_DATABASE_NAME, DEFAULT_SCHEMA_NAME, &table.value),
154160
[schema, table] => (DEFAULT_DATABASE_NAME, &schema.value, &table.value),
155161
[database, schema, table] => (&database.value, &schema.value, &table.value),
156162
_ => return Err(BindError::InvalidTableName(obj_name)),
157163
};
158-
if let Some(alias) = alias {
159-
table = &alias.name.value;
160-
}
161164

162-
self._bind_single_table_ref(joint_type, table)?
165+
let (table, plan) =
166+
self._bind_single_table_ref(joint_type, table, Self::trans_alias(alias))?;
167+
(Some(table), plan)
168+
}
169+
TableFactor::Derived {
170+
subquery, alias, ..
171+
} => {
172+
let plan = self.bind_query(subquery)?;
173+
let mut tables = plan.referenced_table();
174+
175+
if let Some(alias) = Self::trans_alias(alias) {
176+
let alias = Arc::new(alias.clone());
177+
178+
if tables.len() > 1 {
179+
todo!("Implement virtual tables for multiple table aliases");
180+
}
181+
// FIXME
182+
self.context
183+
.add_table_alias(alias.to_string(), tables.remove(0))?;
184+
185+
(Some(alias), plan)
186+
} else {
187+
((tables.len() > 1).then(|| tables.pop()).flatten(), plan)
188+
}
163189
}
164190
_ => unimplemented!(),
165191
};
166192

167193
Ok(plan_with_name)
168194
}
169195

196+
pub(crate) fn trans_alias(alias: &Option<TableAlias>) -> Option<&String> {
197+
alias.as_ref().map(|alias| &alias.name.value)
198+
}
199+
170200
pub(crate) fn _bind_single_table_ref(
171201
&mut self,
172-
joint_type: Option<JoinType>,
202+
join_type: Option<JoinType>,
173203
table: &str,
204+
alias: Option<&String>,
174205
) -> Result<(Arc<String>, LogicalPlan), BindError> {
175206
let table_name = Arc::new(table.to_string());
176207

177-
if self.context.bind_table.contains_key(&table_name) {
178-
return Err(BindError::InvalidTable(format!("{} duplicated", table)));
179-
}
180-
181208
let table_catalog = self
182209
.context
183-
.transaction
184210
.table(&table_name)
211+
.cloned()
185212
.ok_or_else(|| BindError::InvalidTable(format!("bind table {}", table)))?;
186213

187214
self.context
188-
.bind_table
189-
.insert(table_name.clone(), (table_catalog.clone(), joint_type));
215+
.add_bind_table(table_name.clone(), table_catalog.clone(), join_type)?;
216+
217+
if let Some(alias) = alias {
218+
self.context
219+
.add_table_alias(alias.to_string(), table_name.clone())?;
220+
}
190221

191222
Ok((
192223
table_name.clone(),
@@ -213,7 +244,7 @@ impl<'a, T: Transaction> Binder<'a, T> {
213244
let expr = self.bind_expr(expr)?;
214245
let alias_name = alias.to_string();
215246

216-
self.context.add_alias(alias_name.clone(), expr.clone());
247+
self.context.add_alias(alias_name.clone(), expr.clone())?;
217248

218249
select_items.push(ScalarExpression::Alias {
219250
expr: Box::new(expr),
@@ -236,7 +267,6 @@ impl<'a, T: Transaction> Binder<'a, T> {
236267
for table_name in self.context.bind_table.keys().cloned() {
237268
let table = self
238269
.context
239-
.transaction
240270
.table(&table_name)
241271
.ok_or_else(|| BindError::InvalidTable(table_name.to_string()))?;
242272
for col in table.all_columns() {
@@ -249,7 +279,7 @@ impl<'a, T: Transaction> Binder<'a, T> {
249279

250280
fn bind_join(
251281
&mut self,
252-
left_table: TableName,
282+
left_table: &String,
253283
left: LogicalPlan,
254284
join: &Join,
255285
) -> Result<LogicalPlan, BindError> {
@@ -266,21 +296,17 @@ impl<'a, T: Transaction> Binder<'a, T> {
266296
JoinOperator::CrossJoin => (JoinType::Cross, None),
267297
_ => unimplemented!(),
268298
};
269-
270299
let (right_table, right) = self.bind_single_table_ref(relation, Some(join_type))?;
271-
272-
let left_table = self
273-
.context
274-
.transaction
275-
.table(&left_table)
276-
.cloned()
277-
.ok_or_else(|| BindError::InvalidTable(format!("Left: {} not found", left_table)))?;
278-
let right_table = self
279-
.context
280-
.transaction
281-
.table(&right_table)
282-
.cloned()
283-
.ok_or_else(|| BindError::InvalidTable(format!("Right: {} not found", right_table)))?;
300+
let right_table = Self::unpack_name(right_table, false);
301+
302+
let left_table =
303+
self.context.table(left_table).cloned().ok_or_else(|| {
304+
BindError::InvalidTable(format!("Left: {} not found", left_table))
305+
})?;
306+
let right_table =
307+
self.context.table(&right_table).cloned().ok_or_else(|| {
308+
BindError::InvalidTable(format!("Right: {} not found", right_table))
309+
})?;
284310

285311
let on = match joint_condition {
286312
Some(constraint) => self.bind_join_constraint(&left_table, &right_table, constraint)?,

src/catalog/table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ pub type TableName = Arc<String>;
99

1010
#[derive(Debug, Clone, PartialEq)]
1111
pub struct TableCatalog {
12-
pub name: TableName,
12+
pub(crate) name: TableName,
1313
/// Mapping from column names to column ids
1414
column_idxs: BTreeMap<String, ColumnId>,
1515
pub(crate) columns: BTreeMap<ColumnId, ColumnRef>,
16-
pub indexes: Vec<IndexMetaRef>,
16+
pub(crate) indexes: Vec<IndexMetaRef>,
1717
}
1818

1919
impl TableCatalog {

src/db.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ impl<S: Storage> Database<S> {
8484
RuleImpl::PushPredicateIntoScan,
8585
],
8686
)
87+
.batch(
88+
"Combine Operators".to_string(),
89+
HepBatchStrategy::fix_point_topdown(10),
90+
vec![RuleImpl::CollapseProject, RuleImpl::CombineFilter],
91+
)
8792
.batch(
8893
"Column Pruning".to_string(),
8994
HepBatchStrategy::fix_point_topdown(10),
@@ -102,11 +107,6 @@ impl<S: Storage> Database<S> {
102107
RuleImpl::EliminateLimits,
103108
],
104109
)
105-
.batch(
106-
"Combine Operators".to_string(),
107-
HepBatchStrategy::fix_point_topdown(10),
108-
vec![RuleImpl::CollapseProject, RuleImpl::CombineFilter],
109-
)
110110
}
111111
}
112112

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::planner::operator::copy_to_file::CopyToFileOperator;
22

3-
#[warn(dead_code)]
3+
#[allow(dead_code)]
44
pub struct CopyToFile {
55
op: CopyToFileOperator,
66
}

src/optimizer/rule/column_pruning.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl Rule for PushProjectIntoScan {
5252
new_scan_op.columns = project_op
5353
.columns
5454
.iter()
55-
.filter(|expr| matches!(expr.unpack_alias(), ScalarExpression::ColumnRef(_)))
55+
.map(ScalarExpression::unpack_alias)
5656
.cloned()
5757
.collect_vec();
5858

0 commit comments

Comments
 (0)