1use crate::{
86 type_::{BaseType, FullType},
87 type_statement,
88 typer::unqualified_name,
89 Type, TypeOptions,
90};
91use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
92use sql_parse::{parse_statements, DataType, Expression, Identifier, Issues, Span, Spanned};
93
94#[derive(Debug)]
96pub struct Column<'a> {
97 pub identifier: Identifier<'a>,
98 pub type_: FullType<'a>,
100 pub auto_increment: bool,
102 pub as_: Option<alloc::boxed::Box<Expression<'a>>>,
103}
104
105#[derive(Debug)]
107pub struct Schema<'a> {
108 pub identifier_span: Span,
110 pub columns: Vec<Column<'a>>,
112 pub view: bool,
114}
115
116impl<'a> Schema<'a> {
117 pub fn get_column(&self, identifier: &str) -> Option<&Column<'a>> {
118 self.columns
119 .iter()
120 .find(|&column| column.identifier.value == identifier)
121 }
122 pub fn get_column_mut(&mut self, identifier: &str) -> Option<&mut Column<'a>> {
123 self.columns
124 .iter_mut()
125 .find(|column| column.identifier.value == identifier)
126 }
127}
128
129#[derive(Debug)]
131pub struct Procedure {}
132
133#[derive(Debug)]
135pub struct Functions {}
136
137#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
138pub struct IndexKey<'a> {
139 pub table: Option<Identifier<'a>>,
140 pub index: Identifier<'a>,
141}
142
143#[derive(Debug, Default)]
145pub struct Schemas<'a> {
146 pub schemas: BTreeMap<Identifier<'a>, Schema<'a>>,
148 pub procedures: BTreeMap<Identifier<'a>, Procedure>,
150 pub functions: BTreeMap<Identifier<'a>, Functions>,
152 pub indices: BTreeMap<IndexKey<'a>, Span>,
154}
155
156pub(crate) fn parse_column<'a>(
157 data_type: DataType<'a>,
158 identifier: Identifier<'a>,
159 _issues: &mut Issues<'a>,
160) -> Column<'a> {
161 let mut not_null = false;
162 let mut unsigned = false;
163 let mut auto_increment = false;
164 let mut _as = None;
165 for p in data_type.properties {
166 match p {
167 sql_parse::DataTypeProperty::Signed(_) => unsigned = false,
168 sql_parse::DataTypeProperty::Unsigned(_) => unsigned = true,
169 sql_parse::DataTypeProperty::Null(_) => not_null = false,
170 sql_parse::DataTypeProperty::NotNull(_) => not_null = true,
171 sql_parse::DataTypeProperty::AutoIncrement(_) => auto_increment = true,
172 sql_parse::DataTypeProperty::As((_, e)) => _as = Some(e),
173 _ => {} }
175 }
176 let type_ = match data_type.type_ {
177 sql_parse::Type::TinyInt(v) => {
178 if !unsigned && matches!(v, Some((1, _))) {
179 BaseType::Bool.into()
180 } else if unsigned {
181 Type::U8
182 } else {
183 Type::I8
184 }
185 }
186 sql_parse::Type::SmallInt(_) => {
187 if unsigned {
188 Type::U16
189 } else {
190 Type::I16
191 }
192 }
193 sql_parse::Type::Int(_) => {
194 if unsigned {
195 Type::U32
196 } else {
197 Type::I32
198 }
199 }
200 sql_parse::Type::BigInt(_) => {
201 if unsigned {
202 Type::U64
203 } else {
204 Type::I64
205 }
206 }
207 sql_parse::Type::Char(_) => BaseType::String.into(),
208 sql_parse::Type::VarChar(_) => BaseType::String.into(),
209 sql_parse::Type::TinyText(_) => BaseType::String.into(),
210 sql_parse::Type::MediumText(_) => BaseType::String.into(),
211 sql_parse::Type::Text(_) => BaseType::String.into(),
212 sql_parse::Type::LongText(_) => BaseType::String.into(),
213 sql_parse::Type::Enum(e) => Type::Enum(Arc::new(e.into_iter().map(|s| s.value).collect())),
214 sql_parse::Type::Set(s) => Type::Set(Arc::new(s.into_iter().map(|s| s.value).collect())),
215 sql_parse::Type::Float(_) => Type::F32,
216 sql_parse::Type::Double(_) => Type::F64,
217 sql_parse::Type::DateTime(_) => BaseType::DateTime.into(),
218 sql_parse::Type::Timestamp(_) => BaseType::TimeStamp.into(),
219 sql_parse::Type::Time(_) => BaseType::Time.into(),
220 sql_parse::Type::TinyBlob(_) => BaseType::Bytes.into(),
221 sql_parse::Type::MediumBlob(_) => BaseType::Bytes.into(),
222 sql_parse::Type::Date => BaseType::Date.into(),
223 sql_parse::Type::Blob(_) => BaseType::Bytes.into(),
224 sql_parse::Type::LongBlob(_) => BaseType::Bytes.into(),
225 sql_parse::Type::VarBinary(_) => BaseType::Bytes.into(),
226 sql_parse::Type::Binary(_) => BaseType::Bytes.into(),
227 sql_parse::Type::Boolean => BaseType::Bool.into(),
228 sql_parse::Type::Integer(_) => BaseType::Integer.into(),
229 sql_parse::Type::Float8 => BaseType::Float.into(),
230 sql_parse::Type::Numeric(_, _, _) => todo!("Numeric"),
231 sql_parse::Type::Timestamptz => BaseType::TimeStamp.into(),
232 sql_parse::Type::Json => BaseType::String.into(),
233 sql_parse::Type::Bit(_, _) => BaseType::Bytes.into(),
234 sql_parse::Type::Bytea => BaseType::Bytes.into(),
235 sql_parse::Type::Named(_) => BaseType::String.into(), sql_parse::Type::Inet4 => BaseType::String.into(),
237 sql_parse::Type::Inet6 => BaseType::String.into(),
238 };
239
240 Column {
241 identifier,
242 type_: FullType {
243 t: type_,
244 not_null,
245 list_hack: false,
246 },
247 auto_increment,
248 as_: _as,
249 }
250}
251
252pub fn parse_schemas<'a>(
269 src: &'a str,
270 issues: &mut Issues<'a>,
271 options: &TypeOptions,
272) -> Schemas<'a> {
273 let statements = parse_statements(src, issues, &options.parse_options);
274
275 let mut schemas = Schemas {
276 schemas: Default::default(),
277 procedures: Default::default(),
278 functions: Default::default(),
279 indices: Default::default(),
280 };
281
282 for statement in statements {
283 match statement {
284 sql_parse::Statement::CreateTable(t) => {
285 let mut replace = false;
286
287 let id = unqualified_name(issues, &t.identifier);
288
289 let mut schema = Schema {
290 view: false,
291 identifier_span: id.span.clone(),
292 columns: Default::default(),
293 };
294
295 for o in t.create_options {
296 match o {
297 sql_parse::CreateOption::OrReplace(_) => {
298 replace = true;
299 }
300 sql_parse::CreateOption::Temporary(s) => {
301 issues.err("Not supported", &s);
302 }
303 sql_parse::CreateOption::Unique(s) => {
304 issues.err("Not supported", &s);
305 }
306 sql_parse::CreateOption::Algorithm(_, _) => {}
307 sql_parse::CreateOption::Definer { .. } => {}
308 sql_parse::CreateOption::SqlSecurityDefiner(_, _) => {}
309 sql_parse::CreateOption::SqlSecurityUser(_, _) => {}
310 }
311 }
312 for d in t.create_definitions {
314 match d {
315 sql_parse::CreateDefinition::ColumnDefinition {
316 identifier,
317 data_type,
318 } => {
319 let column = parse_column(data_type, identifier.clone(), issues);
320 if let Some(oc) = schema.get_column(column.identifier.value) {
321 issues
322 .err("Column already defined", &identifier)
323 .frag("Defined here", &oc.identifier);
324 } else {
325 schema.columns.push(column);
326 }
327 }
328 sql_parse::CreateDefinition::ConstraintDefinition { .. } => {}
329 }
330 }
331 match schemas.schemas.entry(id.clone()) {
332 alloc::collections::btree_map::Entry::Occupied(mut e) => {
333 if replace {
334 e.insert(schema);
335 } else if t.if_not_exists.is_none() {
336 issues
337 .err("Table already defined", &t.identifier)
338 .frag("Defined here", &e.get().identifier_span);
339 }
340 }
341 alloc::collections::btree_map::Entry::Vacant(e) => {
342 e.insert(schema);
343 }
344 }
345 }
346 sql_parse::Statement::CreateView(v) => {
347 let mut replace = false;
348 let mut schema = Schema {
349 view: true,
350 identifier_span: v.name.span(),
351 columns: Default::default(),
352 };
353 for o in v.create_options {
354 match o {
355 sql_parse::CreateOption::OrReplace(_) => {
356 replace = true;
357 }
358 sql_parse::CreateOption::Temporary(s) => {
359 issues.err("Not supported", &s);
360 }
361 sql_parse::CreateOption::Unique(s) => {
362 issues.err("Not supported", &s);
363 }
364 sql_parse::CreateOption::Algorithm(_, _) => {}
365 sql_parse::CreateOption::Definer { .. } => {}
366 sql_parse::CreateOption::SqlSecurityDefiner(_, _) => {}
367 sql_parse::CreateOption::SqlSecurityUser(_, _) => {}
368 }
369 }
370
371 {
372 let mut typer: crate::typer::Typer<'a, '_> = crate::typer::Typer {
373 schemas: &schemas,
374 issues,
375 reference_types: Vec::new(),
376 arg_types: Default::default(),
377 options,
378 with_schemas: Default::default(),
379 };
380
381 let t = type_statement::type_statement(&mut typer, &v.select);
382 let s = if let type_statement::InnerStatementType::Select(s) = t {
383 s
384 } else {
385 issues.err("Not supported", &v.select.span());
386 continue;
387 };
388
389 for column in s.columns {
390 let name = column.name.unwrap();
392
393 schema.columns.push(Column {
394 identifier: name,
395 type_: column.type_,
396 auto_increment: false,
397 as_: None,
398 });
399 }
400 }
401
402 match schemas
403 .schemas
404 .entry(unqualified_name(issues, &v.name).clone())
405 {
406 alloc::collections::btree_map::Entry::Occupied(mut e) => {
407 if replace {
408 e.insert(schema);
409 } else if v.if_not_exists.is_none() {
410 issues
411 .err("View already defined", &v.name)
412 .frag("Defined here", &e.get().identifier_span);
413 }
414 }
415 alloc::collections::btree_map::Entry::Vacant(e) => {
416 e.insert(schema);
417 }
418 }
419 }
420 sql_parse::Statement::CreateTrigger(_) => {}
421 sql_parse::Statement::DropTable(t) => {
427 for i in t.tables {
428 match schemas.schemas.entry(unqualified_name(issues, &i).clone()) {
429 alloc::collections::btree_map::Entry::Occupied(e) => {
430 if e.get().view {
431 issues
432 .err("Name defines a view not a table", &i)
433 .frag("View defined here", &e.get().identifier_span);
434 } else {
435 e.remove();
436 }
437 }
438 alloc::collections::btree_map::Entry::Vacant(_) => {
439 if t.if_exists.is_none() {
440 issues.err("A table with this name does not exist to drop", &i);
441 }
442 }
443 }
444 }
445 }
446 sql_parse::Statement::DropFunction(f) => {
447 match schemas
448 .functions
449 .entry(unqualified_name(issues, &f.function).clone())
450 {
451 alloc::collections::btree_map::Entry::Occupied(e) => {
452 e.remove();
453 }
454 alloc::collections::btree_map::Entry::Vacant(_) => {
455 if f.if_exists.is_none() {
456 issues.err(
457 "A function with this name does not exist to drop",
458 &f.function,
459 );
460 }
461 }
462 }
463 }
464 sql_parse::Statement::DropProcedure(p) => {
465 match schemas
466 .procedures
467 .entry(unqualified_name(issues, &p.procedure).clone())
468 {
469 alloc::collections::btree_map::Entry::Occupied(e) => {
470 e.remove();
471 }
472 alloc::collections::btree_map::Entry::Vacant(_) => {
473 if p.if_exists.is_none() {
474 issues.err(
475 "A procedure with this name does not exist to drop",
476 &p.procedure,
477 );
478 }
479 }
480 }
481 }
482 sql_parse::Statement::DropDatabase(_) => {}
484 sql_parse::Statement::DropServer(_) => {}
485 sql_parse::Statement::DropTrigger(_) => {}
486 sql_parse::Statement::DropView(v) => {
487 for i in v.views {
488 match schemas.schemas.entry(unqualified_name(issues, &i).clone()) {
489 alloc::collections::btree_map::Entry::Occupied(e) => {
490 if !e.get().view {
491 issues
492 .err("Name defines a table not a view", &i)
493 .frag("Table defined here", &e.get().identifier_span);
494 } else {
495 e.remove();
496 }
497 }
498 alloc::collections::btree_map::Entry::Vacant(_) => {
499 if v.if_exists.is_none() {
500 issues.err("A view with this name does not exist to drop", &i);
501 }
502 }
503 }
504 }
505 }
506 sql_parse::Statement::Set(_) => {}
507 sql_parse::Statement::AlterTable(a) => {
508 let e = match schemas
509 .schemas
510 .entry(unqualified_name(issues, &a.table).clone())
511 {
512 alloc::collections::btree_map::Entry::Occupied(e) => {
513 let e = e.into_mut();
514 if e.view {
515 issues.err("Cannot alter view", &a.table);
516 continue;
517 }
518 e
519 }
520 alloc::collections::btree_map::Entry::Vacant(_) => {
521 if a.if_exists.is_none() {
522 issues.err("Table not found", &a.table);
523 }
524 continue;
525 }
526 };
527 for s in a.alter_specifications {
528 match s {
529 sql_parse::AlterSpecification::AddIndex {
530 if_not_exists,
531 name,
532 cols,
533 ..
534 } => {
535 for col in &cols {
536 if e.get_column(&col.name).is_none() {
537 issues
538 .err("No such column in table", col)
539 .frag("Table defined here", &a.table);
540 }
541 }
542
543 if let Some(name) = &name {
544 let ident = if options.parse_options.get_dialect().is_postgresql() {
545 IndexKey {
546 table: None,
547 index: name.clone(),
548 }
549 } else {
550 IndexKey {
551 table: Some(unqualified_name(issues, &a.table).clone()),
552 index: name.clone(),
553 }
554 };
555
556 if let Some(old) = schemas.indices.insert(ident, name.span()) {
557 if if_not_exists.is_none() {
558 issues
559 .err(
560 "Multiple indeces with the same identifier",
561 &name.span(),
562 )
563 .frag("Already defined here", &old);
564 }
565 }
566 }
567 }
568 sql_parse::AlterSpecification::AddForeignKey { .. } => {}
569 sql_parse::AlterSpecification::Modify {
570 if_exists,
571 col,
572 definition,
573 ..
574 } => {
575 let c = match e.get_column_mut(col.value) {
576 Some(v) => v,
577 None => {
578 if if_exists.is_none() {
579 issues
580 .err("No such column in table", &col)
581 .frag("Table defined here", &e.identifier_span);
582 }
583 continue;
584 }
585 };
586 *c = parse_column(definition, c.identifier.clone(), issues);
587 }
588 sql_parse::AlterSpecification::AddColumn {
589 identifier,
590 data_type,
591 ..
592 } => {
593 e.columns.push(parse_column(data_type, identifier, issues));
594 }
595 sql_parse::AlterSpecification::OwnerTo { .. } => {}
596 sql_parse::AlterSpecification::DropColumn { column, .. } => {
597 let cnt = e.columns.len();
598 e.columns.retain(|c| c.identifier != column);
599 if cnt == e.columns.len() {
600 issues
601 .err("No such column in table", &column)
602 .frag("Table defined here", &e.identifier_span);
603 }
604 }
605 sql_parse::AlterSpecification::AlterColumn {
606 column,
607 alter_column_action,
608 ..
609 } => {
610 let c = match e.get_column_mut(&column.value) {
611 Some(v) => v,
612 None => {
613 issues
614 .err("No such column in table", &column)
615 .frag("Table defined here", &e.identifier_span);
616 continue;
617 }
618 };
619 match alter_column_action {
620 sql_parse::AlterColumnAction::SetDefault { .. } => (),
621 sql_parse::AlterColumnAction::DropDefault { .. } => (),
622 sql_parse::AlterColumnAction::Type { type_, .. } => {
623 *c = parse_column(type_, column, issues)
624 }
625 sql_parse::AlterColumnAction::SetNotNull { .. } => {
626 c.type_.not_null = true
627 }
628 sql_parse::AlterColumnAction::DropNotNull { .. } => {
629 c.type_.not_null = false
630 }
631 }
632 }
633 }
634 }
635 }
636 sql_parse::Statement::Do(_) => {
637 }
639 sql_parse::Statement::CreateIndex(ci) => {
646 let t = unqualified_name(issues, &ci.table_name);
647
648 if let Some(table) = schemas.schemas.get(t) {
649 for col in &ci.column_names {
650 if table.get_column(col).is_none() {
651 issues
652 .err("No such column in table", col)
653 .frag("Table defined here", &table.identifier_span);
654 }
655 }
656 } else {
658 issues.err("No such table", &ci.table_name);
659 }
660
661 let ident = if options.parse_options.get_dialect().is_postgresql() {
662 IndexKey {
663 table: None,
664 index: ci.index_name.clone(),
665 }
666 } else {
667 IndexKey {
668 table: Some(t.clone()),
669 index: ci.index_name.clone(),
670 }
671 };
672
673 if let Some(old) = schemas.indices.insert(ident, ci.span()) {
674 if ci.if_not_exists.is_none() {
675 issues
676 .err("Multiple indeces with the same identifier", &ci)
677 .frag("Already defined here", &old);
678 }
679 }
680 }
681 sql_parse::Statement::DropIndex(ci) => {
682 let key = IndexKey {
683 table: ci.on.as_ref().map(|(_, t)| t.identifier.clone()),
684 index: ci.index_name.clone(),
685 };
686 if schemas.indices.remove(&key).is_none() && ci.if_exists.is_none() {
687 issues.err("No such index", &ci);
688 }
689 }
690 sql_parse::Statement::Commit(_) => (),
691 sql_parse::Statement::Begin(_) => (),
692 sql_parse::Statement::CreateFunction(_) => (),
693 s => {
694 issues.err(
695 alloc::format!("Unsupported statement {:?} in schema definition", s),
696 &s,
697 );
698 }
699 }
700 }
701
702 let dummy_schemas = Schemas::default();
703
704 let mut typer = crate::typer::Typer {
705 schemas: &dummy_schemas,
706 issues,
707 reference_types: Vec::new(),
708 arg_types: Default::default(),
709 options,
710 with_schemas: Default::default(),
711 };
712
713 for (name, schema) in &mut schemas.schemas {
715 if schema.columns.iter().all(|v| v.as_.is_none()) {
716 continue;
717 }
718 typer.reference_types.clear();
719 let mut columns = Vec::new();
720 for c in &schema.columns {
721 columns.push((c.identifier.clone(), c.type_.clone()));
722 }
723 typer.reference_types.push(crate::typer::ReferenceType {
724 name: Some(name.clone()),
725 span: schema.identifier_span.clone(),
726 columns,
727 });
728 for c in &mut schema.columns {
729 if let Some(as_) = &c.as_ {
730 let full_type = crate::type_expression::type_expression(
731 &mut typer,
732 as_,
733 crate::type_expression::ExpressionFlags::default(),
734 BaseType::Any,
735 );
736 c.type_.not_null = full_type.not_null;
737 }
738 }
739 }
740 schemas
741}