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