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