Skip to main content

uqa_sql/semantics/
mutation_rows.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Declared and hidden column schemas shared by mutation analysis and row execution.
8use super::{DOC_ID_COLUMN, TABLE_OID_COLUMN, XMIN_COLUMN};
9use crate::{ast::ColumnDef, ColumnType, RowSchema, SQLError};
10
11/// Relation metadata observed by mutation row construction.
12pub trait MutationRowCatalog: Sync {
13    fn column_definitions(&self, table: &str) -> Result<Option<Vec<ColumnDef>>, String>;
14    fn column_names(&self, table: &str) -> Result<Vec<String>, String>;
15    fn view_schema(&self, name: &str) -> Result<RowSchema, SQLError>;
16}
17
18pub fn null_target_schema(
19    relations: &dyn MutationRowCatalog,
20    table: &str,
21    qualifier: &str,
22) -> Result<RowSchema, SQLError> {
23    let definitions = relations
24        .column_definitions(table)
25        .map_err(|error| dml_storage_error("DML row schema lookup", error))?
26        .ok_or_else(|| SQLError::UnknownTable(table.to_string()))?;
27    let mut columns = if definitions.is_empty() {
28        relations
29            .column_names(table)
30            .map_err(|error| dml_storage_error("DML row schema lookup", error))?
31    } else {
32        definitions
33            .iter()
34            .map(|definition| definition.name.clone())
35            .collect::<Vec<_>>()
36    };
37    let mut types = columns
38        .iter()
39        .map(|column| {
40            definitions
41                .iter()
42                .find(|definition| definition.name == *column)
43                .map(|definition| definition.ty.clone())
44        })
45        .collect::<Vec<_>>();
46    if !columns.iter().any(|column| column == DOC_ID_COLUMN) {
47        columns.push(DOC_ID_COLUMN.into());
48        types.push(Some(ColumnType::BigInteger));
49    }
50    columns.push(TABLE_OID_COLUMN.into());
51    types.push(Some(ColumnType::Oid));
52    columns.push(XMIN_COLUMN.into());
53    types.push(Some(ColumnType::Xid));
54    Ok(RowSchema::with_qualified_types(qualifier, columns, types))
55}
56
57fn dml_storage_error(action: &str, error: impl std::fmt::Display) -> SQLError {
58    SQLError::Internal(format!("{action} failed in storage backend: {error}"))
59}