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