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 Insert(Insert),
46 Setting(Setting),
48 Checkpoint,
50 Transaction(ast::Transaction),
52 Explain { plan: Plan, analyze: bool, statistics: bool },
65}
66
67#[derive(Debug)]
79pub struct Setting {
80 pub name: String,
82 pub scope: ast::Scope,
84 pub value: Option<Value>,
86 pub pragma: bool,
88}
89
90#[derive(Debug)]
92pub struct CreateTable {
93 pub name: QualifiedName,
95 pub columns: Vec<Field>,
98 pub source: Option<Plan>,
100 pub if_not_exists: bool,
102 pub or_replace: bool,
104 pub keys: Vec<rudb_catalog::Key>,
106 pub defaults: Vec<Option<String>>,
108 pub checks: Vec<String>,
110 pub foreign: Vec<rudb_catalog::ForeignKey>,
112}
113
114#[derive(Debug)]
121pub struct CreateView {
122 pub name: QualifiedName,
124 pub sql: String,
126 pub statement: String,
131 pub aliases: Vec<String>,
133 pub if_not_exists: bool,
135 pub or_replace: bool,
137 pub columns: Vec<Field>,
143}
144
145#[derive(Debug)]
147pub struct DropTable {
148 pub names: Vec<QualifiedName>,
153 pub kind: Entry,
155}
156
157#[derive(Debug)]
159pub struct Insert {
160 pub name: QualifiedName,
162 pub source: Plan,
165 pub write: Write,
167 pub returning: Option<Box<Plan>>,
170 pub conflict: Option<Conflict>,
172 pub checks: Option<Checks>,
174}
175
176#[derive(Debug)]
182pub struct Checks {
183 pub plan: Box<Plan>,
185 pub messages: Vec<String>,
187}
188
189#[derive(Debug)]
191pub struct Conflict {
192 pub key: Option<usize>,
194 pub action: ConflictAction,
196}
197
198#[derive(Debug)]
200pub enum ConflictAction {
201 Nothing,
203 Replace(Vec<usize>),
205 Update {
209 columns: Vec<usize>,
211 plan: Box<Plan>,
213 },
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum Write {
219 Append,
221 Update,
224 Delete,
227}
228
229fn returning(
231 ast: &Ast,
232 catalog: &Catalog,
233 parameters: &Parameters,
234 session: &Session,
235 query: Option<ast::QueryRef>,
236) -> Result<Option<Box<Plan>>> {
237 let Some(query) = query else { return Ok(None) };
238 let mut binder = Binder::with(catalog, parameters, session);
239 let (root, _) = binder.bind_query(ast, query)?;
240 Ok(Some(Box::new(finish(binder, root)?)))
241}
242
243pub fn bind_statement(ast: &Ast, catalog: &Catalog) -> Result<Bound> {
250 bind_statement_with(ast, catalog, &Parameters::new(), &Session::new())
251}
252
253pub fn bind_statement_with(
263 ast: &Ast,
264 catalog: &Catalog,
265 parameters: &Parameters,
266 session: &Session,
267) -> Result<Bound> {
268 bind_one(ast, catalog, parameters, session, false)
269}
270
271pub fn bind_statement_outlined(
284 ast: &Ast,
285 catalog: &Catalog,
286 parameters: &Parameters,
287 session: &Session,
288) -> Result<Bound> {
289 bind_one(ast, catalog, parameters, session, true)
290}
291
292fn bind_one(
293 ast: &Ast,
294 catalog: &Catalog,
295 parameters: &Parameters,
296 session: &Session,
297 outlined: bool,
298) -> Result<Bound> {
299 let statement = match ast.statements.as_slice() {
300 [statement] => *statement,
301 [] => return Err(Error::binder("no statement to bind")),
302 _ => return Err(Error::not_implemented("a script of more than one statement")),
303 };
304 match statement {
305 ast::Statement::Query(query) => {
306 let mut binder = Binder::with(catalog, parameters, session);
307 binder.outlined = outlined;
308 let (root, _) = binder.bind_query(ast, query)?;
309 Ok(Bound::Query(finish(binder, root)?))
310 }
311 ast::Statement::CreateTable(index) => {
312 create_table(ast, catalog, parameters, session, index)
313 }
314 ast::Statement::CreateView(index) => create_view(ast, catalog, parameters, session, index),
315 ast::Statement::DropTable(index) => drop_table(ast, catalog, index),
316 ast::Statement::Insert(index) => insert(ast, catalog, parameters, session, index),
317 ast::Statement::Update(index) => change(ast, catalog, parameters, session, index, false),
318 ast::Statement::Delete(index) => change(ast, catalog, parameters, session, index, true),
319 ast::Statement::Set(index) | ast::Statement::Reset(index) => {
320 setting(ast, catalog, parameters, session, index)
321 }
322 ast::Statement::Checkpoint => Ok(Bound::Checkpoint),
323 ast::Statement::Transaction(kind) => Ok(Bound::Transaction(kind)),
324 ast::Statement::Explain { query, analyze, statistics } => {
325 let mut binder = Binder::with(catalog, parameters, session);
326 let (root, _) = binder.bind_query(ast, query)?;
327 Ok(Bound::Explain { plan: finish(binder, root)?, analyze, statistics })
328 }
329 }
330}
331
332pub fn bind_statement_sql(sql: &str, catalog: &Catalog) -> Result<Bound> {
338 let ast = parse_ast(sql)?;
339 bind_statement(&ast, catalog)
340}
341
342fn finish(binder: Binder<'_>, root: rudb_plan::NodeRef) -> Result<Plan> {
344 let mut plan = binder.into_plan();
345 plan.set_root(root);
346 plan.validate()?;
347 Ok(plan)
348}
349
350fn create_table(
351 ast: &Ast,
352 catalog: &Catalog,
353 parameters: &Parameters,
354 session: &Session,
355 index: ast::CreateTableRef,
356) -> Result<Bound> {
357 let written = ast.create_table(index);
358 let parts: Vec<&str> = ast.name(written.name).collect();
359 let name = if written.temporary {
360 catalog.resolve_for_create_temporary(&parts)?
361 } else {
362 catalog.resolve_for_create(&parts)?
363 };
364 let defs = ast.column_defs(written.columns);
365 let (mut columns, source) = if written.query == NONE {
366 let mut columns = Vec::with_capacity(defs.len());
367 for def in defs {
368 let text = ast.string(def.ty);
369 if text.is_empty() {
370 return Err(Error::binder(format!(
371 "Column \"{}\" was declared without a type",
372 ast.string(def.name)
373 )));
374 }
375 let ty = LogicalType::parse(text)?;
376 let column = ast.string(def.name);
377 columns.push(if def.not_null {
378 Field::required(column, ty)
379 } else {
380 Field::new(column, ty)
381 });
382 }
383 (columns, None)
384 } else {
385 let mut binder = Binder::with(catalog, parameters, session);
386 let (root, scope) = binder.bind_query(ast, written.query)?;
387 if defs.len() > scope.len() {
388 return Err(Error::binder("Target table has more colum names than query result."));
391 }
392 let mut columns = Vec::with_capacity(scope.columns.len());
393 for (at, column) in scope.columns.iter().enumerate() {
394 let named = match defs.get(at) {
395 Some(def) => ast.string(def.name).to_string(),
396 None => column.name.clone(),
397 };
398 columns.push(Field::new(named, column.ty.clone()));
399 }
400 if defs.is_empty() {
401 deduplicate(&mut columns);
402 }
403 (columns, Some(finish(binder, root)?))
404 };
405 duplicate_check(&columns)?;
406 let mut defaults = Vec::with_capacity(defs.len());
407 for def in defs {
408 defaults.push(if def.default == NONE {
409 None
410 } else {
411 Some(default_text(ast, def.default, catalog, parameters, session)?)
412 });
413 }
414 let mut checks = Vec::new();
415 for &expr in ast.expr_list(written.checks) {
416 checks.push(check_text(ast, expr, &columns, catalog, parameters, session)?);
417 }
418 let mut keys = Vec::new();
419 for (at, &names) in ast.name_list(written.keys).iter().enumerate() {
420 let mut places = Vec::new();
421 for wanted in ast.name(names) {
422 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted))
423 else {
424 return Err(Error::catalog(format!(
425 "table \"{}\" does not have a column named \"{wanted}\"",
426 name.table
427 )));
428 };
429 places.push(place);
430 }
431 let primary = at as u32 == written.primary;
432 if primary {
433 for &place in &places {
434 columns[place].not_null = true;
435 }
436 }
437 keys.push(rudb_catalog::Key { columns: places, primary });
438 }
439 let mut foreign = Vec::new();
440 let lists = ast.name_list(written.foreign).iter();
441 let tables = ast.name_list(written.foreign_tables).iter();
442 let referenced = ast.name_list(written.foreign_referenced).iter();
443 for ((&names, &table), &wanted) in lists.zip(tables).zip(referenced) {
444 let names: Vec<&str> = ast.name(names).collect();
445 let parts: Vec<&str> = ast.name(table).collect();
446 let wanted: Vec<&str> = ast.name(wanted).collect();
447 let key = (names.as_slice(), parts.as_slice(), wanted.as_slice());
448 foreign.push(foreign_key(catalog, &name, (&columns, &keys), key)?);
449 }
450 Ok(Bound::CreateTable(CreateTable {
451 name,
452 columns,
453 source,
454 if_not_exists: written.if_not_exists,
455 or_replace: written.or_replace,
456 keys,
457 defaults,
458 checks,
459 foreign,
460 }))
461}
462
463fn foreign_key(
469 catalog: &Catalog,
470 made: &QualifiedName,
471 (columns, keys): (&[Field], &[rudb_catalog::Key]),
472 (names, parts, wanted): (&[&str], &[&str], &[&str]),
473) -> Result<rudb_catalog::ForeignKey> {
474 let mut places = Vec::with_capacity(names.len());
475 for &wanted in names {
476 let Some(place) = columns.iter().position(|field| same_name(&field.name, wanted)) else {
477 return Err(Error::binder(format!(
478 "Failed to create foreign key: referencing column \"{wanted}\" does not exist"
479 )));
480 };
481 places.push(place);
482 }
483 let own = parts.last().is_some_and(|last| same_name(last, &made.table))
484 && catalog.resolve(parts).map_or(true, |resolved| resolved == *made);
485 let (table, fields, held): (QualifiedName, Vec<Field>, Vec<rudb_catalog::Key>) = if own {
486 (made.clone(), columns.to_vec(), keys.to_vec())
487 } else {
488 let resolved = catalog.resolve(parts)?;
489 let table = catalog.table(&resolved)?;
490 (resolved, table.columns().to_vec(), table.keys().to_vec())
491 };
492 let referenced = if wanted.is_empty() {
493 let Some(primary) = held.iter().find(|key| key.primary) else {
494 return Err(Error::binder(format!(
495 "Failed to create foreign key: there is no primary key for referenced table \"{}\"",
496 table.table
497 )));
498 };
499 if primary.columns.len() != places.len() {
500 return Err(Error::parser(
501 "The number of referencing and referenced columns for foreign keys must be the same",
502 ));
503 }
504 primary.columns.clone()
505 } else {
506 let mut referenced = Vec::with_capacity(wanted.len());
507 for &column in wanted {
508 let Some(place) = fields.iter().position(|field| same_name(&field.name, column)) else {
509 return Err(Error::binder(format!(
510 "Failed to create foreign key: referenced table \"{}\" does not have a column \
511 named \"{column}\"",
512 table.table
513 )));
514 };
515 referenced.push(place);
516 }
517 let mut sorted = referenced.clone();
518 sorted.sort_unstable();
519 let matched = held.iter().any(|key| {
520 let mut columns = key.columns.clone();
521 columns.sort_unstable();
522 columns == sorted
523 });
524 if !matched && held.is_empty() {
525 return Err(Error::binder(format!(
526 "Failed to create foreign key: there is no primary key or unique constraint for \
527 referenced table \"{}\"",
528 table.table
529 )));
530 }
531 if !matched {
532 return Err(Error::binder(format!(
533 "Failed to create foreign key: referenced table \"{}\" does not have a primary key \
534 or unique constraint on the columns {}",
535 table.table,
536 wanted.join(", ")
537 )));
538 }
539 referenced
540 };
541 for (&from, &to) in places.iter().zip(&referenced) {
542 if columns[from].ty != fields[to].ty {
543 return Err(Error::binder(format!(
544 "Failed to create foreign key: incompatible types between column \"{}\" (\"{}\") \
545 and column \"{}\" (\"{}\")",
546 fields[to].name, fields[to].ty, columns[from].name, columns[from].ty
547 )));
548 }
549 }
550 Ok(rudb_catalog::ForeignKey { columns: places, table, referenced })
551}
552
553fn check_text(
555 ast: &Ast,
556 expr: ast::ExprRef,
557 columns: &[Field],
558 catalog: &Catalog,
559 parameters: &Parameters,
560 session: &Session,
561) -> Result<String> {
562 if crate::expr::has_aggregate(ast, expr) {
563 return Err(Error::binder("aggregate functions are not allowed in check constraints"));
564 }
565 let mut binder = Binder::with(catalog, parameters, session);
566 let index = binder.fresh_index();
567 let mut scope = crate::scope::Scope::empty();
568 for (at, field) in columns.iter().enumerate() {
569 scope.push(crate::scope::Visible {
570 table: String::new(),
571 name: field.name.clone(),
572 binding: rudb_plan::ColumnBinding::new(index, at as u32),
573 ty: field.ty.clone(),
574 not_null: false,
575 key: None,
576 default: None,
577 qualified: false,
578 also: None,
579 });
580 }
581 match binder.bind_expr(ast, expr, &scope) {
582 Err(error) if error.message().starts_with("Referenced column \"") => {
583 let column = error.message().split('"').nth(1).unwrap_or_default();
584 Err(Error::binder(format!(
585 "Table does not contain column \"{column}\" referenced in check constraint!"
586 )))
587 }
588 Err(error) => Err(error),
589 Ok(_) if !binder.windows.is_empty() => {
590 Err(Error::binder("window functions are not allowed in check constraints"))
591 }
592 Ok(_) => Ok(deparse::expression(ast, expr)),
593 }
594}
595
596fn bind_checks(
599 catalog: &Catalog,
600 parameters: &Parameters,
601 session: &Session,
602 name: &QualifiedName,
603) -> Result<Option<Checks>> {
604 let table = catalog.table(name)?;
605 if table.checks().is_empty() {
606 return Ok(None);
607 }
608 let failed: Vec<String> =
609 table.checks().iter().map(|text| format!("NOT CAST(({text}) AS BOOLEAN)")).collect();
610 let ast = parse_ast(&format!("SELECT {}", failed.join(", ")))?;
611 let ast::Statement::Query(query) = ast.statements[0] else {
612 return Err(Error::internal("a check that is not an expression"));
613 };
614 let ast::QueryBody::Select(select) = ast.query(query).body else {
615 return Err(Error::internal("a check that is not an expression"));
616 };
617 let mut binder = Binder::with(catalog, parameters, session);
618 let (root, scope) =
619 binder.bind_catalog_table(&ast, name, name.table.clone(), ast::Slice::default())?;
620 let mut exprs = Vec::with_capacity(failed.len());
621 let mut names = Vec::with_capacity(failed.len());
622 for target in ast.target_list(ast.select(select).targets) {
623 exprs.push(binder.bind_expr(&ast, target.expr, &scope)?);
624 names.push(binder.plan_mut().intern("failed"));
625 }
626 let exprs = binder.plan_mut().add_expr_list(&exprs);
627 let names = binder.plan_mut().add_name_list(&names);
628 let index = binder.fresh_index();
629 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
630 let messages = table
631 .checks()
632 .iter()
633 .map(|text| {
634 format!(
635 "CHECK constraint failed on table \"{}\" with expression CHECK({text})",
636 name.table
637 )
638 })
639 .collect();
640 Ok(Some(Checks { plan: Box::new(finish(binder, root)?), messages }))
641}
642
643fn default_text(
647 ast: &Ast,
648 expr: ast::ExprRef,
649 catalog: &Catalog,
650 parameters: &Parameters,
651 session: &Session,
652) -> Result<String> {
653 if crate::expr::has_aggregate(ast, expr) {
654 return Err(Error::binder("DEFAULT value cannot contain aggregates!"));
655 }
656 let mut binder = Binder::with(catalog, parameters, session);
657 let before = binder.plan_mut().node_count();
658 match binder.bind_expr(ast, expr, &crate::scope::Scope::empty()) {
659 Err(error) if error.message().starts_with("Referenced ") => {
660 Err(Error::binder("DEFAULT value cannot contain column names"))
661 }
662 Err(error) => Err(error),
663 Ok(_) if binder.plan_mut().node_count() > before => {
665 Err(Error::binder("DEFAULT value cannot contain subqueries"))
666 }
667 Ok(_) if !binder.windows.is_empty() => {
668 Err(Error::binder("DEFAULT value cannot contain window functions!"))
669 }
670 Ok(_) => Ok(deparse::expression(ast, expr)),
671 }
672}
673
674fn deduplicate(columns: &mut [Field]) {
687 for at in 0..columns.len() {
688 let taken = |name: &str, upto: usize, columns: &[Field]| {
689 columns[..upto].iter().any(|held| same_name(&held.name, name))
690 };
691 if !taken(&columns[at].name, at, columns) {
692 continue;
693 }
694 let mut suffix = 1;
695 let mut candidate = format!("{}_{suffix}", columns[at].name);
696 while taken(&candidate, at, columns) {
697 suffix += 1;
698 candidate = format!("{}_{suffix}", columns[at].name);
699 }
700 columns[at].name = candidate;
701 }
702}
703
704fn create_view(
711 ast: &Ast,
712 catalog: &Catalog,
713 parameters: &Parameters,
714 session: &Session,
715 index: ast::CreateViewRef,
716) -> Result<Bound> {
717 let written = ast.create_view(index);
718 let parts: Vec<&str> = ast.name(written.name).collect();
719 let name = if written.temporary {
720 catalog.resolve_for_create_temporary(&parts)?
721 } else {
722 catalog.resolve_for_create(&parts)?
723 };
724 let aliases: Vec<String> = ast.name(written.columns).map(str::to_string).collect();
725
726 let mut binder = Binder::with(catalog, parameters, session);
727 binder.outlined = true;
730 let (_, mut scope) = binder.bind_query(ast, written.query)?;
731 if aliases.len() > scope.len() {
732 return Err(Error::binder("More VIEW aliases than columns in query result"));
733 }
734 if !aliases.is_empty() {
735 let written: Vec<&str> = aliases.iter().map(String::as_str).collect();
736 scope.rename(&written, "unnamed_subquery")?;
737 }
738
739 Ok(Bound::CreateView(CreateView {
740 name,
741 sql: ast.string(written.sql).to_string(),
742 statement: deparse::create_view(ast, index),
743 aliases,
744 if_not_exists: written.if_not_exists,
745 or_replace: written.or_replace,
746 columns: scope.fields(),
747 }))
748}
749
750fn drop_table(ast: &Ast, catalog: &Catalog, index: ast::DropTableRef) -> Result<Bound> {
751 let written = ast.drop_table(index);
752 let kind = if written.view { Entry::View } else { Entry::Table };
753 let mut names = Vec::new();
754 for &name in ast.name_list(written.names) {
755 let parts: Vec<&str> = ast.name(name).collect();
756 match catalog.resolve_as(&parts, kind) {
759 Ok(resolved) => names.push(resolved),
760 Err(error) if written.if_exists => drop(error),
761 Err(error) => return Err(error),
762 }
763 }
764 Ok(Bound::DropTable(DropTable { names, kind }))
765}
766
767fn setting(
773 ast: &Ast,
774 catalog: &Catalog,
775 parameters: &Parameters,
776 session: &Session,
777 index: ast::SettingRef,
778) -> Result<Bound> {
779 let written = ast.setting(index);
780 let name = ast.string(written.name).to_string();
781 let value = if written.value == NONE {
782 None
783 } else {
784 let mut binder = Binder::with(catalog, parameters, session);
785 let bound = binder.bind_setting_value(ast, written.value)?;
786 let Expr::Constant(value) = *binder.plan().expr(bound) else {
787 return Err(Error::not_implemented(format!(
788 "a value for {name} that is not a constant"
789 )));
790 };
791 Some(binder.plan().value(value).clone())
792 };
793 Ok(Bound::Setting(Setting { name, scope: written.scope, value, pragma: written.pragma }))
794}
795
796fn clustered(
808 binder: &mut Binder<'_>,
809 input: rudb_plan::NodeRef,
810 scope: &crate::scope::Scope,
811 clustering: &Clustering,
812 targets: &[usize],
813 fields: &[Field],
814) -> Result<rudb_plan::NodeRef> {
815 let mut keys: Vec<SortKey> = Vec::with_capacity(clustering.columns().len());
816 for (at, &column) in clustering.columns().iter().enumerate() {
817 let Some(from) = targets.iter().position(|&target| target == column as usize) else {
818 continue;
819 };
820 let source = &scope.columns[from];
821 let expr = binder.plan_mut().add_expr(Expr::Column(source.binding), source.ty.clone());
822 let expr = binder.checked_cast_to(expr, &fields[column as usize].ty, false)?;
827 let expr =
828 if at == 0 { bucketed(binder, expr, clustering.width(), fields, column) } else { expr };
829 keys.push(SortKey { expr, descending: false, nulls_first: false });
830 }
831 if keys.is_empty() {
832 return Ok(input);
833 }
834 let keys = binder.plan_mut().add_sort_keys(&keys);
835 Ok(binder.plan_mut().add_node(Node::Sort { input, keys }))
836}
837
838fn fitted(
852 binder: &Binder<'_>,
853 scope: &crate::scope::Scope,
854 clustering: &Clustering,
855 targets: &[usize],
856) -> Clustering {
857 if clustering.width() != Width::Auto {
858 return clustering.clone();
859 }
860 let Some(from) = targets.iter().position(|&target| target == clustering.partition() as usize)
861 else {
862 return clustering.fitted(0, 0);
863 };
864 let source = &scope.columns[from];
865 let Some(zones) = binder.plan().sole_zones() else {
866 return clustering.fitted(0, 0);
867 };
868 let Some(at) = zones.column(&source.name) else {
873 return clustering.fitted(0, 0);
874 };
875 let rows = zones.surviving(&[]).unwrap_or(0);
876 let days = span(&zones.extreme(at, End::Low), &zones.extreme(at, End::High)).unwrap_or(0);
877 clustering.fitted(rows, days)
878}
879
880fn span(low: &Stat<ColumnBound>, high: &Stat<ColumnBound>) -> Option<u64> {
886 let (Stat::Known { value: low, .. }, Stat::Known { value: high, .. }) = (low, high) else {
887 return None;
888 };
889 let days = match (low, high) {
890 (ColumnBound::Int(low), ColumnBound::Int(high)) => high.checked_sub(*low)?,
892 (
896 ColumnBound::Scaled { unscaled: low, scale: at },
897 ColumnBound::Scaled { unscaled: high, scale: to },
898 ) if at == to => {
899 let day = 86_400_i128.checked_mul(10_i128.checked_pow(u32::from(*at))?)?;
900 high.checked_sub(*low)? / day
901 }
902 _ => return None,
903 };
904 u64::try_from(days).ok()
905}
906
907fn bucketed(
909 binder: &mut Binder<'_>,
910 expr: ExprRef,
911 width: Width,
912 fields: &[Field],
913 column: u32,
914) -> ExprRef {
915 if width == Width::Exact {
916 return expr;
917 }
918 let unit = binder.plan_mut().add_value(Value::Varchar(width.to_string().to_lowercase()));
919 let unit = binder.plan_mut().add_expr(Expr::Constant(unit), LogicalType::Varchar);
920 let args = binder.plan_mut().add_expr_list(&[unit, expr]);
921 let name = binder.plan_mut().intern("date_trunc");
922 let ty = fields[column as usize].ty.clone();
923 binder.plan_mut().add_expr(Expr::Function { name, args }, ty)
924}
925
926fn insert(
927 ast: &Ast,
928 catalog: &Catalog,
929 parameters: &Parameters,
930 session: &Session,
931 index: ast::InsertRef,
932) -> Result<Bound> {
933 let written = ast.insert(index);
934 let parts: Vec<&str> = ast.name(written.name).collect();
935 let name = catalog.resolve(&parts)?;
936 if catalog.entry(&name)? == Entry::View {
937 return Err(Error::catalog(format!("{} is not an table", name.table)));
940 }
941 let target = catalog.table(&name)?;
942 let fields: Vec<Field> = target.columns().to_vec();
943 let clustering = target.clustering().cloned();
944
945 let targets: Vec<usize> = if written.columns.is_empty() {
949 (0..fields.len()).collect()
950 } else {
951 let mut targets = Vec::new();
952 for column in ast.name(written.columns) {
953 let at = fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(
954 || {
955 Error::binder(format!(
956 "Table \"{}\" does not have a column named \"{column}\"",
957 name.table
958 ))
959 },
960 )?;
961 if targets.contains(&at) {
962 return Err(Error::binder(format!(
963 "Column \"{column}\" is named twice in the same INSERT"
964 )));
965 }
966 targets.push(at);
967 }
968 targets
969 };
970
971 let defaults: Vec<(LogicalType, Option<String>)> = (0..fields.len())
972 .map(|at| (fields[at].ty.clone(), target.default(at).map(str::to_owned)))
973 .collect();
974 let mut binder = Binder::with(catalog, parameters, session);
975 let (root, scope) = if written.source == NONE {
976 (binder.plan_mut().add_node(Node::Dummy), crate::scope::Scope::empty())
979 } else {
980 if matches!(ast.query(written.source).body, ast::QueryBody::Values(_)) {
983 binder.insert_defaults = Some(targets.iter().map(|&at| defaults[at].clone()).collect());
984 }
985 binder.bind_query(ast, written.source)?
986 };
987 let targets = if written.source == NONE { Vec::new() } else { targets };
988 if scope.len() != targets.len() {
989 return Err(Error::binder(format!(
990 "Table \"{}\" has {} columns but {} values were supplied",
991 name.table,
992 targets.len(),
993 scope.len()
994 )));
995 }
996
997 let root = match &clustering {
1003 None => root,
1004 Some(clustering) => {
1005 let fitted = fitted(&binder, &scope, clustering, &targets);
1010 clustered(&mut binder, root, &scope, &fitted, &targets, &fields)?
1011 }
1012 };
1013
1014 let mut exprs: Vec<ExprRef> = Vec::with_capacity(fields.len());
1018 let mut names = Vec::with_capacity(fields.len());
1019 for (at, field) in fields.iter().enumerate() {
1020 let expr = match targets.iter().position(|&target| target == at) {
1021 Some(from) => {
1022 let column = &scope.columns[from];
1023 let expr =
1024 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1025 binder.checked_cast_to(expr, &field.ty, false)?
1026 }
1027 None => binder.bind_default(defaults[at].1.as_deref(), &field.ty)?,
1029 };
1030 exprs.push(expr);
1031 let interned = binder.plan_mut().intern(&field.name);
1032 names.push(interned);
1033 }
1034 let exprs = binder.plan_mut().add_expr_list(&exprs);
1035 let names = binder.plan_mut().add_name_list(&names);
1036 let index = binder.fresh_index();
1037 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1038 let source = finish(binder, root)?;
1039 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1040 let conflict = match written.conflict {
1041 Some(conflict) => {
1042 Some(bind_conflict(ast, catalog, parameters, session, &name, &targets, conflict)?)
1043 }
1044 None => None,
1045 };
1046 let checks = bind_checks(catalog, parameters, session, &name)?;
1047 Ok(Bound::Insert(Insert { name, source, write: Write::Append, returning, conflict, checks }))
1048}
1049
1050fn bind_conflict(
1053 ast: &Ast,
1054 catalog: &Catalog,
1055 parameters: &Parameters,
1056 session: &Session,
1057 name: &QualifiedName,
1058 targets: &[usize],
1059 conflict: ast::Conflict,
1060) -> Result<Conflict> {
1061 let table = catalog.table(name)?;
1062 let fields = table.columns();
1063 let keys = table.keys();
1064 let key = if conflict.target.is_empty() {
1065 if keys.is_empty() {
1066 return Err(Error::binder(
1067 "There are no UNIQUE/PRIMARY KEY constraints that refer to this table, specify ON \
1068 CONFLICT columns manually",
1069 ));
1070 }
1071 match conflict.action {
1072 ast::ConflictAction::Nothing => None,
1073 _ if keys.len() > 1 => {
1074 return Err(Error::binder(
1075 "Conflict target has to be provided for a DO UPDATE operation when the table \
1076 has multiple UNIQUE/PRIMARY KEY constraints",
1077 ));
1078 }
1079 _ => Some(0),
1080 }
1081 } else {
1082 let mut wanted = Vec::new();
1083 for column in ast.name(conflict.target) {
1084 let Some(at) = fields.iter().position(|field| same_name(&field.name, column)) else {
1085 return Err(Error::binder(format!(
1086 "Table \"{}\" does not have a column with name \"{column}\"",
1087 name.table
1088 )));
1089 };
1090 wanted.push(at);
1091 }
1092 wanted.sort_unstable();
1093 wanted.dedup();
1094 let found = keys.iter().position(|key| {
1095 let mut held = key.columns.clone();
1096 held.sort_unstable();
1097 held == wanted
1098 });
1099 let Some(found) = found else {
1100 return Err(Error::binder(
1101 "The specified columns as conflict target are not referenced by a UNIQUE/PRIMARY \
1102 KEY CONSTRAINT or INDEX",
1103 ));
1104 };
1105 Some(found)
1106 };
1107 let action = match conflict.action {
1108 ast::ConflictAction::Nothing => ConflictAction::Nothing,
1109 ast::ConflictAction::Replace => ConflictAction::Replace(targets.to_vec()),
1110 ast::ConflictAction::Update { columns: written, query } => {
1111 let mut columns = Vec::new();
1112 for column in ast.name(written) {
1113 let Some(at) = fields.iter().position(|field| same_name(&field.name, column))
1114 else {
1115 return Err(Error::binder(format!(
1116 "Referenced update column {column} not found in table!"
1117 )));
1118 };
1119 if columns.contains(&at) {
1120 return Err(Error::binder(format!(
1121 "Multiple assignments to same column \"\"{column}\"\""
1122 )));
1123 }
1124 columns.push(at);
1125 }
1126 let mut binder = Binder::with(catalog, parameters, session);
1127 binder.upsert = true;
1128 let (root, scope) = binder.bind_query(ast, query)?;
1129 let mut exprs = Vec::with_capacity(scope.columns.len());
1132 let mut names = Vec::with_capacity(scope.columns.len());
1133 for (at, column) in scope.columns.iter().enumerate() {
1134 let expr =
1135 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone());
1136 let ty = columns.get(at).map_or(LogicalType::Boolean, |&to| fields[to].ty.clone());
1137 exprs.push(binder.checked_cast_to(expr, &ty, false)?);
1138 names.push(binder.plan_mut().intern(&column.name));
1139 }
1140 let exprs = binder.plan_mut().add_expr_list(&exprs);
1141 let names = binder.plan_mut().add_name_list(&names);
1142 let index = binder.fresh_index();
1143 let root =
1144 binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1145 ConflictAction::Update { columns, plan: Box::new(finish(binder, root)?) }
1146 }
1147 };
1148 Ok(Conflict { key, action })
1149}
1150
1151fn change(
1160 ast: &Ast,
1161 catalog: &Catalog,
1162 parameters: &Parameters,
1163 session: &Session,
1164 index: ast::InsertRef,
1165 delete: bool,
1166) -> Result<Bound> {
1167 let written = ast.insert(index);
1168 let parts: Vec<&str> = ast.name(written.name).collect();
1169 let name = catalog.resolve(&parts)?;
1170 if catalog.entry(&name)? == Entry::View {
1171 return Err(Error::binder(if delete {
1172 "Can only delete from base table"
1173 } else {
1174 "Can only update base table"
1175 }));
1176 }
1177 let fields: Vec<Field> = catalog.table(&name)?.columns().to_vec();
1178 let mut targets: Vec<usize> = Vec::new();
1179 for column in ast.name(written.columns) {
1180 let at =
1181 fields.iter().position(|field| same_name(&field.name, column)).ok_or_else(|| {
1182 Error::binder(format!("Referenced update column {column} not found in table!"))
1183 })?;
1184 if targets.contains(&at) {
1185 return Err(Error::binder(format!(
1186 "Multiple assignments to same column \"\"{column}\"\""
1187 )));
1188 }
1189 targets.push(at);
1190 }
1191
1192 let mut defaulted = vec![false; targets.len()];
1194 if let ast::QueryBody::Select(select) = ast.query(written.source).body {
1195 let items = ast.target_list(ast.select(select).targets);
1196 let first = items.len().saturating_sub(targets.len());
1197 for (at, item) in items[first..].iter().enumerate() {
1198 defaulted[at] = matches!(ast.expr(item.expr), ast::Expr::Default);
1199 }
1200 }
1201 let table = catalog.table(&name)?;
1202 let mut binder = Binder::with(catalog, parameters, session);
1203 binder.default_as_null = defaulted.contains(&true);
1204 let (root, scope) = binder.bind_query(ast, written.source)?;
1205 binder.default_as_null = false;
1206 let width = fields.len();
1207 if scope.len() != width + 1 + targets.len() {
1208 return Err(Error::internal(format!(
1209 "an UPDATE source of {} columns over a table of {width}",
1210 scope.len()
1211 )));
1212 }
1213 let column = |binder: &mut Binder<'_>, at: usize| {
1214 let column = &scope.columns[at];
1215 binder.plan_mut().add_expr(Expr::Column(column.binding), column.ty.clone())
1216 };
1217 let hit = column(&mut binder, width);
1218 let hit = binder.checked_cast_to(hit, &LogicalType::Boolean, false)?;
1219 let mut exprs = Vec::with_capacity(width);
1220 let mut names = Vec::with_capacity(width);
1221 for (at, field) in fields.iter().enumerate() {
1222 let old = column(&mut binder, at);
1223 let expr = match targets.iter().position(|&target| target == at) {
1224 Some(from) => {
1225 let then = if defaulted[from] {
1226 binder.bind_default(table.default(at), &field.ty)?
1227 } else {
1228 let new = column(&mut binder, width + 1 + from);
1229 binder.checked_cast_to(new, &field.ty, false)?
1230 };
1231 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then }]);
1232 binder
1233 .plan_mut()
1234 .add_expr(Expr::Case { arms, otherwise: Some(old) }, field.ty.clone())
1235 }
1236 None => old,
1237 };
1238 exprs.push(expr);
1239 let interned = binder.plan_mut().intern(&field.name);
1240 names.push(interned);
1241 }
1242 let yes = binder.add_constant(Value::Boolean(true));
1245 let arms = binder.plan_mut().add_arms(&[Arm { when: hit, then: yes }]);
1246 let otherwise = Some(binder.add_constant(Value::Boolean(false)));
1247 exprs.push(binder.plan_mut().add_expr(Expr::Case { arms, otherwise }, LogicalType::Boolean));
1248 let interned = binder.plan_mut().intern("changed");
1249 names.push(interned);
1250 let exprs = binder.plan_mut().add_expr_list(&exprs);
1251 let names = binder.plan_mut().add_name_list(&names);
1252 let index = binder.fresh_index();
1253 let root = binder.plan_mut().add_node(Node::Project { input: root, index, exprs, names });
1254 let source = finish(binder, root)?;
1255 let returning = returning(ast, catalog, parameters, session, written.returning)?;
1256 let write = if delete { Write::Delete } else { Write::Update };
1257 let checks = if delete { None } else { bind_checks(catalog, parameters, session, &name)? };
1258 Ok(Bound::Insert(Insert { name, source, write, returning, conflict: None, checks }))
1259}