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}
189
190#[derive(Debug)]
192pub struct DropTable {
193 pub names: Vec<QualifiedName>,
198 pub kind: Entry,
200}
201
202#[derive(Debug)]
204pub struct Insert {
205 pub name: QualifiedName,
207 pub source: Plan,
210 pub write: Write,
212 pub returning: Option<Box<Plan>>,
215 pub conflict: Option<Conflict>,
217 pub checks: Option<Checks>,
219}
220
221#[derive(Debug)]
227pub struct Checks {
228 pub plan: Box<Plan>,
230 pub messages: Vec<String>,
232}
233
234#[derive(Debug)]
236pub struct Conflict {
237 pub key: Option<usize>,
239 pub action: ConflictAction,
241}
242
243#[derive(Debug)]
245pub enum ConflictAction {
246 Nothing,
248 Replace(Vec<usize>),
250 Update {
254 columns: Vec<usize>,
256 plan: Box<Plan>,
258 },
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum Write {
264 Append,
266 Update,
269 Delete,
272}
273
274fn returning(
276 ast: &Ast,
277 catalog: &Catalog,
278 parameters: &Parameters,
279 session: &Session,
280 query: Option<ast::QueryRef>,
281) -> Result<Option<Box<Plan>>> {
282 let Some(query) = query else { return Ok(None) };
283 let mut binder = Binder::with(catalog, parameters, session);
284 let (root, _) = binder.bind_query(ast, query)?;
285 Ok(Some(Box::new(finish(binder, root)?)))
286}
287
288pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
295 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
296}
297
298pub fn bind_statement_with(
308 ast: &Ast,
309 catalog: &Catalog,
310 parameters: &Parameters,
311 session: &Session,
312) -> Result<Bound> {
313 bind_one(ast, catalog, parameters, session, false)
314}
315
316pub fn bind_statement_outlined(
329 ast: &Ast,
330 catalog: &Catalog,
331 parameters: &Parameters,
332 session: &Session,
333) -> Result<Bound> {
334 bind_one(ast, catalog, parameters, session, true)
335}
336
337fn bind_one(
338 ast: &Ast,
339 catalog: &Catalog,
340 parameters: &Parameters,
341 session: &Session,
342 outlined: bool,
343) -> Result<Bound> {
344 let statement = match ast.statements.as_slice() {
345 [statement] => *statement,
346 [] => return Err(Error::binder("no statement to bind")),
347 _ => return Err(Error::not_implemented("a script of more than one statement")),
348 };
349 match statement {
350 ast::Statement::Query(query) => {
351 let mut binder = Binder::with(catalog, parameters, session);
352 binder.outlined = outlined;
353 let (root, _) = binder.bind_query(ast, query)?;
354 Ok(Bound::Query(finish(binder, root)?))
355 }
356 ast::Statement::CreateTable(index) => {
357 create_table(ast, catalog, parameters, session, index)
358 }
359 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
360 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
361 ast::Statement::Schema(index) => {
362 let written = ast.schema(index);
363 if written.temporary {
364 return Err(Error::binder("Temporary schemas are not supported"));
365 }
366 let parts: Vec<&str> = ast.name(written.name).collect();
367 let (catalog, name) = catalog.schema_name(&parts)?;
368 Ok(Bound::Schema(SchemaChange {
369 catalog,
370 name,
371 drop: written.drop,
372 quiet: written.quiet,
373 or_replace: written.or_replace,
374 cascade: written.cascade,
375 }))
376 }
377 ast::Statement::Sequence(index) => {
378 let written = ast.sequence(index);
379 let parts: Vec<&str> = ast.name(written.name).collect();
380 let name = if written.drop {
381 match catalog.resolve_sequence(&parts) {
382 Ok(name) => Some(name),
383 Err(_) if written.quiet => None,
384 Err(error) => return Err(error),
385 }
386 } else if written.temporary {
387 Some(catalog.resolve_for_create_temporary(&parts)?)
388 } else {
389 Some(catalog.resolve_for_create(&parts)?)
390 };
391 Ok(Bound::Sequence(SequenceChange {
392 name,
393 drop: written.drop,
394 if_not_exists: written.quiet,
395 or_replace: written.or_replace,
396 cascade: written.cascade,
397 options: written.options,
398 }))
399 }
400 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
401 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
402 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
403 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
404 setting(ast, catalog, parameters, session, index)
405 }
406 ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
407 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
408 ast::Statement::Explain { query, analyze, statistics } => {
409 let mut binder = Binder::with(catalog, parameters, session);
410 let (root, _) = binder.bind_query(ast, query)?;
411 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
412 }
413 }
414}
415
416pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
422 let ast = parse_ast(sql)?;
423 bind_statement(&ast, catalog)
424}
425
426fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
428 let mut plan = binder.into_plan();
429 plan.set_root(root);
430 plan.validate()?;
431 Ok(plan)
432}
433
434fn create_table(
435 ast: &Ast,
436 catalog: &Catalog,
437 parameters: &Parameters,
438 session: &Session,
439 index: ast::CreateTableRef,
440) -> Result<Bound> {
441 let written = ast.create_table(index);
442 let parts: Vec<&str> = ast.name(written.name).collect();
443 let name = if written.temporary {
444 catalog.resolve_for_create_temporary(&parts)?
445 } else {
446 catalog.resolve_for_create(&parts)?
447 };
448 let defs = ast.column_defs(written.columns);
449 let (mut columns, source) = if written.query == NONE {
450 let mut columns = Vec::with_capacity(defs.len());
451 for def in defs {
452 let text = ast.string(def.ty);
453 if text.is_empty() {
454 return Err(Error::binder(format!(
455 "Column \"{}\" was declared without a type",
456 ast.string(def.name)
457 )));
458 }
459 let ty = LogicalType::parse(text)?;
460 let column = ast.string(def.name);
461 columns.push(if def.not_null {
462 Field::required(column, ty)
463 } else {
464 Field::new(column, ty)
465 });
466 }
467 (columns, None)
468 } else {
469 let mut binder = Binder::with(catalog, parameters, session);
470 let (root, scope) = binder.bind_query(ast, written.query)?;
471 if defs.len() > scope.len() {
472 return Err(Error::binder("Target table has more colum names than query result."));
475 }
476 let mut columns = Vec::with_capacity(scope.columns.len());
477 for (at, column) in scope.columns.iter().enumerate() {
478 let named = match defs.get(at) {
479 Some(def) => ast.string(def.name).to_string(),
480 None => column.name.clone(),
481 };
482 columns.push(Field::new(named, column.ty.clone()));
483 }
484 if defs.is_empty() {
485 deduplicate(&mut columns);
486 }
487 (columns, Some(finish(binder, root)?))
488 };
489 duplicate_check(&columns)?;
490 let mut defaults = Vec::with_capacity(defs.len());
491 let mut sequences = Vec::new();
492 for def in defs {
493 defaults.push(if def.default == NONE {
494 None
495 } else {
496 let (text, used) = default_text(ast, def.default, catalog, parameters, session)?;
497 for name in used {
498 if !sequences.contains(&name) {
499 sequences.push(name);
500 }
501 }
502 Some(text)
503 });
504 }
505 let mut checks = Vec::new();
506 for &expr in ast.expr_list(written.checks) {
507 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
508 }
509 let mut keys = Vec::new();
510 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
511 let mut places = Vec::new();
512 for wanted in ast.name(names) {
513 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
514 else {
515 return Err(Error::catalog(format!(
516 "table \"{}\" does not have a column named \"{wanted}\"",
517 name.table
518 )));
519 };
520 places.push(place);
521 }
522 let primary = at as u32 == written.primary;
523 if primary {
524 for &place in &places {
525 columns[place].not_null = true;
526 }
527 }
528 keys.push(rudb_catalog::Key { columns: places, primary });
529 }
530 let mut foreign = Vec::new();
531 let lists = ast.name_list(written.foreign).iter();
532 let tables = ast.name_list(written.foreign_tables).iter();
533 let referenced = ast.name_list(written.foreign_referenced).iter();
534 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
535 let names: Vec<&str> = ast.name(names).collect();
536 let parts: Vec<&str> = ast.name(table).collect();
537 let wanted: Vec<&str> = ast.name(wanted).collect();
538 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
539 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
540 }
541 Ok(Bound::CreateTable(CreateTable {
542 name,
543 columns,
544 source,
545 if_not_exists: written.if_not_exists,
546 or_replace: written.or_replace,
547 keys,
548 defaults,
549 checks,
550 foreign,
551 sequences,
552 }))
553}
554
555fn foreign_key(
561 catalog: &Catalog,
562 made: &QualifiedName,
563 (columns, keys): (&[Field], &[rudb_catalog::Key]),
564 (names, parts, wanted): (&[&str], &[&str], &[&str]),
565) -> Result<rudb_catalog::ForeignKey> {
566 let mut places = Vec::with_capacity(names.len());
567 for &wanted in names {
568 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
569 return Err(Error::binder(format!(
570 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
571 )));
572 };
573 places.push(place);
574 }
575 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
576 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
577 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
578 (made.clone(), columns.to_vec(), keys.to_vec())
579 } else {
580 let resolved = catalog.resolve(parts)?;
581 if catalog.view(&resolved).is_ok() {
582 return Err(Error::binder("cannot reference a VIEW with a FOREIGN KEY"));
583 }
584 let table = catalog.table(&resolved)?;
585 (resolved, table.columns().to_vec(), table.keys().to_vec())
586 };
587 let referenced = if wanted.is_empty() {
588 let Some(primary) = held.iter().find(|key| key.primary) else {
589 return Err(Error::binder(format!(
590 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
591 table.table
592 )));
593 };
594 if primary.columns.len() != places.len() {
595 return Err(Error::parser(
596 "The number of referencing and referenced columns for foreign keys must be the same",
597 ));
598 }
599 primary.columns.clone()
600 } else {
601 let mut referenced = Vec::with_capacity(wanted.len());
602 for &column in wanted {
603 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
604 return Err(Error::binder(format!(
605 "Failed to create foreign key: referenced table \"{}\" does not have a column \
606 named \"{column}\"",
607 table.table
608 )));
609 };
610 referenced.push(place);
611 }
612 let mut sorted = referenced.clone();
613 sorted.sort_unstable();
614 let matched = held.iter().any(|key| {
615 let mut columns = key.columns.clone();
616 columns.sort_unstable();
617 columns == sorted
618 });
619 if !matched && held.is_empty() {
620 return Err(Error::binder(format!(
621 "Failed to create foreign key: there is no primary key or unique constraint for \
622 referenced table \"{}\"",
623 table.table
624 )));
625 }
626 if !matched {
627 return Err(Error::binder(format!(
628 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
629 or unique constraint on the columns {}",
630 table.table,
631 wanted.join(", ")
632 )));
633 }
634 referenced
635 };
636 for (&from, &to) in places.iter().zip(&referenced) {
637 if columns[from].ty != fields[to].ty {
638 return Err(Error::binder(format!(
639 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
640 and column \"{}\" (\"{}\")",
641 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
642 )));
643 }
644 }
645 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
646}
647
648fn check_text(
650 ast: &Ast,
651 expr: ast::ExprRef,
652 columns: &[Field],
653 catalog: &Catalog,
654 parameters: &Parameters,
655 session: &Session,
656) -> Result<String> {
657 if crate::expr::has_aggregate(ast, expr) {
658 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
659 }
660 let mut binder = Binder::with(catalog, parameters, session);
661 let index = binder.fresh_index();
662 let mut scope = crate::scope::Scope::empty();
663 for (at, field) in columns.iter().enumerate() {
664 scope.push(crate::scope::Visible {
665 table: String::new(),
666 name: field.name.clone(),
667 binding: rudb_plan::ColumnBinding::new(index, at as u32),
668 ty: field.ty.clone(),
669 not_null: false,
670 key: None,
671 default: None,
672 qualified: false,
673 also: None,
674 });
675 }
676 match binder.bind_expr(ast, expr, &scope) {
677 Err(error) if error.message().starts_with("Referenced column \"") => {
678 let column = error.message().split('"').nth(1).unwrap_or_default();
679 Err(Error::binder(format!(
680 "Table does not contain column \"{column}\" referenced in check constraint!"
681 )))
682 }
683 Err(error) => Err(error),
684 Ok(_) if !binder.windows.is_empty() => {
685 Err(Error::binder("window functions are not allowed in check constraints"))
686 }
687 Ok(_) => Ok(deparse::expression(ast, expr)),
688 }
689}
690
691fn bind_checks(
694 catalog: &Catalog,
695 parameters: &Parameters,
696 session: &Session,
697 name: &QualifiedName,
698) -> Result<Option<Checks>> {
699 let table = catalog.table(name)?;
700 if table.checks().is_empty() {
701 return Ok(None);
702 }
703 let failed: Vec<String> =
704 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
705 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
706 let ast::Statement::Query(query) = ast.statements[0] else {
707 return Err(Error::internal("a check that is not an expression"));
708 };
709 let ast::QueryBody::Select(select) = ast.query(query).body else {
710 return Err(Error::internal("a check that is not an expression"));
711 };
712 let mut binder = Binder::with(catalog, parameters, session);
713 let (root, scope) =
714 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
715 let mut exprs = Vec::with_capacity(failed.len());
716 let mut names = Vec::with_capacity(failed.len());
717 for target in ast.target_list(ast.select(select).targets) {
718 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
719 names.push(binder.plan_mut().intern("failed"));
720 }
721 let exprs = binder.plan_mut().add_expr_list(&exprs);
722 let names = binder.plan_mut().add_name_list(&names);
723 let index = binder.fresh_index();
724 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
725 let messages = table
726 .checks()
727 .iter()
728 .map(|text| {
729 format!(
730 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
731 name.table
732 )
733 })
734 .collect();
735 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
736}
737
738fn default_text(
742 ast: &Ast,
743 expr: ast::ExprRef,
744 catalog: &Catalog,
745 parameters: &Parameters,
746 session: &Session,
747) -> Result<(String, Vec<QualifiedName>)> {
748 if crate::expr::has_aggregate(ast, expr) {
749 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
750 }
751 let mut binder = Binder::with(catalog, parameters, session);
752 let before = binder.plan_mut().node_count();
753 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
754 Err(error) if error.message().starts_with("Referenced ") => {
755 Err(Error::binder("DEFAULT value cannot contain column names"))
756 }
757 Err(error) => Err(error),
758 Ok(_) if binder.plan_mut().node_count() > before => {
760 Err(Error::binder("DEFAULT value cannot contain subqueries"))
761 }
762 Ok(_) if !binder.windows.is_empty() => {
763 Err(Error::binder("DEFAULT value cannot contain window functions!"))
764 }
765 Ok(_) => Ok((deparse::expression(ast, expr), binder.sequences)),
766 }
767}
768
769fn deduplicate(columns: &mut [Field]) {
782 for at in 0..columns.len() {
783 let taken = |name: &str, upto: usize, columns: &[Field]| {
784 columns[..upto].iter().any(|held| same_name(&held.name, name))
785 };
786 if !taken(&columns[at].name, at, columns) {
787 continue;
788 }
789 let mut suffix = 1;
790 let mut candidate = format!("{}_{suffix}", columns[at].name);
791 while taken(&candidate, at, columns) {
792 suffix += 1;
793 candidate = format!("{}_{suffix}", columns[at].name);
794 }
795 columns[at].name = candidate;
796 }
797}
798
799fn create_view(
806 ast: &Ast,
807 catalog: &Catalog,
808 parameters: &Parameters,
809 session: &Session,
810 index: ast::CreateViewRef,
811) -> Result<Bound> {
812 let written = ast.create_view(index);
813 let parts: Vec<&str> = ast.name(written.name).collect();
814 let name = if written.temporary {
815 catalog.resolve_for_create_temporary(&parts)?
816 } else {
817 catalog.resolve_for_create(&parts)?
818 };
819 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
820
821 let mut binder = Binder::with(catalog, parameters, session);
822 binder.outlined = true;
825 let (_, mut scope) = binder.bind_query(ast, written.query)?;
826 if aliases.len() > scope.len() {
827 return Err(Error::binder("More VIEW aliases than columns in query result"));
828 }
829 if !aliases.is_empty() {
830 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
831 scope.rename(&written, "unnamed_subquery")?;
832 }
833
834 Ok(Bound::CreateView(CreateView {
835 name,
836 sql: ast.string(written.sql).to_string(),
837 statement: deparse::create_view(ast, index),
838 aliases,
839 if_not_exists: written.if_not_exists,
840 or_replace: written.or_replace,
841 columns: scope.fields(),
842 }))
843}
844
845fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
846 let written = ast.drop_table(index);
847 let kind = if written.view { Entry::View } else { Entry::Table };
848 let mut names = Vec::new();
849 for &name in ast.name_list(written.names) {
850 let parts: Vec<&str> = ast.name(name).collect();
851 match catalog.resolve_as(&parts, kind) {
854 Ok(resolved) => names.push(resolved),
855 Err(error) if written.if_exists => drop(error),
856 Err(error) => return Err(error),
857 }
858 }
859 Ok(Bound::DropTable(DropTable { names, kind }))
860}
861
862fn setting(
868 ast: &Ast,
869 catalog: &Catalog,
870 parameters: &Parameters,
871 session: &Session,
872 index: ast::SettingRef,
873) -> Result<Bound> {
874 let written = ast.setting(index);
875 let name = ast.string(written.name).to_string();
876 let value = if written.value == NONE {
877 None
878 } else {
879 let mut binder = Binder::with(catalog, parameters, session);
880 let bound = binder.bind_setting_value(ast, written.value)?;
881 let Expr::Constant(value) = *binder.plan().expr(bound) else {
882 return Err(Error::not_implemented(format!(
883 "a value for {name} that is not a constant"
884 )));
885 };
886 Some(binder.plan().value(value).clone())
887 };
888 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
889}
890
891fn clustered(
903 binder: &mut Binder<'_>,
904 input: rudb_plan::NodeRef,
905 scope: &crate::scope::Scope,
906 clustering: &Clustering,
907 targets: &[usize],
908 fields: &[Field],
909) -> Result<rudb_plan::NodeRef> {
910 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
911 for (at, &column) in clustering.columns().iter().enumerate() {
912 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
913 continue;
914 };
915 let source = &scope.columns[from];
916 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
917 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
922 let expr =
923 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
924 keys.push(SortKey { expr, descending: false, nulls_first: false });
925 }
926 if keys.is_empty() {
927 return Ok(input);
928 }
929 let keys = binder.plan_mut().add_sort_keys(&keys);
930 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
931}
932
933fn fitted(
947 binder: &Binder<'_>,
948 scope: &crate::scope::Scope,
949 clustering: &Clustering,
950 targets: &[usize],
951) -> Clustering {
952 if clustering.width() != Width::Auto {
953 return clustering.clone();
954 }
955 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
956 else {
957 return clustering.fitted(0, 0);
958 };
959 let source = &scope.columns[from];
960 let Some(zones) = binder.plan().sole_zones() else {
961 return clustering.fitted(0, 0);
962 };
963 let Some(at) = zones.column(&source.name) else {
968 return clustering.fitted(0, 0);
969 };
970 let rows = zones.surviving(&[]).unwrap_or(0);
971 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
972 clustering.fitted(rows, days)
973}
974
975fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
981 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
982 return None;
983 };
984 let days = match (low, high) {
985 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
987 (
991 ColumnBound::Scaled { unscaled: low, scale: at },
992 ColumnBound::Scaled { unscaled: high, scale: to },
993 ) if at == to => {
994 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
995 high.checked_sub(*low)? / day
996 }
997 _ => return None,
998 };
999 u64::try_from(days).ok()
1000}
1001
1002fn bucketed(
1004 binder: &mut Binder<'_>,
1005 expr: ExprRef,
1006 width: Width,
1007 fields: &[Field],
1008 column: u32,
1009) -> ExprRef {
1010 if width == Width::Exact {
1011 return expr;
1012 }
1013 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
1014 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
1015 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
1016 let name = binder.plan_mut().intern("date_trunc");
1017 let ty = fields[column as usize].ty.clone();
1018 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
1019}
1020
1021fn insert(
1022 ast: &Ast,
1023 catalog: &Catalog,
1024 parameters: &Parameters,
1025 session: &Session,
1026 index: ast::InsertRef,
1027) -> Result<Bound> {
1028 let written = ast.insert(index);
1029 let parts: Vec<&str> = ast.name(written.name).collect();
1030 let name = catalog.resolve(&parts)?;
1031 if catalog.entry(&name)? == Entry::View {
1032 return Err(Error::catalog(format!("{} is not an table", name.table)));
1035 }
1036 let target = catalog.table(&name)?;
1037 let fields: Vec<Field> = target.columns().to_vec();
1038 let clustering = target.clustering().cloned();
1039
1040 let targets: Vec<usize> = if written.columns.is_empty() {
1044 (0..fields.len()).collect()
1045 } else {
1046 let mut targets = Vec::new();
1047 for column in ast.name(written.columns) {
1048 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
1049 || {
1050 Error::binder(format!(
1051 "Table \"{}\" does not have a column named \"{column}\"",
1052 name.table
1053 ))
1054 },
1055 )?;
1056 if targets.contains(&at) {
1057 return Err(Error::binder(format!(
1058 "Column \"{column}\" is named twice in the same INSERT"
1059 )));
1060 }
1061 targets.push(at);
1062 }
1063 targets
1064 };
1065
1066 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
1067 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
1068 .collect();
1069 let mut binder = Binder::with(catalog, parameters, session);
1070 let (root, scope) = if written.source == NONE {
1071 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
1074 } else {
1075 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
1078 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
1079 }
1080 binder.bind_query(ast, written.source)?
1081 };
1082 let targets = if written.source == NONE { Vec::new() } else { targets };
1083 if scope.len() != targets.len() {
1084 return Err(Error::binder(format!(
1085 "Table \"{}\" has {} columns but {} values were supplied",
1086 name.table,
1087 targets.len(),
1088 scope.len()
1089 )));
1090 }
1091
1092 let root = match &clustering {
1098 None => root,
1099 Some(clustering) => {
1100 let fitted = fitted(&binder, &scope, clustering, &targets);
1105 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1106 }
1107 };
1108
1109 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1113 let mut names = Vec::with_capacity(fields.len());
1114 for (at, field) in fields.iter().enumerate() {
1115 let expr = match targets.iter().position(|&target| target == at) {
1116 Some(from) => {
1117 let column = &scope.columns[from];
1118 let expr =
1119 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1120 binder.checked_cast_to(expr, &field.ty, false)?
1121 }
1122 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1124 };
1125 exprs.push(expr);
1126 let interned = binder.plan_mut().intern(&field.name);
1127 names.push(interned);
1128 }
1129 let exprs = binder.plan_mut().add_expr_list(&exprs);
1130 let names = binder.plan_mut().add_name_list(&names);
1131 let index = binder.fresh_index();
1132 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1133 let source = finish(binder, root)?;
1134 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1135 let conflict = match written.conflict {
1136 Some(conflict) => {
1137 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1138 }
1139 None => None,
1140 };
1141 let checks = bind_checks(catalog, parameters, session, &name)?;
1142 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1143}
1144
1145fn bind_conflict(
1148 ast: &Ast,
1149 catalog: &Catalog,
1150 parameters: &Parameters,
1151 session: &Session,
1152 name: &QualifiedName,
1153 targets: &[usize],
1154 conflict: ast::Conflict,
1155) -> Result<Conflict> {
1156 let table = catalog.table(name)?;
1157 let fields = table.columns();
1158 let keys = table.keys();
1159 let key = if conflict.target.is_empty() {
1160 if keys.is_empty() {
1161 return Err(Error::binder(
1162 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1163 CONFLICT columns manually",
1164 ));
1165 }
1166 match conflict.action {
1167 ast::ConflictAction::Nothing => None,
1168 _ if keys.len() > 1 => {
1169 return Err(Error::binder(
1170 "Conflict target has to be provided for a DO UPDATE operation when the table \
1171 has multiple UNIQUE/PRIMARY KEY constraints",
1172 ));
1173 }
1174 _ => Some(0),
1175 }
1176 } else {
1177 let mut wanted = Vec::new();
1178 for column in ast.name(conflict.target) {
1179 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1180 return Err(Error::binder(format!(
1181 "Table \"{}\" does not have a column with name \"{column}\"",
1182 name.table
1183 )));
1184 };
1185 wanted.push(at);
1186 }
1187 wanted.sort_unstable();
1188 wanted.dedup();
1189 let found = keys.iter().position(|key| {
1190 let mut held = key.columns.clone();
1191 held.sort_unstable();
1192 held == wanted
1193 });
1194 let Some(found) = found else {
1195 return Err(Error::binder(
1196 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1197 KEY CONSTRAINT or INDEX",
1198 ));
1199 };
1200 Some(found)
1201 };
1202 let action = match conflict.action {
1203 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1204 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1205 ast::ConflictAction::Update { columns: written, query } => {
1206 let mut columns = Vec::new();
1207 for column in ast.name(written) {
1208 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1209 else {
1210 return Err(Error::binder(format!(
1211 "Referenced update column {column} not found in table!"
1212 )));
1213 };
1214 if columns.contains(&at) {
1215 return Err(Error::binder(format!(
1216 "Multiple assignments to same column \"\"{column}\"\""
1217 )));
1218 }
1219 columns.push(at);
1220 }
1221 let mut binder = Binder::with(catalog, parameters, session);
1222 binder.upsert = true;
1223 let (root, scope) = binder.bind_query(ast, query)?;
1224 let mut exprs = Vec::with_capacity(scope.columns.len());
1227 let mut names = Vec::with_capacity(scope.columns.len());
1228 for (at, column) in scope.columns.iter().enumerate() {
1229 let expr =
1230 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1231 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1232 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1233 names.push(binder.plan_mut().intern(&column.name));
1234 }
1235 let exprs = binder.plan_mut().add_expr_list(&exprs);
1236 let names = binder.plan_mut().add_name_list(&names);
1237 let index = binder.fresh_index();
1238 let root =
1239 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1240 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1241 }
1242 };
1243 Ok(Conflict { key, action })
1244}
1245
1246fn change(
1255 ast: &Ast,
1256 catalog: &Catalog,
1257 parameters: &Parameters,
1258 session: &Session,
1259 index: ast::InsertRef,
1260 delete: bool,
1261) -> Result<Bound> {
1262 let written = ast.insert(index);
1263 let parts: Vec<&str> = ast.name(written.name).collect();
1264 let name = catalog.resolve(&parts)?;
1265 if catalog.entry(&name)? == Entry::View {
1266 return Err(Error::binder(if delete {
1267 "Can only delete from base table"
1268 } else {
1269 "Can only update base table"
1270 }));
1271 }
1272 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1273 let mut targets: Vec<usize> = Vec::new();
1274 for column in ast.name(written.columns) {
1275 let at =
1276 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1277 Error::binder(format!("Referenced update column {column} not found in table!"))
1278 })?;
1279 if targets.contains(&at) {
1280 return Err(Error::binder(format!(
1281 "Multiple assignments to same column \"\"{column}\"\""
1282 )));
1283 }
1284 targets.push(at);
1285 }
1286
1287 let mut defaulted = vec![false; targets.len()];
1289 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1290 let items = ast.target_list(ast.select(select).targets);
1291 let first = items.len().saturating_sub(targets.len());
1292 for (at, item) in items[first..].iter().enumerate() {
1293 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1294 }
1295 }
1296 let table = catalog.table(&name)?;
1297 let mut binder = Binder::with(catalog, parameters, session);
1298 binder.default_as_null = defaulted.contains(&true);
1299 let (root, scope) = binder.bind_query(ast, written.source)?;
1300 binder.default_as_null = false;
1301 let width = fields.len();
1302 if scope.len() != width + 1 + targets.len() {
1303 return Err(Error::internal(format!(
1304 "an UPDATE source of {} columns over a table of {width}",
1305 scope.len()
1306 )));
1307 }
1308 let column = |binder: &mut Binder<'_>, at: usize| {
1309 let column = &scope.columns[at];
1310 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1311 };
1312 let hit = column(&mut binder, width);
1313 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1314 let mut exprs = Vec::with_capacity(width);
1315 let mut names = Vec::with_capacity(width);
1316 for (at, field) in fields.iter().enumerate() {
1317 let old = column(&mut binder, at);
1318 let expr = match targets.iter().position(|&target| target == at) {
1319 Some(from) => {
1320 let then = if defaulted[from] {
1321 binder.bind_default(table.default(at), &field.ty)?
1322 } else {
1323 let new = column(&mut binder, width + 1 + from);
1324 binder.checked_cast_to(new, &field.ty, false)?
1325 };
1326 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1327 binder
1328 .plan_mut()
1329 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1330 }
1331 None => old,
1332 };
1333 exprs.push(expr);
1334 let interned = binder.plan_mut().intern(&field.name);
1335 names.push(interned);
1336 }
1337 let yes = binder.add_constant(Value::Boolean(true));
1340 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1341 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1342 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1343 let interned = binder.plan_mut().intern("changed");
1344 names.push(interned);
1345 let exprs = binder.plan_mut().add_expr_list(&exprs);
1346 let names = binder.plan_mut().add_name_list(&names);
1347 let index = binder.fresh_index();
1348 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1349 let source = finish(binder, root)?;
1350 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1351 let write = if delete { Write::Delete } else { Write::Update };
1352 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1353 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1354}