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,
60 Transaction(ast::Transaction),
62 Explain { plan: Plan, analyze: bool, statistics: bool },
75}
76
77#[derive(Debug)]
89pub struct Setting {
90 pub name: String,
92 pub scope: ast::Scope,
94 pub value: Option<Value>,
96 pub pragma: bool,
98}
99
100#[derive(Debug)]
102pub struct CreateTable {
103 pub name: QualifiedName,
105 pub columns: Vec<Field>,
108 pub source: Option<Plan>,
110 pub if_not_exists: bool,
112 pub or_replace: bool,
114 pub keys: Vec<rudb_catalog::Key>,
116 pub defaults: Vec<Option<String>>,
118 pub sequences: Vec<QualifiedName>,
120 pub checks: Vec<String>,
122 pub foreign: Vec<rudb_catalog::ForeignKey>,
124 pub order: Vec<rudb_catalog::Constraint>,
126}
127
128#[derive(Debug)]
135pub struct CreateView {
136 pub name: QualifiedName,
138 pub sql: String,
140 pub statement: String,
145 pub aliases: Vec<String>,
147 pub if_not_exists: bool,
149 pub or_replace: bool,
151 pub columns: Vec<Field>,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
165pub struct SchemaChange {
166 pub catalog: String,
168 pub name: String,
170 pub drop: bool,
172 pub quiet: bool,
174 pub or_replace: bool,
177 pub cascade: bool,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct SequenceChange {
184 pub name: Option<QualifiedName>,
186 pub drop: bool,
188 pub if_not_exists: bool,
190 pub or_replace: bool,
192 pub cascade: bool,
194 pub options: rudb_common::sequence::Options,
196 pub owner: Option<QualifiedName>,
199}
200
201#[derive(Debug, Clone, PartialEq, Eq)]
203pub struct TypeChange {
204 pub name: Option<QualifiedName>,
206 pub ty: Option<LogicalType>,
208 pub uses: Vec<QualifiedName>,
210 pub if_not_exists: bool,
212 pub or_replace: bool,
214 pub cascade: bool,
216}
217
218#[derive(Debug)]
220pub struct Alter {
221 pub name: Option<QualifiedName>,
223 pub alteration: Option<rudb_catalog::Alteration>,
225 pub rewrite: Option<Plan>,
227}
228
229#[derive(Debug)]
231pub struct IndexChange {
232 pub table: Option<QualifiedName>,
234 pub index: Option<rudb_catalog::Index>,
236 pub name: Vec<String>,
238 pub quiet: bool,
240}
241
242#[derive(Debug)]
244pub struct DropTable {
245 pub names: Vec<QualifiedName>,
250 pub kind: Entry,
252}
253
254#[derive(Debug)]
256pub struct Insert {
257 pub name: QualifiedName,
259 pub source: Plan,
262 pub write: Write,
264 pub returning: Option<Box<Plan>>,
267 pub conflict: Option<Conflict>,
269 pub checks: Option<Checks>,
271}
272
273#[derive(Debug)]
279pub struct Checks {
280 pub plan: Box<Plan>,
282 pub messages: Vec<String>,
284}
285
286#[derive(Debug)]
288pub struct Conflict {
289 pub key: Option<usize>,
291 pub action: ConflictAction,
293}
294
295#[derive(Debug)]
297pub enum ConflictAction {
298 Nothing,
300 Replace(Vec<usize>),
302 Update {
306 columns: Vec<usize>,
308 plan: Box<Plan>,
310 },
311}
312
313#[derive(Debug, Clone, Copy, PartialEq, Eq)]
315pub enum Write {
316 Append,
318 Update,
321 Delete,
324}
325
326fn returning(
328 ast: &Ast,
329 catalog: &Catalog,
330 parameters: &Parameters,
331 session: &Session,
332 query: Option<ast::QueryRef>,
333) -> Result<Option<Box<Plan>>> {
334 let Some(query) = query else { return Ok(None) };
335 let mut binder = Binder::with(catalog, parameters, session);
336 let (root, _) = binder.bind_query(ast, query)?;
337 Ok(Some(Box::new(finish(binder, root)?)))
338}
339
340pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
347 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
348}
349
350pub fn bind_statement_with(
360 ast: &Ast,
361 catalog: &Catalog,
362 parameters: &Parameters,
363 session: &Session,
364) -> Result<Bound> {
365 bind_one(ast, catalog, parameters, session, false)
366}
367
368pub fn bind_statement_outlined(
381 ast: &Ast,
382 catalog: &Catalog,
383 parameters: &Parameters,
384 session: &Session,
385) -> Result<Bound> {
386 bind_one(ast, catalog, parameters, session, true)
387}
388
389fn bind_one(
390 ast: &Ast,
391 catalog: &Catalog,
392 parameters: &Parameters,
393 session: &Session,
394 outlined: bool,
395) -> Result<Bound> {
396 let statement = match ast.statements.as_slice() {
397 [statement] => *statement,
398 [] => return Err(Error::binder("no statement to bind")),
399 _ => return Err(Error::not_implemented("a script of more than one statement")),
400 };
401 match statement {
402 ast::Statement::Query(query) => {
403 let mut binder = Binder::with(catalog, parameters, session);
404 binder.outlined = outlined;
405 let (root, _) = binder.bind_query(ast, query)?;
406 Ok(Bound::Query(finish(binder, root)?))
407 }
408 ast::Statement::CreateTable(index) => {
409 create_table(ast, catalog, parameters, session, index)
410 }
411 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
412 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
413 ast::Statement::Schema(index) => {
414 let written = ast.schema(index);
415 if written.temporary {
416 return Err(Error::binder("Temporary schemas are not supported"));
417 }
418 let parts: Vec<&str> = ast.name(written.name).collect();
419 let (catalog, name) = catalog.schema_name(&parts)?;
420 Ok(Bound::Schema(SchemaChange {
421 catalog,
422 name,
423 drop: written.drop,
424 quiet: written.quiet,
425 or_replace: written.or_replace,
426 cascade: written.cascade,
427 }))
428 }
429 ast::Statement::Sequence(index) => {
430 let written = ast.sequence(index);
431 let parts: Vec<&str> = ast.name(written.name).collect();
432 let alter = !written.owner.is_empty();
433 let mut owner = None;
434 let name = if written.drop || alter {
435 match catalog.resolve_sequence(&parts) {
436 Ok(name) => Some(name),
437 Err(_) if written.quiet => None,
438 Err(error) => return Err(error),
439 }
440 } else if written.temporary {
441 Some(catalog.resolve_for_create_temporary(&parts)?)
442 } else {
443 Some(catalog.resolve_for_create(&parts)?)
444 };
445 if alter && name.is_some() {
446 let parts: Vec<&str> = ast.name(written.owner).collect();
447 owner = Some(catalog.resolve_owner(&parts)?);
448 }
449 Ok(Bound::Sequence(SequenceChange {
450 name,
451 drop: written.drop,
452 if_not_exists: written.quiet,
453 or_replace: written.or_replace,
454 cascade: written.cascade,
455 options: written.options,
456 owner,
457 }))
458 }
459 ast::Statement::Type(index) => {
460 let written = ast.type_def(index);
461 let parts: Vec<&str> = ast.name(written.name).collect();
462 let (name, ty, uses) = if written.drop {
463 let name = catalog.resolve_type(&parts).map(|made| made.name().clone());
464 if name.is_none() && !written.quiet {
465 return Err(Error::catalog(format!(
466 "Type with name {} does not exist!",
467 parts.last().copied().unwrap_or_default()
468 )));
469 }
470 (name, None, Vec::new())
471 } else {
472 let name = if written.temporary {
473 catalog.resolve_for_create_temporary(&parts)?
474 } else {
475 catalog.resolve_for_create(&parts)?
476 };
477 let (ty, uses) = written_type(catalog, ast.string(written.ty))?;
478 (Some(name), Some(ty), uses)
479 };
480 Ok(Bound::Type(TypeChange {
481 name,
482 ty,
483 uses,
484 if_not_exists: written.quiet,
485 or_replace: written.or_replace,
486 cascade: written.cascade,
487 }))
488 }
489 ast::Statement::Alter(index) => alter(ast, catalog, parameters, session, index),
490 ast::Statement::Index(index) => create_index(ast, catalog, parameters, session, index),
491 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
492 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
493 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
494 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
495 setting(ast, catalog, parameters, session, index)
496 }
497 ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
498 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
499 ast::Statement::Explain { query, analyze, statistics } => {
500 let mut binder = Binder::with(catalog, parameters, session);
501 let (root, _) = binder.bind_query(ast, query)?;
502 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
503 }
504 }
505}
506
507pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
513 let ast = parse_ast(sql)?;
514 bind_statement(&ast, catalog)
515}
516
517pub(crate) fn written_type(
521 catalog: &Catalog,
522 text: &str,
523) -> Result<(LogicalType, Vec<QualifiedName>)> {
524 let mut uses = Vec::new();
525 let ty = LogicalType::parse_with(text, &mut |parts| {
526 let parts: Vec<&str> = parts.iter().map(String::as_str).collect();
527 let made = catalog.resolve_type(&parts)?;
528 uses.push(made.name().clone());
529 Some(made.ty().clone())
530 })?;
531 Ok((ty, uses))
532}
533
534pub(crate) fn read_type(catalog: &Catalog, text: &str) -> Result<LogicalType> {
536 written_type(catalog, text).map(|(ty, _)| ty)
537}
538
539fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
540 let mut plan = binder.into_plan();
541 plan.set_root(root);
542 plan.validate()?;
543 Ok(plan)
544}
545
546fn create_table(
547 ast: &Ast,
548 catalog: &Catalog,
549 parameters: &Parameters,
550 session: &Session,
551 index: ast::CreateTableRef,
552) -> Result<Bound> {
553 let written = ast.create_table(index);
554 let parts: Vec<&str> = ast.name(written.name).collect();
555 let name = if written.temporary {
556 catalog.resolve_for_create_temporary(&parts)?
557 } else {
558 catalog.resolve_for_create(&parts)?
559 };
560 let defs = ast.column_defs(written.columns);
561 let (mut columns, source) = if written.query == NONE {
562 let mut columns = Vec::with_capacity(defs.len());
563 for def in defs {
564 let text = ast.string(def.ty);
565 if text.is_empty() {
566 return Err(Error::binder(format!(
567 "Column \"{}\" was declared without a type",
568 ast.string(def.name)
569 )));
570 }
571 let ty = read_type(catalog, text)?;
572 let column = ast.string(def.name);
573 columns.push(if def.not_null {
574 Field::required(column, ty)
575 } else {
576 Field::new(column, ty)
577 });
578 }
579 (columns, None)
580 } else {
581 let mut binder = Binder::with(catalog, parameters, session);
582 let (root, scope) = binder.bind_query(ast, written.query)?;
583 if defs.len() > scope.len() {
584 return Err(Error::binder("Target table has more colum names than query result."));
587 }
588 let mut columns = Vec::with_capacity(scope.columns.len());
589 for (at, column) in scope.columns.iter().enumerate() {
590 let named = match defs.get(at) {
591 Some(def) => ast.string(def.name).to_string(),
592 None => column.name.clone(),
593 };
594 columns.push(Field::new(named, column.ty.clone()));
595 }
596 if defs.is_empty() {
597 deduplicate(&mut columns);
598 }
599 (columns, Some(finish(binder, root)?))
600 };
601 duplicate_check(&columns)?;
602 let mut defaults = Vec::with_capacity(defs.len());
603 let mut sequences = Vec::new();
604 for def in defs {
605 defaults.push(if def.default == NONE {
606 None
607 } else {
608 let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
609 for name in used {
610 if !sequences.contains(&name) {
611 sequences.push(name);
612 }
613 }
614 Some(text)
615 });
616 }
617 let mut checks = Vec::new();
618 for &expr in ast.expr_list(written.checks) {
619 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
620 }
621 let mut keys = Vec::new();
622 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
623 let mut places = Vec::new();
624 for wanted in ast.name(names) {
625 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
626 else {
627 return Err(Error::catalog(format!(
628 "table \"{}\" does not have a column named \"{wanted}\"",
629 name.table
630 )));
631 };
632 places.push(place);
633 }
634 let primary = at as u32 == written.primary;
635 if primary {
636 for &place in &places {
637 columns[place].not_null = true;
638 }
639 }
640 keys.push(rudb_catalog::Key { columns: places, primary });
641 }
642 let mut foreign = Vec::new();
643 let lists = ast.name_list(written.foreign).iter();
644 let tables = ast.name_list(written.foreign_tables).iter();
645 let referenced = ast.name_list(written.foreign_referenced).iter();
646 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
647 let names: Vec<&str> = ast.name(names).collect();
648 let parts: Vec<&str> = ast.name(table).collect();
649 let wanted: Vec<&str> = ast.name(wanted).collect();
650 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
651 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
652 }
653 Ok(Bound::CreateTable(CreateTable {
654 name,
655 columns,
656 source,
657 if_not_exists: written.if_not_exists,
658 or_replace: written.or_replace,
659 keys,
660 defaults,
661 checks,
662 foreign,
663 sequences,
664 order: ast.constraint_list(written.order).iter().map(|&held| constraint(held)).collect(),
665 }))
666}
667
668fn constraint(held: ast::Constraint) -> rudb_catalog::Constraint {
670 match held {
671 ast::Constraint::Key(at) => rudb_catalog::Constraint::Key(at as usize),
672 ast::Constraint::Check(at) => rudb_catalog::Constraint::Check(at as usize),
673 ast::Constraint::Foreign(at) => rudb_catalog::Constraint::Foreign(at as usize),
674 ast::Constraint::NotNull(at) => rudb_catalog::Constraint::NotNull(at as usize),
675 }
676}
677
678fn foreign_key(
684 catalog: &Catalog,
685 made: &QualifiedName,
686 (columns, keys): (&[Field], &[rudb_catalog::Key]),
687 (names, parts, wanted): (&[&str], &[&str], &[&str]),
688) -> Result<rudb_catalog::ForeignKey> {
689 let mut places = Vec::with_capacity(names.len());
690 for &wanted in names {
691 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
692 return Err(Error::binder(format!(
693 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
694 )));
695 };
696 places.push(place);
697 }
698 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
699 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
700 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
701 (made.clone(), columns.to_vec(), keys.to_vec())
702 } else {
703 let resolved = catalog.resolve(parts)?;
704 if catalog.view(&resolved).is_ok() {
705 return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
706 }
707 let table = catalog.table(&resolved)?;
708 (resolved, table.columns().to_vec(), table.keys().to_vec())
709 };
710 let referenced = if wanted.is_empty() {
711 let Some(primary) = held.iter().find(|key| key.primary) else {
712 return Err(Error::binder(format!(
713 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
714 table.table
715 )));
716 };
717 if primary.columns.len() != places.len() {
718 return Err(Error::parser(
719 "The number of referencing and referenced columns for foreign keys must be the same",
720 ));
721 }
722 primary.columns.clone()
723 } else {
724 let mut referenced = Vec::with_capacity(wanted.len());
725 for &column in wanted {
726 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
727 return Err(Error::binder(format!(
728 "Failed to create foreign key: referenced table \"{}\" does not have a column \
729 named \"{column}\"",
730 table.table
731 )));
732 };
733 referenced.push(place);
734 }
735 let mut sorted = referenced.clone();
736 sorted.sort_unstable();
737 let matched = held.iter().any(|key| {
738 let mut columns = key.columns.clone();
739 columns.sort_unstable();
740 columns == sorted
741 });
742 if !matched && held.is_empty() {
743 return Err(Error::binder(format!(
744 "Failed to create foreign key: there is no primary key or unique constraint for \
745 referenced table \"{}\"",
746 table.table
747 )));
748 }
749 if !matched {
750 return Err(Error::binder(format!(
751 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
752 or unique constraint on the columns {}",
753 table.table,
754 wanted.join(", ")
755 )));
756 }
757 referenced
758 };
759 for (&from, &to) in places.iter().zip(&referenced) {
760 if columns[from].ty != fields[to].ty {
761 return Err(Error::binder(format!(
762 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
763 and column \"{}\" (\"{}\")",
764 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
765 )));
766 }
767 }
768 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
769}
770
771fn check_text(
773 ast: &Ast,
774 expr: ast::ExprRef,
775 columns: &[Field],
776 catalog: &Catalog,
777 parameters: &Parameters,
778 session: &Session,
779) -> Result<String> {
780 if crate::expr::has_aggregate(ast, expr) {
781 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
782 }
783 let mut binder = Binder::with(catalog, parameters, session);
784 let index = binder.fresh_index();
785 let mut scope = crate::scope::Scope::empty();
786 for (at, field) in columns.iter().enumerate() {
787 scope.push(crate::scope::Visible {
788 table: String::new(),
789 name: field.name.clone(),
790 binding: rudb_plan::ColumnBinding::new(index, at as u32),
791 ty: field.ty.clone(),
792 not_null: false,
793 key: None,
794 default: None,
795 qualified: false,
796 also: None,
797 });
798 }
799 match binder.bind_expr(ast, expr, &scope) {
800 Err(error) if error.message().starts_with("Referenced column \"") => {
801 let column = error.message().split('"').nth(1).unwrap_or_default();
802 Err(Error::binder(format!(
803 "Table does not contain column \"{column}\" referenced in check constraint!"
804 )))
805 }
806 Err(error) => Err(error),
807 Ok(_) if !binder.windows.is_empty() => {
808 Err(Error::binder("window functions are not allowed in check constraints"))
809 }
810 Ok(_) => Ok(deparse::expression(ast, expr)),
811 }
812}
813
814fn bind_checks(
817 catalog: &Catalog,
818 parameters: &Parameters,
819 session: &Session,
820 name: &QualifiedName,
821) -> Result<Option<Checks>> {
822 let table = catalog.table(name)?;
823 if table.checks().is_empty() {
824 return Ok(None);
825 }
826 let failed: Vec<String> =
827 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
828 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
829 let ast::Statement::Query(query) = ast.statements[0] else {
830 return Err(Error::internal("a check that is not an expression"));
831 };
832 let ast::QueryBody::Select(select) = ast.query(query).body else {
833 return Err(Error::internal("a check that is not an expression"));
834 };
835 let mut binder = Binder::with(catalog, parameters, session);
836 let (root, scope) =
837 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
838 let mut exprs = Vec::with_capacity(failed.len());
839 let mut names = Vec::with_capacity(failed.len());
840 for target in ast.target_list(ast.select(select).targets) {
841 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
842 names.push(binder.plan_mut().intern("failed"));
843 }
844 let exprs = binder.plan_mut().add_expr_list(&exprs);
845 let names = binder.plan_mut().add_name_list(&names);
846 let index = binder.fresh_index();
847 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
848 let messages = table
849 .checks()
850 .iter()
851 .map(|text| {
852 format!(
853 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
854 name.table
855 )
856 })
857 .collect();
858 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
859}
860
861fn default_text(
865 ast: &Ast,
866 expr: ast::ExprRef,
867 catalog: &Catalog,
868 parameters: &Parameters,
869 session: &Session,
870) -> Result<(String, Vec<QualifiedName>)> {
871 if crate::expr::has_aggregate(ast, expr) {
872 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
873 }
874 let mut binder = Binder::with(catalog, parameters, session);
875 let before = binder.plan_mut().node_count();
876 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
877 Err(error) if error.message().starts_with("Referenced ") => {
878 Err(Error::binder("DEFAULT value cannot contain column names"))
879 }
880 Err(error) => Err(error),
881 Ok(_) if binder.plan_mut().node_count() > before => {
883 Err(Error::binder("DEFAULT value cannot contain subqueries"))
884 }
885 Ok(_) if !binder.windows.is_empty() => {
886 Err(Error::binder("DEFAULT value cannot contain window functions!"))
887 }
888 Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
889 }
890}
891
892fn alter(
896 ast: &Ast,
897 catalog: &Catalog,
898 parameters: &Parameters,
899 session: &Session,
900 index: ast::AlterRef,
901) -> Result<Bound> {
902 let written = ast.alter(index);
903 let nothing = |name| Ok(Bound::Alter(Alter { name, alteration: None, rewrite: None }));
904 let parts: Vec<&str> = ast.name(written.name).collect();
905 let wanted = if written.view { Entry::View } else { Entry::Table };
906 let name = match catalog.resolve_as(&parts, wanted) {
907 Ok(name) => name,
908 Err(_) if written.quiet => return nothing(None),
909 Err(error) => return Err(error),
910 };
911 let kind = catalog.entry(&name)?;
912 if written.view && kind == Entry::Table {
913 return Err(Error::catalog("Can only modify table with ALTER TABLE statement"));
914 }
915 if let ast::AlterAction::Rename { to } = written.action {
916 let alteration = rudb_catalog::Alteration::Rename(ast.string(to).to_string());
917 return Ok(Bound::Alter(Alter {
918 name: Some(name),
919 alteration: Some(alteration),
920 rewrite: None,
921 }));
922 }
923 if kind == Entry::View {
924 return Err(Error::catalog("Can only modify view with ALTER VIEW statement"));
925 }
926 let table = catalog.table(&name)?;
927 let fields = table.columns();
928 let place = |column: ast::StrRef| {
929 fields.iter().position(|field| same_name(&field.name, ast.string(column)))
930 };
931 let missing = |column: ast::StrRef| {
932 let names: Vec<String> = fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
933 Error::binder(format!(
934 "Table \"{}\" does not have a column with name \"{}\"\n\nDid you mean: {}",
935 name.table,
936 ast.string(column),
937 names.join(", ")
938 ))
939 };
940 let found = |column: ast::StrRef| place(column).ok_or_else(|| missing(column));
941 let checks = table.checks();
942 let mut rewrite = None;
943 let alteration = match written.action {
944 ast::AlterAction::Rename { .. } => unreachable!("a rename is handled above"),
945 ast::AlterAction::RenameColumn { column, to } => {
946 let at = found(column)?;
947 let (old, to) = (fields[at].name.as_str(), ast.string(to));
948 if in_foreign_key(catalog, &name, table, at) {
949 return Err(Error::catalog(format!(
951 "Cannot rename column \"\"{old}\"\" because this is involved in the foreign key \
952 constraint"
953 )));
954 }
955 let checks =
956 checks.iter().map(|text| rename_in(text, old, to)).collect::<Result<Vec<_>>>()?;
957 rudb_catalog::Alteration::RenameColumn { column: at, to: to.to_string(), checks }
958 }
959 ast::AlterAction::AddColumn { column, quiet } => {
960 if quiet && place(column.name).is_some() {
961 return nothing(Some(name));
962 }
963 let ty = read_type(catalog, ast.string(column.ty))?;
964 let field = Field {
965 not_null: column.not_null,
966 ..Field::new(ast.string(column.name), ty.clone())
967 };
968 let (default, sequences) = if column.default == NONE {
969 (None, Vec::new())
970 } else {
971 let (text, used) = default_text(ast, column.default, catalog, parameters, session)?;
972 (Some(text), used)
973 };
974 rewrite = Some(table_rewrite(
975 ast,
976 (catalog, parameters, session),
977 &name,
978 |binder, _, out| {
979 let value = if column.default == NONE {
980 let null = binder.add_constant(Value::Null);
981 binder.cast_to(null, &ty)
982 } else {
983 let value =
984 binder.bind_expr(ast, column.default, &crate::scope::Scope::empty())?;
985 binder.checked_cast_to(value, &ty, false)?
986 };
987 out.push((value, field.name.clone()));
988 Ok(())
989 },
990 )?);
991 rudb_catalog::Alteration::AddColumn { field, default, sequences }
992 }
993 ast::AlterAction::DropColumn { column, quiet } => {
994 let Some(at) = place(column) else {
995 return if quiet { nothing(Some(name)) } else { Err(missing(column)) };
996 };
997 let dropped = fields[at].name.as_str();
998 let mut kept = Vec::with_capacity(checks.len());
999 for text in checks {
1000 let used = columns_in(text)?;
1001 if !used.iter().any(|used| same_name(used, dropped)) {
1002 kept.push(text.clone());
1003 } else if used.iter().any(|used| !same_name(used, dropped)) {
1004 return Err(Error::catalog(format!(
1005 "Cannot drop column \"{dropped}\" because there is a CHECK constraint that \
1006 depends on it"
1007 )));
1008 }
1009 }
1010 rewrite =
1011 Some(table_rewrite(ast, (catalog, parameters, session), &name, |_, _, out| {
1012 out.remove(at);
1013 Ok(())
1014 })?);
1015 rudb_catalog::Alteration::DropColumn { column: at, checks: kept }
1016 }
1017 ast::AlterAction::Default { column, default } => {
1018 let at = found(column)?;
1019 let (default, sequences) = if default == NONE {
1020 (None, Vec::new())
1021 } else {
1022 let (text, used) = default_text(ast, default, catalog, parameters, session)?;
1023 (Some(text), used)
1024 };
1025 rudb_catalog::Alteration::Default { column: at, default, sequences }
1026 }
1027 ast::AlterAction::NotNull { column, set } => {
1028 rudb_catalog::Alteration::NotNull { column: found(column)?, set }
1029 }
1030 ast::AlterAction::Type { column, ty, using } => {
1031 let at = found(column)?;
1032 let changed = fields[at].name.as_str();
1033 if table.keys().iter().any(|key| key.columns.contains(&at)) {
1034 return Err(Error::binder(
1035 "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY \
1036 constraint specified",
1037 ));
1038 }
1039 for text in checks {
1040 if columns_in(text)?.iter().any(|used| same_name(used, changed)) {
1041 return Err(Error::binder(
1042 "Cannot change the type of a column that has a CHECK constraint specified",
1043 ));
1044 }
1045 }
1046 if in_foreign_key(catalog, &name, table, at) {
1047 return Err(Error::binder(
1048 "Cannot change the type of a column that has a FOREIGN KEY constraint specified",
1049 ));
1050 }
1051 let mut target =
1052 if ty == NONE { None } else { Some(read_type(catalog, ast.string(ty))?) };
1053 rewrite = Some(table_rewrite(
1054 ast,
1055 (catalog, parameters, session),
1056 &name,
1057 |binder, scope, out| {
1058 let value = if using == NONE {
1059 out[at].0
1060 } else {
1061 binder.bind_expr(ast, using, scope)?
1062 };
1063 let ty = target
1064 .get_or_insert_with(|| binder.plan_mut().expr_type(value).clone())
1065 .clone();
1066 out[at].0 = binder.checked_cast_to(value, &ty, false)?;
1067 Ok(())
1068 },
1069 )?);
1070 let ty = target.ok_or_else(|| Error::internal("an ALTER TYPE that settled no type"))?;
1071 rudb_catalog::Alteration::Type { column: at, ty }
1072 }
1073 };
1074 Ok(Bound::Alter(Alter { name: Some(name), alteration: Some(alteration), rewrite }))
1075}
1076
1077fn create_index(
1085 ast: &Ast,
1086 catalog: &Catalog,
1087 parameters: &Parameters,
1088 session: &Session,
1089 at: ast::IndexRef,
1090) -> Result<Bound> {
1091 let written = ast.index(at);
1092 let parts: Vec<String> = ast.name(written.name).map(str::to_string).collect();
1093 if written.drop {
1094 return Ok(Bound::Index(IndexChange {
1095 table: None,
1096 index: None,
1097 name: parts,
1098 quiet: written.quiet,
1099 }));
1100 }
1101 let written_table: Vec<&str> = ast.name(written.table).collect();
1102 let name = catalog.resolve_as(&written_table, Entry::Table)?;
1103 if catalog.entry(&name)? == Entry::View {
1104 return Err(Error::binder("can only create an index on a base table"));
1105 }
1106 if written.using != NONE && !same_name(ast.string(written.using), "art") {
1107 return Err(Error::binder(format!("Unknown index type: {}", ast.string(written.using))));
1108 }
1109 let fields = catalog.table(&name)?.columns();
1110 let mut binder = Binder::with(catalog, parameters, session);
1111 let (_, scope) =
1112 binder.bind_catalog_table(ast, &name, name.table.clone(), ast::Slice::default())?;
1113 let mut columns = Vec::new();
1114 let mut plain = true;
1115 let mut texts = Vec::new();
1116 for &expr in ast.expr_list(written.elements) {
1117 if let ast::Expr::Column { name: column } = ast.exprs[expr as usize] {
1118 let column: Vec<&str> = ast.name(column).collect();
1119 if let [only] = column[..] {
1120 if !fields.iter().any(|field| same_name(&field.name, only)) {
1121 let names: Vec<String> =
1122 fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
1123 return Err(Error::binder(format!(
1125 "Table \"{}\" does not have a column named \"{only}\"\n\nCandidate bindings: \
1126 : {}",
1127 name.table,
1128 names.join(", ")
1129 )));
1130 }
1131 }
1132 }
1133 if crate::expr::has_aggregate(ast, expr) {
1134 return Err(Error::binder("aggregate functions are not allowed in index expressions"));
1135 }
1136 let before = binder.plan_mut().node_count();
1137 let value = binder.bind_expr(ast, expr, &scope)?;
1138 if binder.plan_mut().node_count() > before {
1139 return Err(Error::binder("cannot use subquery in index expressions"));
1140 }
1141 if !binder.windows.is_empty() {
1142 return Err(Error::binder("window functions are not allowed in index expressions"));
1143 }
1144 let ty = binder.plan_mut().expr_type(value).clone();
1145 if ty.is_nested() {
1146 return Err(Error::invalid_type(format!(
1147 "Invalid Type [{ty}]: Invalid type for index key."
1148 )));
1149 }
1150 let bare = match binder.plan_mut().expr(value) {
1151 Expr::Column(binding) => scope.columns.iter().position(|held| held.binding == *binding),
1152 _ => None,
1153 };
1154 if let Some(at) = bare {
1155 columns.push(at);
1156 texts.push(rudb_parse::quoted(&fields[at].name));
1157 continue;
1158 }
1159 plain = false;
1160 let text = deparse::expression(ast, expr);
1161 let used = columns_in(&text)?;
1162 if used.is_empty() {
1163 return Err(Error::binder(
1164 "CREATE INDEX does not refer to any columns in the base table!",
1165 ));
1166 }
1167 for used in used {
1168 if let Some(at) = fields.iter().position(|field| same_name(&field.name, &used)) {
1169 columns.push(at);
1170 }
1171 }
1172 texts.push(format!("({text})"));
1173 }
1174 if written.unique && !plain {
1175 return Err(Error::not_implemented("A UNIQUE index over an expression is not supported"));
1176 }
1177 let expressions = Value::List {
1178 element: LogicalType::Varchar,
1179 values: texts.iter().map(|text| Value::Varchar(text.clone())).collect(),
1180 };
1181 let unique = if written.unique { "UNIQUE " } else { "" };
1182 let table: Vec<String> = written_table.iter().map(|part| rudb_parse::quoted(part)).collect();
1183 let using = if written.using == NONE {
1184 String::new()
1185 } else {
1186 format!(" USING {} ", ast.string(written.using))
1187 };
1188 let index_name = parts.last().cloned().unwrap_or_default();
1189 let sql = format!(
1190 "CREATE {unique}INDEX {} ON {}{using}({});",
1191 rudb_parse::quoted(&index_name),
1192 table.join("."),
1193 texts.join(", ")
1194 );
1195 if !plain {
1196 columns.sort_unstable();
1197 columns.dedup();
1198 }
1199 let index = rudb_catalog::Index {
1200 name: index_name,
1201 unique: written.unique,
1202 columns,
1203 plain,
1204 expressions: expressions.to_string(),
1205 sql,
1206 oid: 0,
1207 };
1208 Ok(Bound::Index(IndexChange {
1209 table: Some(name),
1210 index: Some(index),
1211 name: Vec::new(),
1212 quiet: written.quiet,
1213 }))
1214}
1215
1216fn in_foreign_key(
1219 catalog: &Catalog,
1220 name: &QualifiedName,
1221 table: &rudb_catalog::Table,
1222 at: usize,
1223) -> bool {
1224 table.foreign().iter().any(|key| key.columns.contains(&at))
1225 || catalog.tables().any(|held| {
1226 held.foreign().iter().any(|key| key.table == *name && key.referenced.contains(&at))
1227 })
1228}
1229
1230fn table_rewrite(
1233 ast: &Ast,
1234 (catalog, parameters, session): (&Catalog, &Parameters, &Session),
1235 name: &QualifiedName,
1236 change: impl FnOnce(
1237 &mut Binder<'_>,
1238 &crate::scope::Scope,
1239 &mut Vec<(ExprRef, String)>,
1240 ) -> Result<()>,
1241) -> Result<Plan> {
1242 let mut binder = Binder::with(catalog, parameters, session);
1243 let (root, scope) =
1244 binder.bind_catalog_table(ast, name, name.table.clone(), ast::Slice::default())?;
1245 let mut out = Vec::with_capacity(scope.columns.len() + 1);
1246 for column in &scope.columns {
1247 let expr = binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1248 out.push((expr, column.name.clone()));
1249 }
1250 change(&mut binder, &scope, &mut out)?;
1251 let exprs: Vec<ExprRef> = out.iter().map(|(expr, _)| *expr).collect();
1252 let names: Vec<_> = out.iter().map(|(_, name)| binder.plan_mut().intern(name)).collect();
1253 let exprs = binder.plan_mut().add_expr_list(&exprs);
1254 let names = binder.plan_mut().add_name_list(&names);
1255 let index = binder.fresh_index();
1256 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1257 finish(binder, root)
1258}
1259
1260fn check_ast(text: &str) -> Result<(Ast, ast::ExprRef)> {
1262 let ast = parse_ast(&format!("SELECT {text}"))?;
1263 let found = match ast.statements.first() {
1264 Some(&ast::Statement::Query(query)) => match ast.query(query).body {
1265 ast::QueryBody::Select(select) => {
1266 ast.target_list(ast.select(select).targets).first().map(|target| target.expr)
1267 }
1268 _ => None,
1269 },
1270 _ => None,
1271 };
1272 let expr = found.ok_or_else(|| Error::internal("a check that is not an expression"))?;
1273 Ok((ast, expr))
1274}
1275
1276fn columns_in(text: &str) -> Result<Vec<String>> {
1278 let (ast, _) = check_ast(text)?;
1279 let mut out = Vec::new();
1280 for expr in &ast.exprs {
1281 if let ast::Expr::Column { name } = *expr {
1282 if let Some(last) = ast.name(name).last() {
1283 out.push(last.to_string());
1284 }
1285 }
1286 }
1287 Ok(out)
1288}
1289
1290fn rename_in(text: &str, old: &str, to: &str) -> Result<String> {
1293 let (mut ast, expr) = check_ast(text)?;
1294 let mut renamed = false;
1295 for at in 0..ast.exprs.len() {
1296 let ast::Expr::Column { name } = ast.exprs[at] else { continue };
1297 if name.len == 0 {
1298 continue;
1299 }
1300 let last = (name.start + name.len - 1) as usize;
1301 if same_name(ast.string(ast.parts[last]), old) {
1302 let index = ast.strings.len() as u32;
1303 ast.strings.push(to.to_string());
1304 ast.parts[last] = index;
1305 renamed = true;
1306 }
1307 }
1308 Ok(if renamed { deparse::expression(&ast, expr) } else { text.to_string() })
1309}
1310
1311fn deduplicate(columns: &mut [Field]) {
1324 for at in 0..columns.len() {
1325 let taken = |name: &str, upto: usize, columns: &[Field]| {
1326 columns[..upto].iter().any(|held| same_name(&held.name, name))
1327 };
1328 if !taken(&columns[at].name, at, columns) {
1329 continue;
1330 }
1331 let mut suffix = 1;
1332 let mut candidate = format!("{}_{suffix}", columns[at].name);
1333 while taken(&candidate, at, columns) {
1334 suffix += 1;
1335 candidate = format!("{}_{suffix}", columns[at].name);
1336 }
1337 columns[at].name = candidate;
1338 }
1339}
1340
1341fn create_view(
1348 ast: &Ast,
1349 catalog: &Catalog,
1350 parameters: &Parameters,
1351 session: &Session,
1352 index: ast::CreateViewRef,
1353) -> Result<Bound> {
1354 let written = ast.create_view(index);
1355 let parts: Vec<&str> = ast.name(written.name).collect();
1356 let name = if written.temporary {
1357 catalog.resolve_for_create_temporary(&parts)?
1358 } else {
1359 catalog.resolve_for_create(&parts)?
1360 };
1361 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
1362
1363 let mut binder = Binder::with(catalog, parameters, session);
1364 binder.outlined = true;
1367 let (_, mut scope) = binder.bind_query(ast, written.query)?;
1368 if aliases.len() > scope.len() {
1369 return Err(Error::binder("More VIEW aliases than columns in query result"));
1370 }
1371 if !aliases.is_empty() {
1372 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
1373 scope.rename(&written, "unnamed_subquery")?;
1374 }
1375
1376 Ok(Bound::CreateView(CreateView {
1377 name,
1378 sql: ast.string(written.sql).to_string(),
1379 statement: deparse::create_view(ast, index),
1380 aliases,
1381 if_not_exists: written.if_not_exists,
1382 or_replace: written.or_replace,
1383 columns: scope.fields(),
1384 }))
1385}
1386
1387fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
1388 let written = ast.drop_table(index);
1389 let kind = if written.view { Entry::View } else { Entry::Table };
1390 let mut names = Vec::new();
1391 for &name in ast.name_list(written.names) {
1392 let parts: Vec<&str> = ast.name(name).collect();
1393 match catalog.resolve_as(&parts, kind) {
1396 Ok(resolved) => names.push(resolved),
1397 Err(error) if written.if_exists => drop(error),
1398 Err(error) => return Err(error),
1399 }
1400 }
1401 Ok(Bound::DropTable(DropTable { names, kind }))
1402}
1403
1404fn setting(
1410 ast: &Ast,
1411 catalog: &Catalog,
1412 parameters: &Parameters,
1413 session: &Session,
1414 index: ast::SettingRef,
1415) -> Result<Bound> {
1416 let written = ast.setting(index);
1417 let name = ast.string(written.name).to_string();
1418 let value = if written.value == NONE {
1419 None
1420 } else {
1421 let mut binder = Binder::with(catalog, parameters, session);
1422 let bound = binder.bind_setting_value(ast, written.value)?;
1423 let Expr::Constant(value) = *binder.plan().expr(bound) else {
1424 return Err(Error::not_implemented(format!(
1425 "a value for {name} that is not a constant"
1426 )));
1427 };
1428 Some(binder.plan().value(value).clone())
1429 };
1430 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
1431}
1432
1433fn clustered(
1445 binder: &mut Binder<'_>,
1446 input: rudb_plan::NodeRef,
1447 scope: &crate::scope::Scope,
1448 clustering: &Clustering,
1449 targets: &[usize],
1450 fields: &[Field],
1451) -> Result<rudb_plan::NodeRef> {
1452 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
1453 for (at, &column) in clustering.columns().iter().enumerate() {
1454 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
1455 continue;
1456 };
1457 let source = &scope.columns[from];
1458 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
1459 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
1464 let expr =
1465 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
1466 keys.push(SortKey { expr, descending: false, nulls_first: false });
1467 }
1468 if keys.is_empty() {
1469 return Ok(input);
1470 }
1471 let keys = binder.plan_mut().add_sort_keys(&keys);
1472 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
1473}
1474
1475fn fitted(
1489 binder: &Binder<'_>,
1490 scope: &crate::scope::Scope,
1491 clustering: &Clustering,
1492 targets: &[usize],
1493) -> Clustering {
1494 if clustering.width() != Width::Auto {
1495 return clustering.clone();
1496 }
1497 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
1498 else {
1499 return clustering.fitted(0, 0);
1500 };
1501 let source = &scope.columns[from];
1502 let Some(zones) = binder.plan().sole_zones() else {
1503 return clustering.fitted(0, 0);
1504 };
1505 let Some(at) = zones.column(&source.name) else {
1510 return clustering.fitted(0, 0);
1511 };
1512 let rows = zones.surviving(&[]).unwrap_or(0);
1513 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
1514 clustering.fitted(rows, days)
1515}
1516
1517fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
1523 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
1524 return None;
1525 };
1526 let days = match (low, high) {
1527 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
1529 (
1533 ColumnBound::Scaled { unscaled: low, scale: at },
1534 ColumnBound::Scaled { unscaled: high, scale: to },
1535 ) if at == to => {
1536 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
1537 high.checked_sub(*low)? / day
1538 }
1539 _ => return None,
1540 };
1541 u64::try_from(days).ok()
1542}
1543
1544fn bucketed(
1546 binder: &mut Binder<'_>,
1547 expr: ExprRef,
1548 width: Width,
1549 fields: &[Field],
1550 column: u32,
1551) -> ExprRef {
1552 if width == Width::Exact {
1553 return expr;
1554 }
1555 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1556 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1557 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1558 let name = binder.plan_mut().intern("date_trunc");
1559 let ty = fields[column as usize].ty.clone();
1560 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1561}
1562
1563fn insert(
1564 ast: &Ast,
1565 catalog: &Catalog,
1566 parameters: &Parameters,
1567 session: &Session,
1568 index: ast::InsertRef,
1569) -> Result<Bound> {
1570 let written = ast.insert(index);
1571 let parts: Vec<&str> = ast.name(written.name).collect();
1572 let name = catalog.resolve(&parts)?;
1573 if catalog.entry(&name)? == Entry::View {
1574 return Err(Error::catalog(format!("{} is not an table", name.table)));
1577 }
1578 let target = catalog.table(&name)?;
1579 let fields: Vec<Field> = target.columns().to_vec();
1580 let clustering = target.clustering().cloned();
1581
1582 let targets: Vec<usize> = if written.columns.is_empty() {
1586 (0..fields.len()).collect()
1587 } else {
1588 let mut targets = Vec::new();
1589 for column in ast.name(written.columns) {
1590 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1591 || {
1592 Error::binder(format!(
1593 "Table \"{}\" does not have a column named \"{column}\"",
1594 name.table
1595 ))
1596 },
1597 )?;
1598 if targets.contains(&at) {
1599 return Err(Error::binder(format!(
1600 "Column \"{column}\" is named twice in the same INSERT"
1601 )));
1602 }
1603 targets.push(at);
1604 }
1605 targets
1606 };
1607
1608 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1609 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1610 .collect();
1611 let mut binder = Binder::with(catalog, parameters, session);
1612 let (root, scope) = if written.source == NONE {
1613 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1616 } else {
1617 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1620 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1621 }
1622 binder.bind_query(ast, written.source)?
1623 };
1624 let targets = if written.source == NONE { Vec::new() } else { targets };
1625 if scope.len() != targets.len() {
1626 return Err(Error::binder(format!(
1627 "Table \"{}\" has {} columns but {} values were supplied",
1628 name.table,
1629 targets.len(),
1630 scope.len()
1631 )));
1632 }
1633
1634 let root = match &clustering {
1640 None => root,
1641 Some(clustering) => {
1642 let fitted = fitted(&binder, &scope, clustering, &targets);
1647 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1648 }
1649 };
1650
1651 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1655 let mut names = Vec::with_capacity(fields.len());
1656 for (at, field) in fields.iter().enumerate() {
1657 let expr = match targets.iter().position(|&target| target == at) {
1658 Some(from) => {
1659 let column = &scope.columns[from];
1660 let expr =
1661 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1662 binder.checked_cast_to(expr, &field.ty, false)?
1663 }
1664 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1666 };
1667 exprs.push(expr);
1668 let interned = binder.plan_mut().intern(&field.name);
1669 names.push(interned);
1670 }
1671 let exprs = binder.plan_mut().add_expr_list(&exprs);
1672 let names = binder.plan_mut().add_name_list(&names);
1673 let index = binder.fresh_index();
1674 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1675 let source = finish(binder, root)?;
1676 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1677 let conflict = match written.conflict {
1678 Some(conflict) => {
1679 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1680 }
1681 None => None,
1682 };
1683 let checks = bind_checks(catalog, parameters, session, &name)?;
1684 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1685}
1686
1687fn bind_conflict(
1690 ast: &Ast,
1691 catalog: &Catalog,
1692 parameters: &Parameters,
1693 session: &Session,
1694 name: &QualifiedName,
1695 targets: &[usize],
1696 conflict: ast::Conflict,
1697) -> Result<Conflict> {
1698 let table = catalog.table(name)?;
1699 let fields = table.columns();
1700 let keys = table.keys();
1701 let key = if conflict.target.is_empty() {
1702 if keys.is_empty() {
1703 return Err(Error::binder(
1704 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1705 CONFLICT columns manually",
1706 ));
1707 }
1708 match conflict.action {
1709 ast::ConflictAction::Nothing => None,
1710 _ if keys.len() > 1 => {
1711 return Err(Error::binder(
1712 "Conflict target has to be provided for a DO UPDATE operation when the table \
1713 has multiple UNIQUE/PRIMARY KEY constraints",
1714 ));
1715 }
1716 _ => Some(0),
1717 }
1718 } else {
1719 let mut wanted = Vec::new();
1720 for column in ast.name(conflict.target) {
1721 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1722 return Err(Error::binder(format!(
1723 "Table \"{}\" does not have a column with name \"{column}\"",
1724 name.table
1725 )));
1726 };
1727 wanted.push(at);
1728 }
1729 wanted.sort_unstable();
1730 wanted.dedup();
1731 let found = keys.iter().position(|key| {
1732 let mut held = key.columns.clone();
1733 held.sort_unstable();
1734 held == wanted
1735 });
1736 let Some(found) = found else {
1737 return Err(Error::binder(
1738 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1739 KEY CONSTRAINT or INDEX",
1740 ));
1741 };
1742 Some(found)
1743 };
1744 let action = match conflict.action {
1745 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1746 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1747 ast::ConflictAction::Update { columns: written, query } => {
1748 let mut columns = Vec::new();
1749 for column in ast.name(written) {
1750 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1751 else {
1752 return Err(Error::binder(format!(
1753 "Referenced update column {column} not found in table!"
1754 )));
1755 };
1756 if columns.contains(&at) {
1757 return Err(Error::binder(format!(
1758 "Multiple assignments to same column \"\"{column}\"\""
1759 )));
1760 }
1761 columns.push(at);
1762 }
1763 let mut binder = Binder::with(catalog, parameters, session);
1764 binder.upsert = true;
1765 let (root, scope) = binder.bind_query(ast, query)?;
1766 let mut exprs = Vec::with_capacity(scope.columns.len());
1769 let mut names = Vec::with_capacity(scope.columns.len());
1770 for (at, column) in scope.columns.iter().enumerate() {
1771 let expr =
1772 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1773 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1774 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1775 names.push(binder.plan_mut().intern(&column.name));
1776 }
1777 let exprs = binder.plan_mut().add_expr_list(&exprs);
1778 let names = binder.plan_mut().add_name_list(&names);
1779 let index = binder.fresh_index();
1780 let root =
1781 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1782 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1783 }
1784 };
1785 Ok(Conflict { key, action })
1786}
1787
1788fn change(
1797 ast: &Ast,
1798 catalog: &Catalog,
1799 parameters: &Parameters,
1800 session: &Session,
1801 index: ast::InsertRef,
1802 delete: bool,
1803) -> Result<Bound> {
1804 let written = ast.insert(index);
1805 let parts: Vec<&str> = ast.name(written.name).collect();
1806 let name = catalog.resolve(&parts)?;
1807 if catalog.entry(&name)? == Entry::View {
1808 return Err(Error::binder(if delete {
1809 "Can only delete from base table"
1810 } else {
1811 "Can only update base table"
1812 }));
1813 }
1814 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1815 let mut targets: Vec<usize> = Vec::new();
1816 for column in ast.name(written.columns) {
1817 let at =
1818 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1819 Error::binder(format!("Referenced update column {column} not found in table!"))
1820 })?;
1821 if targets.contains(&at) {
1822 return Err(Error::binder(format!(
1823 "Multiple assignments to same column \"\"{column}\"\""
1824 )));
1825 }
1826 targets.push(at);
1827 }
1828
1829 let mut defaulted = vec![false; targets.len()];
1831 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1832 let items = ast.target_list(ast.select(select).targets);
1833 let first = items.len().saturating_sub(targets.len());
1834 for (at, item) in items[first..].iter().enumerate() {
1835 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1836 }
1837 }
1838 let table = catalog.table(&name)?;
1839 let mut binder = Binder::with(catalog, parameters, session);
1840 binder.default_as_null = defaulted.contains(&true);
1841 let (root, scope) = binder.bind_query(ast, written.source)?;
1842 binder.default_as_null = false;
1843 let width = fields.len();
1844 if scope.len() != width + 1 + targets.len() {
1845 return Err(Error::internal(format!(
1846 "an UPDATE source of {} columns over a table of {width}",
1847 scope.len()
1848 )));
1849 }
1850 let column = |binder: &mut Binder<'_>, at: usize| {
1851 let column = &scope.columns[at];
1852 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1853 };
1854 let hit = column(&mut binder, width);
1855 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1856 let mut exprs = Vec::with_capacity(width);
1857 let mut names = Vec::with_capacity(width);
1858 for (at, field) in fields.iter().enumerate() {
1859 let old = column(&mut binder, at);
1860 let expr = match targets.iter().position(|&target| target == at) {
1861 Some(from) => {
1862 let then = if defaulted[from] {
1863 binder.bind_default(table.default(at), &field.ty)?
1864 } else {
1865 let new = column(&mut binder, width + 1 + from);
1866 binder.checked_cast_to(new, &field.ty, false)?
1867 };
1868 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1869 binder
1870 .plan_mut()
1871 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1872 }
1873 None => old,
1874 };
1875 exprs.push(expr);
1876 let interned = binder.plan_mut().intern(&field.name);
1877 names.push(interned);
1878 }
1879 let yes = binder.add_constant(Value::Boolean(true));
1882 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1883 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1884 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1885 let interned = binder.plan_mut().intern("changed");
1886 names.push(interned);
1887 let exprs = binder.plan_mut().add_expr_list(&exprs);
1888 let names = binder.plan_mut().add_name_list(&names);
1889 let index = binder.fresh_index();
1890 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1891 let source = finish(binder, root)?;
1892 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1893 let write = if delete { Write::Delete } else { Write::Update };
1894 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1895 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1896}