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/// 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.
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(deny_unknown_fields)]
47pub struct CompositeRowBinding {
48    pub ty: String,
49    pub attributes: Vec<i16>,
50}
51
52/// 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.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct CompositeTypeReference {
55    pub schema: String,
56    pub name: String,
57    /// The row type's `pg_type` OID.
58    pub oid: u32,
59    pub array_oid: u32,
60    /// The `pg_class` OID of the relation that describes the attributes (`pg_type.typrelid`).
61    pub relation_oid: u32,
62}
63
64impl PartialEq for CompositeTypeReference {
65    fn eq(&self, other: &Self) -> bool {
66        self.oid == other.oid
67    }
68}
69
70impl Eq for CompositeTypeReference {}
71
72impl CompositeTypeReference {
73    /// Copy the owned catalog names under the production reservation; the identities are inline.
74    pub fn clone_with_control(
75        &self,
76        control: &ProductionControl<'_>,
77    ) -> Result<Produced<Self>, ValueRetentionError> {
78        let schema = control.copy_text(&self.schema)?;
79        let name = control.copy_text(&self.name)?;
80        let (schema, schema_memory) = schema.into_parts();
81        let (name, name_memory) = name.into_parts();
82        control.finish(
83            Self {
84                schema,
85                name,
86                oid: self.oid,
87                array_oid: self.array_oid,
88                relation_oid: self.relation_oid,
89            },
90            control.combine(schema_memory, name_memory),
91        )
92    }
93}