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 Insert(Insert),
50 Setting(Setting),
52 Checkpoint,
54 Transaction(ast::Transaction),
56 Explain { plan: Plan, analyze: bool, statistics: bool },
69}
70
71#[derive(Debug)]
83pub struct Setting {
84 pub name: String,
86 pub scope: ast::Scope,
88 pub value: Option<Value>,
90 pub pragma: bool,
92}
93
94#[derive(Debug)]
96pub struct CreateTable {
97 pub name: QualifiedName,
99 pub columns: Vec<Field>,
102 pub source: Option<Plan>,
104 pub if_not_exists: bool,
106 pub or_replace: bool,
108 pub keys: Vec<rudb_catalog::Key>,
110 pub defaults: Vec<Option<String>>,
112 pub sequences: Vec<QualifiedName>,
114 pub checks: Vec<String>,
116 pub foreign: Vec<rudb_catalog::ForeignKey>,
118}
119
120#[derive(Debug)]
127pub struct CreateView {
128 pub name: QualifiedName,
130 pub sql: String,
132 pub statement: String,
137 pub aliases: Vec<String>,
139 pub if_not_exists: bool,
141 pub or_replace: bool,
143 pub columns: Vec<Field>,
149}
150
151#[derive(Debug, Clone, PartialEq, Eq)]
157pub struct SchemaChange {
158 pub catalog: String,
160 pub name: String,
162 pub drop: bool,
164 pub quiet: bool,
166 pub or_replace: bool,
169 pub cascade: bool,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq)]
175pub struct SequenceChange {
176 pub name: Option<QualifiedName>,
178 pub drop: bool,
180 pub if_not_exists: bool,
182 pub or_replace: bool,
184 pub cascade: bool,
186 pub options: rudb_common::sequence::Options,
188 pub owner: Option<QualifiedName>,
191}
192
193#[derive(Debug)]
195pub struct DropTable {
196 pub names: Vec<QualifiedName>,
201 pub kind: Entry,
203}
204
205#[derive(Debug)]
207pub struct Insert {
208 pub name: QualifiedName,
210 pub source: Plan,
213 pub write: Write,
215 pub returning: Option<Box<Plan>>,
218 pub conflict: Option<Conflict>,
220 pub checks: Option<Checks>,
222}
223
224#[derive(Debug)]
230pub struct Checks {
231 pub plan: Box<Plan>,
233 pub messages: Vec<String>,
235}
236
237#[derive(Debug)]
239pub struct Conflict {
240 pub key: Option<usize>,
242 pub action: ConflictAction,
244}
245
246#[derive(Debug)]
248pub enum ConflictAction {
249 Nothing,
251 Replace(Vec<usize>),
253 Update {
257 columns: Vec<usize>,
259 plan: Box<Plan>,
261 },
262}
263
264#[derive(Debug, Clone, Copy, PartialEq, Eq)]
266pub enum Write {
267 Append,
269 Update,
272 Delete,
275}
276
277fn returning(
279 ast: &Ast,
280 catalog: &Catalog,
281 parameters: &Parameters,
282 session: &Session,
283 query: Option<ast::QueryRef>,
284) -> Result<Option<Box<Plan>>> {
285 let Some(query) = query else { return Ok(None) };
286 let mut binder = Binder::with(catalog, parameters, session);
287 let (root, _) = binder.bind_query(ast, query)?;
288 Ok(Some(Box::new(finish(binder, root)?)))
289}
290
291pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
298 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
299}
300
301pub fn bind_statement_with(
311 ast: &Ast,
312 catalog: &Catalog,
313 parameters: &Parameters,
314 session: &Session,
315) -> Result<Bound> {
316 bind_one(ast, catalog, parameters, session, false)
317}
318
319pub fn bind_statement_outlined(
332 ast: &Ast,
333 catalog: &Catalog,
334 parameters: &Parameters,
335 session: &Session,
336) -> Result<Bound> {
337 bind_one(ast, catalog, parameters, session, true)
338}
339
340fn bind_one(
341 ast: &Ast,
342 catalog: &Catalog,
343 parameters: &Parameters,
344 session: &Session,
345 outlined: bool,
346) -> Result<Bound> {
347 let statement = match ast.statements.as_slice() {
348 [statement] => *statement,
349 [] => return Err(Error::binder("no statement to bind")),
350 _ => return Err(Error::not_implemented("a script of more than one statement")),
351 };
352 match statement {
353 ast::Statement::Query(query) => {
354 let mut binder = Binder::with(catalog, parameters, session);
355 binder.outlined = outlined;
356 let (root, _) = binder.bind_query(ast, query)?;
357 Ok(Bound::Query(finish(binder, root)?))
358 }
359 ast::Statement::CreateTable(index) => {
360 create_table(ast, catalog, parameters, session, index)
361 }
362 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
363 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
364 ast::Statement::Schema(index) => {
365 let written = ast.schema(index);
366 if written.temporary {
367 return Err(Error::binder("Temporary schemas are not supported"));
368 }
369 let parts: Vec<&str> = ast.name(written.name).collect();
370 let (catalog, name) = catalog.schema_name(&parts)?;
371 Ok(Bound::Schema(SchemaChange {
372 catalog,
373 name,
374 drop: written.drop,
375 quiet: written.quiet,
376 or_replace: written.or_replace,
377 cascade: written.cascade,
378 }))
379 }
380 ast::Statement::Sequence(index) => {
381 let written = ast.sequence(index);
382 let parts: Vec<&str> = ast.name(written.name).collect();
383 let alter = !written.owner.is_empty();
384 let mut owner = None;
385 let name = if written.drop || alter {
386 match catalog.resolve_sequence(&parts) {
387 Ok(name) => Some(name),
388 Err(_) if written.quiet => None,
389 Err(error) => return Err(error),
390 }
391 } else if written.temporary {
392 Some(catalog.resolve_for_create_temporary(&parts)?)
393 } else {
394 Some(catalog.resolve_for_create(&parts)?)
395 };
396 if alter && name.is_some() {
397 let parts: Vec<&str> = ast.name(written.owner).collect();
398 owner = Some(catalog.resolve_owner(&parts)?);
399 }
400 Ok(Bound::Sequence(SequenceChange {
401 name,
402 drop: written.drop,
403 if_not_exists: written.quiet,
404 or_replace: written.or_replace,
405 cascade: written.cascade,
406 options: written.options,
407 owner,
408 }))
409 }
410 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
411 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
412 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
413 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
414 setting(ast, catalog, parameters, session, index)
415 }
416 ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
417 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
418 ast::Statement::Explain { query, analyze, statistics } => {
419 let mut binder = Binder::with(catalog, parameters, session);
420 let (root, _) = binder.bind_query(ast, query)?;
421 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
422 }
423 }
424}
425
426pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
432 let ast = parse_ast(sql)?;
433 bind_statement(&ast, catalog)
434}
435
436fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
438 let mut plan = binder.into_plan();
439 plan.set_root(root);
440 plan.validate()?;
441 Ok(plan)
442}
443
444fn create_table(
445 ast: &Ast,
446 catalog: &Catalog,
447 parameters: &Parameters,
448 session: &Session,
449 index: ast::CreateTableRef,
450) -> Result<Bound> {
451 let written = ast.create_table(index);
452 let parts: Vec<&str> = ast.name(written.name).collect();
453 let name = if written.temporary {
454 catalog.resolve_for_create_temporary(&parts)?
455 } else {
456 catalog.resolve_for_create(&parts)?
457 };
458 let defs = ast.column_defs(written.columns);
459 let (mut columns, source) = if written.query == NONE {
460 let mut columns = Vec::with_capacity(defs.len());
461 for def in defs {
462 let text = ast.string(def.ty);
463 if text.is_empty() {
464 return Err(Error::binder(format!(
465 "Column \"{}\" was declared without a type",
466 ast.string(def.name)
467 )));
468 }
469 let ty = LogicalType::parse(text)?;
470 let column = ast.string(def.name);
471 columns.push(if def.not_null {
472 Field::required(column, ty)
473 } else {
474 Field::new(column, ty)
475 });
476 }
477 (columns, None)
478 } else {
479 let mut binder = Binder::with(catalog, parameters, session);
480 let (root, scope) = binder.bind_query(ast, written.query)?;
481 if defs.len() > scope.len() {
482 return Err(Error::binder("Target table has more colum names than query result."));
485 }
486 let mut columns = Vec::with_capacity(scope.columns.len());
487 for (at, column) in scope.columns.iter().enumerate() {
488 let named = match defs.get(at) {
489 Some(def) => ast.string(def.name).to_string(),
490 None => column.name.clone(),
491 };
492 columns.push(Field::new(named, column.ty.clone()));
493 }
494 if defs.is_empty() {
495 deduplicate(&mut columns);
496 }
497 (columns, Some(finish(binder, root)?))
498 };
499 duplicate_check(&columns)?;
500 let mut defaults = Vec::with_capacity(defs.len());
501 let mut sequences = Vec::new();
502 for def in defs {
503 defaults.push(if def.default == NONE {
504 None
505 } else {
506 let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
507 for name in used {
508 if !sequences.contains(&name) {
509 sequences.push(name);
510 }
511 }
512 Some(text)
513 });
514 }
515 let mut checks = Vec::new();
516 for &expr in ast.expr_list(written.checks) {
517 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
518 }
519 let mut keys = Vec::new();
520 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
521 let mut places = Vec::new();
522 for wanted in ast.name(names) {
523 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
524 else {
525 return Err(Error::catalog(format!(
526 "table \"{}\" does not have a column named \"{wanted}\"",
527 name.table
528 )));
529 };
530 places.push(place);
531 }
532 let primary = at as u32 == written.primary;
533 if primary {
534 for &place in &places {
535 columns[place].not_null = true;
536 }
537 }
538 keys.push(rudb_catalog::Key { columns: places, primary });
539 }
540 let mut foreign = Vec::new();
541 let lists = ast.name_list(written.foreign).iter();
542 let tables = ast.name_list(written.foreign_tables).iter();
543 let referenced = ast.name_list(written.foreign_referenced).iter();
544 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
545 let names: Vec<&str> = ast.name(names).collect();
546 let parts: Vec<&str> = ast.name(table).collect();
547 let wanted: Vec<&str> = ast.name(wanted).collect();
548 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
549 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
550 }
551 Ok(Bound::CreateTable(CreateTable {
552 name,
553 columns,
554 source,
555 if_not_exists: written.if_not_exists,
556 or_replace: written.or_replace,
557 keys,
558 defaults,
559 checks,
560 foreign,
561 sequences,
562 }))
563}
564
565fn foreign_key(
571 catalog: &Catalog,
572 made: &QualifiedName,
573 (columns, keys): (&[Field], &[rudb_catalog::Key]),
574 (names, parts, wanted): (&[&str], &[&str], &[&str]),
575) -> Result<rudb_catalog::ForeignKey> {
576 let mut places = Vec::with_capacity(names.len());
577 for &wanted in names {
578 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
579 return Err(Error::binder(format!(
580 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
581 )));
582 };
583 places.push(place);
584 }
585 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
586 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
587 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
588 (made.clone(), columns.to_vec(), keys.to_vec())
589 } else {
590 let resolved = catalog.resolve(parts)?;
591 if catalog.view(&resolved).is_ok() {
592 return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
593 }
594 let table = catalog.table(&resolved)?;
595 (resolved, table.columns().to_vec(), table.keys().to_vec())
596 };
597 let referenced = if wanted.is_empty() {
598 let Some(primary) = held.iter().find(|key| key.primary) else {
599 return Err(Error::binder(format!(
600 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
601 table.table
602 )));
603 };
604 if primary.columns.len() != places.len() {
605 return Err(Error::parser(
606 "The number of referencing and referenced columns for foreign keys must be the same",
607 ));
608 }
609 primary.columns.clone()
610 } else {
611 let mut referenced = Vec::with_capacity(wanted.len());
612 for &column in wanted {
613 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
614 return Err(Error::binder(format!(
615 "Failed to create foreign key: referenced table \"{}\" does not have a column \
616 named \"{column}\"",
617 table.table
618 )));
619 };
620 referenced.push(place);
621 }
622 let mut sorted = referenced.clone();
623 sorted.sort_unstable();
624 let matched = held.iter().any(|key| {
625 let mut columns = key.columns.clone();
626 columns.sort_unstable();
627 columns == sorted
628 });
629 if !matched && held.is_empty() {
630 return Err(Error::binder(format!(
631 "Failed to create foreign key: there is no primary key or unique constraint for \
632 referenced table \"{}\"",
633 table.table
634 )));
635 }
636 if !matched {
637 return Err(Error::binder(format!(
638 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
639 or unique constraint on the columns {}",
640 table.table,
641 wanted.join(", ")
642 )));
643 }
644 referenced
645 };
646 for (&from, &to) in places.iter().zip(&referenced) {
647 if columns[from].ty != fields[to].ty {
648 return Err(Error::binder(format!(
649 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
650 and column \"{}\" (\"{}\")",
651 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
652 )));
653 }
654 }
655 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
656}
657
658fn check_text(
660 ast: &Ast,
661 expr: ast::ExprRef,
662 columns: &[Field],
663 catalog: &Catalog,
664 parameters: &Parameters,
665 session: &Session,
666) -> Result<String> {
667 if crate::expr::has_aggregate(ast, expr) {
668 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
669 }
670 let mut binder = Binder::with(catalog, parameters, session);
671 let index = binder.fresh_index();
672 let mut scope = crate::scope::Scope::empty();
673 for (at, field) in columns.iter().enumerate() {
674 scope.push(crate::scope::Visible {
675 table: String::new(),
676 name: field.name.clone(),
677 binding: rudb_plan::ColumnBinding::new(index, at as u32),
678 ty: field.ty.clone(),
679 not_null: false,
680 key: None,
681 default: None,
682 qualified: false,
683 also: None,
684 });
685 }
686 match binder.bind_expr(ast, expr, &scope) {
687 Err(error) if error.message().starts_with("Referenced column \"") => {
688 let column = error.message().split('"').nth(1).unwrap_or_default();
689 Err(Error::binder(format!(
690 "Table does not contain column \"{column}\" referenced in check constraint!"
691 )))
692 }
693 Err(error) => Err(error),
694 Ok(_) if !binder.windows.is_empty() => {
695 Err(Error::binder("window functions are not allowed in check constraints"))
696 }
697 Ok(_) => Ok(deparse::expression(ast, expr)),
698 }
699}
700
701fn bind_checks(
704 catalog: &Catalog,
705 parameters: &Parameters,
706 session: &Session,
707 name: &QualifiedName,
708) -> Result<Option<Checks>> {
709 let table = catalog.table(name)?;
710 if table.checks().is_empty() {
711 return Ok(None);
712 }
713 let failed: Vec<String> =
714 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
715 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
716 let ast::Statement::Query(query) = ast.statements[0] else {
717 return Err(Error::internal("a check that is not an expression"));
718 };
719 let ast::QueryBody::Select(select) = ast.query(query).body else {
720 return Err(Error::internal("a check that is not an expression"));
721 };
722 let mut binder = Binder::with(catalog, parameters, session);
723 let (root, scope) =
724 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
725 let mut exprs = Vec::with_capacity(failed.len());
726 let mut names = Vec::with_capacity(failed.len());
727 for target in ast.target_list(ast.select(select).targets) {
728 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
729 names.push(binder.plan_mut().intern("failed"));
730 }
731 let exprs = binder.plan_mut().add_expr_list(&exprs);
732 let names = binder.plan_mut().add_name_list(&names);
733 let index = binder.fresh_index();
734 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
735 let messages = table
736 .checks()
737 .iter()
738 .map(|text| {
739 format!(
740 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
741 name.table
742 )
743 })
744 .collect();
745 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
746}
747
748fn default_text(
752 ast: &Ast,
753 expr: ast::ExprRef,
754 catalog: &Catalog,
755 parameters: &Parameters,
756 session: &Session,
757) -> Result<(String, Vec<QualifiedName>)> {
758 if crate::expr::has_aggregate(ast, expr) {
759 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
760 }
761 let mut binder = Binder::with(catalog, parameters, session);
762 let before = binder.plan_mut().node_count();
763 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
764 Err(error) if error.message().starts_with("Referenced ") => {
765 Err(Error::binder("DEFAULT value cannot contain column names"))
766 }
767 Err(error) => Err(error),
768 Ok(_) if binder.plan_mut().node_count() > before => {
770 Err(Error::binder("DEFAULT value cannot contain subqueries"))
771 }
772 Ok(_) if !binder.windows.is_empty() => {
773 Err(Error::binder("DEFAULT value cannot contain window functions!"))
774 }
775 Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
776 }
777}
778
779fn deduplicate(columns: &mut [Field]) {
792 for at in 0..columns.len() {
793 let taken = |name: &str, upto: usize, columns: &[Field]| {
794 columns[..upto].iter().any(|held| same_name(&held.name, name))
795 };
796 if !taken(&columns[at].name, at, columns) {
797 continue;
798 }
799 let mut suffix = 1;
800 let mut candidate = format!("{}_{suffix}", columns[at].name);
801 while taken(&candidate, at, columns) {
802 suffix += 1;
803 candidate = format!("{}_{suffix}", columns[at].name);
804 }
805 columns[at].name = candidate;
806 }
807}
808
809fn create_view(
816 ast: &Ast,
817 catalog: &Catalog,
818 parameters: &Parameters,
819 session: &Session,
820 index: ast::CreateViewRef,
821) -> Result<Bound> {
822 let written = ast.create_view(index);
823 let parts: Vec<&str> = ast.name(written.name).collect();
824 let name = if written.temporary {
825 catalog.resolve_for_create_temporary(&parts)?
826 } else {
827 catalog.resolve_for_create(&parts)?
828 };
829 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
830
831 let mut binder = Binder::with(catalog, parameters, session);
832 binder.outlined = true;
835 let (_, mut scope) = binder.bind_query(ast, written.query)?;
836 if aliases.len() > scope.len() {
837 return Err(Error::binder("More VIEW aliases than columns in query result"));
838 }
839 if !aliases.is_empty() {
840 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
841 scope.rename(&written, "unnamed_subquery")?;
842 }
843
844 Ok(Bound::CreateView(CreateView {
845 name,
846 sql: ast.string(written.sql).to_string(),
847 statement: deparse::create_view(ast, index),
848 aliases,
849 if_not_exists: written.if_not_exists,
850 or_replace: written.or_replace,
851 columns: scope.fields(),
852 }))
853}
854
855fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
856 let written = ast.drop_table(index);
857 let kind = if written.view { Entry::View } else { Entry::Table };
858 let mut names = Vec::new();
859 for &name in ast.name_list(written.names) {
860 let parts: Vec<&str> = ast.name(name).collect();
861 match catalog.resolve_as(&parts, kind) {
864 Ok(resolved) => names.push(resolved),
865 Err(error) if written.if_exists => drop(error),
866 Err(error) => return Err(error),
867 }
868 }
869 Ok(Bound::DropTable(DropTable { names, kind }))
870}
871
872fn setting(
878 ast: &Ast,
879 catalog: &Catalog,
880 parameters: &Parameters,
881 session: &Session,
882 index: ast::SettingRef,
883) -> Result<Bound> {
884 let written = ast.setting(index);
885 let name = ast.string(written.name).to_string();
886 let value = if written.value == NONE {
887 None
888 } else {
889 let mut binder = Binder::with(catalog, parameters, session);
890 let bound = binder.bind_setting_value(ast, written.value)?;
891 let Expr::Constant(value) = *binder.plan().expr(bound) else {
892 return Err(Error::not_implemented(format!(
893 "a value for {name} that is not a constant"
894 )));
895 };
896 Some(binder.plan().value(value).clone())
897 };
898 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
899}
900
901fn clustered(
913 binder: &mut Binder<'_>,
914 input: rudb_plan::NodeRef,
915 scope: &crate::scope::Scope,
916 clustering: &Clustering,
917 targets: &[usize],
918 fields: &[Field],
919) -> Result<rudb_plan::NodeRef> {
920 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
921 for (at, &column) in clustering.columns().iter().enumerate() {
922 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
923 continue;
924 };
925 let source = &scope.columns[from];
926 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
927 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
932 let expr =
933 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
934 keys.push(SortKey { expr, descending: false, nulls_first: false });
935 }
936 if keys.is_empty() {
937 return Ok(input);
938 }
939 let keys = binder.plan_mut().add_sort_keys(&keys);
940 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
941}
942
943fn fitted(
957 binder: &Binder<'_>,
958 scope: &crate::scope::Scope,
959 clustering: &Clustering,
960 targets: &[usize],
961) -> Clustering {
962 if clustering.width() != Width::Auto {
963 return clustering.clone();
964 }
965 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
966 else {
967 return clustering.fitted(0, 0);
968 };
969 let source = &scope.columns[from];
970 let Some(zones) = binder.plan().sole_zones() else {
971 return clustering.fitted(0, 0);
972 };
973 let Some(at) = zones.column(&source.name) else {
978 return clustering.fitted(0, 0);
979 };
980 let rows = zones.surviving(&[]).unwrap_or(0);
981 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
982 clustering.fitted(rows, days)
983}
984
985fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
991 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
992 return None;
993 };
994 let days = match (low, high) {
995 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
997 (
1001 ColumnBound::Scaled { unscaled: low, scale: at },
1002 ColumnBound::Scaled { unscaled: high, scale: to },
1003 ) if at == to => {
1004 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
1005 high.checked_sub(*low)? / day
1006 }
1007 _ => return None,
1008 };
1009 u64::try_from(days).ok()
1010}
1011
1012fn bucketed(
1014 binder: &mut Binder<'_>,
1015 expr: ExprRef,
1016 width: Width,
1017 fields: &[Field],
1018 column: u32,
1019) -> ExprRef {
1020 if width == Width::Exact {
1021 return expr;
1022 }
1023 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1024 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1025 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1026 let name = binder.plan_mut().intern("date_trunc");
1027 let ty = fields[column as usize].ty.clone();
1028 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1029}
1030
1031fn insert(
1032 ast: &Ast,
1033 catalog: &Catalog,
1034 parameters: &Parameters,
1035 session: &Session,
1036 index: ast::InsertRef,
1037) -> Result<Bound> {
1038 let written = ast.insert(index);
1039 let parts: Vec<&str> = ast.name(written.name).collect();
1040 let name = catalog.resolve(&parts)?;
1041 if catalog.entry(&name)? == Entry::View {
1042 return Err(Error::catalog(format!("{} is not an table", name.table)));
1045 }
1046 let target = catalog.table(&name)?;
1047 let fields: Vec<Field> = target.columns().to_vec();
1048 let clustering = target.clustering().cloned();
1049
1050 let targets: Vec<usize> = if written.columns.is_empty() {
1054 (0..fields.len()).collect()
1055 } else {
1056 let mut targets = Vec::new();
1057 for column in ast.name(written.columns) {
1058 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1059 || {
1060 Error::binder(format!(
1061 "Table \"{}\" does not have a column named \"{column}\"",
1062 name.table
1063 ))
1064 },
1065 )?;
1066 if targets.contains(&at) {
1067 return Err(Error::binder(format!(
1068 "Column \"{column}\" is named twice in the same INSERT"
1069 )));
1070 }
1071 targets.push(at);
1072 }
1073 targets
1074 };
1075
1076 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1077 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1078 .collect();
1079 let mut binder = Binder::with(catalog, parameters, session);
1080 let (root, scope) = if written.source == NONE {
1081 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1084 } else {
1085 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1088 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1089 }
1090 binder.bind_query(ast, written.source)?
1091 };
1092 let targets = if written.source == NONE { Vec::new() } else { targets };
1093 if scope.len() != targets.len() {
1094 return Err(Error::binder(format!(
1095 "Table \"{}\" has {} columns but {} values were supplied",
1096 name.table,
1097 targets.len(),
1098 scope.len()
1099 )));
1100 }
1101
1102 let root = match &clustering {
1108 None => root,
1109 Some(clustering) => {
1110 let fitted = fitted(&binder, &scope, clustering, &targets);
1115 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1116 }
1117 };
1118
1119 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1123 let mut names = Vec::with_capacity(fields.len());
1124 for (at, field) in fields.iter().enumerate() {
1125 let expr = match targets.iter().position(|&target| target == at) {
1126 Some(from) => {
1127 let column = &scope.columns[from];
1128 let expr =
1129 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1130 binder.checked_cast_to(expr, &field.ty, false)?
1131 }
1132 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1134 };
1135 exprs.push(expr);
1136 let interned = binder.plan_mut().intern(&field.name);
1137 names.push(interned);
1138 }
1139 let exprs = binder.plan_mut().add_expr_list(&exprs);
1140 let names = binder.plan_mut().add_name_list(&names);
1141 let index = binder.fresh_index();
1142 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1143 let source = finish(binder, root)?;
1144 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1145 let conflict = match written.conflict {
1146 Some(conflict) => {
1147 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1148 }
1149 None => None,
1150 };
1151 let checks = bind_checks(catalog, parameters, session, &name)?;
1152 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1153}
1154
1155fn bind_conflict(
1158 ast: &Ast,
1159 catalog: &Catalog,
1160 parameters: &Parameters,
1161 session: &Session,
1162 name: &QualifiedName,
1163 targets: &[usize],
1164 conflict: ast::Conflict,
1165) -> Result<Conflict> {
1166 let table = catalog.table(name)?;
1167 let fields = table.columns();
1168 let keys = table.keys();
1169 let key = if conflict.target.is_empty() {
1170 if keys.is_empty() {
1171 return Err(Error::binder(
1172 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1173 CONFLICT columns manually",
1174 ));
1175 }
1176 match conflict.action {
1177 ast::ConflictAction::Nothing => None,
1178 _ if keys.len() > 1 => {
1179 return Err(Error::binder(
1180 "Conflict target has to be provided for a DO UPDATE operation when the table \
1181 has multiple UNIQUE/PRIMARY KEY constraints",
1182 ));
1183 }
1184 _ => Some(0),
1185 }
1186 } else {
1187 let mut wanted = Vec::new();
1188 for column in ast.name(conflict.target) {
1189 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1190 return Err(Error::binder(format!(
1191 "Table \"{}\" does not have a column with name \"{column}\"",
1192 name.table
1193 )));
1194 };
1195 wanted.push(at);
1196 }
1197 wanted.sort_unstable();
1198 wanted.dedup();
1199 let found = keys.iter().position(|key| {
1200 let mut held = key.columns.clone();
1201 held.sort_unstable();
1202 held == wanted
1203 });
1204 let Some(found) = found else {
1205 return Err(Error::binder(
1206 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1207 KEY CONSTRAINT or INDEX",
1208 ));
1209 };
1210 Some(found)
1211 };
1212 let action = match conflict.action {
1213 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1214 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1215 ast::ConflictAction::Update { columns: written, query } => {
1216 let mut columns = Vec::new();
1217 for column in ast.name(written) {
1218 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1219 else {
1220 return Err(Error::binder(format!(
1221 "Referenced update column {column} not found in table!"
1222 )));
1223 };
1224 if columns.contains(&at) {
1225 return Err(Error::binder(format!(
1226 "Multiple assignments to same column \"\"{column}\"\""
1227 )));
1228 }
1229 columns.push(at);
1230 }
1231 let mut binder = Binder::with(catalog, parameters, session);
1232 binder.upsert = true;
1233 let (root, scope) = binder.bind_query(ast, query)?;
1234 let mut exprs = Vec::with_capacity(scope.columns.len());
1237 let mut names = Vec::with_capacity(scope.columns.len());
1238 for (at, column) in scope.columns.iter().enumerate() {
1239 let expr =
1240 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1241 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1242 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1243 names.push(binder.plan_mut().intern(&column.name));
1244 }
1245 let exprs = binder.plan_mut().add_expr_list(&exprs);
1246 let names = binder.plan_mut().add_name_list(&names);
1247 let index = binder.fresh_index();
1248 let root =
1249 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1250 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1251 }
1252 };
1253 Ok(Conflict { key, action })
1254}
1255
1256fn change(
1265 ast: &Ast,
1266 catalog: &Catalog,
1267 parameters: &Parameters,
1268 session: &Session,
1269 index: ast::InsertRef,
1270 delete: bool,
1271) -> Result<Bound> {
1272 let written = ast.insert(index);
1273 let parts: Vec<&str> = ast.name(written.name).collect();
1274 let name = catalog.resolve(&parts)?;
1275 if catalog.entry(&name)? == Entry::View {
1276 return Err(Error::binder(if delete {
1277 "Can only delete from base table"
1278 } else {
1279 "Can only update base table"
1280 }));
1281 }
1282 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1283 let mut targets: Vec<usize> = Vec::new();
1284 for column in ast.name(written.columns) {
1285 let at =
1286 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1287 Error::binder(format!("Referenced update column {column} not found in table!"))
1288 })?;
1289 if targets.contains(&at) {
1290 return Err(Error::binder(format!(
1291 "Multiple assignments to same column \"\"{column}\"\""
1292 )));
1293 }
1294 targets.push(at);
1295 }
1296
1297 let mut defaulted = vec![false; targets.len()];
1299 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1300 let items = ast.target_list(ast.select(select).targets);
1301 let first = items.len().saturating_sub(targets.len());
1302 for (at, item) in items[first..].iter().enumerate() {
1303 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1304 }
1305 }
1306 let table = catalog.table(&name)?;
1307 let mut binder = Binder::with(catalog, parameters, session);
1308 binder.default_as_null = defaulted.contains(&true);
1309 let (root, scope) = binder.bind_query(ast, written.source)?;
1310 binder.default_as_null = false;
1311 let width = fields.len();
1312 if scope.len() != width + 1 + targets.len() {
1313 return Err(Error::internal(format!(
1314 "an UPDATE source of {} columns over a table of {width}",
1315 scope.len()
1316 )));
1317 }
1318 let column = |binder: &mut Binder<'_>, at: usize| {
1319 let column = &scope.columns[at];
1320 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1321 };
1322 let hit = column(&mut binder, width);
1323 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1324 let mut exprs = Vec::with_capacity(width);
1325 let mut names = Vec::with_capacity(width);
1326 for (at, field) in fields.iter().enumerate() {
1327 let old = column(&mut binder, at);
1328 let expr = match targets.iter().position(|&target| target == at) {
1329 Some(from) => {
1330 let then = if defaulted[from] {
1331 binder.bind_default(table.default(at), &field.ty)?
1332 } else {
1333 let new = column(&mut binder, width + 1 + from);
1334 binder.checked_cast_to(new, &field.ty, false)?
1335 };
1336 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1337 binder
1338 .plan_mut()
1339 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1340 }
1341 None => old,
1342 };
1343 exprs.push(expr);
1344 let interned = binder.plan_mut().intern(&field.name);
1345 names.push(interned);
1346 }
1347 let yes = binder.add_constant(Value::Boolean(true));
1350 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1351 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1352 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1353 let interned = binder.plan_mut().intern("changed");
1354 names.push(interned);
1355 let exprs = binder.plan_mut().add_expr_list(&exprs);
1356 let names = binder.plan_mut().add_name_list(&names);
1357 let index = binder.fresh_index();
1358 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1359 let source = finish(binder, root)?;
1360 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1361 let write = if delete { Write::Delete } else { Write::Update };
1362 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1363 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1364}