Skip to content
Merged
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
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ clean:

run:
cargo run --release

debug:
RUST_BACKTRACE=1 cargo run
4 changes: 2 additions & 2 deletions src/binder/expression/agg_func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use sqlparser::ast::{Function, FunctionArg, FunctionArgExpr};
use super::BoundExpr;
use crate::binder::{BindError, Binder};

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AggFunc {
Count,
Sum,
Expand All @@ -25,7 +25,7 @@ impl fmt::Display for AggFunc {
}
}

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct BoundAggFunc {
pub func: AggFunc,
pub exprs: Vec<BoundExpr>,
Expand Down
2 changes: 1 addition & 1 deletion src/binder/expression/binary_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use sqlparser::ast::{BinaryOperator, Expr};
use super::BoundExpr;
use crate::binder::{BindError, Binder, BoundTypeCast};

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct BoundBinaryOp {
pub op: BinaryOperator,
pub left: Box<BoundExpr>,
Expand Down
91 changes: 77 additions & 14 deletions src/binder/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use itertools::Itertools;
use sqlparser::ast::{Expr, Ident};

use super::{BindError, Binder};
use crate::catalog::ColumnCatalog;
use crate::catalog::{ColumnCatalog, ColumnId, TableId};
use crate::types::ScalarValue;

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum BoundExpr {
Constant(ScalarValue),
ColumnRef(BoundColumnRef),
Expand All @@ -24,6 +24,18 @@ pub enum BoundExpr {
}

impl BoundExpr {
pub fn nullable(&self) -> bool {
match self {
BoundExpr::Constant(_) => false,
BoundExpr::ColumnRef(e) => e.column_catalog.nullable,
BoundExpr::InputRef(_) => unreachable!(),
BoundExpr::BinaryOp(e) => e.left.nullable() && e.right.nullable(),
BoundExpr::TypeCast(e) => e.expr.nullable(),
BoundExpr::AggFunc(e) => e.exprs[0].nullable(),
BoundExpr::Alias(e) => e.expr.nullable(),
}
}

pub fn return_type(&self) -> Option<DataType> {
match self {
BoundExpr::Constant(value) => Some(value.data_type()),
Expand Down Expand Up @@ -52,51 +64,96 @@ impl BoundExpr {
}
}

pub fn get_column_catalog(&self) -> Vec<ColumnCatalog> {
pub fn get_referenced_column_catalog(&self) -> Vec<ColumnCatalog> {
match self {
BoundExpr::Constant(_) => vec![],
BoundExpr::InputRef(_) => vec![],
BoundExpr::ColumnRef(column_ref) => vec![column_ref.column_catalog.clone()],
BoundExpr::BinaryOp(binary_op) => binary_op
.left
.get_column_catalog()
.get_referenced_column_catalog()
.into_iter()
.chain(binary_op.right.get_column_catalog().into_iter())
.chain(binary_op.right.get_referenced_column_catalog().into_iter())
.collect::<Vec<_>>(),
BoundExpr::TypeCast(tc) => tc.expr.get_column_catalog(),
BoundExpr::TypeCast(tc) => tc.expr.get_referenced_column_catalog(),
BoundExpr::AggFunc(agg) => agg
.exprs
.iter()
.flat_map(|arg| arg.get_column_catalog())
.flat_map(|arg| arg.get_referenced_column_catalog())
.collect::<Vec<_>>(),
BoundExpr::Alias(alias) => alias.expr.get_column_catalog(),
BoundExpr::Alias(alias) => alias.expr.get_referenced_column_catalog(),
}
}

/// Generate a new column catalog in table alias or subquery for outside referenced.
/// Such as `t.v` in subquery: select t.v from (select a as v from t1) t.
pub fn output_column_catalog_for_alias_table(&self, alias_table_id: String) -> ColumnCatalog {
let (column_id, data_type) = match self {
BoundExpr::Constant(e) => (e.to_string(), e.data_type()),
BoundExpr::ColumnRef(e) => (
e.column_catalog.column_id.clone(),
e.column_catalog.desc.data_type.clone(),
),
BoundExpr::InputRef(_) => unreachable!(),
BoundExpr::BinaryOp(e) => {
let l = e
.left
.output_column_catalog_for_alias_table(alias_table_id.clone());
let r = e
.right
.output_column_catalog_for_alias_table(alias_table_id.clone());
let column_id = format!("{}{}{}", l.column_id, e.op, r.column_id);
let data_type = e.return_type.clone().unwrap();
(column_id, data_type)
}
BoundExpr::TypeCast(e) => {
let c = e
.expr
.output_column_catalog_for_alias_table(alias_table_id.clone());
let column_id = format!("{}({})", e.cast_type, c.column_id);
let data_type = e.cast_type.clone();
(column_id, data_type)
}
BoundExpr::AggFunc(agg) => {
let c = agg.exprs[0].output_column_catalog_for_alias_table(alias_table_id.clone());
let column_id = format!("{}({})", agg.func, c.column_id);
let data_type = agg.return_type.clone();
(column_id, data_type)
}
BoundExpr::Alias(e) => {
let column_id = e.column_id.to_string();
let data_type = e.expr.return_type().unwrap();
(column_id, data_type)
}
};
ColumnCatalog::new(alias_table_id, column_id, self.nullable(), data_type)
}
}

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct BoundColumnRef {
pub column_catalog: ColumnCatalog,
}

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct BoundInputRef {
/// column index in data chunk
pub index: usize,
pub return_type: DataType,
}

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct BoundTypeCast {
/// original expression
pub expr: Box<BoundExpr>,
pub cast_type: DataType,
}

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct BoundAlias {
pub expr: Box<BoundExpr>,
pub alias: String,
pub column_id: ColumnId,
pub table_id: TableId,
}

impl Binder {
Expand Down Expand Up @@ -185,7 +242,13 @@ impl fmt::Debug for BoundExpr {
BoundExpr::BinaryOp(binary_op) => write!(f, "{:?}", binary_op),
BoundExpr::TypeCast(type_cast) => write!(f, "{:?}", type_cast),
BoundExpr::AggFunc(agg_func) => write!(f, "{:?}", agg_func),
BoundExpr::Alias(alias) => write!(f, "{:?} as {}", alias.expr, alias.alias),
BoundExpr::Alias(alias) => {
write!(
f,
"({:?}) as {}.{}",
alias.expr, alias.table_id, alias.column_id
)
}
}
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/binder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct BinderContext {
/// table_id -> table_catalog
tables: HashMap<String, TableCatalog>,
aliases: HashMap<String, BoundExpr>,
subquery_base_index: usize,
}

impl Binder {
Expand Down Expand Up @@ -57,6 +58,8 @@ pub enum BindError {
AmbiguousColumn(String),
#[error("binary operator types mismatch: {0} != {1}")]
BinaryOpTypeMismatch(String, String),
#[error("subquery in FROM must have an alias")]
SubqueryMustHaveAlias,
}

#[cfg(test)]
Expand Down Expand Up @@ -108,8 +111,8 @@ mod binder_test {
BoundStatement::Select(select) => {
assert_eq!(select.select_list.len(), 2);
assert!(select.from_table.is_some());
if let BoundTableRef::Table(table_catalog) = select.from_table.unwrap() {
assert_eq!(table_catalog.id, "t1");
if let BoundTableRef::Table(table) = select.from_table.unwrap() {
assert_eq!(table.catalog.id, "t1");
}
}
}
Expand Down Expand Up @@ -352,7 +355,10 @@ pub mod test_util {
}

pub fn build_table_ref(table_id: &str, columns: Vec<&str>) -> BoundTableRef {
BoundTableRef::Table(build_table_catalog(table_id, columns))
BoundTableRef::Table(BoundSimpleTable::new(
build_table_catalog(table_id, columns),
None,
))
}

pub fn build_table_ref_box(table_id: &str, columns: Vec<&str>) -> Box<BoundTableRef> {
Expand Down
9 changes: 7 additions & 2 deletions src/binder/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use sqlparser::ast::{Join, JoinOperator, Query, SelectItem, TableWithJoins};

use super::expression::BoundExpr;
use super::table::BoundTableRef;
use super::{BindError, Binder, BoundAlias, BoundColumnRef};
use super::{BindError, Binder, BoundAlias, BoundColumnRef, EMPTY_DATABASE_ID};

#[derive(Debug)]
pub enum BoundStatement {
Expand Down Expand Up @@ -57,6 +57,10 @@ impl Binder {
} else {
Some(self.bind_table_with_joins(&select.from[0])?)
};
let bound_table_id = from_table
.clone()
.map(|t| t.bound_table_id())
.unwrap_or_else(|| EMPTY_DATABASE_ID.to_string());

// bind select list
let mut select_list = vec![];
Expand All @@ -71,7 +75,8 @@ impl Binder {
self.context.aliases.insert(alias.to_string(), expr.clone());
select_list.push(BoundExpr::Alias(BoundAlias {
expr: Box::new(expr),
alias: alias.to_string().to_lowercase(),
column_id: alias.to_string().to_lowercase(),
table_id: bound_table_id.clone(),
}));
}
SelectItem::QualifiedWildcard(object_name) => {
Expand Down
Loading