quill_sql/plan/logical_planner/
plan_create_table.rs

1use crate::error::{QuillSQLError, QuillSQLResult};
2use std::collections::HashSet;
3
4use crate::catalog::{Column, DataType};
5use crate::expression::Expr;
6use crate::plan::logical_plan::{CreateTable, LogicalPlan};
7use crate::utils::scalar::ScalarValue;
8
9use super::LogicalPlanner;
10
11impl<'a> LogicalPlanner<'a> {
12    pub fn plan_create_table(
13        &self,
14        name: &sqlparser::ast::ObjectName,
15        column_defs: &Vec<sqlparser::ast::ColumnDef>,
16        if_not_exists: bool,
17    ) -> QuillSQLResult<LogicalPlan> {
18        let name = self.bind_table_name(name)?;
19        let mut columns = vec![];
20        for col_def in column_defs {
21            let data_type: DataType = (&col_def.data_type).try_into()?;
22            let not_null: bool = col_def
23                .options
24                .iter()
25                .any(|opt| matches!(opt.option, sqlparser::ast::ColumnOption::NotNull));
26            let default_expr: Option<&sqlparser::ast::Expr> = col_def
27                .options
28                .iter()
29                .find(|opt| matches!(opt.option, sqlparser::ast::ColumnOption::Default(_)))
30                .map(|opt| {
31                    if let sqlparser::ast::ColumnOption::Default(expr) = &opt.option {
32                        expr
33                    } else {
34                        unreachable!()
35                    }
36                });
37            let default = if let Some(expr) = default_expr {
38                let expr = self.bind_expr(expr)?;
39                match expr {
40                    Expr::Literal(lit) => lit.value.cast_to(&data_type)?,
41                    _ => {
42                        return Err(QuillSQLError::Internal(
43                            "The expr is not literal".to_string(),
44                        ))
45                    }
46                }
47            } else {
48                ScalarValue::new_empty(data_type)
49            };
50
51            columns.push(
52                Column::new(col_def.name.value.clone(), data_type, !not_null)
53                    .with_relation(Some(name.clone()))
54                    .with_default(default),
55            )
56        }
57
58        check_column_name_conflict(&columns)?;
59        Ok(LogicalPlan::CreateTable(CreateTable {
60            name,
61            columns,
62            if_not_exists,
63        }))
64    }
65}
66
67fn check_column_name_conflict(columns: &[Column]) -> QuillSQLResult<()> {
68    let mut names = HashSet::new();
69    for col in columns {
70        if names.contains(col.name.as_str()) {
71            return Err(QuillSQLError::Plan(format!(
72                "Column names have conflict on '{}'",
73                col.name
74            )));
75        } else {
76            names.insert(col.name.as_str());
77        }
78    }
79    Ok(())
80}