1use rudb_catalog::{Catalog, Entry, QualifiedName, duplicate_check, same_name};
18use rudb_common::bounds::End;
19use rudb_common::{
20 Bound as ColumnBound, Clustering, Error, Field, LogicalType, Result, Session, Stat, Value,
21 Width,
22};
23use rudb_parse::ast::{self, Ast};
24use rudb_parse::{NONE, deparse, parse_ast};
25use rudb_plan::{Arm, Expr, ExprRef, Node, Plan, SortKey};
26
27use crate::binder::Binder;
28use crate::parameters::Parameters;
29
30#[derive(Debug)]
35pub enum Bound {
36 Query(Plan),
38 CreateTable(CreateTable),
40 CreateView(CreateView),
42 DropTable(DropTable),
44 Schema(SchemaChange),
46 Sequence(SequenceChange),
48 Type(TypeChange),
50 Alter(Alter),
52 Index(IndexChange),
54 Insert(Insert),
56 Setting(Setting),
58 Checkpoint(Option<String>),
60 Attach(Attach),
62 Detach { name: String, if_exists: bool },
64 Transaction(ast::Transaction),
66 Explain { plan: Plan, analyze: bool, statistics: bool, codegen: bool },
82 CopyTo(CopyTo),
84}
85
86#[derive(Debug)]
92pub struct CopyTo {
93 pub plan: Plan,
95 pub path: String,
97 pub header: bool,
99 pub delimiter: String,
101 pub quote: String,
103 pub escape: String,
105 pub null: String,
107 pub force_quote: Vec<String>,
109 pub force_quote_all: bool,
111}
112
113#[derive(Debug)]
125pub struct Setting {
126 pub name: String,
128 pub scope: ast::Scope,
130 pub value: Option<Value>,
132 pub pragma: bool,
134}
135
136#[derive(Debug)]
141pub struct Attach {
142 pub path: String,
144 pub alias: Option<String>,
146 pub or_replace: bool,
148 pub if_not_exists: bool,
150 pub options: Vec<(String, Option<Value>)>,
152}
153
154#[derive(Debug)]
156pub struct CreateTable {
157 pub name: QualifiedName,
159 pub columns: Vec<Field>,
162 pub source: Option<Plan>,
164 pub if_not_exists: bool,
166 pub or_replace: bool,
168 pub keys: Vec<rudb_catalog::Key>,
170 pub defaults: Vec<Option<String>>,
172 pub sequences: Vec<QualifiedName>,
174 pub checks: Vec<String>,
176 pub foreign: Vec<rudb_catalog::ForeignKey>,
178 pub order: Vec<rudb_catalog::Constraint>,
180}
181
182#[derive(Debug)]
189pub struct CreateView {
190 pub name: QualifiedName,
192 pub sql: String,
194 pub statement: String,
199 pub aliases: Vec<String>,
201 pub if_not_exists: bool,
203 pub or_replace: bool,
205 pub columns: Vec<Field>,
211}
212
213#[derive(Debug, Clone, PartialEq, Eq)]
219pub struct SchemaChange {
220 pub catalog: String,
222 pub name: String,
224 pub drop: bool,
226 pub quiet: bool,
228 pub or_replace: bool,
231 pub cascade: bool,
233}
234
235#[derive(Debug, Clone, PartialEq, Eq)]
237pub struct SequenceChange {
238 pub name: Option<QualifiedName>,
240 pub drop: bool,
242 pub if_not_exists: bool,
244 pub or_replace: bool,
246 pub cascade: bool,
248 pub options: rudb_common::sequence::Options,
250 pub owner: Option<QualifiedName>,
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
257pub struct TypeChange {
258 pub name: Option<QualifiedName>,
260 pub ty: Option<LogicalType>,
262 pub uses: Vec<QualifiedName>,
264 pub if_not_exists: bool,
266 pub or_replace: bool,
268 pub cascade: bool,
270}
271
272#[derive(Debug)]
274pub struct Alter {
275 pub name: Option<QualifiedName>,
277 pub alteration: Option<rudb_catalog::Alteration>,
279 pub rewrite: Option<Plan>,
281}
282
283#[derive(Debug)]
285pub struct IndexChange {
286 pub table: Option<QualifiedName>,
288 pub index: Option<rudb_catalog::Index>,
290 pub name: Vec<String>,
292 pub quiet: bool,
294}
295
296#[derive(Debug)]
298pub struct DropTable {
299 pub names: Vec<QualifiedName>,
304 pub kind: Entry,
306}
307
308#[derive(Debug)]
310pub struct Insert {
311 pub name: QualifiedName,
313 pub source: Plan,
316 pub write: Write,
318 pub returning: Option<Box<Plan>>,
321 pub conflict: Option<Conflict>,
323 pub checks: Option<Checks>,
325}
326
327#[derive(Debug)]
333pub struct Checks {
334 pub plan: Box<Plan>,
336 pub messages: Vec<String>,
338}
339
340#[derive(Debug)]
342pub struct Conflict {
343 pub key: Option<usize>,
345 pub action: ConflictAction,
347}
348
349#[derive(Debug)]
351pub enum ConflictAction {
352 Nothing,
354 Replace(Vec<usize>),
356 Update {
360 columns: Vec<usize>,
362 plan: Box<Plan>,
364 },
365}
366
367#[derive(Debug, Clone, Copy, PartialEq, Eq)]
369pub enum Write {
370 Append,
372 Update,
375 Delete,
378}
379
380fn returning(
382 ast: &Ast,
383 catalog: &Catalog,
384 parameters: &Parameters,
385 session: &Session,
386 query: Option<ast::QueryRef>,
387) -> Result<Option<Box<Plan>>> {
388 let Some(query) = query else { return Ok(None) };
389 let mut binder = Binder::with(catalog, parameters, session);
390 let (root, _) = binder.bind_query(ast, query)?;
391 Ok(Some(Box::new(finish(binder, root)?)))
392}
393
394pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
401 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
402}
403
404pub fn bind_statement_with(
414 ast: &Ast,
415 catalog: &Catalog,
416 parameters: &Parameters,
417 session: &Session,
418) -> Result<Bound> {
419 bind_one(ast, catalog, parameters, session, false)
420}
421
422pub fn bind_statement_outlined(
435 ast: &Ast,
436 catalog: &Catalog,
437 parameters: &Parameters,
438 session: &Session,
439) -> Result<Bound> {
440 bind_one(ast, catalog, parameters, session, true)
441}
442
443fn bind_one(
444 ast: &Ast,
445 catalog: &Catalog,
446 parameters: &Parameters,
447 session: &Session,
448 outlined: bool,
449) -> Result<Bound> {
450 let statement = match ast.statements.as_slice() {
451 [statement] => *statement,
452 [] => return Err(Error::binder("no statement to bind")),
453 _ => return Err(Error::not_implemented("a script of more than one statement")),
454 };
455 match statement {
456 ast::Statement::Query(query) => {
457 let mut binder = Binder::with(catalog, parameters, session);
458 binder.outlined = outlined;
459 let (root, _) = binder.bind_query(ast, query)?;
460 Ok(Bound::Query(finish(binder, root)?))
461 }
462 ast::Statement::CreateTable(index) => {
463 create_table(ast, catalog, parameters, session, index)
464 }
465 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
466 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
467 ast::Statement::Schema(index) => {
468 let written = ast.schema(index);
469 if written.temporary {
470 return Err(Error::binder("Temporary schemas are not supported"));
471 }
472 let parts: Vec<&str> = ast.name(written.name).collect();
473 let (catalog, name) = catalog.schema_name(&parts)?;
474 Ok(Bound::Schema(SchemaChange {
475 catalog,
476 name,
477 drop: written.drop,
478 quiet: written.quiet,
479 or_replace: written.or_replace,
480 cascade: written.cascade,
481 }))
482 }
483 ast::Statement::Sequence(index) => {
484 let written = ast.sequence(index);
485 let parts: Vec<&str> = ast.name(written.name).collect();
486 let alter = !written.owner.is_empty();
487 let mut owner = None;
488 let name = if written.drop || alter {
489 match catalog.resolve_sequence(&parts) {
490 Ok(name) => Some(name),
491 Err(_) if written.quiet => None,
492 Err(error) => return Err(error),
493 }
494 } else if written.temporary {
495 Some(catalog.resolve_for_create_temporary(&parts)?)
496 } else {
497 Some(catalog.resolve_for_create(&parts)?)
498 };
499 if alter && name.is_some() {
500 let parts: Vec<&str> = ast.name(written.owner).collect();
501 owner = Some(catalog.resolve_owner(&parts)?);
502 }
503 Ok(Bound::Sequence(SequenceChange {
504 name,
505 drop: written.drop,
506 if_not_exists: written.quiet,
507 or_replace: written.or_replace,
508 cascade: written.cascade,
509 options: written.options,
510 owner,
511 }))
512 }
513 ast::Statement::Type(index) => {
514 let written = ast.type_def(index);
515 let parts: Vec<&str> = ast.name(written.name).collect();
516 let (name, ty, uses) = if written.drop {
517 let name = catalog.resolve_type(&parts).map(|made| made.name().clone());
518 if name.is_none() && !written.quiet {
519 return Err(Error::catalog(format!(
520 "Type with name {} does not exist!",
521 parts.last().copied().unwrap_or_default()
522 )));
523 }
524 (name, None, Vec::new())
525 } else {
526 let name = if written.temporary {
527 catalog.resolve_for_create_temporary(&parts)?
528 } else {
529 catalog.resolve_for_create(&parts)?
530 };
531 let (ty, uses) = written_type(catalog, ast.string(written.ty))?;
532 (Some(name), Some(ty), uses)
533 };
534 Ok(Bound::Type(TypeChange {
535 name,
536 ty,
537 uses,
538 if_not_exists: written.quiet,
539 or_replace: written.or_replace,
540 cascade: written.cascade,
541 }))
542 }
543 ast::Statement::Alter(index) => alter(ast, catalog, parameters, session, index),
544 ast::Statement::Index(index) => create_index(ast, catalog, parameters, session, index),
545 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
546 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
547 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
548 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
549 setting(ast, catalog, parameters, session, index)
550 }
551 ast::Statement::Checkpoint(name) => {
552 Ok(Bound::Checkpoint((name != NONE).then(|| ast.string(name).to_string())))
553 }
554 ast::Statement::Attach(index) => attach(ast, catalog, parameters, session, index),
555 ast::Statement::Detach { name, if_exists } => {
556 Ok(Bound::Detach { name: ast.string(name).to_string(), if_exists })
557 }
558 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
559 ast::Statement::Explain { query, analyze, statistics, codegen } => {
560 let mut binder = Binder::with(catalog, parameters, session);
561 let (root, _) = binder.bind_query(ast, query)?;
562 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics, codegen })
563 }
564 ast::Statement::CopyTo(index) => {
565 let copy = &ast.copies[index as usize];
566 let mut binder = Binder::with(catalog, parameters, session);
567 let (root, _) = binder.bind_query(ast, copy.query)?;
568 copy_to(copy, finish(binder, root)?).map(Bound::CopyTo)
569 }
570 }
571}
572
573fn copy_to(copy: &ast::CopyTo, plan: Plan) -> Result<CopyTo> {
579 let lowered = copy.path.to_ascii_lowercase();
580 let mut format = if lowered.ends_with(".parquet") {
581 "parquet"
582 } else if lowered.ends_with(".json") || lowered.ends_with(".ndjson") {
583 "json"
584 } else {
585 "csv"
586 }
587 .to_string();
588 if let Some((_, Some(written))) = copy.options.iter().rev().find(|(name, _)| name == "format") {
589 format = written.trim_matches('\'').to_ascii_lowercase();
590 }
591 if format != "csv" {
592 return Err(Error::not_implemented(format!(
593 "COPY TO with FORMAT {format} is not supported yet"
594 )));
595 }
596 let mut out = CopyTo {
597 plan,
598 path: copy.path.clone(),
599 header: true,
600 delimiter: ",".to_string(),
601 quote: "\"".to_string(),
602 escape: "\"".to_string(),
603 null: String::new(),
604 force_quote: Vec::new(),
605 force_quote_all: false,
606 };
607 for (name, value) in ©.options {
608 let text = || {
609 value.clone().ok_or_else(|| {
610 Error::binder(format!("\"{name}\" expects a single argument as a string value"))
611 })
612 };
613 match name.as_str() {
614 "format" => {}
615 "header" => {
616 out.header = match value.as_deref().map(str::to_ascii_lowercase).as_deref() {
617 None | Some("true" | "1" | "on") => true,
618 Some("false" | "0" | "off") => false,
619 Some(other) => {
620 return Err(Error::binder(format!(
621 "\"header\" expects a boolean value, not {other}"
622 )));
623 }
624 };
625 }
626 "delimiter" | "delim" | "sep" => {
628 out.delimiter = text()?.replace("\\t", "\t");
629 }
630 "quote" => out.quote = text()?,
631 "escape" => out.escape = text()?,
632 "null" | "nullstr" => out.null = text()?,
633 "force_quote" => {
634 let written = text()?;
635 let written = written.trim();
636 let list = written.strip_prefix('(').and_then(|rest| rest.strip_suffix(')'));
637 let list = list.unwrap_or(written);
638 if list.trim() == "*" {
639 out.force_quote_all = true;
640 } else {
641 for column in list.split(',') {
642 let column = column.trim();
643 let unquoted =
644 column.strip_prefix('"').and_then(|rest| rest.strip_suffix('"'));
645 out.force_quote.push(unquoted.unwrap_or(column).to_string());
646 }
647 }
648 }
649 "compression"
650 | "dateformat"
651 | "date_format"
652 | "timestampformat"
653 | "timestamp_format"
654 | "new_line"
655 | "prefix"
656 | "suffix"
657 | "per_thread_output"
658 | "file_size_bytes"
659 | "partition_by"
660 | "overwrite"
661 | "overwrite_or_ignore"
662 | "filename_pattern"
663 | "file_extension"
664 | "use_tmp_file"
665 | "return_files"
666 | "write_partition_columns"
667 | "preserve_order"
668 | "force_not_null"
669 | "encoding" => {
670 return Err(Error::not_implemented(format!(
671 "COPY TO with the option {name} is not supported yet"
672 )));
673 }
674 _ => {
675 return Err(Error::not_implemented(format!(
676 "Unrecognized option \"{name}\" for csv"
677 )));
678 }
679 }
680 }
681 if out.delimiter.is_empty() {
682 return Err(Error::binder("The delimiter option cannot be empty"));
683 }
684 Ok(out)
685}
686
687pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
693 let ast = parse_ast(sql)?;
694 bind_statement(&ast, catalog)
695}
696
697pub(crate) fn written_type(
701 catalog: &Catalog,
702 text: &str,
703) -> Result<(LogicalType, Vec<QualifiedName>)> {
704 let mut uses = Vec::new();
705 let ty = LogicalType::parse_with(text, &mut |parts| {
706 let parts: Vec<&str> = parts.iter().map(String::as_str).collect();
707 let made = catalog.resolve_type(&parts)?;
708 uses.push(made.name().clone());
709 Some(made.ty().clone())
710 })?;
711 Ok((ty, uses))
712}
713
714pub(crate) fn read_type(catalog: &Catalog, text: &str) -> Result<LogicalType> {
716 written_type(catalog, text).map(|(ty, _)| ty)
717}
718
719fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
720 let mut plan = binder.into_plan();
721 plan.set_root(root);
722 plan.validate()?;
723 Ok(plan)
724}
725
726fn create_table(
727 ast: &Ast,
728 catalog: &Catalog,
729 parameters: &Parameters,
730 session: &Session,
731 index: ast::CreateTableRef,
732) -> Result<Bound> {
733 let written = ast.create_table(index);
734 let parts: Vec<&str> = ast.name(written.name).collect();
735 let name = if written.temporary {
736 catalog.resolve_for_create_temporary(&parts)?
737 } else {
738 catalog.resolve_for_create(&parts)?
739 };
740 let defs = ast.column_defs(written.columns);
741 let (mut columns, source) = if written.query == NONE {
742 let mut columns = Vec::with_capacity(defs.len());
743 for def in defs {
744 let text = ast.string(def.ty);
745 if text.is_empty() {
746 return Err(Error::binder(format!(
747 "Column \"{}\" was declared without a type",
748 ast.string(def.name)
749 )));
750 }
751 let ty = read_type(catalog, text)?;
752 let column = ast.string(def.name);
753 columns.push(if def.not_null {
754 Field::required(column, ty)
755 } else {
756 Field::new(column, ty)
757 });
758 }
759 (columns, None)
760 } else {
761 let mut binder = Binder::with(catalog, parameters, session);
762 let (root, scope) = binder.bind_query(ast, written.query)?;
763 if defs.len() > scope.len() {
764 return Err(Error::binder("Target table has more colum names than query result."));
767 }
768 let mut columns = Vec::with_capacity(scope.columns.len());
769 for (at, column) in scope.columns.iter().enumerate() {
770 let named = match defs.get(at) {
771 Some(def) => ast.string(def.name).to_string(),
772 None => column.name.clone(),
773 };
774 columns.push(Field::new(named, column.ty.clone()));
775 }
776 if defs.is_empty() {
777 deduplicate(&mut columns);
778 }
779 (columns, Some(finish(binder, root)?))
780 };
781 duplicate_check(&columns)?;
782 let mut defaults = Vec::with_capacity(defs.len());
783 let mut sequences = Vec::new();
784 for def in defs {
785 defaults.push(if def.default == NONE {
786 None
787 } else {
788 let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
789 for name in used {
790 if !sequences.contains(&name) {
791 sequences.push(name);
792 }
793 }
794 Some(text)
795 });
796 }
797 let mut checks = Vec::new();
798 for &expr in ast.expr_list(written.checks) {
799 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
800 }
801 let mut keys = Vec::new();
802 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
803 let mut places = Vec::new();
804 for wanted in ast.name(names) {
805 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
806 else {
807 return Err(Error::catalog(format!(
808 "table \"{}\" does not have a column named \"{wanted}\"",
809 name.table
810 )));
811 };
812 places.push(place);
813 }
814 let primary = at as u32 == written.primary;
815 if primary {
816 for &place in &places {
817 columns[place].not_null = true;
818 }
819 }
820 keys.push(rudb_catalog::Key { columns: places, primary });
821 }
822 let mut foreign = Vec::new();
823 let lists = ast.name_list(written.foreign).iter();
824 let tables = ast.name_list(written.foreign_tables).iter();
825 let referenced = ast.name_list(written.foreign_referenced).iter();
826 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
827 let names: Vec<&str> = ast.name(names).collect();
828 let parts: Vec<&str> = ast.name(table).collect();
829 let wanted: Vec<&str> = ast.name(wanted).collect();
830 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
831 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
832 }
833 Ok(Bound::CreateTable(CreateTable {
834 name,
835 columns,
836 source,
837 if_not_exists: written.if_not_exists,
838 or_replace: written.or_replace,
839 keys,
840 defaults,
841 checks,
842 foreign,
843 sequences,
844 order: ast.constraint_list(written.order).iter().map(|&held| constraint(held)).collect(),
845 }))
846}
847
848fn constraint(held: ast::Constraint) -> rudb_catalog::Constraint {
850 match held {
851 ast::Constraint::Key(at) => rudb_catalog::Constraint::Key(at as usize),
852 ast::Constraint::Check(at) => rudb_catalog::Constraint::Check(at as usize),
853 ast::Constraint::Foreign(at) => rudb_catalog::Constraint::Foreign(at as usize),
854 ast::Constraint::NotNull(at) => rudb_catalog::Constraint::NotNull(at as usize),
855 }
856}
857
858fn foreign_key(
864 catalog: &Catalog,
865 made: &QualifiedName,
866 (columns, keys): (&[Field], &[rudb_catalog::Key]),
867 (names, parts, wanted): (&[&str], &[&str], &[&str]),
868) -> Result<rudb_catalog::ForeignKey> {
869 let mut places = Vec::with_capacity(names.len());
870 for &wanted in names {
871 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
872 return Err(Error::binder(format!(
873 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
874 )));
875 };
876 places.push(place);
877 }
878 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
879 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
880 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
881 (made.clone(), columns.to_vec(), keys.to_vec())
882 } else {
883 let resolved = catalog.resolve(parts)?;
884 if catalog.view(&resolved).is_ok() {
885 return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
886 }
887 let table = catalog.table(&resolved)?;
888 (resolved, table.columns().to_vec(), table.keys().to_vec())
889 };
890 let referenced = if wanted.is_empty() {
891 let Some(primary) = held.iter().find(|key| key.primary) else {
892 return Err(Error::binder(format!(
893 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
894 table.table
895 )));
896 };
897 if primary.columns.len() != places.len() {
898 return Err(Error::parser(
899 "The number of referencing and referenced columns for foreign keys must be the same",
900 ));
901 }
902 primary.columns.clone()
903 } else {
904 let mut referenced = Vec::with_capacity(wanted.len());
905 for &column in wanted {
906 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
907 return Err(Error::binder(format!(
908 "Failed to create foreign key: referenced table \"{}\" does not have a column \
909 named \"{column}\"",
910 table.table
911 )));
912 };
913 referenced.push(place);
914 }
915 let mut sorted = referenced.clone();
916 sorted.sort_unstable();
917 let matched = held.iter().any(|key| {
918 let mut columns = key.columns.clone();
919 columns.sort_unstable();
920 columns == sorted
921 });
922 if !matched && held.is_empty() {
923 return Err(Error::binder(format!(
924 "Failed to create foreign key: there is no primary key or unique constraint for \
925 referenced table \"{}\"",
926 table.table
927 )));
928 }
929 if !matched {
930 return Err(Error::binder(format!(
931 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
932 or unique constraint on the columns {}",
933 table.table,
934 wanted.join(", ")
935 )));
936 }
937 referenced
938 };
939 for (&from, &to) in places.iter().zip(&referenced) {
940 if columns[from].ty != fields[to].ty {
941 return Err(Error::binder(format!(
942 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
943 and column \"{}\" (\"{}\")",
944 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
945 )));
946 }
947 }
948 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
949}
950
951fn check_text(
953 ast: &Ast,
954 expr: ast::ExprRef,
955 columns: &[Field],
956 catalog: &Catalog,
957 parameters: &Parameters,
958 session: &Session,
959) -> Result<String> {
960 if crate::expr::has_aggregate(ast, expr) {
961 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
962 }
963 let mut binder = Binder::with(catalog, parameters, session);
964 let index = binder.fresh_index();
965 let mut scope = crate::scope::Scope::empty();
966 for (at, field) in columns.iter().enumerate() {
967 scope.push(crate::scope::Visible {
968 table: String::new(),
969 name: field.name.clone(),
970 binding: rudb_plan::ColumnBinding::new(index, at as u32),
971 ty: field.ty.clone(),
972 not_null: false,
973 key: None,
974 default: None,
975 qualified: false,
976 also: None,
977 });
978 }
979 match binder.bind_expr(ast, expr, &scope) {
980 Err(error) if error.message().starts_with("Referenced column \"") => {
981 let column = error.message().split('"').nth(1).unwrap_or_default();
982 Err(Error::binder(format!(
983 "Table does not contain column \"{column}\" referenced in check constraint!"
984 )))
985 }
986 Err(error) => Err(error),
987 Ok(_) if !binder.windows.is_empty() => {
988 Err(Error::binder("window functions are not allowed in check constraints"))
989 }
990 Ok(_) => Ok(deparse::expression(ast, expr)),
991 }
992}
993
994pub fn bind_checks(
1001 catalog: &Catalog,
1002 parameters: &Parameters,
1003 session: &Session,
1004 name: &QualifiedName,
1005) -> Result<Option<Checks>> {
1006 let table = catalog.table(name)?;
1007 if table.checks().is_empty() {
1008 return Ok(None);
1009 }
1010 let failed: Vec<String> =
1011 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
1012 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
1013 let ast::Statement::Query(query) = ast.statements[0] else {
1014 return Err(Error::internal("a check that is not an expression"));
1015 };
1016 let ast::QueryBody::Select(select) = ast.query(query).body else {
1017 return Err(Error::internal("a check that is not an expression"));
1018 };
1019 let mut binder = Binder::with(catalog, parameters, session);
1020 let (root, scope) =
1021 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
1022 let mut exprs = Vec::with_capacity(failed.len());
1023 let mut names = Vec::with_capacity(failed.len());
1024 for target in ast.target_list(ast.select(select).targets) {
1025 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
1026 names.push(binder.plan_mut().intern("failed"));
1027 }
1028 let exprs = binder.plan_mut().add_expr_list(&exprs);
1029 let names = binder.plan_mut().add_name_list(&names);
1030 let index = binder.fresh_index();
1031 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1032 let messages = table
1033 .checks()
1034 .iter()
1035 .map(|text| {
1036 format!(
1037 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
1038 name.table
1039 )
1040 })
1041 .collect();
1042 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
1043}
1044
1045fn default_text(
1049 ast: &Ast,
1050 expr: ast::ExprRef,
1051 catalog: &Catalog,
1052 parameters: &Parameters,
1053 session: &Session,
1054) -> Result<(String, Vec<QualifiedName>)> {
1055 if crate::expr::has_aggregate(ast, expr) {
1056 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
1057 }
1058 let mut binder = Binder::with(catalog, parameters, session);
1059 let before = binder.plan_mut().node_count();
1060 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
1061 Err(error) if error.message().starts_with("Referenced ") => {
1062 Err(Error::binder("DEFAULT value cannot contain column names"))
1063 }
1064 Err(error) => Err(error),
1065 Ok(_) if binder.plan_mut().node_count() > before => {
1067 Err(Error::binder("DEFAULT value cannot contain subqueries"))
1068 }
1069 Ok(_) if !binder.windows.is_empty() => {
1070 Err(Error::binder("DEFAULT value cannot contain window functions!"))
1071 }
1072 Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
1073 }
1074}
1075
1076fn alter(
1080 ast: &Ast,
1081 catalog: &Catalog,
1082 parameters: &Parameters,
1083 session: &Session,
1084 index: ast::AlterRef,
1085) -> Result<Bound> {
1086 let written = ast.alter(index);
1087 let nothing = |name| Ok(Bound::Alter(Alter { name, alteration: None, rewrite: None }));
1088 let parts: Vec<&str> = ast.name(written.name).collect();
1089 let wanted = if written.view { Entry::View } else { Entry::Table };
1090 let name = match catalog.resolve_as(&parts, wanted) {
1091 Ok(name) => name,
1092 Err(_) if written.quiet => return nothing(None),
1093 Err(error) => return Err(error),
1094 };
1095 let kind = catalog.entry(&name)?;
1096 if written.view && kind == Entry::Table {
1097 return Err(Error::catalog("Can only modify table with ALTER TABLE statement"));
1098 }
1099 if let ast::AlterAction::Rename { to } = written.action {
1100 let alteration = rudb_catalog::Alteration::Rename(ast.string(to).to_string());
1101 return Ok(Bound::Alter(Alter {
1102 name: Some(name),
1103 alteration: Some(alteration),
1104 rewrite: None,
1105 }));
1106 }
1107 if kind == Entry::View {
1108 return Err(Error::catalog("Can only modify view with ALTER VIEW statement"));
1109 }
1110 let table = catalog.table(&name)?;
1111 let fields = table.columns();
1112 let place = |column: ast::StrRef| {
1113 fields.iter().position(|field| same_name(&field.name, ast.string(column)))
1114 };
1115 let missing = |column: ast::StrRef| {
1116 let names: Vec<String> = fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
1117 Error::binder(format!(
1118 "Table \"{}\" does not have a column with name \"{}\"\n\nDid you mean: {}",
1119 name.table,
1120 ast.string(column),
1121 names.join(", ")
1122 ))
1123 };
1124 let found = |column: ast::StrRef| place(column).ok_or_else(|| missing(column));
1125 let checks = table.checks();
1126 let mut rewrite = None;
1127 let alteration = match written.action {
1128 ast::AlterAction::Rename { .. } => unreachable!("a rename is handled above"),
1129 ast::AlterAction::RenameColumn { column, to } => {
1130 let at = found(column)?;
1131 let (old, to) = (fields[at].name.as_str(), ast.string(to));
1132 if in_foreign_key(catalog, &name, table, at) {
1133 return Err(Error::catalog(format!(
1135 "Cannot rename column \"\"{old}\"\" because this is involved in the foreign key \
1136 constraint"
1137 )));
1138 }
1139 let checks =
1140 checks.iter().map(|text| rename_in(text, old, to)).collect::<Result<Vec<_>>>()?;
1141 rudb_catalog::Alteration::RenameColumn { column: at, to: to.to_string(), checks }
1142 }
1143 ast::AlterAction::AddColumn { column, quiet } => {
1144 if quiet && place(column.name).is_some() {
1145 return nothing(Some(name));
1146 }
1147 let ty = read_type(catalog, ast.string(column.ty))?;
1148 let field = Field {
1149 not_null: column.not_null,
1150 ..Field::new(ast.string(column.name), ty.clone())
1151 };
1152 let (default, sequences) = if column.default == NONE {
1153 (None, Vec::new())
1154 } else {
1155 let (text, used) = default_text(ast, column.default, catalog, parameters, session)?;
1156 (Some(text), used)
1157 };
1158 rewrite = Some(table_rewrite(
1159 ast,
1160 (catalog, parameters, session),
1161 &name,
1162 |binder, _, out| {
1163 let value = if column.default == NONE {
1164 let null = binder.add_constant(Value::Null);
1165 binder.cast_to(null, &ty)
1166 } else {
1167 let value =
1168 binder.bind_expr(ast, column.default, &crate::scope::Scope::empty())?;
1169 binder.checked_cast_to(value, &ty, false)?
1170 };
1171 out.push((value, field.name.clone()));
1172 Ok(())
1173 },
1174 )?);
1175 rudb_catalog::Alteration::AddColumn { field, default, sequences }
1176 }
1177 ast::AlterAction::DropColumn { column, quiet } => {
1178 let Some(at) = place(column) else {
1179 return if quiet { nothing(Some(name)) } else { Err(missing(column)) };
1180 };
1181 let dropped = fields[at].name.as_str();
1182 let mut kept = Vec::with_capacity(checks.len());
1183 for text in checks {
1184 let used = columns_in(text)?;
1185 if !used.iter().any(|used| same_name(used, dropped)) {
1186 kept.push(text.clone());
1187 } else if used.iter().any(|used| !same_name(used, dropped)) {
1188 return Err(Error::catalog(format!(
1189 "Cannot drop column \"{dropped}\" because there is a CHECK constraint that \
1190 depends on it"
1191 )));
1192 }
1193 }
1194 rewrite =
1195 Some(table_rewrite(ast, (catalog, parameters, session), &name, |_, _, out| {
1196 out.remove(at);
1197 Ok(())
1198 })?);
1199 rudb_catalog::Alteration::DropColumn { column: at, checks: kept }
1200 }
1201 ast::AlterAction::Default { column, default } => {
1202 let at = found(column)?;
1203 let (default, sequences) = if default == NONE {
1204 (None, Vec::new())
1205 } else {
1206 let (text, used) = default_text(ast, default, catalog, parameters, session)?;
1207 (Some(text), used)
1208 };
1209 rudb_catalog::Alteration::Default { column: at, default, sequences }
1210 }
1211 ast::AlterAction::NotNull { column, set } => {
1212 rudb_catalog::Alteration::NotNull { column: found(column)?, set }
1213 }
1214 ast::AlterAction::Type { column, ty, using } => {
1215 let at = found(column)?;
1216 let changed = fields[at].name.as_str();
1217 if table.keys().iter().any(|key| key.columns.contains(&at)) {
1218 return Err(Error::binder(
1219 "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY \
1220 constraint specified",
1221 ));
1222 }
1223 for text in checks {
1224 if columns_in(text)?.iter().any(|used| same_name(used, changed)) {
1225 return Err(Error::binder(
1226 "Cannot change the type of a column that has a CHECK constraint specified",
1227 ));
1228 }
1229 }
1230 if in_foreign_key(catalog, &name, table, at) {
1231 return Err(Error::binder(
1232 "Cannot change the type of a column that has a FOREIGN KEY constraint specified",
1233 ));
1234 }
1235 let mut target =
1236 if ty == NONE { None } else { Some(read_type(catalog, ast.string(ty))?) };
1237 rewrite = Some(table_rewrite(
1238 ast,
1239 (catalog, parameters, session),
1240 &name,
1241 |binder, scope, out| {
1242 let value = if using == NONE {
1243 out[at].0
1244 } else {
1245 binder.bind_expr(ast, using, scope)?
1246 };
1247 let ty = target
1248 .get_or_insert_with(|| binder.plan_mut().expr_type(value).clone())
1249 .clone();
1250 out[at].0 = binder.checked_cast_to(value, &ty, false)?;
1251 Ok(())
1252 },
1253 )?);
1254 let ty = target.ok_or_else(|| Error::internal("an ALTER TYPE that settled no type"))?;
1255 rudb_catalog::Alteration::Type { column: at, ty }
1256 }
1257 };
1258 Ok(Bound::Alter(Alter { name: Some(name), alteration: Some(alteration), rewrite }))
1259}
1260
1261fn create_index(
1269 ast: &Ast,
1270 catalog: &Catalog,
1271 parameters: &Parameters,
1272 session: &Session,
1273 at: ast::IndexRef,
1274) -> Result<Bound> {
1275 let written = ast.index(at);
1276 let parts: Vec<String> = ast.name(written.name).map(str::to_string).collect();
1277 if written.drop {
1278 return Ok(Bound::Index(IndexChange {
1279 table: None,
1280 index: None,
1281 name: parts,
1282 quiet: written.quiet,
1283 }));
1284 }
1285 let written_table: Vec<&str> = ast.name(written.table).collect();
1286 let name = catalog.resolve_as(&written_table, Entry::Table)?;
1287 if catalog.entry(&name)? == Entry::View {
1288 return Err(Error::binder("can only create an index on a base table"));
1289 }
1290 if written.using != NONE && !same_name(ast.string(written.using), "art") {
1291 return Err(Error::binder(format!("Unknown index type: {}", ast.string(written.using))));
1292 }
1293 let fields = catalog.table(&name)?.columns();
1294 let mut binder = Binder::with(catalog, parameters, session);
1295 let (_, scope) =
1296 binder.bind_catalog_table(ast, &name, name.table.clone(), ast::Slice::default())?;
1297 let mut columns = Vec::new();
1298 let mut plain = true;
1299 let mut texts = Vec::new();
1300 for &expr in ast.expr_list(written.elements) {
1301 if let ast::Expr::Column { name: column } = ast.exprs[expr as usize] {
1302 let column: Vec<&str> = ast.name(column).collect();
1303 if let [only] = column[..]
1304 && !fields.iter().any(|field| same_name(&field.name, only))
1305 {
1306 let names: Vec<String> =
1307 fields.iter().map(|field| format!("\"{}\"", field.name)).collect();
1308 return Err(Error::binder(format!(
1310 "Table \"{}\" does not have a column named \"{only}\"\n\nCandidate bindings: \
1311 : {}",
1312 name.table,
1313 names.join(", ")
1314 )));
1315 }
1316 }
1317 if crate::expr::has_aggregate(ast, expr) {
1318 return Err(Error::binder("aggregate functions are not allowed in index expressions"));
1319 }
1320 let before = binder.plan_mut().node_count();
1321 let value = binder.bind_expr(ast, expr, &scope)?;
1322 if binder.plan_mut().node_count() > before {
1323 return Err(Error::binder("cannot use subquery in index expressions"));
1324 }
1325 if !binder.windows.is_empty() {
1326 return Err(Error::binder("window functions are not allowed in index expressions"));
1327 }
1328 let ty = binder.plan_mut().expr_type(value).clone();
1329 if ty.is_nested() {
1330 return Err(Error::invalid_type(format!(
1331 "Invalid Type [{ty}]: Invalid type for index key."
1332 )));
1333 }
1334 let bare = match binder.plan_mut().expr(value) {
1335 Expr::Column(binding) => scope.columns.iter().position(|held| held.binding == *binding),
1336 _ => None,
1337 };
1338 if let Some(at) = bare {
1339 columns.push(at);
1340 texts.push(rudb_parse::quoted(&fields[at].name));
1341 continue;
1342 }
1343 plain = false;
1344 let text = deparse::expression(ast, expr);
1345 let used = columns_in(&text)?;
1346 if used.is_empty() {
1347 return Err(Error::binder(
1348 "CREATE INDEX does not refer to any columns in the base table!",
1349 ));
1350 }
1351 for used in used {
1352 if let Some(at) = fields.iter().position(|field| same_name(&field.name, &used)) {
1353 columns.push(at);
1354 }
1355 }
1356 texts.push(format!("({text})"));
1357 }
1358 if written.unique && !plain {
1359 return Err(Error::not_implemented("A UNIQUE index over an expression is not supported"));
1360 }
1361 let expressions = Value::List {
1362 element: LogicalType::Varchar,
1363 values: texts.iter().map(|text| Value::Varchar(text.clone())).collect(),
1364 };
1365 let unique = if written.unique { "UNIQUE " } else { "" };
1366 let table: Vec<String> = written_table.iter().map(|part| rudb_parse::quoted(part)).collect();
1367 let using = if written.using == NONE {
1368 String::new()
1369 } else {
1370 format!(" USING {} ", ast.string(written.using))
1371 };
1372 let index_name = parts.last().cloned().unwrap_or_default();
1373 let sql = format!(
1374 "CREATE {unique}INDEX {} ON {}{using}({});",
1375 rudb_parse::quoted(&index_name),
1376 table.join("."),
1377 texts.join(", ")
1378 );
1379 if !plain {
1380 columns.sort_unstable();
1381 columns.dedup();
1382 }
1383 let index = rudb_catalog::Index {
1384 name: index_name,
1385 unique: written.unique,
1386 columns,
1387 plain,
1388 expressions: expressions.to_string(),
1389 sql,
1390 oid: 0,
1391 };
1392 Ok(Bound::Index(IndexChange {
1393 table: Some(name),
1394 index: Some(index),
1395 name: Vec::new(),
1396 quiet: written.quiet,
1397 }))
1398}
1399
1400fn in_foreign_key(
1403 catalog: &Catalog,
1404 name: &QualifiedName,
1405 table: &rudb_catalog::Table,
1406 at: usize,
1407) -> bool {
1408 table.foreign().iter().any(|key| key.columns.contains(&at))
1409 || catalog.tables().any(|held| {
1410 held.foreign().iter().any(|key| key.table == *name && key.referenced.contains(&at))
1411 })
1412}
1413
1414fn table_rewrite(
1417 ast: &Ast,
1418 (catalog, parameters, session): (&Catalog, &Parameters, &Session),
1419 name: &QualifiedName,
1420 change: impl FnOnce(
1421 &mut Binder<'_>,
1422 &crate::scope::Scope,
1423 &mut Vec<(ExprRef, String)>,
1424 ) -> Result<()>,
1425) -> Result<Plan> {
1426 let mut binder = Binder::with(catalog, parameters, session);
1427 let (root, scope) =
1428 binder.bind_catalog_table(ast, name, name.table.clone(), ast::Slice::default())?;
1429 let mut out = Vec::with_capacity(scope.columns.len() + 1);
1430 for column in &scope.columns {
1431 let expr = binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1432 out.push((expr, column.name.clone()));
1433 }
1434 change(&mut binder, &scope, &mut out)?;
1435 let exprs: Vec<ExprRef> = out.iter().map(|(expr, _)| *expr).collect();
1436 let names: Vec<_> = out.iter().map(|(_, name)| binder.plan_mut().intern(name)).collect();
1437 let exprs = binder.plan_mut().add_expr_list(&exprs);
1438 let names = binder.plan_mut().add_name_list(&names);
1439 let index = binder.fresh_index();
1440 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1441 finish(binder, root)
1442}
1443
1444fn check_ast(text: &str) -> Result<(Ast, ast::ExprRef)> {
1446 let ast = parse_ast(&format!("SELECT {text}"))?;
1447 let found = match ast.statements.first() {
1448 Some(&ast::Statement::Query(query)) => match ast.query(query).body {
1449 ast::QueryBody::Select(select) => {
1450 ast.target_list(ast.select(select).targets).first().map(|target| target.expr)
1451 }
1452 _ => None,
1453 },
1454 _ => None,
1455 };
1456 let expr = found.ok_or_else(|| Error::internal("a check that is not an expression"))?;
1457 Ok((ast, expr))
1458}
1459
1460fn columns_in(text: &str) -> Result<Vec<String>> {
1462 let (ast, _) = check_ast(text)?;
1463 let mut out = Vec::new();
1464 for expr in &ast.exprs {
1465 if let ast::Expr::Column { name } = *expr
1466 && let Some(last) = ast.name(name).last()
1467 {
1468 out.push(last.to_string());
1469 }
1470 }
1471 Ok(out)
1472}
1473
1474fn rename_in(text: &str, old: &str, to: &str) -> Result<String> {
1477 let (mut ast, expr) = check_ast(text)?;
1478 let mut renamed = false;
1479 for at in 0..ast.exprs.len() {
1480 let ast::Expr::Column { name } = ast.exprs[at] else { continue };
1481 if name.len == 0 {
1482 continue;
1483 }
1484 let last = (name.start + name.len - 1) as usize;
1485 if same_name(ast.string(ast.parts[last]), old) {
1486 let index = ast.strings.len() as u32;
1487 ast.strings.push(to.to_string());
1488 ast.parts[last] = index;
1489 renamed = true;
1490 }
1491 }
1492 Ok(if renamed { deparse::expression(&ast, expr) } else { text.to_string() })
1493}
1494
1495fn deduplicate(columns: &mut [Field]) {
1508 for at in 0..columns.len() {
1509 let taken = |name: &str, upto: usize, columns: &[Field]| {
1510 columns[..upto].iter().any(|held| same_name(&held.name, name))
1511 };
1512 if !taken(&columns[at].name, at, columns) {
1513 continue;
1514 }
1515 let mut suffix = 1;
1516 let mut candidate = format!("{}_{suffix}", columns[at].name);
1517 while taken(&candidate, at, columns) {
1518 suffix += 1;
1519 candidate = format!("{}_{suffix}", columns[at].name);
1520 }
1521 columns[at].name = candidate;
1522 }
1523}
1524
1525fn create_view(
1532 ast: &Ast,
1533 catalog: &Catalog,
1534 parameters: &Parameters,
1535 session: &Session,
1536 index: ast::CreateViewRef,
1537) -> Result<Bound> {
1538 let written = ast.create_view(index);
1539 let parts: Vec<&str> = ast.name(written.name).collect();
1540 let name = if written.temporary {
1541 catalog.resolve_for_create_temporary(&parts)?
1542 } else {
1543 catalog.resolve_for_create(&parts)?
1544 };
1545 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
1546
1547 let mut binder = Binder::with(catalog, parameters, session);
1548 binder.outlined = true;
1551 let (_, mut scope) = binder.bind_query(ast, written.query)?;
1552 if aliases.len() > scope.len() {
1553 return Err(Error::binder("More VIEW aliases than columns in query result"));
1554 }
1555 if !aliases.is_empty() {
1556 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
1557 scope.rename(&written, "unnamed_subquery")?;
1558 }
1559
1560 Ok(Bound::CreateView(CreateView {
1561 name,
1562 sql: ast.string(written.sql).to_string(),
1563 statement: deparse::create_view(ast, index),
1564 aliases,
1565 if_not_exists: written.if_not_exists,
1566 or_replace: written.or_replace,
1567 columns: scope.fields(),
1568 }))
1569}
1570
1571fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
1572 let written = ast.drop_table(index);
1573 let kind = if written.view { Entry::View } else { Entry::Table };
1574 let mut names = Vec::new();
1575 for &name in ast.name_list(written.names) {
1576 let parts: Vec<&str> = ast.name(name).collect();
1577 match catalog.resolve_as(&parts, kind) {
1580 Ok(resolved) => names.push(resolved),
1581 Err(error) if written.if_exists => drop(error),
1582 Err(error) => return Err(error),
1583 }
1584 }
1585 Ok(Bound::DropTable(DropTable { names, kind }))
1586}
1587
1588fn setting(
1594 ast: &Ast,
1595 catalog: &Catalog,
1596 parameters: &Parameters,
1597 session: &Session,
1598 index: ast::SettingRef,
1599) -> Result<Bound> {
1600 let written = ast.setting(index);
1601 let name = ast.string(written.name).to_string();
1602 let value = if written.value == NONE {
1603 None
1604 } else {
1605 let mut binder = Binder::with(catalog, parameters, session);
1606 let bound = binder.bind_setting_value(ast, written.value)?;
1607 let Expr::Constant(value) = *binder.plan().expr(bound) else {
1608 return Err(Error::not_implemented(format!(
1609 "a value for {name} that is not a constant"
1610 )));
1611 };
1612 Some(binder.plan().value(value).clone())
1613 };
1614 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
1615}
1616
1617fn attach(
1619 ast: &Ast,
1620 catalog: &Catalog,
1621 parameters: &Parameters,
1622 session: &Session,
1623 index: ast::AttachRef,
1624) -> Result<Bound> {
1625 let written = ast.attach(index);
1626 let mut binder = Binder::with(catalog, parameters, session);
1627 let mut constant = |expr: ast::ExprRef, what: &str| -> Result<Value> {
1628 let bound = binder.bind_setting_value(ast, expr)?;
1629 let Expr::Constant(value) = *binder.plan().expr(bound) else {
1630 return Err(Error::not_implemented(format!("{what} of ATTACH that is not a constant")));
1631 };
1632 Ok(binder.plan().value(value).clone())
1633 };
1634 let path = match constant(written.path, "a path")? {
1635 Value::Null => {
1636 return Err(Error::binder("ATTACH path expression must not evaluate to NULL"));
1637 }
1638 value => value.to_string(),
1639 };
1640 let names = ast.name(written.names).map(str::to_string).collect::<Vec<_>>();
1641 let mut options = Vec::with_capacity(names.len());
1642 for (name, &value) in names.into_iter().zip(ast.expr_list(written.values)) {
1643 let value = if value == NONE { None } else { Some(constant(value, "an option")?) };
1644 options.push((name, value));
1645 }
1646 let alias = (written.alias != NONE).then(|| ast.string(written.alias).to_string());
1647 Ok(Bound::Attach(Attach {
1648 path,
1649 alias,
1650 or_replace: written.or_replace,
1651 if_not_exists: written.if_not_exists,
1652 options,
1653 }))
1654}
1655
1656fn clustered(
1668 binder: &mut Binder<'_>,
1669 input: rudb_plan::NodeRef,
1670 scope: &crate::scope::Scope,
1671 clustering: &Clustering,
1672 targets: &[usize],
1673 fields: &[Field],
1674) -> Result<rudb_plan::NodeRef> {
1675 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
1676 for (at, &column) in clustering.columns().iter().enumerate() {
1677 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
1678 continue;
1679 };
1680 let source = &scope.columns[from];
1681 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
1682 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
1687 let expr =
1688 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
1689 keys.push(SortKey { expr, descending: false, nulls_first: false });
1690 }
1691 if keys.is_empty() {
1692 return Ok(input);
1693 }
1694 let keys = binder.plan_mut().add_sort_keys(&keys);
1695 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
1696}
1697
1698fn fitted(
1712 binder: &Binder<'_>,
1713 scope: &crate::scope::Scope,
1714 clustering: &Clustering,
1715 targets: &[usize],
1716) -> Clustering {
1717 if clustering.width() != Width::Auto {
1718 return clustering.clone();
1719 }
1720 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
1721 else {
1722 return clustering.fitted(0, 0);
1723 };
1724 let source = &scope.columns[from];
1725 let Some(zones) = binder.plan().sole_zones() else {
1726 return clustering.fitted(0, 0);
1727 };
1728 let Some(at) = zones.column(&source.name) else {
1733 return clustering.fitted(0, 0);
1734 };
1735 let rows = zones.surviving(&[]).unwrap_or(0);
1736 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
1737 clustering.fitted(rows, days)
1738}
1739
1740fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
1746 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
1747 return None;
1748 };
1749 let days = match (low, high) {
1750 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
1752 (
1756 ColumnBound::Scaled { unscaled: low, scale: at },
1757 ColumnBound::Scaled { unscaled: high, scale: to },
1758 ) if at == to => {
1759 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
1760 high.checked_sub(*low)? / day
1761 }
1762 _ => return None,
1763 };
1764 u64::try_from(days).ok()
1765}
1766
1767fn bucketed(
1769 binder: &mut Binder<'_>,
1770 expr: ExprRef,
1771 width: Width,
1772 fields: &[Field],
1773 column: u32,
1774) -> ExprRef {
1775 if width == Width::Exact {
1776 return expr;
1777 }
1778 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1779 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1780 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1781 let name = binder.plan_mut().intern("date_trunc");
1782 let ty = fields[column as usize].ty.clone();
1783 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1784}
1785
1786fn insert(
1787 ast: &Ast,
1788 catalog: &Catalog,
1789 parameters: &Parameters,
1790 session: &Session,
1791 index: ast::InsertRef,
1792) -> Result<Bound> {
1793 let written = ast.insert(index);
1794 let parts: Vec<&str> = ast.name(written.name).collect();
1795 let name = catalog.resolve(&parts)?;
1796 if catalog.entry(&name)? == Entry::View {
1797 return Err(Error::catalog(format!("{} is not an table", name.table)));
1800 }
1801 let target = catalog.table(&name)?;
1802 let fields: Vec<Field> = target.columns().to_vec();
1803 let clustering = target.clustering().cloned();
1804
1805 let targets: Vec<usize> = if written.columns.is_empty() {
1809 (0..fields.len()).collect()
1810 } else {
1811 let mut targets = Vec::new();
1812 for column in ast.name(written.columns) {
1813 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1814 || {
1815 Error::binder(format!(
1816 "Table \"{}\" does not have a column with name \"{column}\"",
1817 name.table
1818 ))
1819 },
1820 )?;
1821 if targets.contains(&at) {
1822 return Err(Error::binder(format!("Duplicate column name \"{column}\" in INSERT")));
1823 }
1824 targets.push(at);
1825 }
1826 targets
1827 };
1828
1829 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1830 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1831 .collect();
1832 let mut binder = Binder::with(catalog, parameters, session);
1833 let (root, scope) = if written.source == NONE {
1834 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1837 } else {
1838 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1841 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1842 }
1843 if written.copy {
1847 binder.copy_into = Some(targets.iter().map(|&at| fields[at].clone()).collect());
1848 }
1849 let bound = binder.bind_query(ast, written.source)?;
1850 binder.copy_into = None;
1851 bound
1852 };
1853 let targets = if written.source == NONE { Vec::new() } else { targets };
1854 if scope.len() != targets.len() {
1856 return Err(Error::binder(if written.columns.is_empty() {
1857 format!(
1858 "table \"{}\" has {} columns but {} values were supplied",
1859 name.table,
1860 targets.len(),
1861 scope.len()
1862 )
1863 } else {
1864 format!(
1865 "Column name/value mismatch for insert on \"{}\": expected {} columns but {} \
1866 values were supplied",
1867 name.table,
1868 targets.len(),
1869 scope.len()
1870 )
1871 }));
1872 }
1873
1874 let root = match &clustering {
1880 None => root,
1881 Some(clustering) => {
1882 let fitted = fitted(&binder, &scope, clustering, &targets);
1887 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1888 }
1889 };
1890
1891 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1895 let mut names = Vec::with_capacity(fields.len());
1896 for (at, field) in fields.iter().enumerate() {
1897 let expr = match targets.iter().position(|&target| target == at) {
1898 Some(from) => {
1899 let column = &scope.columns[from];
1900 let expr =
1901 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1902 binder.checked_cast_to(expr, &field.ty, false)?
1903 }
1904 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1906 };
1907 exprs.push(expr);
1908 let interned = binder.plan_mut().intern(&field.name);
1909 names.push(interned);
1910 }
1911 let exprs = binder.plan_mut().add_expr_list(&exprs);
1912 let names = binder.plan_mut().add_name_list(&names);
1913 let index = binder.fresh_index();
1914 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1915 let source = finish(binder, root)?;
1916 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1917 let conflict = match written.conflict {
1918 Some(conflict) => {
1919 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1920 }
1921 None => None,
1922 };
1923 let checks = bind_checks(catalog, parameters, session, &name)?;
1924 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1925}
1926
1927fn bind_conflict(
1930 ast: &Ast,
1931 catalog: &Catalog,
1932 parameters: &Parameters,
1933 session: &Session,
1934 name: &QualifiedName,
1935 targets: &[usize],
1936 conflict: ast::Conflict,
1937) -> Result<Conflict> {
1938 let table = catalog.table(name)?;
1939 let fields = table.columns();
1940 let keys = table.keys();
1941 let key = if conflict.target.is_empty() {
1942 if keys.is_empty() {
1943 return Err(Error::binder(
1944 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1945 CONFLICT columns manually",
1946 ));
1947 }
1948 match conflict.action {
1949 ast::ConflictAction::Nothing => None,
1950 _ if keys.len() > 1 => {
1951 return Err(Error::binder(
1952 "Conflict target has to be provided for a DO UPDATE operation when the table \
1953 has multiple UNIQUE/PRIMARY KEY constraints",
1954 ));
1955 }
1956 _ => Some(0),
1957 }
1958 } else {
1959 let mut wanted = Vec::new();
1960 for column in ast.name(conflict.target) {
1961 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1962 return Err(Error::binder(format!(
1963 "Table \"{}\" does not have a column with name \"{column}\"",
1964 name.table
1965 )));
1966 };
1967 wanted.push(at);
1968 }
1969 wanted.sort_unstable();
1970 wanted.dedup();
1971 let found = keys.iter().position(|key| {
1972 let mut held = key.columns.clone();
1973 held.sort_unstable();
1974 held == wanted
1975 });
1976 let Some(found) = found else {
1977 return Err(Error::binder(
1978 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1979 KEY CONSTRAINT or INDEX",
1980 ));
1981 };
1982 Some(found)
1983 };
1984 let action = match conflict.action {
1985 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1986 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1987 ast::ConflictAction::Update { columns: written, query } => {
1988 let mut columns = Vec::new();
1989 for column in ast.name(written) {
1990 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1991 else {
1992 return Err(Error::binder(format!(
1993 "Referenced update column {column} not found in table!"
1994 )));
1995 };
1996 if columns.contains(&at) {
1997 return Err(Error::binder(format!(
1998 "Multiple assignments to same column \"\"{column}\"\""
1999 )));
2000 }
2001 columns.push(at);
2002 }
2003 let mut binder = Binder::with(catalog, parameters, session);
2004 binder.upsert = true;
2005 let (root, scope) = binder.bind_query(ast, query)?;
2006 let mut exprs = Vec::with_capacity(scope.columns.len());
2009 let mut names = Vec::with_capacity(scope.columns.len());
2010 for (at, column) in scope.columns.iter().enumerate() {
2011 let expr =
2012 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
2013 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
2014 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
2015 names.push(binder.plan_mut().intern(&column.name));
2016 }
2017 let exprs = binder.plan_mut().add_expr_list(&exprs);
2018 let names = binder.plan_mut().add_name_list(&names);
2019 let index = binder.fresh_index();
2020 let root =
2021 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
2022 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
2023 }
2024 };
2025 Ok(Conflict { key, action })
2026}
2027
2028fn change(
2037 ast: &Ast,
2038 catalog: &Catalog,
2039 parameters: &Parameters,
2040 session: &Session,
2041 index: ast::InsertRef,
2042 delete: bool,
2043) -> Result<Bound> {
2044 let written = ast.insert(index);
2045 let parts: Vec<&str> = ast.name(written.name).collect();
2046 let name = catalog.resolve(&parts)?;
2047 if catalog.entry(&name)? == Entry::View {
2048 return Err(Error::binder(if delete {
2049 "Can only delete from base table"
2050 } else {
2051 "Can only update base table"
2052 }));
2053 }
2054 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
2055 let mut targets: Vec<usize> = Vec::new();
2056 for column in ast.name(written.columns) {
2057 let at =
2058 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
2059 Error::binder(format!("Referenced update column {column} not found in table!"))
2060 })?;
2061 if targets.contains(&at) {
2062 return Err(Error::binder(format!(
2063 "Multiple assignments to same column \"\"{column}\"\""
2064 )));
2065 }
2066 targets.push(at);
2067 }
2068
2069 let mut defaulted = vec![false; targets.len()];
2071 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
2072 let items = ast.target_list(ast.select(select).targets);
2073 let first = items.len().saturating_sub(targets.len());
2074 for (at, item) in items[first..].iter().enumerate() {
2075 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
2076 }
2077 }
2078 let table = catalog.table(&name)?;
2079 let mut binder = Binder::with(catalog, parameters, session);
2080 binder.default_as_null = defaulted.contains(&true);
2081 let (root, scope) = binder.bind_query(ast, written.source)?;
2082 binder.default_as_null = false;
2083 let width = fields.len();
2084 if scope.len() != width + 1 + targets.len() {
2085 return Err(Error::internal(format!(
2086 "an UPDATE source of {} columns over a table of {width}",
2087 scope.len()
2088 )));
2089 }
2090 let column = |binder: &mut Binder<'_>, at: usize| {
2091 let column = &scope.columns[at];
2092 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
2093 };
2094 let hit = column(&mut binder, width);
2095 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
2096 let mut exprs = Vec::with_capacity(width);
2097 let mut names = Vec::with_capacity(width);
2098 for (at, field) in fields.iter().enumerate() {
2099 let old = column(&mut binder, at);
2100 let expr = match targets.iter().position(|&target| target == at) {
2101 Some(from) => {
2102 let then = if defaulted[from] {
2103 binder.bind_default(table.default(at), &field.ty)?
2104 } else {
2105 let new = column(&mut binder, width + 1 + from);
2106 binder.checked_cast_to(new, &field.ty, false)?
2107 };
2108 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
2109 binder
2110 .plan_mut()
2111 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
2112 }
2113 None => old,
2114 };
2115 exprs.push(expr);
2116 let interned = binder.plan_mut().intern(&field.name);
2117 names.push(interned);
2118 }
2119 let yes = binder.add_constant(Value::Boolean(true));
2122 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
2123 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
2124 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
2125 let interned = binder.plan_mut().intern("changed");
2126 names.push(interned);
2127 let exprs = binder.plan_mut().add_expr_list(&exprs);
2128 let names = binder.plan_mut().add_name_list(&names);
2129 let index = binder.fresh_index();
2130 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
2131 let source = finish(binder, root)?;
2132 let returning = returning(ast, catalog, parameters, session, written.returning)?;
2133 let write = if delete { Write::Delete } else { Write::Update };
2134 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
2135 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
2136}