Skip to main content

uqa_sql/ast/
composites.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Composite type declarations and their bound type references.
8
9use serde::{Deserialize, Serialize};
10use uqa_core::{
11    memory::{Produced, ProductionControl},
12    ValueRetentionError,
13};
14
15use super::ColumnType;
16
17/// `CREATE TYPE name AS (attribute type [COLLATE collation], ...)` with attributes in declaration order.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct CreateCompositeType {
20    /// Rendered qualified type name, resolved against the creation namespace during execution.
21    pub name: String,
22    pub attributes: Vec<CompositeAttributeDefinition>,
23}
24
25/// One declared attribute. The type is a declaration until execution binds it through the catalog.
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct CompositeAttributeDefinition {
28    pub name: String,
29    pub ty: ColumnType,
30    /// The rendered qualified collation name of an explicit `COLLATE` clause.
31    pub collation: Option<String>,
32    /// `SETOF type`, which the grammar accepts and `BuildDescForRelation` rejects.
33    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
34    pub setof: bool,
35}
36
37/// One ADD ATTRIBUTE declaration. Unlike CREATE TYPE, ALTER applies column declaration lowering, including SERIAL.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct CompositeAttributeAddition {
40    pub attribute: CompositeAttributeDefinition,
41    pub declaration: super::ColumnDeclaration,
42}
43
44/// One DROP ATTRIBUTE action; missing-name handling and dependency behavior remain execution-time decisions.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct CompositeAttributeRemoval {
47    pub name: String,
48    pub if_exists: bool,
49    pub cascade: bool,
50}
51
52/// Creation-time positional binding of a stored ROW constructor. Type references use the same canonical-name lifecycle as stored casts; attribute numbers survive additions and dropped slots.
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(deny_unknown_fields)]
55pub struct CompositeRowBinding {
56    pub ty: String,
57    pub attributes: Vec<i16>,
58    /// Types of the admitted arguments; absent only in predecessor definitions.
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub argument_types: Option<Vec<ColumnType>>,
61}
62
63/// A composite type bound by catalog identity: a standalone composite type or the row type of a relation. The schema and name are the catalog's current names; equality compares the type identity only.
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct CompositeTypeReference {
66    pub schema: String,
67    pub name: String,
68    /// The row type's `pg_type` OID.
69    pub oid: u32,
70    pub array_oid: u32,
71    /// The `pg_class` OID of the relation that describes the attributes (`pg_type.typrelid`).
72    pub relation_oid: u32,
73}
74
75impl PartialEq for CompositeTypeReference {
76    fn eq(&self, other: &Self) -> bool {
77        self.oid == other.oid
78    }
79}
80
81impl Eq for CompositeTypeReference {}
82
83impl CompositeTypeReference {
84    /// Copy the owned catalog names under the production reservation; the identities are inline.
85    pub fn clone_with_control(
86        &self,
87        control: &ProductionControl<'_>,
88    ) -> Result<Produced<Self>, ValueRetentionError> {
89        let schema = control.copy_text(&self.schema)?;
90        let name = control.copy_text(&self.name)?;
91        let (schema, schema_memory) = schema.into_parts();
92        let (name, name_memory) = name.into_parts();
93        control.finish(
94            Self {
95                schema,
96                name,
97                oid: self.oid,
98                array_oid: self.array_oid,
99                relation_oid: self.relation_oid,
100            },
101            control.combine(schema_memory, name_memory),
102        )
103    }
104}