quill_sql/plan/logical_planner/
bind_expr.rs

1use crate::error::{QuillSQLError, QuillSQLResult};
2use crate::expression::{AggregateFunction, BinaryExpr, ColumnExpr, Expr, Literal};
3use crate::function::AggregateFunctionKind;
4use crate::plan::LogicalPlanner;
5use crate::sql::ast;
6use crate::utils::scalar::ScalarValue;
7use crate::utils::table_ref::TableReference;
8
9impl LogicalPlanner<'_> {
10    pub fn bind_expr(&self, sql: &ast::Expr) -> QuillSQLResult<Expr> {
11        match sql {
12            ast::Expr::Identifier(ident) => Ok(Expr::Column(ColumnExpr {
13                relation: None,
14                name: ident.value.clone(),
15            })),
16            ast::Expr::BinaryOp { left, op, right } => {
17                let left = Box::new(self.bind_expr(left)?);
18                let right = Box::new(self.bind_expr(right)?);
19                Ok(Expr::Binary(BinaryExpr {
20                    left,
21                    op: op.try_into()?,
22                    right,
23                }))
24            }
25            ast::Expr::Value(value) => self.bind_value(value),
26            ast::Expr::CompoundIdentifier(idents) => match idents.as_slice() {
27                [col] => Ok(Expr::Column(ColumnExpr {
28                    relation: None,
29                    name: col.value.clone(),
30                })),
31                [table, col] => Ok(Expr::Column(ColumnExpr {
32                    relation: Some(TableReference::Bare {
33                        table: table.value.clone(),
34                    }),
35                    name: col.value.clone(),
36                })),
37                [schema, table, col] => Ok(Expr::Column(ColumnExpr {
38                    relation: Some(TableReference::Partial {
39                        schema: schema.value.clone(),
40                        table: table.value.clone(),
41                    }),
42                    name: col.value.clone(),
43                })),
44                [catalog, schema, table, col] => Ok(Expr::Column(ColumnExpr {
45                    relation: Some(TableReference::Full {
46                        catalog: catalog.value.clone(),
47                        schema: schema.value.clone(),
48                        table: table.value.clone(),
49                    }),
50                    name: col.value.clone(),
51                })),
52                _ => Err(QuillSQLError::NotSupport(format!(
53                    "sqlparser expr CompoundIdentifier has more than 4 identifiers: {:?}",
54                    idents
55                ))),
56            },
57            ast::Expr::Function(function) => self.bind_function(function),
58            _ => Err(QuillSQLError::NotSupport(format!(
59                "sqlparser expr {} not supported",
60                sql
61            ))),
62        }
63    }
64
65    pub fn bind_value(&self, value: &ast::Value) -> QuillSQLResult<Expr> {
66        match value {
67            ast::Value::Number(s, _) => {
68                if let Ok(num) = s.parse::<i64>() {
69                    return Ok(Expr::Literal(Literal { value: num.into() }));
70                }
71                if let Ok(num) = s.parse::<f64>() {
72                    return Ok(Expr::Literal(Literal { value: num.into() }));
73                }
74                Err(QuillSQLError::Internal(
75                    "Failed to parse sql number value".to_string(),
76                ))
77            }
78            ast::Value::Boolean(b) => Ok(Expr::Literal(Literal { value: (*b).into() })),
79            ast::Value::Null => Ok(Expr::Literal(Literal {
80                value: ScalarValue::Int8(None),
81            })),
82            ast::Value::SingleQuotedString(s) => Ok(Expr::Literal(Literal {
83                value: s.clone().into(),
84            })),
85            _ => Err(QuillSQLError::NotSupport(format!(
86                "sqlparser value {} not supported",
87                value
88            ))),
89        }
90    }
91
92    pub fn bind_function(&self, function: &ast::Function) -> QuillSQLResult<Expr> {
93        let name = function.name.to_string();
94
95        if let Some(func_kind) = AggregateFunctionKind::find(name.as_str()) {
96            let args = function
97                .args
98                .iter()
99                .map(|arg| self.bind_function_arg(arg))
100                .collect::<QuillSQLResult<Vec<Expr>>>()?;
101            return Ok(Expr::AggregateFunction(AggregateFunction {
102                func_kind,
103                args,
104                distinct: function.distinct,
105            }));
106        }
107
108        Err(QuillSQLError::Plan(format!(
109            "The function {} is not supported",
110            function
111        )))
112    }
113
114    pub fn bind_function_arg(&self, arg: &ast::FunctionArg) -> QuillSQLResult<Expr> {
115        match arg {
116            ast::FunctionArg::Named {
117                name: _,
118                arg: sqlparser::ast::FunctionArgExpr::Expr(arg),
119            } => self.bind_expr(arg),
120            ast::FunctionArg::Unnamed(sqlparser::ast::FunctionArgExpr::Expr(arg)) => {
121                self.bind_expr(arg)
122            }
123            ast::FunctionArg::Unnamed(sqlparser::ast::FunctionArgExpr::Wildcard) => {
124                // Treat COUNT(*) etc. as a non-null literal so accumulators count rows
125                Ok(Expr::Literal(Literal { value: 1i64.into() }))
126            }
127            _ => Err(QuillSQLError::Plan(format!(
128                "The function arg {} is not supported",
129                arg
130            ))),
131        }
132    }
133}