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 Alter(Alter),
50 Index(IndexChange),
52 Insert(Insert),
54 Setting(Setting),
56 Checkpoint,
58 Transaction(ast::Transaction),
60 Explain { plan: Plan, analyze: bool, statistics: bool },
73}
74
75#[derive(Debug)]
87pub struct Setting {
88 pub name: String,
90 pub scope: ast::Scope,
92 pub value: Option<Value>,
94 pub pragma: bool,
96}
97
98#[derive(Debug)]
100pub struct CreateTable {
101 pub name: QualifiedName,
103 pub columns: Vec<Field>,
106 pub source: Option<Plan>,
108 pub if_not_exists: bool,
110 pub or_replace: bool,
112 pub keys: Vec<rudb_catalog::Key>,
114 pub defaults: Vec<Option<String>>,
116 pub sequences: Vec<QualifiedName>,
118 pub checks: Vec<String>,
120 pub foreign: Vec<rudb_catalog::ForeignKey>,
122}
123
124#[derive(Debug)]
131pub struct CreateView {
132 pub name: QualifiedName,
134 pub sql: String,
136 pub statement: String,
141 pub aliases: Vec<String>,
143 pub if_not_exists: bool,
145 pub or_replace: bool,
147 pub columns: Vec<Field>,
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct SchemaChange {
162 pub catalog: String,
164 pub name: String,
166 pub drop: bool,
168 pub quiet: bool,
170 pub or_replace: bool,
173 pub cascade: bool,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq)]
179pub struct SequenceChange {
180 pub name: Option<QualifiedName>,
182 pub drop: bool,
184 pub if_not_exists: bool,
186 pub or_replace: bool,
188 pub cascade: bool,
190 pub options: rudb_common::sequence::Options,
192 pub owner: Option<QualifiedName>,
195}
196
197#[derive(Debug)]
199pub struct Alter {
200 pub name: Option<QualifiedName>,
202 pub alteration: Option<rudb_catalog::Alteration>,
204 pub rewrite: Option<Plan>,
206}
207
208#[derive(Debug)]
210pub struct IndexChange {
211 pub table: Option<QualifiedName>,
213 pub index: Option<rudb_catalog::Index>,
215 pub name: Vec<String>,
217 pub quiet: bool,
219}
220
221#[derive(Debug)]
223pub struct DropTable {
224 pub names: Vec<QualifiedName>,
229 pub kind: Entry,
231}
232
233#[derive(Debug)]
235pub struct Insert {
236 pub name: QualifiedName,
238 pub source: Plan,
241 pub write: Write,
243 pub returning: Option<Box<Plan>>,
246 pub conflict: Option<Conflict>,
248 pub checks: Option<Checks>,
250}
251
252#[derive(Debug)]
258pub struct Checks {
259 pub plan: Box<Plan>,
261 pub messages: Vec<String>,
263}
264
265#[derive(Debug)]
267pub struct Conflict {
268 pub key: Option<usize>,
270 pub action: ConflictAction,
272}
273
274#[derive(Debug)]
276pub enum ConflictAction {
277 Nothing,
279 Replace(Vec<usize>),
281 Update {
285 columns: Vec<usize>,
287 plan: Box<Plan>,
289 },
290}
291
292#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294pub enum Write {
295 Append,
297 Update,
300 Delete,
303}
304
305fn returning(
307 ast: &Ast,
308 catalog: &Catalog,
309 parameters: &Parameters,
310 session: &Session,
311 query: Option<ast::QueryRef>,
312) -> Result<Option<Box<Plan>>> {
313 let Some(query) = query else { return Ok(None) };
314 let mut binder = Binder::with(catalog, parameters, session);
315 let (root, _) = binder.bind_query(ast, query)?;
316 Ok(Some(Box::new(finish(binder, root)?)))
317}
318
319pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
326 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
327}
328
329pub fn bind_statement_with(
339 ast: &Ast,
340 catalog: &Catalog,
341 parameters: &Parameters,
342 session: &Session,
343) -> Result<Bound> {
344 bind_one(ast, catalog, parameters, session, false)
345}
346
347pub fn bind_statement_outlined(
360 ast: &Ast,
361 catalog: &Catalog,
362 parameters: &Parameters,
363 session: &Session,
364) -> Result<Bound> {
365 bind_one(ast, catalog, parameters, session, true)
366}
367
368fn bind_one(
369 ast: &Ast,
370 catalog: &Catalog,
371 parameters: &Parameters,
372 session: &Session,
373 outlined: bool,
374) -> Result<Bound> {
375 let statement = match ast.statements.as_slice() {
376 [statement] => *statement,
377 [] => return Err(Error::binder("no statement to bind")),
378 _ => return Err(Error::not_implemented("a script of more than one statement")),
379 };
380 match statement {
381 ast::Statement::Query(query) => {
382 let mut binder = Binder::with(catalog, parameters, session);
383 binder.outlined = outlined;
384 let (root, _) = binder.bind_query(ast, query)?;
385 Ok(Bound::Query(finish(binder, root)?))
386 }
387 ast::Statement::CreateTable(index) => {
388 create_table(ast, catalog, parameters, session, index)
389 }
390 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
391 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
392 ast::Statement::Schema(index) => {
393 let written = ast.schema(index);
394 if written.temporary {
395 return Err(Error::binder("Temporary schemas are not supported"));
396 }
397 let parts: Vec<&str> = ast.name(written.name).collect();
398 let (catalog, name) = catalog.schema_name(&parts)?;
399 Ok(Bound::Schema(SchemaChange {
400 catalog,
401 name,
402 drop: written.drop,
403 quiet: written.quiet,
404 or_replace: written.or_replace,
405 cascade: written.cascade,
406 }))
407 }
408 ast::Statement::Sequence(index) => {
409 let written = ast.sequence(index);
410 let parts: Vec<&str> = ast.name(written.name).collect();
411 let alter = !written.owner.is_empty();
412 let mut owner = None;
413 let name = if written.drop || alter {
414 match catalog.resolve_sequence(&parts) {
415 Ok(name) => Some(name),
416 Err(_) if written.quiet => None,
417 Err(error) => return Err(error),
418 }
419 } else if written.temporary {
420 Some(catalog.resolve_for_create_temporary(&parts)?)
421 } else {
422 Some(catalog.resolve_for_create(&parts)?)
423 };
424 if alter && name.is_some() {
425 let parts: Vec<&str> = ast.name(written.owner).collect();
426 owner = Some(catalog.resolve_owner(&parts)?);
427 }
428 Ok(Bound::Sequence(SequenceChange {
429 name,
430 drop: written.drop,
431 if_not_exists: written.quiet,
432 or_replace: written.or_replace,
433 cascade: written.cascade,
434 options: written.options,
435 owner,
436 }))
437 }
438 ast::Statement::Alter(index) => alter(ast, catalog, parameters, session, index),
439 ast::Statement::Index(index) => create_index(ast, catalog, parameters, session, index),
440 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
441 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
442 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
443 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
444 setting(ast, catalog, parameters, session, index)
445 }
446 ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
447 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
448 ast::Statement::Explain { query, analyze, statistics } => {
449 let mut binder = Binder::with(catalog, parameters, session);
450 let (root, _) = binder.bind_query(ast, query)?;
451 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
452 }
453 }
454}
455
456pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
462 let ast = parse_ast(sql)?;
463 bind_statement(&ast, catalog)
464}
465
466fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
468 let mut plan = binder.into_plan();
469 plan.set_root(root);
470 plan.validate()?;
471 Ok(plan)
472}
473
474fn create_table(
475 ast: &Ast,
476 catalog: &Catalog,
477 parameters: &Parameters,
478 session: &Session,
479 index: ast::CreateTableRef,
480) -> Result<Bound> {
481 let written = ast.create_table(index);
482 let parts: Vec<&str> = ast.name(written.name).collect();
483 let name = if written.temporary {
484 catalog.resolve_for_create_temporary(&parts)?
485 } else {
486 catalog.resolve_for_create(&parts)?
487 };
488 let defs = ast.column_defs(written.columns);
489 let (mut columns, source) = if written.query == NONE {
490 let mut columns = Vec::with_capacity(defs.len());
491 for def in defs {
492 let text = ast.string(def.ty);
493 if text.is_empty() {
494 return Err(Error::binder(format!(
495 "Column \"{}\" was declared without a type",
496 ast.string(def.name)
497 )));
498 }
499 let ty = LogicalType::parse(text)?;
500 let column = ast.string(def.name);
501 columns.push(if def.not_null {
502 Field::required(column, ty)
503 } else {
504 Field::new(column, ty)
505 });
506 }
507 (columns, None)
508 } else {
509 let mut binder = Binder::with(catalog, parameters, session);
510 let (root, scope) = binder.bind_query(ast, written.query)?;
511 if defs.len() > scope.len() {
512 return Err(Error::binder("Target table has more colum names than query result."));
515 }
516 let mut columns = Vec::with_capacity(scope.columns.len());
517 for (at, column) in scope.columns.iter().enumerate() {
518 let named = match defs.get(at) {
519 Some(def) => ast.string(def.name).to_string(),
520 None => column.name.clone(),
521 };
522 columns.push(Field::new(named, column.ty.clone()));
523 }
524 if defs.is_empty() {
525 deduplicate(&mut columns);
526 }
527 (columns, Some(finish(binder, root)?))
528 };
529 duplicate_check(&columns)?;
530 let mut defaults = Vec::with_capacity(defs.len());
531 let mut sequences = Vec::new();
532 for def in defs {
533 defaults.push(if def.default == NONE {
534 None
535 } else {
536 let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
537 for name in used {
538 if !sequences.contains(&name) {
539 sequences.push(name);
540 }
541 }
542 Some(text)
543 });
544 }
545 let mut checks = Vec::new();
546 for &expr in ast.expr_list(written.checks) {
547 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
548 }
549 let mut keys = Vec::new();
550 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
551 let mut places = Vec::new();
552 for wanted in ast.name(names) {
553 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
554 else {
555 return Err(Error::catalog(format!(
556 "table \"{}\" does not have a column named \"{wanted}\"",
557 name.table
558 )));
559 };
560 places.push(place);
561 }
562 let primary = at as u32 == written.primary;
563 if primary {
564 for &place in &places {
565 columns[place].not_null = true;
566 }
567 }
568 keys.push(rudb_catalog::Key { columns: places, primary });
569 }
570 let mut foreign = Vec::new();
571 let lists = ast.name_list(written.foreign).iter();
572 let tables = ast.name_list(written.foreign_tables).iter();
573 let referenced = ast.name_list(written.foreign_referenced).iter();
574 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
575 let names: Vec<&str> = ast.name(names).collect();
576 let parts: Vec<&str> = ast.name(table).collect();
577 let wanted: Vec<&str> = ast.name(wanted).collect();
578 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
579 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
580 }
581 Ok(Bound::CreateTable(CreateTable {
582 name,
583 columns,
584 source,
585 if_not_exists: written.if_not_exists,
586 or_replace: written.or_replace,
587 keys,
588 defaults,
589 checks,
590 foreign,
591 sequences,
592 }))
593}
594
595fn foreign_key(
601 catalog: &Catalog,
602 made: &QualifiedName,
603 (columns, keys): (&[Field], &[rudb_catalog::Key]),
604 (names, parts, wanted): (&[&str], &[&str], &[&str]),
605) -> Result<rudb_catalog::ForeignKey> {
606 let mut places = Vec::with_capacity(names.len());
607 for &wanted in names {
608 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
609 return Err(Error::binder(format!(
610 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
611 )));
612 };
613 places.push(place);
614 }
615 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
616 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
617 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
618 (made.clone(), columns.to_vec(), keys.to_vec())
619 } else {
620 let resolved = catalog.resolve(parts)?;
621 if catalog.view(&resolved).is_ok() {
622 return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
623 }
624 let table = catalog.table(&resolved)?;
625 (resolved, table.columns().to_vec(), table.keys().to_vec())
626 };
627 let referenced = if wanted.is_empty() {
628 let Some(primary) = held.iter().find(|key| key.primary) else {
629 return Err(Error::binder(format!(
630 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
631 table.table
632 )));
633 };
634 if primary.columns.len() != places.len() {
635 return Err(Error::parser(
636 "The number of referencing and referenced columns for foreign keys must be the same",
637 ));
638 }
639 primary.columns.clone()
640 } else {
641 let mut referenced = Vec::with_capacity(wanted.len());
642 for &column in wanted {
643 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
644 return Err(Error::binder(format!(
645 "Failed to create foreign key: referenced table \"{}\" does not have a column \
646 named \"{column}\"",
647 table.table
648 )));
649 };
650 referenced.push(place);
651 }
652 let mut sorted = referenced.clone();
653 sorted.sort_unstable();
654 let matched = held.iter().any(|key| {
655 let mut columns = key.columns.clone();
656 columns.sort_unstable();
657 columns == sorted
658 });
659 if !matched && held.is_empty() {
660 return Err(Error::binder(format!(
661 "Failed to create foreign key: there is no primary key or unique constraint for \
662 referenced table \"{}\"",
663 table.table
664 )));
665 }
666 if !matched {
667 return Err(Error::binder(format!(
668 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
669 or unique constraint on the columns {}",
670 table.table,
671 wanted.join(", ")
672 )));
673 }
674 referenced
675 };
676 for (&from, &to) in places.iter().zip(&referenced) {
677 if columns[from].ty != fields[to].ty {
678 return Err(Error::binder(format!(
679 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
680 and column \"{}\" (\"{}\")",
681 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
682 )));
683 }
684 }
685 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
686}
687
688fn check_text(
690 ast: &Ast,
691 expr: ast::ExprRef,
692 columns: &[Field],
693 catalog: &Catalog,
694 parameters: &Parameters,
695 session: &Session,
696) -> Result<String> {
697 if crate::expr::has_aggregate(ast, expr) {
698 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
699 }
700 let mut binder = Binder::with(catalog, parameters, session);
701 let index = binder.fresh_index();
702 let mut scope = crate::scope::Scope::empty();
703 for (at, field) in columns.iter().enumerate() {
704 scope.push(crate::scope::Visible {
705 table: String::new(),
706 name: field.name.clone(),
707 binding: rudb_plan::ColumnBinding::new(index, at as u32),
708 ty: field.ty.clone(),
709 not_null: false,
710 key: None,
711 default: None,
712 qualified: false,
713 also: None,
714 });
715 }
716 match binder.bind_expr(ast, expr, &scope) {
717 Err(error) if error.message().starts_with("Referenced column \"") => {
718 let column = error.message().split('"').nth(1).unwrap_or_default();
719 Err(Error::binder(format!(
720 "Table does not contain column \"{column}\" referenced in check constraint!"
721 )))
722 }
723 Err(error) => Err(error),
724 Ok(_) if !binder.windows.is_empty() => {
725 Err(Error::binder("window functions are not allowed in check constraints"))
726 }
727 Ok(_) => Ok(deparse::expression(ast, expr)),
728 }
729}
730
731fn bind_checks(
734 catalog: &Catalog,
735 parameters: &Parameters,
736 session: &Session,
737 name: &QualifiedName,
738) -> Result<Option<Checks>> {
739 let table = catalog.table(name)?;
740 if table.checks().is_empty() {
741 return Ok(None);
742 }
743 let failed: Vec<String> =
744 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
745 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
746 let ast::Statement::Query(query) = ast.statements[0] else {
747 return Err(Error::internal("a check that is not an expression"));
748 };
749 let ast::QueryBody::Select(select) = ast.query(query).body else {
750 return Err(Error::internal("a check that is not an expression"));
751 };
752 let mut binder = Binder::with(catalog, parameters, session);
753 let (root, scope) =
754 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
755 let mut exprs = Vec::with_capacity(failed.len());
756 let mut names = Vec::with_capacity(failed.len());
757 for target in ast.target_list(ast.select(select).targets) {
758 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
759 names.push(binder.plan_mut().intern("failed"));
760 }
761 let exprs = binder.plan_mut().add_expr_list(&exprs);
762 let names = binder.plan_mut().add_name_list(&names);
763 let index = binder.fresh_index();
764 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
765 let messages = table
766 .checks()
767 .iter()
768 .map(|text| {
769 format!(
770 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
771 name.table
772 )
773 })
774 .collect();
775 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
776}
777
778fn default_text(
782 ast: &Ast,
783 expr: ast::ExprRef,
784 catalog: &Catalog,
785 parameters: &Parameters,
786 session: &Session,
787) -> Result<(String, Vec<QualifiedName>)> {
788 if crate::expr::has_aggregate(ast, expr) {
789 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
790 }
791 let mut binder = Binder::with(catalog, parameters, session);
792 let before = binder.plan_mut().node_count();
793 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
794 Err(error) if error.message().starts_with("Referenced ") => {
795 Err(Error::binder("DEFAULT value cannot contain column names"))
796 }
797 Err(error) => Err(error),
798 Ok(_) if binder.plan_mut().node_count() > before => {
800 Err(Error::binder("DEFAULT value cannot contain subqueries"))
801 }
802 Ok(_) if !binder.windows.is_empty() => {
803 Err(Error::binder("DEFAULT value cannot contain window functions!"))
804 }
805 Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
806 }
807}
808
809fn alter(
813 ast: &Ast,
814 catalog: &Catalog,
815 parameters: &Parameters,
816 session: &Session,
817 index: ast::AlterRef,
818) -> Result<Bound> {
819 let written = ast.alter(index);
820 let nothing = |name| Ok(Bound::Alter(Alter { name, alteration: None, rewrite: None }));
821 let parts: Vec<&str> = ast.name(written.name).collect();
822 let wanted = if written.view { Entry::View } else { Entry::Table };
823 let name = match catalog.resolve_as(&parts, wanted) {
824 Ok(name) => name,
825 Err(_) if written.quiet => return nothing(None),
826 Err(error) => return Err(error),
827 };
828 let kind = catalog.entry(&name)?;
829 if written.view && kind == Entry::Table {
830 return Err(Error::catalog("Can only modify table with ALTER TABLE statement"));
831 }
832 if let ast::AlterAction::Rename { to } = written.action {
833 let alteration = rudb_catalog::Alteration::Rename(ast.string(to).to_string());
834 return Ok(Bound::Alter(Alter {
835 name: Some(name),
836 alteration: Some(alteration),
837 rewrite: None,
838 }));
839 }
840 if kind == Entry::View {
841 return Err(Error::catalog("Can only modify view with ALTER VIEW statement"));
842 }
843 let table = catalog.table(&name)?;
844 let fields = table.columns();
845 let place = |column: ast::StrRef| {
846 fields.iter().position(|field| same_name(&field.name, ast.string(column)))
847 };
848 let missing = |column: ast::StrRef| {
849 let names: Vec<String> = fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
850 Error::binder(format!(
851 "Table \"{}\" does not have a column with name \"{}\"\n\nDid you mean: {}",
852 name.table,
853 ast.string(column),
854 names.join(", ")
855 ))
856 };
857 let found = |column: ast::StrRef| place(column).ok_or_else(|| missing(column));
858 let checks = table.checks();
859 let mut rewrite = None;
860 let alteration = match written.action {
861 ast::AlterAction::Rename { .. } => unreachable!("a rename is handled above"),
862 ast::AlterAction::RenameColumn { column, to } => {
863 let at = found(column)?;
864 let (old, to) = (fields[at].name.as_str(), ast.string(to));
865 if in_foreign_key(catalog, &name, table, at) {
866 return Err(Error::catalog(format!(
868 "Cannot rename column \"\"{old}\"\" because this is involved in the foreign key \
869 constraint"
870 )));
871 }
872 let checks =
873 checks.iter().map(|text| rename_in(text, old, to)).collect::<Result<Vec<_>>>()?;
874 rudb_catalog::Alteration::RenameColumn { column: at, to: to.to_string(), checks }
875 }
876 ast::AlterAction::AddColumn { column, quiet } => {
877 if quiet && place(column.name).is_some() {
878 return nothing(Some(name));
879 }
880 let ty = LogicalType::parse(ast.string(column.ty))?;
881 let field = Field {
882 not_null: column.not_null,
883 ..Field::new(ast.string(column.name), ty.clone())
884 };
885 let (default, sequences) = if column.default == NONE {
886 (None, Vec::new())
887 } else {
888 let (text, used) = default_text(ast, column.default, catalog, parameters, session)?;
889 (Some(text), used)
890 };
891 rewrite = Some(table_rewrite(
892 ast,
893 (catalog, parameters, session),
894 &name,
895 |binder, _, out| {
896 let value = if column.default == NONE {
897 let null = binder.add_constant(Value::Null);
898 binder.cast_to(null, &ty)
899 } else {
900 let value =
901 binder.bind_expr(ast, column.default, &crate::scope::Scope::empty())?;
902 binder.checked_cast_to(value, &ty, false)?
903 };
904 out.push((value, field.name.clone()));
905 Ok(())
906 },
907 )?);
908 rudb_catalog::Alteration::AddColumn { field, default, sequences }
909 }
910 ast::AlterAction::DropColumn { column, quiet } => {
911 let Some(at) = place(column) else {
912 return if quiet { nothing(Some(name)) } else { Err(missing(column)) };
913 };
914 let dropped = fields[at].name.as_str();
915 let mut kept = Vec::with_capacity(checks.len());
916 for text in checks {
917 let used = columns_in(text)?;
918 if !used.iter().any(|used| same_name(used, dropped)) {
919 kept.push(text.clone());
920 } else if used.iter().any(|used| !same_name(used, dropped)) {
921 return Err(Error::catalog(format!(
922 "Cannot drop column \"{dropped}\" because there is a CHECK constraint that \
923 depends on it"
924 )));
925 }
926 }
927 rewrite =
928 Some(table_rewrite(ast, (catalog, parameters, session), &name, |_, _, out| {
929 out.remove(at);
930 Ok(())
931 })?);
932 rudb_catalog::Alteration::DropColumn { column: at, checks: kept }
933 }
934 ast::AlterAction::Default { column, default } => {
935 let at = found(column)?;
936 let (default, sequences) = if default == NONE {
937 (None, Vec::new())
938 } else {
939 let (text, used) = default_text(ast, default, catalog, parameters, session)?;
940 (Some(text), used)
941 };
942 rudb_catalog::Alteration::Default { column: at, default, sequences }
943 }
944 ast::AlterAction::NotNull { column, set } => {
945 rudb_catalog::Alteration::NotNull { column: found(column)?, set }
946 }
947 ast::AlterAction::Type { column, ty, using } => {
948 let at = found(column)?;
949 let changed = fields[at].name.as_str();
950 if table.keys().iter().any(|key| key.columns.contains(&at)) {
951 return Err(Error::binder(
952 "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY \
953 constraint specified",
954 ));
955 }
956 for text in checks {
957 if columns_in(text)?.iter().any(|used| same_name(used, changed)) {
958 return Err(Error::binder(
959 "Cannot change the type of a column that has a CHECK constraint specified",
960 ));
961 }
962 }
963 if in_foreign_key(catalog, &name, table, at) {
964 return Err(Error::binder(
965 "Cannot change the type of a column that has a FOREIGN KEY constraint specified",
966 ));
967 }
968 let mut target =
969 if ty == NONE { None } else { Some(LogicalType::parse(ast.string(ty))?) };
970 rewrite = Some(table_rewrite(
971 ast,
972 (catalog, parameters, session),
973 &name,
974 |binder, scope, out| {
975 let value = if using == NONE {
976 out[at].0
977 } else {
978 binder.bind_expr(ast, using, scope)?
979 };
980 let ty = target
981 .get_or_insert_with(|| binder.plan_mut().expr_type(value).clone())
982 .clone();
983 out[at].0 = binder.checked_cast_to(value, &ty, false)?;
984 Ok(())
985 },
986 )?);
987 let ty = target.ok_or_else(|| Error::internal("an ALTER TYPE that settled no type"))?;
988 rudb_catalog::Alteration::Type { column: at, ty }
989 }
990 };
991 Ok(Bound::Alter(Alter { name: Some(name), alteration: Some(alteration), rewrite }))
992}
993
994fn create_index(
1002 ast: &Ast,
1003 catalog: &Catalog,
1004 parameters: &Parameters,
1005 session: &Session,
1006 at: ast::IndexRef,
1007) -> Result<Bound> {
1008 let written = ast.index(at);
1009 let parts: Vec<String> = ast.name(written.name).map(str::to_string).collect();
1010 if written.drop {
1011 return Ok(Bound::Index(IndexChange {
1012 table: None,
1013 index: None,
1014 name: parts,
1015 quiet: written.quiet,
1016 }));
1017 }
1018 let written_table: Vec<&str> = ast.name(written.table).collect();
1019 let name = catalog.resolve_as(&written_table, Entry::Table)?;
1020 if catalog.entry(&name)? == Entry::View {
1021 return Err(Error::binder("can only create an index on a base table"));
1022 }
1023 if written.using != NONE && !same_name(ast.string(written.using), "art") {
1024 return Err(Error::binder(format!("Unknown index type: {}", ast.string(written.using))));
1025 }
1026 let fields = catalog.table(&name)?.columns();
1027 let mut binder = Binder::with(catalog, parameters, session);
1028 let (_, scope) =
1029 binder.bind_catalog_table(ast, &name, name.table.clone(), ast::Slice::default())?;
1030 let mut columns = Vec::new();
1031 let mut plain = true;
1032 let mut texts = Vec::new();
1033 for &expr in ast.expr_list(written.elements) {
1034 if let ast::Expr::Column { name: column } = ast.exprs[expr as usize] {
1035 let column: Vec<&str> = ast.name(column).collect();
1036 if let [only] = column[..] {
1037 if !fields.iter().any(|field| same_name(&field.name, only)) {
1038 let names: Vec<String> =
1039 fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
1040 return Err(Error::binder(format!(
1042 "Table \"{}\" does not have a column named \"{only}\"\n\nCandidate bindings: \
1043 : {}",
1044 name.table,
1045 names.join(", ")
1046 )));
1047 }
1048 }
1049 }
1050 if crate::expr::has_aggregate(ast, expr) {
1051 return Err(Error::binder("aggregate functions are not allowed in index expressions"));
1052 }
1053 let before = binder.plan_mut().node_count();
1054 let value = binder.bind_expr(ast, expr, &scope)?;
1055 if binder.plan_mut().node_count() > before {
1056 return Err(Error::binder("cannot use subquery in index expressions"));
1057 }
1058 if !binder.windows.is_empty() {
1059 return Err(Error::binder("window functions are not allowed in index expressions"));
1060 }
1061 let ty = binder.plan_mut().expr_type(value).clone();
1062 if ty.is_nested() {
1063 return Err(Error::invalid_type(format!(
1064 "Invalid Type [{ty}]: Invalid type for index key."
1065 )));
1066 }
1067 let bare = match binder.plan_mut().expr(value) {
1068 Expr::Column(binding) => scope.columns.iter().position(|held| held.binding == *binding),
1069 _ => None,
1070 };
1071 if let Some(at) = bare {
1072 columns.push(at);
1073 texts.push(rudb_parse::quoted(&fields[at].name));
1074 continue;
1075 }
1076 plain = false;
1077 let text = deparse::expression(ast, expr);
1078 let used = columns_in(&text)?;
1079 if used.is_empty() {
1080 return Err(Error::binder(
1081 "CREATE INDEX does not refer to any columns in the base table!",
1082 ));
1083 }
1084 for used in used {
1085 if let Some(at) = fields.iter().position(|field| same_name(&field.name, &used)) {
1086 columns.push(at);
1087 }
1088 }
1089 texts.push(format!("({text})"));
1090 }
1091 if written.unique && !plain {
1092 return Err(Error::not_implemented("A UNIQUE index over an expression is not supported"));
1093 }
1094 let expressions = Value::List {
1095 element: LogicalType::Varchar,
1096 values: texts.iter().map(|text| Value::Varchar(text.clone())).collect(),
1097 };
1098 let unique = if written.unique { "UNIQUE " } else { "" };
1099 let table: Vec<String> = written_table.iter().map(|part| rudb_parse::quoted(part)).collect();
1100 let using = if written.using == NONE {
1101 String::new()
1102 } else {
1103 format!(" USING {} ", ast.string(written.using))
1104 };
1105 let index_name = parts.last().cloned().unwrap_or_default();
1106 let sql = format!(
1107 "CREATE {unique}INDEX {} ON {}{using}({});",
1108 rudb_parse::quoted(&index_name),
1109 table.join("."),
1110 texts.join(", ")
1111 );
1112 if !plain {
1113 columns.sort_unstable();
1114 columns.dedup();
1115 }
1116 let index = rudb_catalog::Index {
1117 name: index_name,
1118 unique: written.unique,
1119 columns,
1120 plain,
1121 expressions: expressions.to_string(),
1122 sql,
1123 oid: 0,
1124 };
1125 Ok(Bound::Index(IndexChange {
1126 table: Some(name),
1127 index: Some(index),
1128 name: Vec::new(),
1129 quiet: written.quiet,
1130 }))
1131}
1132
1133fn in_foreign_key(
1136 catalog: &Catalog,
1137 name: &QualifiedName,
1138 table: &rudb_catalog::Table,
1139 at: usize,
1140) -> bool {
1141 table.foreign().iter().any(|key| key.columns.contains(&at))
1142 || catalog.tables().any(|held| {
1143 held.foreign().iter().any(|key| key.table == *name && key.referenced.contains(&at))
1144 })
1145}
1146
1147fn table_rewrite(
1150 ast: &Ast,
1151 (catalog, parameters, session): (&Catalog, &Parameters, &Session),
1152 name: &QualifiedName,
1153 change: impl FnOnce(
1154 &mut Binder<'_>,
1155 &crate::scope::Scope,
1156 &mut Vec<(ExprRef, String)>,
1157 ) -> Result<()>,
1158) -> Result<Plan> {
1159 let mut binder = Binder::with(catalog, parameters, session);
1160 let (root, scope) =
1161 binder.bind_catalog_table(ast, name, name.table.clone(), ast::Slice::default())?;
1162 let mut out = Vec::with_capacity(scope.columns.len() + 1);
1163 for column in &scope.columns {
1164 let expr = binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1165 out.push((expr, column.name.clone()));
1166 }
1167 change(&mut binder, &scope, &mut out)?;
1168 let exprs: Vec<ExprRef> = out.iter().map(|(expr, _)| *expr).collect();
1169 let names: Vec<_> = out.iter().map(|(_, name)| binder.plan_mut().intern(name)).collect();
1170 let exprs = binder.plan_mut().add_expr_list(&exprs);
1171 let names = binder.plan_mut().add_name_list(&names);
1172 let index = binder.fresh_index();
1173 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1174 finish(binder, root)
1175}
1176
1177fn check_ast(text: &str) -> Result<(Ast, ast::ExprRef)> {
1179 let ast = parse_ast(&format!("SELECT {text}"))?;
1180 let found = match ast.statements.first() {
1181 Some(&ast::Statement::Query(query)) => match ast.query(query).body {
1182 ast::QueryBody::Select(select) => {
1183 ast.target_list(ast.select(select).targets).first().map(|target| target.expr)
1184 }
1185 _ => None,
1186 },
1187 _ => None,
1188 };
1189 let expr = found.ok_or_else(|| Error::internal("a check that is not an expression"))?;
1190 Ok((ast, expr))
1191}
1192
1193fn columns_in(text: &str) -> Result<Vec<String>> {
1195 let (ast, _) = check_ast(text)?;
1196 let mut out = Vec::new();
1197 for expr in &ast.exprs {
1198 if let ast::Expr::Column { name } = *expr {
1199 if let Some(last) = ast.name(name).last() {
1200 out.push(last.to_string());
1201 }
1202 }
1203 }
1204 Ok(out)
1205}
1206
1207fn rename_in(text: &str, old: &str, to: &str) -> Result<String> {
1210 let (mut ast, expr) = check_ast(text)?;
1211 let mut renamed = false;
1212 for at in 0..ast.exprs.len() {
1213 let ast::Expr::Column { name } = ast.exprs[at] else { continue };
1214 if name.len == 0 {
1215 continue;
1216 }
1217 let last = (name.start + name.len - 1) as usize;
1218 if same_name(ast.string(ast.parts[last]), old) {
1219 let index = ast.strings.len() as u32;
1220 ast.strings.push(to.to_string());
1221 ast.parts[last] = index;
1222 renamed = true;
1223 }
1224 }
1225 Ok(if renamed { deparse::expression(&ast, expr) } else { text.to_string() })
1226}
1227
1228fn deduplicate(columns: &mut [Field]) {
1241 for at in 0..columns.len() {
1242 let taken = |name: &str, upto: usize, columns: &[Field]| {
1243 columns[..upto].iter().any(|held| same_name(&held.name, name))
1244 };
1245 if !taken(&columns[at].name, at, columns) {
1246 continue;
1247 }
1248 let mut suffix = 1;
1249 let mut candidate = format!("{}_{suffix}", columns[at].name);
1250 while taken(&candidate, at, columns) {
1251 suffix += 1;
1252 candidate = format!("{}_{suffix}", columns[at].name);
1253 }
1254 columns[at].name = candidate;
1255 }
1256}
1257
1258fn create_view(
1265 ast: &Ast,
1266 catalog: &Catalog,
1267 parameters: &Parameters,
1268 session: &Session,
1269 index: ast::CreateViewRef,
1270) -> Result<Bound> {
1271 let written = ast.create_view(index);
1272 let parts: Vec<&str> = ast.name(written.name).collect();
1273 let name = if written.temporary {
1274 catalog.resolve_for_create_temporary(&parts)?
1275 } else {
1276 catalog.resolve_for_create(&parts)?
1277 };
1278 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
1279
1280 let mut binder = Binder::with(catalog, parameters, session);
1281 binder.outlined = true;
1284 let (_, mut scope) = binder.bind_query(ast, written.query)?;
1285 if aliases.len() > scope.len() {
1286 return Err(Error::binder("More VIEW aliases than columns in query result"));
1287 }
1288 if !aliases.is_empty() {
1289 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
1290 scope.rename(&written, "unnamed_subquery")?;
1291 }
1292
1293 Ok(Bound::CreateView(CreateView {
1294 name,
1295 sql: ast.string(written.sql).to_string(),
1296 statement: deparse::create_view(ast, index),
1297 aliases,
1298 if_not_exists: written.if_not_exists,
1299 or_replace: written.or_replace,
1300 columns: scope.fields(),
1301 }))
1302}
1303
1304fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
1305 let written = ast.drop_table(index);
1306 let kind = if written.view { Entry::View } else { Entry::Table };
1307 let mut names = Vec::new();
1308 for &name in ast.name_list(written.names) {
1309 let parts: Vec<&str> = ast.name(name).collect();
1310 match catalog.resolve_as(&parts, kind) {
1313 Ok(resolved) => names.push(resolved),
1314 Err(error) if written.if_exists => drop(error),
1315 Err(error) => return Err(error),
1316 }
1317 }
1318 Ok(Bound::DropTable(DropTable { names, kind }))
1319}
1320
1321fn setting(
1327 ast: &Ast,
1328 catalog: &Catalog,
1329 parameters: &Parameters,
1330 session: &Session,
1331 index: ast::SettingRef,
1332) -> Result<Bound> {
1333 let written = ast.setting(index);
1334 let name = ast.string(written.name).to_string();
1335 let value = if written.value == NONE {
1336 None
1337 } else {
1338 let mut binder = Binder::with(catalog, parameters, session);
1339 let bound = binder.bind_setting_value(ast, written.value)?;
1340 let Expr::Constant(value) = *binder.plan().expr(bound) else {
1341 return Err(Error::not_implemented(format!(
1342 "a value for {name} that is not a constant"
1343 )));
1344 };
1345 Some(binder.plan().value(value).clone())
1346 };
1347 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
1348}
1349
1350fn clustered(
1362 binder: &mut Binder<'_>,
1363 input: rudb_plan::NodeRef,
1364 scope: &crate::scope::Scope,
1365 clustering: &Clustering,
1366 targets: &[usize],
1367 fields: &[Field],
1368) -> Result<rudb_plan::NodeRef> {
1369 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
1370 for (at, &column) in clustering.columns().iter().enumerate() {
1371 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
1372 continue;
1373 };
1374 let source = &scope.columns[from];
1375 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
1376 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
1381 let expr =
1382 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
1383 keys.push(SortKey { expr, descending: false, nulls_first: false });
1384 }
1385 if keys.is_empty() {
1386 return Ok(input);
1387 }
1388 let keys = binder.plan_mut().add_sort_keys(&keys);
1389 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
1390}
1391
1392fn fitted(
1406 binder: &Binder<'_>,
1407 scope: &crate::scope::Scope,
1408 clustering: &Clustering,
1409 targets: &[usize],
1410) -> Clustering {
1411 if clustering.width() != Width::Auto {
1412 return clustering.clone();
1413 }
1414 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
1415 else {
1416 return clustering.fitted(0, 0);
1417 };
1418 let source = &scope.columns[from];
1419 let Some(zones) = binder.plan().sole_zones() else {
1420 return clustering.fitted(0, 0);
1421 };
1422 let Some(at) = zones.column(&source.name) else {
1427 return clustering.fitted(0, 0);
1428 };
1429 let rows = zones.surviving(&[]).unwrap_or(0);
1430 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
1431 clustering.fitted(rows, days)
1432}
1433
1434fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
1440 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
1441 return None;
1442 };
1443 let days = match (low, high) {
1444 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
1446 (
1450 ColumnBound::Scaled { unscaled: low, scale: at },
1451 ColumnBound::Scaled { unscaled: high, scale: to },
1452 ) if at == to => {
1453 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
1454 high.checked_sub(*low)? / day
1455 }
1456 _ => return None,
1457 };
1458 u64::try_from(days).ok()
1459}
1460
1461fn bucketed(
1463 binder: &mut Binder<'_>,
1464 expr: ExprRef,
1465 width: Width,
1466 fields: &[Field],
1467 column: u32,
1468) -> ExprRef {
1469 if width == Width::Exact {
1470 return expr;
1471 }
1472 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1473 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1474 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1475 let name = binder.plan_mut().intern("date_trunc");
1476 let ty = fields[column as usize].ty.clone();
1477 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1478}
1479
1480fn insert(
1481 ast: &Ast,
1482 catalog: &Catalog,
1483 parameters: &Parameters,
1484 session: &Session,
1485 index: ast::InsertRef,
1486) -> Result<Bound> {
1487 let written = ast.insert(index);
1488 let parts: Vec<&str> = ast.name(written.name).collect();
1489 let name = catalog.resolve(&parts)?;
1490 if catalog.entry(&name)? == Entry::View {
1491 return Err(Error::catalog(format!("{} is not an table", name.table)));
1494 }
1495 let target = catalog.table(&name)?;
1496 let fields: Vec<Field> = target.columns().to_vec();
1497 let clustering = target.clustering().cloned();
1498
1499 let targets: Vec<usize> = if written.columns.is_empty() {
1503 (0..fields.len()).collect()
1504 } else {
1505 let mut targets = Vec::new();
1506 for column in ast.name(written.columns) {
1507 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1508 || {
1509 Error::binder(format!(
1510 "Table \"{}\" does not have a column named \"{column}\"",
1511 name.table
1512 ))
1513 },
1514 )?;
1515 if targets.contains(&at) {
1516 return Err(Error::binder(format!(
1517 "Column \"{column}\" is named twice in the same INSERT"
1518 )));
1519 }
1520 targets.push(at);
1521 }
1522 targets
1523 };
1524
1525 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1526 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1527 .collect();
1528 let mut binder = Binder::with(catalog, parameters, session);
1529 let (root, scope) = if written.source == NONE {
1530 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1533 } else {
1534 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1537 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1538 }
1539 binder.bind_query(ast, written.source)?
1540 };
1541 let targets = if written.source == NONE { Vec::new() } else { targets };
1542 if scope.len() != targets.len() {
1543 return Err(Error::binder(format!(
1544 "Table \"{}\" has {} columns but {} values were supplied",
1545 name.table,
1546 targets.len(),
1547 scope.len()
1548 )));
1549 }
1550
1551 let root = match &clustering {
1557 None => root,
1558 Some(clustering) => {
1559 let fitted = fitted(&binder, &scope, clustering, &targets);
1564 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1565 }
1566 };
1567
1568 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1572 let mut names = Vec::with_capacity(fields.len());
1573 for (at, field) in fields.iter().enumerate() {
1574 let expr = match targets.iter().position(|&target| target == at) {
1575 Some(from) => {
1576 let column = &scope.columns[from];
1577 let expr =
1578 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1579 binder.checked_cast_to(expr, &field.ty, false)?
1580 }
1581 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1583 };
1584 exprs.push(expr);
1585 let interned = binder.plan_mut().intern(&field.name);
1586 names.push(interned);
1587 }
1588 let exprs = binder.plan_mut().add_expr_list(&exprs);
1589 let names = binder.plan_mut().add_name_list(&names);
1590 let index = binder.fresh_index();
1591 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1592 let source = finish(binder, root)?;
1593 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1594 let conflict = match written.conflict {
1595 Some(conflict) => {
1596 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1597 }
1598 None => None,
1599 };
1600 let checks = bind_checks(catalog, parameters, session, &name)?;
1601 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1602}
1603
1604fn bind_conflict(
1607 ast: &Ast,
1608 catalog: &Catalog,
1609 parameters: &Parameters,
1610 session: &Session,
1611 name: &QualifiedName,
1612 targets: &[usize],
1613 conflict: ast::Conflict,
1614) -> Result<Conflict> {
1615 let table = catalog.table(name)?;
1616 let fields = table.columns();
1617 let keys = table.keys();
1618 let key = if conflict.target.is_empty() {
1619 if keys.is_empty() {
1620 return Err(Error::binder(
1621 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1622 CONFLICT columns manually",
1623 ));
1624 }
1625 match conflict.action {
1626 ast::ConflictAction::Nothing => None,
1627 _ if keys.len() > 1 => {
1628 return Err(Error::binder(
1629 "Conflict target has to be provided for a DO UPDATE operation when the table \
1630 has multiple UNIQUE/PRIMARY KEY constraints",
1631 ));
1632 }
1633 _ => Some(0),
1634 }
1635 } else {
1636 let mut wanted = Vec::new();
1637 for column in ast.name(conflict.target) {
1638 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1639 return Err(Error::binder(format!(
1640 "Table \"{}\" does not have a column with name \"{column}\"",
1641 name.table
1642 )));
1643 };
1644 wanted.push(at);
1645 }
1646 wanted.sort_unstable();
1647 wanted.dedup();
1648 let found = keys.iter().position(|key| {
1649 let mut held = key.columns.clone();
1650 held.sort_unstable();
1651 held == wanted
1652 });
1653 let Some(found) = found else {
1654 return Err(Error::binder(
1655 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1656 KEY CONSTRAINT or INDEX",
1657 ));
1658 };
1659 Some(found)
1660 };
1661 let action = match conflict.action {
1662 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1663 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1664 ast::ConflictAction::Update { columns: written, query } => {
1665 let mut columns = Vec::new();
1666 for column in ast.name(written) {
1667 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1668 else {
1669 return Err(Error::binder(format!(
1670 "Referenced update column {column} not found in table!"
1671 )));
1672 };
1673 if columns.contains(&at) {
1674 return Err(Error::binder(format!(
1675 "Multiple assignments to same column \"\"{column}\"\""
1676 )));
1677 }
1678 columns.push(at);
1679 }
1680 let mut binder = Binder::with(catalog, parameters, session);
1681 binder.upsert = true;
1682 let (root, scope) = binder.bind_query(ast, query)?;
1683 let mut exprs = Vec::with_capacity(scope.columns.len());
1686 let mut names = Vec::with_capacity(scope.columns.len());
1687 for (at, column) in scope.columns.iter().enumerate() {
1688 let expr =
1689 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1690 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1691 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1692 names.push(binder.plan_mut().intern(&column.name));
1693 }
1694 let exprs = binder.plan_mut().add_expr_list(&exprs);
1695 let names = binder.plan_mut().add_name_list(&names);
1696 let index = binder.fresh_index();
1697 let root =
1698 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1699 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1700 }
1701 };
1702 Ok(Conflict { key, action })
1703}
1704
1705fn change(
1714 ast: &Ast,
1715 catalog: &Catalog,
1716 parameters: &Parameters,
1717 session: &Session,
1718 index: ast::InsertRef,
1719 delete: bool,
1720) -> Result<Bound> {
1721 let written = ast.insert(index);
1722 let parts: Vec<&str> = ast.name(written.name).collect();
1723 let name = catalog.resolve(&parts)?;
1724 if catalog.entry(&name)? == Entry::View {
1725 return Err(Error::binder(if delete {
1726 "Can only delete from base table"
1727 } else {
1728 "Can only update base table"
1729 }));
1730 }
1731 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1732 let mut targets: Vec<usize> = Vec::new();
1733 for column in ast.name(written.columns) {
1734 let at =
1735 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1736 Error::binder(format!("Referenced update column {column} not found in table!"))
1737 })?;
1738 if targets.contains(&at) {
1739 return Err(Error::binder(format!(
1740 "Multiple assignments to same column \"\"{column}\"\""
1741 )));
1742 }
1743 targets.push(at);
1744 }
1745
1746 let mut defaulted = vec![false; targets.len()];
1748 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1749 let items = ast.target_list(ast.select(select).targets);
1750 let first = items.len().saturating_sub(targets.len());
1751 for (at, item) in items[first..].iter().enumerate() {
1752 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1753 }
1754 }
1755 let table = catalog.table(&name)?;
1756 let mut binder = Binder::with(catalog, parameters, session);
1757 binder.default_as_null = defaulted.contains(&true);
1758 let (root, scope) = binder.bind_query(ast, written.source)?;
1759 binder.default_as_null = false;
1760 let width = fields.len();
1761 if scope.len() != width + 1 + targets.len() {
1762 return Err(Error::internal(format!(
1763 "an UPDATE source of {} columns over a table of {width}",
1764 scope.len()
1765 )));
1766 }
1767 let column = |binder: &mut Binder<'_>, at: usize| {
1768 let column = &scope.columns[at];
1769 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1770 };
1771 let hit = column(&mut binder, width);
1772 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1773 let mut exprs = Vec::with_capacity(width);
1774 let mut names = Vec::with_capacity(width);
1775 for (at, field) in fields.iter().enumerate() {
1776 let old = column(&mut binder, at);
1777 let expr = match targets.iter().position(|&target| target == at) {
1778 Some(from) => {
1779 let then = if defaulted[from] {
1780 binder.bind_default(table.default(at), &field.ty)?
1781 } else {
1782 let new = column(&mut binder, width + 1 + from);
1783 binder.checked_cast_to(new, &field.ty, false)?
1784 };
1785 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1786 binder
1787 .plan_mut()
1788 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1789 }
1790 None => old,
1791 };
1792 exprs.push(expr);
1793 let interned = binder.plan_mut().intern(&field.name);
1794 names.push(interned);
1795 }
1796 let yes = binder.add_constant(Value::Boolean(true));
1799 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1800 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1801 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1802 let interned = binder.plan_mut().intern("changed");
1803 names.push(interned);
1804 let exprs = binder.plan_mut().add_expr_list(&exprs);
1805 let names = binder.plan_mut().add_name_list(&names);
1806 let index = binder.fresh_index();
1807 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1808 let source = finish(binder, root)?;
1809 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1810 let write = if delete { Write::Delete } else { Write::Update };
1811 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1812 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1813}