nodedb_sql/planner/dml/
upsert.rs1use sqlparser::ast;
6
7use super::super::dml_helpers::{
8 KvInsertParams, VectorPrimaryInsertParams, build_kv_insert_plan,
9 build_vector_primary_insert_plan, check_declared_float_ranges_in_assignments,
10 check_declared_int_ranges_in_assignments, is_vector_primary, resolve_insert_columns,
11};
12use super::target::{
13 column_schema, insert_columns, resolve_target, target_scope, typed_rows, values_rows,
14};
15use crate::engine_rules::{self, UpsertParams};
16use crate::error::Result;
17use crate::planner::declared_type_coerce::coerce_assignments_to_declared_types;
18use crate::types::*;
19
20pub fn plan_upsert(ins: &ast::Insert, catalog: &dyn SqlCatalog) -> Result<Vec<SqlPlan>> {
24 plan_upsert_rows(ins, catalog, "UPSERT", Vec::new())
25}
26
27pub(super) fn plan_upsert_with_on_conflict(
29 ins: &ast::Insert,
30 catalog: &dyn SqlCatalog,
31 on_conflict_updates: Vec<(String, SqlExpr)>,
32) -> Result<Vec<SqlPlan>> {
33 plan_upsert_rows(ins, catalog, "INSERT ... ON CONFLICT", on_conflict_updates)
34}
35
36fn plan_upsert_rows(
42 ins: &ast::Insert,
43 catalog: &dyn SqlCatalog,
44 verb: &str,
45 mut on_conflict_updates: Vec<(String, SqlExpr)>,
46) -> Result<Vec<SqlPlan>> {
47 let (table_name, info) = resolve_target(ins, verb, catalog)?;
48 let columns = insert_columns(&ins.columns, &target_scope(&table_name, &info)?)?;
49 let rows_ast = values_rows(ins, verb)?;
50
51 if info.engine == EngineType::KeyValue {
56 return build_kv_insert_plan(KvInsertParams {
57 collection: table_name,
58 columns: &columns,
59 rows_ast,
60 intent: KvInsertIntent::Put,
61 on_conflict_updates,
62 pk_col: info.primary_key.as_deref(),
63 declared_columns: &info.columns,
64 catalog,
65 });
66 }
67
68 let columns = resolve_insert_columns(columns, &info, rows_ast)?;
71
72 let typed = typed_rows(&info, &columns, rows_ast, catalog)?;
73 coerce_assignments_to_declared_types(
76 &info.columns,
77 &mut on_conflict_updates,
78 info.primary_key.as_deref(),
79 )?;
80 check_declared_int_ranges_in_assignments(&info.columns, &on_conflict_updates)?;
81 check_declared_float_ranges_in_assignments(&info.columns, &on_conflict_updates)?;
82
83 if is_vector_primary(&info)
87 && let Some(ref vpc) = info.vector_primary
88 {
89 return build_vector_primary_insert_plan(VectorPrimaryInsertParams {
90 collection: &table_name,
91 vpc,
92 rows: typed.rows,
93 volatile_defaults: typed.volatile_defaults,
94 intent: VectorPrimaryInsertIntent::Upsert,
95 on_conflict_updates,
96 primary_key: info.primary_key.clone(),
97 });
98 }
99
100 let column_schema = column_schema(&info);
101 let rules = engine_rules::resolve_engine_rules(info.engine);
102 rules.plan_upsert(UpsertParams {
103 collection: table_name,
104 columns,
105 rows: typed.rows,
106 volatile_defaults: typed.volatile_defaults,
107 on_conflict_updates,
108 column_schema,
109 primary_key: info.primary_key.clone(),
110 })
111}