quill_sql/plan/logical_planner/
plan_create_table.rs1use 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}