Skip to main content

uqa_sql/expr/
value_catalog.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Borrowed catalog identities and comparison support for SQL value consumers.
8
9use super::enums::{EnumTypeComparisonStates, EnumTypeLabels};
10use super::Result;
11use std::sync::Arc;
12use uqa_core::EnumValue;
13
14/// Type metadata and enum support used to observe already admitted SQL values. Implementations borrow one statement catalog generation and never invoke type input.
15pub trait SQLValueCatalog {
16    /// The declared type for a physical OID, including domains, arrays and composites.
17    fn value_type_by_oid(&self, _oid: u32) -> Result<Option<crate::ColumnType>> {
18        Ok(None)
19    }
20
21    /// The current descriptor of an admitted composite value.
22    fn value_composite_type(
23        &self,
24        _oid: u32,
25    ) -> Result<Option<Arc<super::composites::CompositeTypeDescriptor>>> {
26        Ok(None)
27    }
28
29    /// The session's comparison support functions, shared by declared type across nested array and record calls. Pure catalog readers do not own runtime state.
30    fn enum_type_comparison_states(&self) -> Option<&EnumTypeComparisonStates> {
31        None
32    }
33
34    /// The labels of one enum type in the statement's catalog generation, or `None` when the catalog has no such type.
35    fn enum_type_labels(&self, type_oid: u32) -> Result<Option<Arc<EnumTypeLabels>>>;
36
37    /// Resolve an already admitted physical label OID across enum types. Output uses the label's actual identity even if a retained tuple now declares another enum type; it does not repeat input safety checks.
38    fn enum_value_by_oid(&self, _label_oid: u32) -> Result<Option<EnumValue>> {
39        Ok(None)
40    }
41
42    /// The actual enum type and zero-based label position of an admitted physical OID in this generation. Positions have declaration/key order and avoid copying label keys for comparison.
43    fn enum_label_position(&self, _label_oid: u32) -> Result<Option<(u32, usize)>> {
44        Ok(None)
45    }
46
47    /// Whether the current transaction added this label to a type that it did not create. `PostgreSQL` rejects such a label until the transaction commits.
48    fn enum_label_uncommitted(&self, label_oid: u32) -> bool;
49
50    /// `format_type_be` of the type, which qualifies a type hidden by the search path.
51    fn enum_type_name(&self, type_oid: u32) -> Result<Option<String>>;
52
53    /// Whether the statement catalog defines any enum type; binding skips enum literal validation otherwise.
54    fn has_enum_types(&self) -> bool;
55}
56
57/// Adapt a scalar context without requiring embedders that only provide domain or composite metadata to implement enum support.
58pub struct EngineValueCatalog<'a>(pub &'a dyn super::EngineHook);
59
60impl SQLValueCatalog for EngineValueCatalog<'_> {
61    fn value_type_by_oid(&self, oid: u32) -> Result<Option<crate::ColumnType>> {
62        self.0
63            .resolve_type_oid(oid)
64            .map_err(crate::SQLError::Internal)
65    }
66
67    fn value_composite_type(
68        &self,
69        oid: u32,
70    ) -> Result<Option<Arc<super::composites::CompositeTypeDescriptor>>> {
71        self.0
72            .composite_types()
73            .map(|catalog| catalog.composite_type(oid))
74            .transpose()
75            .map(Option::flatten)
76    }
77
78    fn enum_type_comparison_states(&self) -> Option<&EnumTypeComparisonStates> {
79        self.0.enum_labels()?.enum_type_comparison_states()
80    }
81
82    fn enum_type_labels(&self, oid: u32) -> Result<Option<Arc<EnumTypeLabels>>> {
83        self.0
84            .enum_labels()
85            .map(|catalog| catalog.enum_type_labels(oid))
86            .transpose()
87            .map(Option::flatten)
88    }
89
90    fn enum_value_by_oid(&self, oid: u32) -> Result<Option<EnumValue>> {
91        self.0
92            .enum_labels()
93            .map(|catalog| catalog.enum_value_by_oid(oid))
94            .transpose()
95            .map(Option::flatten)
96    }
97
98    fn enum_label_position(&self, oid: u32) -> Result<Option<(u32, usize)>> {
99        self.0
100            .enum_labels()
101            .map(|catalog| catalog.enum_label_position(oid))
102            .transpose()
103            .map(Option::flatten)
104    }
105
106    fn enum_label_uncommitted(&self, oid: u32) -> bool {
107        self.0
108            .enum_labels()
109            .is_some_and(|catalog| catalog.enum_label_uncommitted(oid))
110    }
111
112    fn enum_type_name(&self, oid: u32) -> Result<Option<String>> {
113        self.0
114            .enum_labels()
115            .map(|catalog| catalog.enum_type_name(oid))
116            .transpose()
117            .map(Option::flatten)
118    }
119
120    fn has_enum_types(&self) -> bool {
121        self.0
122            .enum_labels()
123            .is_some_and(SQLValueCatalog::has_enum_types)
124    }
125}