Skip to main content

uqa_sql/semantics/rules/
insert_inputs.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Required event-row columns and declared types for rewritten INSERT inputs.
8use crate::{
9    plan::InsertPlan,
10    semantics::{
11        rules::analysis::RuleAnalysisContext,
12        view_rewrite::context::{stored_view_schema, ViewRewriteContext},
13    },
14    ColumnType, SQLError,
15};
16use std::collections::BTreeSet;
17pub fn view_rule_insert_column_type(
18    context: ViewRewriteContext<'_>,
19    stmt: &InsertPlan,
20    input_position: usize,
21) -> Result<Option<ColumnType>, SQLError> {
22    for plan in &stmt.view_rule_insert_plans {
23        let Some(column) = plan.supplied_columns.get(input_position) else {
24            continue;
25        };
26        let definition = context
27            .catalog
28            .view_definition(&plan.relation)?
29            .ok_or_else(|| SQLError::UnknownTable(plan.relation.clone()))?;
30        let schema = stored_view_schema(context, &definition)?;
31        let Some(position) =
32            schema
33                .columns()
34                .iter()
35                .enumerate()
36                .find_map(|(position, internal)| {
37                    let public = schema.public_name(position).unwrap_or(internal);
38                    (public == column).then_some(position)
39                })
40        else {
41            return Err(SQLError::UnknownColumn(format!(
42                "{}.{}",
43                plan.relation, column
44            )));
45        };
46        return Ok(schema.column_type(position).cloned());
47    }
48    Ok(None)
49}
50
51pub fn required_view_rule_insert_input_positions(
52    context: RuleAnalysisContext<'_>,
53    stmt: &InsertPlan,
54) -> Result<Option<BTreeSet<usize>>, SQLError> {
55    let mut required = BTreeSet::new();
56    for plan in &stmt.view_rule_insert_plans {
57        let Some(columns) = super::analysis::relation_rule_row_columns(
58            context,
59            &plan.relation,
60            crate::ast::RuleEvent::Insert,
61        )?
62        else {
63            return Ok(None);
64        };
65        required.extend(
66            plan.supplied_columns
67                .iter()
68                .enumerate()
69                .filter_map(|(position, column)| columns.contains(column).then_some(position)),
70        );
71        if super::analysis::relation_suppresses_original_query(
72            context,
73            &plan.relation,
74            crate::ast::RuleEvent::Insert,
75        )? {
76            break;
77        }
78    }
79    Ok(Some(required))
80}