1use rudb_catalog::{Catalog, Entry, QualifiedName, duplicate_check, same_name};
18use rudb_common::bounds::End;
19use rudb_common::{
20 Bound as ColumnBound, Clustering, Error, Field, LogicalType, Result, Session, Stat, Value,
21 Width,
22};
23use rudb_parse::ast::{self, Ast};
24use rudb_parse::{NONE, deparse, parse_ast};
25use rudb_plan::{Arm, Expr, ExprRef, Node, Plan, SortKey};
26
27use crate::binder::Binder;
28use crate::parameters::Parameters;
29
30#[derive(Debug)]
35pub enum Bound {
36 Query(Plan),
38 CreateTable(CreateTable),
40 CreateView(CreateView),
42 DropTable(DropTable),
44 Schema(SchemaChange),
46 Sequence(SequenceChange),
48 Type(TypeChange),
50 Alter(Alter),
52 Index(IndexChange),
54 Insert(Insert),
56 Setting(Setting),
58 Checkpoint(Option<String>),
60 Attach(Attach),
62 Detach { name: String, if_exists: bool },
64 Transaction(ast::Transaction),
66 Explain { plan: Plan, analyze: bool, statistics: bool, codegen: bool },
82}
83
84#[derive(Debug)]
96pub struct Setting {
97 pub name: String,
99 pub scope: ast::Scope,
101 pub value: Option<Value>,
103 pub pragma: bool,
105}
106
107#[derive(Debug)]
112pub struct Attach {
113 pub path: String,
115 pub alias: Option<String>,
117 pub or_replace: bool,
119 pub if_not_exists: bool,
121 pub options: Vec<(String, Option<Value>)>,
123}
124
125#[derive(Debug)]
127pub struct CreateTable {
128 pub name: QualifiedName,
130 pub columns: Vec<Field>,
133 pub source: Option<Plan>,
135 pub if_not_exists: bool,
137 pub or_replace: bool,
139 pub keys: Vec<rudb_catalog::Key>,
141 pub defaults: Vec<Option<String>>,
143 pub sequences: Vec<QualifiedName>,
145 pub checks: Vec<String>,
147 pub foreign: Vec<rudb_catalog::ForeignKey>,
149 pub order: Vec<rudb_catalog::Constraint>,
151}
152
153#[derive(Debug)]
160pub struct CreateView {
161 pub name: QualifiedName,
163 pub sql: String,
165 pub statement: String,
170 pub aliases: Vec<String>,
172 pub if_not_exists: bool,
174 pub or_replace: bool,
176 pub columns: Vec<Field>,
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
190pub struct SchemaChange {
191 pub catalog: String,
193 pub name: String,
195 pub drop: bool,
197 pub quiet: bool,
199 pub or_replace: bool,
202 pub cascade: bool,
204}
205
206#[derive(Debug, Clone, PartialEq, Eq)]
208pub struct SequenceChange {
209 pub name: Option<QualifiedName>,
211 pub drop: bool,
213 pub if_not_exists: bool,
215 pub or_replace: bool,
217 pub cascade: bool,
219 pub options: rudb_common::sequence::Options,
221 pub owner: Option<QualifiedName>,
224}
225
226#[derive(Debug, Clone, PartialEq, Eq)]
228pub struct TypeChange {
229 pub name: Option<QualifiedName>,
231 pub ty: Option<LogicalType>,
233 pub uses: Vec<QualifiedName>,
235 pub if_not_exists: bool,
237 pub or_replace: bool,
239 pub cascade: bool,
241}
242
243#[derive(Debug)]
245pub struct Alter {
246 pub name: Option<QualifiedName>,
248 pub alteration: Option<rudb_catalog::Alteration>,
250 pub rewrite: Option<Plan>,
252}
253
254#[derive(Debug)]
256pub struct IndexChange {
257 pub table: Option<QualifiedName>,
259 pub index: Option<rudb_catalog::Index>,
261 pub name: Vec<String>,
263 pub quiet: bool,
265}
266
267#[derive(Debug)]
269pub struct DropTable {
270 pub names: Vec<QualifiedName>,
275 pub kind: Entry,
277}
278
279#[derive(Debug)]
281pub struct Insert {
282 pub name: QualifiedName,
284 pub source: Plan,
287 pub write: Write,
289 pub returning: Option<Box<Plan>>,
292 pub conflict: Option<Conflict>,
294 pub checks: Option<Checks>,
296}
297
298#[derive(Debug)]
304pub struct Checks {
305 pub plan: Box<Plan>,
307 pub messages: Vec<String>,
309}
310
311#[derive(Debug)]
313pub struct Conflict {
314 pub key: Option<usize>,
316 pub action: ConflictAction,
318}
319
320#[derive(Debug)]
322pub enum ConflictAction {
323 Nothing,
325 Replace(Vec<usize>),
327 Update {
331 columns: Vec<usize>,
333 plan: Box<Plan>,
335 },
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq)]
340pub enum Write {
341 Append,
343 Update,
346 Delete,
349}
350
351fn returning(
353 ast: &Ast,
354 catalog: &Catalog,
355 parameters: &Parameters,
356 session: &Session,
357 query: Option<ast::QueryRef>,
358) -> Result<Option<Box<Plan>>> {
359 let Some(query) = query else { return Ok(None) };
360 let mut binder = Binder::with(catalog, parameters, session);
361 let (root, _) = binder.bind_query(ast, query)?;
362 Ok(Some(Box::new(finish(binder, root)?)))
363}
364
365pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
372 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
373}
374
375pub fn bind_statement_with(
385 ast: &Ast,
386 catalog: &Catalog,
387 parameters: &Parameters,
388 session: &Session,
389) -> Result<Bound> {
390 bind_one(ast, catalog, parameters, session, false)
391}
392
393pub fn bind_statement_outlined(
406 ast: &Ast,
407 catalog: &Catalog,
408 parameters: &Parameters,
409 session: &Session,
410) -> Result<Bound> {
411 bind_one(ast, catalog, parameters, session, true)
412}
413
414fn bind_one(
415 ast: &Ast,
416 catalog: &Catalog,
417 parameters: &Parameters,
418 session: &Session,
419 outlined: bool,
420) -> Result<Bound> {
421 let statement = match ast.statements.as_slice() {
422 [statement] => *statement,
423 [] => return Err(Error::binder("no statement to bind")),
424 _ => return Err(Error::not_implemented("a script of more than one statement")),
425 };
426 match statement {
427 ast::Statement::Query(query) => {
428 let mut binder = Binder::with(catalog, parameters, session);
429 binder.outlined = outlined;
430 let (root, _) = binder.bind_query(ast, query)?;
431 Ok(Bound::Query(finish(binder, root)?))
432 }
433 ast::Statement::CreateTable(index) => {
434 create_table(ast, catalog, parameters, session, index)
435 }
436 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
437 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
438 ast::Statement::Schema(index) => {
439 let written = ast.schema(index);
440 if written.temporary {
441 return Err(Error::binder("Temporary schemas are not supported"));
442 }
443 let parts: Vec<&str> = ast.name(written.name).collect();
444 let (catalog, name) = catalog.schema_name(&parts)?;
445 Ok(Bound::Schema(SchemaChange {
446 catalog,
447 name,
448 drop: written.drop,
449 quiet: written.quiet,
450 or_replace: written.or_replace,
451 cascade: written.cascade,
452 }))
453 }
454 ast::Statement::Sequence(index) => {
455 let written = ast.sequence(index);
456 let parts: Vec<&str> = ast.name(written.name).collect();
457 let alter = !written.owner.is_empty();
458 let mut owner = None;
459 let name = if written.drop || alter {
460 match catalog.resolve_sequence(&parts) {
461 Ok(name) => Some(name),
462 Err(_) if written.quiet => None,
463 Err(error) => return Err(error),
464 }
465 } else if written.temporary {
466 Some(catalog.resolve_for_create_temporary(&parts)?)
467 } else {
468 Some(catalog.resolve_for_create(&parts)?)
469 };
470 if alter && name.is_some() {
471 let parts: Vec<&str> = ast.name(written.owner).collect();
472 owner = Some(catalog.resolve_owner(&parts)?);
473 }
474 Ok(Bound::Sequence(SequenceChange {
475 name,
476 drop: written.drop,
477 if_not_exists: written.quiet,
478 or_replace: written.or_replace,
479 cascade: written.cascade,
480 options: written.options,
481 owner,
482 }))
483 }
484 ast::Statement::Type(index) => {
485 let written = ast.type_def(index);
486 let parts: Vec<&str> = ast.name(written.name).collect();
487 let (name, ty, uses) = if written.drop {
488 let name = catalog.resolve_type(&parts).map(|made| made.name().clone());
489 if name.is_none() && !written.quiet {
490 return Err(Error::catalog(format!(
491 "Type with name {} does not exist!",
492 parts.last().copied().unwrap_or_default()
493 )));
494 }
495 (name, None, Vec::new())
496 } else {
497 let name = if written.temporary {
498 catalog.resolve_for_create_temporary(&parts)?
499 } else {
500 catalog.resolve_for_create(&parts)?
501 };
502 let (ty, uses) = written_type(catalog, ast.string(written.ty))?;
503 (Some(name), Some(ty), uses)
504 };
505 Ok(Bound::Type(TypeChange {
506 name,
507 ty,
508 uses,
509 if_not_exists: written.quiet,
510 or_replace: written.or_replace,
511 cascade: written.cascade,
512 }))
513 }
514 ast::Statement::Alter(index) => alter(ast, catalog, parameters, session, index),
515 ast::Statement::Index(index) => create_index(ast, catalog, parameters, session, index),
516 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
517 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
518 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
519 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
520 setting(ast, catalog, parameters, session, index)
521 }
522 ast::Statement::Checkpoint(name) => {
523 Ok(Bound::Checkpoint((name != NONE).then(|| ast.string(name).to_string())))
524 }
525 ast::Statement::Attach(index) => attach(ast, catalog, parameters, session, index),
526 ast::Statement::Detach { name, if_exists } => {
527 Ok(Bound::Detach { name: ast.string(name).to_string(), if_exists })
528 }
529 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
530 ast::Statement::Explain { query, analyze, statistics, codegen } => {
531 let mut binder = Binder::with(catalog, parameters, session);
532 let (root, _) = binder.bind_query(ast, query)?;
533 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics, codegen })
534 }
535 }
536}
537
538pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
544 let ast = parse_ast(sql)?;
545 bind_statement(&ast, catalog)
546}
547
548pub(crate) fn written_type(
552 catalog: &Catalog,
553 text: &str,
554) -> Result<(LogicalType, Vec<QualifiedName>)> {
555 let mut uses = Vec::new();
556 let ty = LogicalType::parse_with(text, &mut |parts| {
557 let parts: Vec<&str> = parts.iter().map(String::as_str).collect();
558 let made = catalog.resolve_type(&parts)?;
559 uses.push(made.name().clone());
560 Some(made.ty().clone())
561 })?;
562 Ok((ty, uses))
563}
564
565pub(crate) fn read_type(catalog: &Catalog, text: &str) -> Result<LogicalType> {
567 written_type(catalog, text).map(|(ty, _)| ty)
568}
569
570fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
571 let mut plan = binder.into_plan();
572 plan.set_root(root);
573 plan.validate()?;
574 Ok(plan)
575}
576
577fn create_table(
578 ast: &Ast,
579 catalog: &Catalog,
580 parameters: &Parameters,
581 session: &Session,
582 index: ast::CreateTableRef,
583) -> Result<Bound> {
584 let written = ast.create_table(index);
585 let parts: Vec<&str> = ast.name(written.name).collect();
586 let name = if written.temporary {
587 catalog.resolve_for_create_temporary(&parts)?
588 } else {
589 catalog.resolve_for_create(&parts)?
590 };
591 let defs = ast.column_defs(written.columns);
592 let (mut columns, source) = if written.query == NONE {
593 let mut columns = Vec::with_capacity(defs.len());
594 for def in defs {
595 let text = ast.string(def.ty);
596 if text.is_empty() {
597 return Err(Error::binder(format!(
598 "Column \"{}\" was declared without a type",
599 ast.string(def.name)
600 )));
601 }
602 let ty = read_type(catalog, text)?;
603 let column = ast.string(def.name);
604 columns.push(if def.not_null {
605 Field::required(column, ty)
606 } else {
607 Field::new(column, ty)
608 });
609 }
610 (columns, None)
611 } else {
612 let mut binder = Binder::with(catalog, parameters, session);
613 let (root, scope) = binder.bind_query(ast, written.query)?;
614 if defs.len() > scope.len() {
615 return Err(Error::binder("Target table has more colum names than query result."));
618 }
619 let mut columns = Vec::with_capacity(scope.columns.len());
620 for (at, column) in scope.columns.iter().enumerate() {
621 let named = match defs.get(at) {
622 Some(def) => ast.string(def.name).to_string(),
623 None => column.name.clone(),
624 };
625 columns.push(Field::new(named, column.ty.clone()));
626 }
627 if defs.is_empty() {
628 deduplicate(&mut columns);
629 }
630 (columns, Some(finish(binder, root)?))
631 };
632 duplicate_check(&columns)?;
633 let mut defaults = Vec::with_capacity(defs.len());
634 let mut sequences = Vec::new();
635 for def in defs {
636 defaults.push(if def.default == NONE {
637 None
638 } else {
639 let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
640 for name in used {
641 if !sequences.contains(&name) {
642 sequences.push(name);
643 }
644 }
645 Some(text)
646 });
647 }
648 let mut checks = Vec::new();
649 for &expr in ast.expr_list(written.checks) {
650 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
651 }
652 let mut keys = Vec::new();
653 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
654 let mut places = Vec::new();
655 for wanted in ast.name(names) {
656 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
657 else {
658 return Err(Error::catalog(format!(
659 "table \"{}\" does not have a column named \"{wanted}\"",
660 name.table
661 )));
662 };
663 places.push(place);
664 }
665 let primary = at as u32 == written.primary;
666 if primary {
667 for &place in &places {
668 columns[place].not_null = true;
669 }
670 }
671 keys.push(rudb_catalog::Key { columns: places, primary });
672 }
673 let mut foreign = Vec::new();
674 let lists = ast.name_list(written.foreign).iter();
675 let tables = ast.name_list(written.foreign_tables).iter();
676 let referenced = ast.name_list(written.foreign_referenced).iter();
677 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
678 let names: Vec<&str> = ast.name(names).collect();
679 let parts: Vec<&str> = ast.name(table).collect();
680 let wanted: Vec<&str> = ast.name(wanted).collect();
681 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
682 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
683 }
684 Ok(Bound::CreateTable(CreateTable {
685 name,
686 columns,
687 source,
688 if_not_exists: written.if_not_exists,
689 or_replace: written.or_replace,
690 keys,
691 defaults,
692 checks,
693 foreign,
694 sequences,
695 order: ast.constraint_list(written.order).iter().map(|&held| constraint(held)).collect(),
696 }))
697}
698
699fn constraint(held: ast::Constraint) -> rudb_catalog::Constraint {
701 match held {
702 ast::Constraint::Key(at) => rudb_catalog::Constraint::Key(at as usize),
703 ast::Constraint::Check(at) => rudb_catalog::Constraint::Check(at as usize),
704 ast::Constraint::Foreign(at) => rudb_catalog::Constraint::Foreign(at as usize),
705 ast::Constraint::NotNull(at) => rudb_catalog::Constraint::NotNull(at as usize),
706 }
707}
708
709fn foreign_key(
715 catalog: &Catalog,
716 made: &QualifiedName,
717 (columns, keys): (&[Field], &[rudb_catalog::Key]),
718 (names, parts, wanted): (&[&str], &[&str], &[&str]),
719) -> Result<rudb_catalog::ForeignKey> {
720 let mut places = Vec::with_capacity(names.len());
721 for &wanted in names {
722 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
723 return Err(Error::binder(format!(
724 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
725 )));
726 };
727 places.push(place);
728 }
729 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
730 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
731 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
732 (made.clone(), columns.to_vec(), keys.to_vec())
733 } else {
734 let resolved = catalog.resolve(parts)?;
735 if catalog.view(&resolved).is_ok() {
736 return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
737 }
738 let table = catalog.table(&resolved)?;
739 (resolved, table.columns().to_vec(), table.keys().to_vec())
740 };
741 let referenced = if wanted.is_empty() {
742 let Some(primary) = held.iter().find(|key| key.primary) else {
743 return Err(Error::binder(format!(
744 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
745 table.table
746 )));
747 };
748 if primary.columns.len() != places.len() {
749 return Err(Error::parser(
750 "The number of referencing and referenced columns for foreign keys must be the same",
751 ));
752 }
753 primary.columns.clone()
754 } else {
755 let mut referenced = Vec::with_capacity(wanted.len());
756 for &column in wanted {
757 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
758 return Err(Error::binder(format!(
759 "Failed to create foreign key: referenced table \"{}\" does not have a column \
760 named \"{column}\"",
761 table.table
762 )));
763 };
764 referenced.push(place);
765 }
766 let mut sorted = referenced.clone();
767 sorted.sort_unstable();
768 let matched = held.iter().any(|key| {
769 let mut columns = key.columns.clone();
770 columns.sort_unstable();
771 columns == sorted
772 });
773 if !matched && held.is_empty() {
774 return Err(Error::binder(format!(
775 "Failed to create foreign key: there is no primary key or unique constraint for \
776 referenced table \"{}\"",
777 table.table
778 )));
779 }
780 if !matched {
781 return Err(Error::binder(format!(
782 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
783 or unique constraint on the columns {}",
784 table.table,
785 wanted.join(", ")
786 )));
787 }
788 referenced
789 };
790 for (&from, &to) in places.iter().zip(&referenced) {
791 if columns[from].ty != fields[to].ty {
792 return Err(Error::binder(format!(
793 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
794 and column \"{}\" (\"{}\")",
795 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
796 )));
797 }
798 }
799 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
800}
801
802fn check_text(
804 ast: &Ast,
805 expr: ast::ExprRef,
806 columns: &[Field],
807 catalog: &Catalog,
808 parameters: &Parameters,
809 session: &Session,
810) -> Result<String> {
811 if crate::expr::has_aggregate(ast, expr) {
812 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
813 }
814 let mut binder = Binder::with(catalog, parameters, session);
815 let index = binder.fresh_index();
816 let mut scope = crate::scope::Scope::empty();
817 for (at, field) in columns.iter().enumerate() {
818 scope.push(crate::scope::Visible {
819 table: String::new(),
820 name: field.name.clone(),
821 binding: rudb_plan::ColumnBinding::new(index, at as u32),
822 ty: field.ty.clone(),
823 not_null: false,
824 key: None,
825 default: None,
826 qualified: false,
827 also: None,
828 });
829 }
830 match binder.bind_expr(ast, expr, &scope) {
831 Err(error) if error.message().starts_with("Referenced column \"") => {
832 let column = error.message().split('"').nth(1).unwrap_or_default();
833 Err(Error::binder(format!(
834 "Table does not contain column \"{column}\" referenced in check constraint!"
835 )))
836 }
837 Err(error) => Err(error),
838 Ok(_) if !binder.windows.is_empty() => {
839 Err(Error::binder("window functions are not allowed in check constraints"))
840 }
841 Ok(_) => Ok(deparse::expression(ast, expr)),
842 }
843}
844
845fn bind_checks(
848 catalog: &Catalog,
849 parameters: &Parameters,
850 session: &Session,
851 name: &QualifiedName,
852) -> Result<Option<Checks>> {
853 let table = catalog.table(name)?;
854 if table.checks().is_empty() {
855 return Ok(None);
856 }
857 let failed: Vec<String> =
858 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
859 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
860 let ast::Statement::Query(query) = ast.statements[0] else {
861 return Err(Error::internal("a check that is not an expression"));
862 };
863 let ast::QueryBody::Select(select) = ast.query(query).body else {
864 return Err(Error::internal("a check that is not an expression"));
865 };
866 let mut binder = Binder::with(catalog, parameters, session);
867 let (root, scope) =
868 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
869 let mut exprs = Vec::with_capacity(failed.len());
870 let mut names = Vec::with_capacity(failed.len());
871 for target in ast.target_list(ast.select(select).targets) {
872 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
873 names.push(binder.plan_mut().intern("failed"));
874 }
875 let exprs = binder.plan_mut().add_expr_list(&exprs);
876 let names = binder.plan_mut().add_name_list(&names);
877 let index = binder.fresh_index();
878 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
879 let messages = table
880 .checks()
881 .iter()
882 .map(|text| {
883 format!(
884 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
885 name.table
886 )
887 })
888 .collect();
889 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
890}
891
892fn default_text(
896 ast: &Ast,
897 expr: ast::ExprRef,
898 catalog: &Catalog,
899 parameters: &Parameters,
900 session: &Session,
901) -> Result<(String, Vec<QualifiedName>)> {
902 if crate::expr::has_aggregate(ast, expr) {
903 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
904 }
905 let mut binder = Binder::with(catalog, parameters, session);
906 let before = binder.plan_mut().node_count();
907 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
908 Err(error) if error.message().starts_with("Referenced ") => {
909 Err(Error::binder("DEFAULT value cannot contain column names"))
910 }
911 Err(error) => Err(error),
912 Ok(_) if binder.plan_mut().node_count() > before => {
914 Err(Error::binder("DEFAULT value cannot contain subqueries"))
915 }
916 Ok(_) if !binder.windows.is_empty() => {
917 Err(Error::binder("DEFAULT value cannot contain window functions!"))
918 }
919 Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
920 }
921}
922
923fn alter(
927 ast: &Ast,
928 catalog: &Catalog,
929 parameters: &Parameters,
930 session: &Session,
931 index: ast::AlterRef,
932) -> Result<Bound> {
933 let written = ast.alter(index);
934 let nothing = |name| Ok(Bound::Alter(Alter { name, alteration: None, rewrite: None }));
935 let parts: Vec<&str> = ast.name(written.name).collect();
936 let wanted = if written.view { Entry::View } else { Entry::Table };
937 let name = match catalog.resolve_as(&parts, wanted) {
938 Ok(name) => name,
939 Err(_) if written.quiet => return nothing(None),
940 Err(error) => return Err(error),
941 };
942 let kind = catalog.entry(&name)?;
943 if written.view && kind == Entry::Table {
944 return Err(Error::catalog("Can only modify table with ALTER TABLE statement"));
945 }
946 if let ast::AlterAction::Rename { to } = written.action {
947 let alteration = rudb_catalog::Alteration::Rename(ast.string(to).to_string());
948 return Ok(Bound::Alter(Alter {
949 name: Some(name),
950 alteration: Some(alteration),
951 rewrite: None,
952 }));
953 }
954 if kind == Entry::View {
955 return Err(Error::catalog("Can only modify view with ALTER VIEW statement"));
956 }
957 let table = catalog.table(&name)?;
958 let fields = table.columns();
959 let place = |column: ast::StrRef| {
960 fields.iter().position(|field| same_name(&field.name, ast.string(column)))
961 };
962 let missing = |column: ast::StrRef| {
963 let names: Vec<String> = fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
964 Error::binder(format!(
965 "Table \"{}\" does not have a column with name \"{}\"\n\nDid you mean: {}",
966 name.table,
967 ast.string(column),
968 names.join(", ")
969 ))
970 };
971 let found = |column: ast::StrRef| place(column).ok_or_else(|| missing(column));
972 let checks = table.checks();
973 let mut rewrite = None;
974 let alteration = match written.action {
975 ast::AlterAction::Rename { .. } => unreachable!("a rename is handled above"),
976 ast::AlterAction::RenameColumn { column, to } => {
977 let at = found(column)?;
978 let (old, to) = (fields[at].name.as_str(), ast.string(to));
979 if in_foreign_key(catalog, &name, table, at) {
980 return Err(Error::catalog(format!(
982 "Cannot rename column \"\"{old}\"\" because this is involved in the foreign key \
983 constraint"
984 )));
985 }
986 let checks =
987 checks.iter().map(|text| rename_in(text, old, to)).collect::<Result<Vec<_>>>()?;
988 rudb_catalog::Alteration::RenameColumn { column: at, to: to.to_string(), checks }
989 }
990 ast::AlterAction::AddColumn { column, quiet } => {
991 if quiet && place(column.name).is_some() {
992 return nothing(Some(name));
993 }
994 let ty = read_type(catalog, ast.string(column.ty))?;
995 let field = Field {
996 not_null: column.not_null,
997 ..Field::new(ast.string(column.name), ty.clone())
998 };
999 let (default, sequences) = if column.default == NONE {
1000 (None, Vec::new())
1001 } else {
1002 let (text, used) = default_text(ast, column.default, catalog, parameters, session)?;
1003 (Some(text), used)
1004 };
1005 rewrite = Some(table_rewrite(
1006 ast,
1007 (catalog, parameters, session),
1008 &name,
1009 |binder, _, out| {
1010 let value = if column.default == NONE {
1011 let null = binder.add_constant(Value::Null);
1012 binder.cast_to(null, &ty)
1013 } else {
1014 let value =
1015 binder.bind_expr(ast, column.default, &crate::scope::Scope::empty())?;
1016 binder.checked_cast_to(value, &ty, false)?
1017 };
1018 out.push((value, field.name.clone()));
1019 Ok(())
1020 },
1021 )?);
1022 rudb_catalog::Alteration::AddColumn { field, default, sequences }
1023 }
1024 ast::AlterAction::DropColumn { column, quiet } => {
1025 let Some(at) = place(column) else {
1026 return if quiet { nothing(Some(name)) } else { Err(missing(column)) };
1027 };
1028 let dropped = fields[at].name.as_str();
1029 let mut kept = Vec::with_capacity(checks.len());
1030 for text in checks {
1031 let used = columns_in(text)?;
1032 if !used.iter().any(|used| same_name(used, dropped)) {
1033 kept.push(text.clone());
1034 } else if used.iter().any(|used| !same_name(used, dropped)) {
1035 return Err(Error::catalog(format!(
1036 "Cannot drop column \"{dropped}\" because there is a CHECK constraint that \
1037 depends on it"
1038 )));
1039 }
1040 }
1041 rewrite =
1042 Some(table_rewrite(ast, (catalog, parameters, session), &name, |_, _, out| {
1043 out.remove(at);
1044 Ok(())
1045 })?);
1046 rudb_catalog::Alteration::DropColumn { column: at, checks: kept }
1047 }
1048 ast::AlterAction::Default { column, default } => {
1049 let at = found(column)?;
1050 let (default, sequences) = if default == NONE {
1051 (None, Vec::new())
1052 } else {
1053 let (text, used) = default_text(ast, default, catalog, parameters, session)?;
1054 (Some(text), used)
1055 };
1056 rudb_catalog::Alteration::Default { column: at, default, sequences }
1057 }
1058 ast::AlterAction::NotNull { column, set } => {
1059 rudb_catalog::Alteration::NotNull { column: found(column)?, set }
1060 }
1061 ast::AlterAction::Type { column, ty, using } => {
1062 let at = found(column)?;
1063 let changed = fields[at].name.as_str();
1064 if table.keys().iter().any(|key| key.columns.contains(&at)) {
1065 return Err(Error::binder(
1066 "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY \
1067 constraint specified",
1068 ));
1069 }
1070 for text in checks {
1071 if columns_in(text)?.iter().any(|used| same_name(used, changed)) {
1072 return Err(Error::binder(
1073 "Cannot change the type of a column that has a CHECK constraint specified",
1074 ));
1075 }
1076 }
1077 if in_foreign_key(catalog, &name, table, at) {
1078 return Err(Error::binder(
1079 "Cannot change the type of a column that has a FOREIGN KEY constraint specified",
1080 ));
1081 }
1082 let mut target =
1083 if ty == NONE { None } else { Some(read_type(catalog, ast.string(ty))?) };
1084 rewrite = Some(table_rewrite(
1085 ast,
1086 (catalog, parameters, session),
1087 &name,
1088 |binder, scope, out| {
1089 let value = if using == NONE {
1090 out[at].0
1091 } else {
1092 binder.bind_expr(ast, using, scope)?
1093 };
1094 let ty = target
1095 .get_or_insert_with(|| binder.plan_mut().expr_type(value).clone())
1096 .clone();
1097 out[at].0 = binder.checked_cast_to(value, &ty, false)?;
1098 Ok(())
1099 },
1100 )?);
1101 let ty = target.ok_or_else(|| Error::internal("an ALTER TYPE that settled no type"))?;
1102 rudb_catalog::Alteration::Type { column: at, ty }
1103 }
1104 };
1105 Ok(Bound::Alter(Alter { name: Some(name), alteration: Some(alteration), rewrite }))
1106}
1107
1108fn create_index(
1116 ast: &Ast,
1117 catalog: &Catalog,
1118 parameters: &Parameters,
1119 session: &Session,
1120 at: ast::IndexRef,
1121) -> Result<Bound> {
1122 let written = ast.index(at);
1123 let parts: Vec<String> = ast.name(written.name).map(str::to_string).collect();
1124 if written.drop {
1125 return Ok(Bound::Index(IndexChange {
1126 table: None,
1127 index: None,
1128 name: parts,
1129 quiet: written.quiet,
1130 }));
1131 }
1132 let written_table: Vec<&str> = ast.name(written.table).collect();
1133 let name = catalog.resolve_as(&written_table, Entry::Table)?;
1134 if catalog.entry(&name)? == Entry::View {
1135 return Err(Error::binder("can only create an index on a base table"));
1136 }
1137 if written.using != NONE && !same_name(ast.string(written.using), "art") {
1138 return Err(Error::binder(format!("Unknown index type: {}", ast.string(written.using))));
1139 }
1140 let fields = catalog.table(&name)?.columns();
1141 let mut binder = Binder::with(catalog, parameters, session);
1142 let (_, scope) =
1143 binder.bind_catalog_table(ast, &name, name.table.clone(), ast::Slice::default())?;
1144 let mut columns = Vec::new();
1145 let mut plain = true;
1146 let mut texts = Vec::new();
1147 for &expr in ast.expr_list(written.elements) {
1148 if let ast::Expr::Column { name: column } = ast.exprs[expr as usize] {
1149 let column: Vec<&str> = ast.name(column).collect();
1150 if let [only] = column[..]
1151 && !fields.iter().any(|field| same_name(&field.name, only))
1152 {
1153 let names: Vec<String> =
1154 fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
1155 return Err(Error::binder(format!(
1157 "Table \"{}\" does not have a column named \"{only}\"\n\nCandidate bindings: \
1158 : {}",
1159 name.table,
1160 names.join(", ")
1161 )));
1162 }
1163 }
1164 if crate::expr::has_aggregate(ast, expr) {
1165 return Err(Error::binder("aggregate functions are not allowed in index expressions"));
1166 }
1167 let before = binder.plan_mut().node_count();
1168 let value = binder.bind_expr(ast, expr, &scope)?;
1169 if binder.plan_mut().node_count() > before {
1170 return Err(Error::binder("cannot use subquery in index expressions"));
1171 }
1172 if !binder.windows.is_empty() {
1173 return Err(Error::binder("window functions are not allowed in index expressions"));
1174 }
1175 let ty = binder.plan_mut().expr_type(value).clone();
1176 if ty.is_nested() {
1177 return Err(Error::invalid_type(format!(
1178 "Invalid Type [{ty}]: Invalid type for index key."
1179 )));
1180 }
1181 let bare = match binder.plan_mut().expr(value) {
1182 Expr::Column(binding) => scope.columns.iter().position(|held| held.binding == *binding),
1183 _ => None,
1184 };
1185 if let Some(at) = bare {
1186 columns.push(at);
1187 texts.push(rudb_parse::quoted(&fields[at].name));
1188 continue;
1189 }
1190 plain = false;
1191 let text = deparse::expression(ast, expr);
1192 let used = columns_in(&text)?;
1193 if used.is_empty() {
1194 return Err(Error::binder(
1195 "CREATE INDEX does not refer to any columns in the base table!",
1196 ));
1197 }
1198 for used in used {
1199 if let Some(at) = fields.iter().position(|field| same_name(&field.name, &used)) {
1200 columns.push(at);
1201 }
1202 }
1203 texts.push(format!("({text})"));
1204 }
1205 if written.unique && !plain {
1206 return Err(Error::not_implemented("A UNIQUE index over an expression is not supported"));
1207 }
1208 let expressions = Value::List {
1209 element: LogicalType::Varchar,
1210 values: texts.iter().map(|text| Value::Varchar(text.clone())).collect(),
1211 };
1212 let unique = if written.unique { "UNIQUE " } else { "" };
1213 let table: Vec<String> = written_table.iter().map(|part| rudb_parse::quoted(part)).collect();
1214 let using = if written.using == NONE {
1215 String::new()
1216 } else {
1217 format!(" USING {} ", ast.string(written.using))
1218 };
1219 let index_name = parts.last().cloned().unwrap_or_default();
1220 let sql = format!(
1221 "CREATE {unique}INDEX {} ON {}{using}({});",
1222 rudb_parse::quoted(&index_name),
1223 table.join("."),
1224 texts.join(", ")
1225 );
1226 if !plain {
1227 columns.sort_unstable();
1228 columns.dedup();
1229 }
1230 let index = rudb_catalog::Index {
1231 name: index_name,
1232 unique: written.unique,
1233 columns,
1234 plain,
1235 expressions: expressions.to_string(),
1236 sql,
1237 oid: 0,
1238 };
1239 Ok(Bound::Index(IndexChange {
1240 table: Some(name),
1241 index: Some(index),
1242 name: Vec::new(),
1243 quiet: written.quiet,
1244 }))
1245}
1246
1247fn in_foreign_key(
1250 catalog: &Catalog,
1251 name: &QualifiedName,
1252 table: &rudb_catalog::Table,
1253 at: usize,
1254) -> bool {
1255 table.foreign().iter().any(|key| key.columns.contains(&at))
1256 || catalog.tables().any(|held| {
1257 held.foreign().iter().any(|key| key.table == *name && key.referenced.contains(&at))
1258 })
1259}
1260
1261fn table_rewrite(
1264 ast: &Ast,
1265 (catalog, parameters, session): (&Catalog, &Parameters, &Session),
1266 name: &QualifiedName,
1267 change: impl FnOnce(
1268 &mut Binder<'_>,
1269 &crate::scope::Scope,
1270 &mut Vec<(ExprRef, String)>,
1271 ) -> Result<()>,
1272) -> Result<Plan> {
1273 let mut binder = Binder::with(catalog, parameters, session);
1274 let (root, scope) =
1275 binder.bind_catalog_table(ast, name, name.table.clone(), ast::Slice::default())?;
1276 let mut out = Vec::with_capacity(scope.columns.len() + 1);
1277 for column in &scope.columns {
1278 let expr = binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1279 out.push((expr, column.name.clone()));
1280 }
1281 change(&mut binder, &scope, &mut out)?;
1282 let exprs: Vec<ExprRef> = out.iter().map(|(expr, _)| *expr).collect();
1283 let names: Vec<_> = out.iter().map(|(_, name)| binder.plan_mut().intern(name)).collect();
1284 let exprs = binder.plan_mut().add_expr_list(&exprs);
1285 let names = binder.plan_mut().add_name_list(&names);
1286 let index = binder.fresh_index();
1287 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1288 finish(binder, root)
1289}
1290
1291fn check_ast(text: &str) -> Result<(Ast, ast::ExprRef)> {
1293 let ast = parse_ast(&format!("SELECT {text}"))?;
1294 let found = match ast.statements.first() {
1295 Some(&ast::Statement::Query(query)) => match ast.query(query).body {
1296 ast::QueryBody::Select(select) => {
1297 ast.target_list(ast.select(select).targets).first().map(|target| target.expr)
1298 }
1299 _ => None,
1300 },
1301 _ => None,
1302 };
1303 let expr = found.ok_or_else(|| Error::internal("a check that is not an expression"))?;
1304 Ok((ast, expr))
1305}
1306
1307fn columns_in(text: &str) -> Result<Vec<String>> {
1309 let (ast, _) = check_ast(text)?;
1310 let mut out = Vec::new();
1311 for expr in &ast.exprs {
1312 if let ast::Expr::Column { name } = *expr
1313 && let Some(last) = ast.name(name).last()
1314 {
1315 out.push(last.to_string());
1316 }
1317 }
1318 Ok(out)
1319}
1320
1321fn rename_in(text: &str, old: &str, to: &str) -> Result<String> {
1324 let (mut ast, expr) = check_ast(text)?;
1325 let mut renamed = false;
1326 for at in 0..ast.exprs.len() {
1327 let ast::Expr::Column { name } = ast.exprs[at] else { continue };
1328 if name.len == 0 {
1329 continue;
1330 }
1331 let last = (name.start + name.len - 1) as usize;
1332 if same_name(ast.string(ast.parts[last]), old) {
1333 let index = ast.strings.len() as u32;
1334 ast.strings.push(to.to_string());
1335 ast.parts[last] = index;
1336 renamed = true;
1337 }
1338 }
1339 Ok(if renamed { deparse::expression(&ast, expr) } else { text.to_string() })
1340}
1341
1342fn deduplicate(columns: &mut [Field]) {
1355 for at in 0..columns.len() {
1356 let taken = |name: &str, upto: usize, columns: &[Field]| {
1357 columns[..upto].iter().any(|held| same_name(&held.name, name))
1358 };
1359 if !taken(&columns[at].name, at, columns) {
1360 continue;
1361 }
1362 let mut suffix = 1;
1363 let mut candidate = format!("{}_{suffix}", columns[at].name);
1364 while taken(&candidate, at, columns) {
1365 suffix += 1;
1366 candidate = format!("{}_{suffix}", columns[at].name);
1367 }
1368 columns[at].name = candidate;
1369 }
1370}
1371
1372fn create_view(
1379 ast: &Ast,
1380 catalog: &Catalog,
1381 parameters: &Parameters,
1382 session: &Session,
1383 index: ast::CreateViewRef,
1384) -> Result<Bound> {
1385 let written = ast.create_view(index);
1386 let parts: Vec<&str> = ast.name(written.name).collect();
1387 let name = if written.temporary {
1388 catalog.resolve_for_create_temporary(&parts)?
1389 } else {
1390 catalog.resolve_for_create(&parts)?
1391 };
1392 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
1393
1394 let mut binder = Binder::with(catalog, parameters, session);
1395 binder.outlined = true;
1398 let (_, mut scope) = binder.bind_query(ast, written.query)?;
1399 if aliases.len() > scope.len() {
1400 return Err(Error::binder("More VIEW aliases than columns in query result"));
1401 }
1402 if !aliases.is_empty() {
1403 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
1404 scope.rename(&written, "unnamed_subquery")?;
1405 }
1406
1407 Ok(Bound::CreateView(CreateView {
1408 name,
1409 sql: ast.string(written.sql).to_string(),
1410 statement: deparse::create_view(ast, index),
1411 aliases,
1412 if_not_exists: written.if_not_exists,
1413 or_replace: written.or_replace,
1414 columns: scope.fields(),
1415 }))
1416}
1417
1418fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
1419 let written = ast.drop_table(index);
1420 let kind = if written.view { Entry::View } else { Entry::Table };
1421 let mut names = Vec::new();
1422 for &name in ast.name_list(written.names) {
1423 let parts: Vec<&str> = ast.name(name).collect();
1424 match catalog.resolve_as(&parts, kind) {
1427 Ok(resolved) => names.push(resolved),
1428 Err(error) if written.if_exists => drop(error),
1429 Err(error) => return Err(error),
1430 }
1431 }
1432 Ok(Bound::DropTable(DropTable { names, kind }))
1433}
1434
1435fn setting(
1441 ast: &Ast,
1442 catalog: &Catalog,
1443 parameters: &Parameters,
1444 session: &Session,
1445 index: ast::SettingRef,
1446) -> Result<Bound> {
1447 let written = ast.setting(index);
1448 let name = ast.string(written.name).to_string();
1449 let value = if written.value == NONE {
1450 None
1451 } else {
1452 let mut binder = Binder::with(catalog, parameters, session);
1453 let bound = binder.bind_setting_value(ast, written.value)?;
1454 let Expr::Constant(value) = *binder.plan().expr(bound) else {
1455 return Err(Error::not_implemented(format!(
1456 "a value for {name} that is not a constant"
1457 )));
1458 };
1459 Some(binder.plan().value(value).clone())
1460 };
1461 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
1462}
1463
1464fn attach(
1466 ast: &Ast,
1467 catalog: &Catalog,
1468 parameters: &Parameters,
1469 session: &Session,
1470 index: ast::AttachRef,
1471) -> Result<Bound> {
1472 let written = ast.attach(index);
1473 let mut binder = Binder::with(catalog, parameters, session);
1474 let mut constant = |expr: ast::ExprRef, what: &str| -> Result<Value> {
1475 let bound = binder.bind_setting_value(ast, expr)?;
1476 let Expr::Constant(value) = *binder.plan().expr(bound) else {
1477 return Err(Error::not_implemented(format!("{what} of ATTACH that is not a constant")));
1478 };
1479 Ok(binder.plan().value(value).clone())
1480 };
1481 let path = match constant(written.path, "a path")? {
1482 Value::Null => {
1483 return Err(Error::binder("ATTACH path expression must not evaluate to NULL"));
1484 }
1485 value => value.to_string(),
1486 };
1487 let names = ast.name(written.names).map(str::to_string).collect::<Vec<_>>();
1488 let mut options = Vec::with_capacity(names.len());
1489 for (name, &value) in names.into_iter().zip(ast.expr_list(written.values)) {
1490 let value = if value == NONE { None } else { Some(constant(value, "an option")?) };
1491 options.push((name, value));
1492 }
1493 let alias = (written.alias != NONE).then(|| ast.string(written.alias).to_string());
1494 Ok(Bound::Attach(Attach {
1495 path,
1496 alias,
1497 or_replace: written.or_replace,
1498 if_not_exists: written.if_not_exists,
1499 options,
1500 }))
1501}
1502
1503fn clustered(
1515 binder: &mut Binder<'_>,
1516 input: rudb_plan::NodeRef,
1517 scope: &crate::scope::Scope,
1518 clustering: &Clustering,
1519 targets: &[usize],
1520 fields: &[Field],
1521) -> Result<rudb_plan::NodeRef> {
1522 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
1523 for (at, &column) in clustering.columns().iter().enumerate() {
1524 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
1525 continue;
1526 };
1527 let source = &scope.columns[from];
1528 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
1529 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
1534 let expr =
1535 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
1536 keys.push(SortKey { expr, descending: false, nulls_first: false });
1537 }
1538 if keys.is_empty() {
1539 return Ok(input);
1540 }
1541 let keys = binder.plan_mut().add_sort_keys(&keys);
1542 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
1543}
1544
1545fn fitted(
1559 binder: &Binder<'_>,
1560 scope: &crate::scope::Scope,
1561 clustering: &Clustering,
1562 targets: &[usize],
1563) -> Clustering {
1564 if clustering.width() != Width::Auto {
1565 return clustering.clone();
1566 }
1567 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
1568 else {
1569 return clustering.fitted(0, 0);
1570 };
1571 let source = &scope.columns[from];
1572 let Some(zones) = binder.plan().sole_zones() else {
1573 return clustering.fitted(0, 0);
1574 };
1575 let Some(at) = zones.column(&source.name) else {
1580 return clustering.fitted(0, 0);
1581 };
1582 let rows = zones.surviving(&[]).unwrap_or(0);
1583 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
1584 clustering.fitted(rows, days)
1585}
1586
1587fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
1593 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
1594 return None;
1595 };
1596 let days = match (low, high) {
1597 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
1599 (
1603 ColumnBound::Scaled { unscaled: low, scale: at },
1604 ColumnBound::Scaled { unscaled: high, scale: to },
1605 ) if at == to => {
1606 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
1607 high.checked_sub(*low)? / day
1608 }
1609 _ => return None,
1610 };
1611 u64::try_from(days).ok()
1612}
1613
1614fn bucketed(
1616 binder: &mut Binder<'_>,
1617 expr: ExprRef,
1618 width: Width,
1619 fields: &[Field],
1620 column: u32,
1621) -> ExprRef {
1622 if width == Width::Exact {
1623 return expr;
1624 }
1625 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1626 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1627 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1628 let name = binder.plan_mut().intern("date_trunc");
1629 let ty = fields[column as usize].ty.clone();
1630 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1631}
1632
1633fn insert(
1634 ast: &Ast,
1635 catalog: &Catalog,
1636 parameters: &Parameters,
1637 session: &Session,
1638 index: ast::InsertRef,
1639) -> Result<Bound> {
1640 let written = ast.insert(index);
1641 let parts: Vec<&str> = ast.name(written.name).collect();
1642 let name = catalog.resolve(&parts)?;
1643 if catalog.entry(&name)? == Entry::View {
1644 return Err(Error::catalog(format!("{} is not an table", name.table)));
1647 }
1648 let target = catalog.table(&name)?;
1649 let fields: Vec<Field> = target.columns().to_vec();
1650 let clustering = target.clustering().cloned();
1651
1652 let targets: Vec<usize> = if written.columns.is_empty() {
1656 (0..fields.len()).collect()
1657 } else {
1658 let mut targets = Vec::new();
1659 for column in ast.name(written.columns) {
1660 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1661 || {
1662 Error::binder(format!(
1663 "Table \"{}\" does not have a column named \"{column}\"",
1664 name.table
1665 ))
1666 },
1667 )?;
1668 if targets.contains(&at) {
1669 return Err(Error::binder(format!(
1670 "Column \"{column}\" is named twice in the same INSERT"
1671 )));
1672 }
1673 targets.push(at);
1674 }
1675 targets
1676 };
1677
1678 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1679 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1680 .collect();
1681 let mut binder = Binder::with(catalog, parameters, session);
1682 let (root, scope) = if written.source == NONE {
1683 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1686 } else {
1687 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1690 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1691 }
1692 if written.copy {
1696 binder.copy_into = Some(targets.iter().map(|&at| fields[at].clone()).collect());
1697 }
1698 let bound = binder.bind_query(ast, written.source)?;
1699 binder.copy_into = None;
1700 bound
1701 };
1702 let targets = if written.source == NONE { Vec::new() } else { targets };
1703 if scope.len() != targets.len() {
1704 return Err(Error::binder(format!(
1705 "Table \"{}\" has {} columns but {} values were supplied",
1706 name.table,
1707 targets.len(),
1708 scope.len()
1709 )));
1710 }
1711
1712 let root = match &clustering {
1718 None => root,
1719 Some(clustering) => {
1720 let fitted = fitted(&binder, &scope, clustering, &targets);
1725 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1726 }
1727 };
1728
1729 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1733 let mut names = Vec::with_capacity(fields.len());
1734 for (at, field) in fields.iter().enumerate() {
1735 let expr = match targets.iter().position(|&target| target == at) {
1736 Some(from) => {
1737 let column = &scope.columns[from];
1738 let expr =
1739 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1740 binder.checked_cast_to(expr, &field.ty, false)?
1741 }
1742 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1744 };
1745 exprs.push(expr);
1746 let interned = binder.plan_mut().intern(&field.name);
1747 names.push(interned);
1748 }
1749 let exprs = binder.plan_mut().add_expr_list(&exprs);
1750 let names = binder.plan_mut().add_name_list(&names);
1751 let index = binder.fresh_index();
1752 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1753 let source = finish(binder, root)?;
1754 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1755 let conflict = match written.conflict {
1756 Some(conflict) => {
1757 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1758 }
1759 None => None,
1760 };
1761 let checks = bind_checks(catalog, parameters, session, &name)?;
1762 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1763}
1764
1765fn bind_conflict(
1768 ast: &Ast,
1769 catalog: &Catalog,
1770 parameters: &Parameters,
1771 session: &Session,
1772 name: &QualifiedName,
1773 targets: &[usize],
1774 conflict: ast::Conflict,
1775) -> Result<Conflict> {
1776 let table = catalog.table(name)?;
1777 let fields = table.columns();
1778 let keys = table.keys();
1779 let key = if conflict.target.is_empty() {
1780 if keys.is_empty() {
1781 return Err(Error::binder(
1782 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1783 CONFLICT columns manually",
1784 ));
1785 }
1786 match conflict.action {
1787 ast::ConflictAction::Nothing => None,
1788 _ if keys.len() > 1 => {
1789 return Err(Error::binder(
1790 "Conflict target has to be provided for a DO UPDATE operation when the table \
1791 has multiple UNIQUE/PRIMARY KEY constraints",
1792 ));
1793 }
1794 _ => Some(0),
1795 }
1796 } else {
1797 let mut wanted = Vec::new();
1798 for column in ast.name(conflict.target) {
1799 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1800 return Err(Error::binder(format!(
1801 "Table \"{}\" does not have a column with name \"{column}\"",
1802 name.table
1803 )));
1804 };
1805 wanted.push(at);
1806 }
1807 wanted.sort_unstable();
1808 wanted.dedup();
1809 let found = keys.iter().position(|key| {
1810 let mut held = key.columns.clone();
1811 held.sort_unstable();
1812 held == wanted
1813 });
1814 let Some(found) = found else {
1815 return Err(Error::binder(
1816 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1817 KEY CONSTRAINT or INDEX",
1818 ));
1819 };
1820 Some(found)
1821 };
1822 let action = match conflict.action {
1823 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1824 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1825 ast::ConflictAction::Update { columns: written, query } => {
1826 let mut columns = Vec::new();
1827 for column in ast.name(written) {
1828 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1829 else {
1830 return Err(Error::binder(format!(
1831 "Referenced update column {column} not found in table!"
1832 )));
1833 };
1834 if columns.contains(&at) {
1835 return Err(Error::binder(format!(
1836 "Multiple assignments to same column \"\"{column}\"\""
1837 )));
1838 }
1839 columns.push(at);
1840 }
1841 let mut binder = Binder::with(catalog, parameters, session);
1842 binder.upsert = true;
1843 let (root, scope) = binder.bind_query(ast, query)?;
1844 let mut exprs = Vec::with_capacity(scope.columns.len());
1847 let mut names = Vec::with_capacity(scope.columns.len());
1848 for (at, column) in scope.columns.iter().enumerate() {
1849 let expr =
1850 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1851 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1852 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1853 names.push(binder.plan_mut().intern(&column.name));
1854 }
1855 let exprs = binder.plan_mut().add_expr_list(&exprs);
1856 let names = binder.plan_mut().add_name_list(&names);
1857 let index = binder.fresh_index();
1858 let root =
1859 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1860 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1861 }
1862 };
1863 Ok(Conflict { key, action })
1864}
1865
1866fn change(
1875 ast: &Ast,
1876 catalog: &Catalog,
1877 parameters: &Parameters,
1878 session: &Session,
1879 index: ast::InsertRef,
1880 delete: bool,
1881) -> Result<Bound> {
1882 let written = ast.insert(index);
1883 let parts: Vec<&str> = ast.name(written.name).collect();
1884 let name = catalog.resolve(&parts)?;
1885 if catalog.entry(&name)? == Entry::View {
1886 return Err(Error::binder(if delete {
1887 "Can only delete from base table"
1888 } else {
1889 "Can only update base table"
1890 }));
1891 }
1892 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1893 let mut targets: Vec<usize> = Vec::new();
1894 for column in ast.name(written.columns) {
1895 let at =
1896 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1897 Error::binder(format!("Referenced update column {column} not found in table!"))
1898 })?;
1899 if targets.contains(&at) {
1900 return Err(Error::binder(format!(
1901 "Multiple assignments to same column \"\"{column}\"\""
1902 )));
1903 }
1904 targets.push(at);
1905 }
1906
1907 let mut defaulted = vec![false; targets.len()];
1909 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1910 let items = ast.target_list(ast.select(select).targets);
1911 let first = items.len().saturating_sub(targets.len());
1912 for (at, item) in items[first..].iter().enumerate() {
1913 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1914 }
1915 }
1916 let table = catalog.table(&name)?;
1917 let mut binder = Binder::with(catalog, parameters, session);
1918 binder.default_as_null = defaulted.contains(&true);
1919 let (root, scope) = binder.bind_query(ast, written.source)?;
1920 binder.default_as_null = false;
1921 let width = fields.len();
1922 if scope.len() != width + 1 + targets.len() {
1923 return Err(Error::internal(format!(
1924 "an UPDATE source of {} columns over a table of {width}",
1925 scope.len()
1926 )));
1927 }
1928 let column = |binder: &mut Binder<'_>, at: usize| {
1929 let column = &scope.columns[at];
1930 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1931 };
1932 let hit = column(&mut binder, width);
1933 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1934 let mut exprs = Vec::with_capacity(width);
1935 let mut names = Vec::with_capacity(width);
1936 for (at, field) in fields.iter().enumerate() {
1937 let old = column(&mut binder, at);
1938 let expr = match targets.iter().position(|&target| target == at) {
1939 Some(from) => {
1940 let then = if defaulted[from] {
1941 binder.bind_default(table.default(at), &field.ty)?
1942 } else {
1943 let new = column(&mut binder, width + 1 + from);
1944 binder.checked_cast_to(new, &field.ty, false)?
1945 };
1946 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1947 binder
1948 .plan_mut()
1949 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1950 }
1951 None => old,
1952 };
1953 exprs.push(expr);
1954 let interned = binder.plan_mut().intern(&field.name);
1955 names.push(interned);
1956 }
1957 let yes = binder.add_constant(Value::Boolean(true));
1960 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1961 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1962 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1963 let interned = binder.plan_mut().intern("changed");
1964 names.push(interned);
1965 let exprs = binder.plan_mut().add_expr_list(&exprs);
1966 let names = binder.plan_mut().add_name_list(&names);
1967 let index = binder.fresh_index();
1968 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1969 let source = finish(binder, root)?;
1970 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1971 let write = if delete { Write::Delete } else { Write::Update };
1972 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1973 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1974}