-
Notifications
You must be signed in to change notification settings - Fork 216
/
Copy pathcreate_table.rs
194 lines (174 loc) · 6.49 KB
/
create_table.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright 2024 RisingLight Project Authors. Licensed under Apache-2.0.
use std::collections::HashSet;
use std::fmt;
use std::str::FromStr;
use pretty_xmlish::helper::delegate_fmt;
use pretty_xmlish::Pretty;
use serde::{Deserialize, Serialize};
use super::*;
use crate::catalog::{ColumnCatalog, ColumnDesc, ColumnId, SchemaId};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)]
pub struct CreateTable {
pub schema_id: SchemaId,
pub table_name: String,
pub columns: Vec<ColumnCatalog>,
pub ordered_pk_ids: Vec<ColumnId>,
}
impl fmt::Display for CreateTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let explainer = Pretty::childless_record("CreateTable", self.pretty_table());
delegate_fmt(&explainer, f, String::with_capacity(1000))
}
}
impl CreateTable {
pub fn pretty_table<'a>(&self) -> Vec<(&'a str, Pretty<'a>)> {
let cols = Pretty::Array(self.columns.iter().map(|c| c.desc().pretty()).collect());
let ids = Pretty::Array(self.ordered_pk_ids.iter().map(Pretty::display).collect());
vec![
("schema_id", Pretty::display(&self.schema_id)),
("name", Pretty::display(&self.table_name)),
("columns", cols),
("ordered_ids", ids),
]
}
}
impl FromStr for Box<CreateTable> {
type Err = ();
fn from_str(_s: &str) -> std::result::Result<Self, Self::Err> {
Err(())
}
}
impl Binder {
pub(super) fn bind_create_table(
&mut self,
crate::parser::CreateTable {
name,
columns,
constraints,
..
}: crate::parser::CreateTable,
) -> Result {
let name = lower_case_name(&name);
let (schema_name, table_name) = split_name(&name)?;
let schema = self
.catalog
.get_schema_by_name(schema_name)
.ok_or_else(|| ErrorKind::InvalidSchema(schema_name.into()).with_spanned(&name))?;
if schema.get_table_by_name(table_name).is_some() {
return Err(ErrorKind::TableExists(table_name.into()).with_spanned(&name));
}
// check duplicated column names
let mut set = HashSet::new();
for col in &columns {
if !set.insert(col.name.value.to_lowercase()) {
return Err(
ErrorKind::ColumnExists(col.name.value.to_lowercase()).with_spanned(col)
);
}
}
let mut ordered_pk_ids = Binder::ordered_pks_from_columns(&columns);
let has_pk_from_column = !ordered_pk_ids.is_empty();
if ordered_pk_ids.len() > 1 {
// multi primary key should be declared by "primary key(c1, c2...)" syntax
return Err(ErrorKind::NotSupportedTSQL.into());
}
let pks_name_from_constraints = Binder::pks_name_from_constraints(&constraints);
if has_pk_from_column && !pks_name_from_constraints.is_empty() {
// can't get primary key both from "primary key(c1, c2...)" syntax and
// column's option
return Err(ErrorKind::NotSupportedTSQL.into());
} else if !has_pk_from_column {
for name in pks_name_from_constraints {
if !set.contains(&name.value.to_lowercase()) {
return Err(
ErrorKind::InvalidColumn(name.value.to_lowercase()).with_span(name.span)
);
}
}
// We have used `pks_name_from_constraints` to get the primary keys' name sorted by
// declaration order in "primary key(c1, c2..)" syntax. Now we transfer the name to id
// to get the sorted ID
ordered_pk_ids = pks_name_from_constraints
.iter()
.map(|name| {
columns
.iter()
.position(|c| c.name.value.eq_ignore_ascii_case(&name.value))
.unwrap() as ColumnId
})
.collect();
}
let mut columns: Vec<ColumnCatalog> = columns
.iter()
.enumerate()
.map(|(idx, col)| {
let mut col = ColumnCatalog::from(col);
col.set_id(idx as ColumnId);
col
})
.collect();
for &index in &ordered_pk_ids {
columns[index as usize].set_nullable(false);
}
let create = self.egraph.add(Node::CreateTable(Box::new(CreateTable {
schema_id: schema.id(),
table_name: table_name.into(),
columns,
ordered_pk_ids,
})));
Ok(create)
}
/// get primary keys' id in declared order。
/// we use index in columns vector as column id
fn ordered_pks_from_columns(columns: &[ColumnDef]) -> Vec<ColumnId> {
let mut ordered_pks = Vec::new();
for (index, col_def) in columns.iter().enumerate() {
for option_def in &col_def.options {
let is_primary_ = if let ColumnOption::Unique { is_primary, .. } = option_def.option
{
is_primary
} else {
false
};
if is_primary_ {
ordered_pks.push(index as ColumnId);
}
}
}
ordered_pks
}
/// get the primary keys' name sorted by declaration order in "primary key(c1, c2..)" syntax.
fn pks_name_from_constraints(constraints: &[TableConstraint]) -> &[Ident] {
for constraint in constraints {
match constraint {
TableConstraint::PrimaryKey { columns, .. } => return columns,
_ => continue,
}
}
// no primary key
&[]
}
}
impl From<&ColumnDef> for ColumnCatalog {
fn from(cdef: &ColumnDef) -> Self {
let mut is_nullable = true;
let mut is_primary = false;
for opt in &cdef.options {
match opt.option {
ColumnOption::Null => is_nullable = true,
ColumnOption::NotNull => is_nullable = false,
ColumnOption::Unique { is_primary: p, .. } => is_primary = p,
_ => todo!("column options"),
}
}
let mut desc = ColumnDesc::new(
cdef.name.value.to_lowercase(),
(&cdef.data_type).into(),
is_nullable,
);
if is_primary {
desc.set_primary(true);
}
ColumnCatalog::new(0, desc)
}
}