uqa_sql/catalog/node_tree/expressions/
schema.rs1use crate::schema::{ColumnTypeSchema, ScalarTypeSchema};
10use crate::{ColumnType, RowSchema, SQLError};
11
12pub struct ColumnReference<'a> {
14 pub attribute_number: i64,
15 pub ty: &'a ColumnType,
16 pub collation_oid: i64,
17}
18
19pub trait ExpressionSchema: ScalarTypeSchema {
21 fn column_reference(
22 &self,
23 name: &str,
24 qualifier: Option<&str>,
25 ) -> Result<ColumnReference<'_>, SQLError>;
26
27 fn whole_row_reference(&self, qualifier: &str) -> Result<ColumnReference<'_>, SQLError> {
29 self.whole_row_type(qualifier)
30 .map(|ty| ColumnReference {
31 attribute_number: 0,
32 ty,
33 collation_oid: 0,
34 })
35 .ok_or_else(|| SQLError::UnknownTable(qualifier.into()))
36 }
37}
38
39impl ExpressionSchema for RowSchema {
40 fn column_reference(
41 &self,
42 name: &str,
43 qualifier: Option<&str>,
44 ) -> Result<ColumnReference<'_>, SQLError> {
45 let position = qualifier
46 .map_or_else(
47 || self.unqualified_position(name),
48 |qualifier| self.qualified_position(qualifier, name),
49 )
50 .ok_or_else(|| SQLError::UnknownColumn(name.into()))?;
51 let ty = self
52 .column_type(position)
53 .ok_or_else(|| SQLError::Internal("catalog column has no declared type".into()))?;
54 Ok(ColumnReference {
55 attribute_number: i64::try_from(position + 1)
56 .map_err(|_| SQLError::Internal("column ordinal overflow".into()))?,
57 ty,
58 collation_oid: i64::from(
59 self.column_collation(position)
60 .expect("typed catalog column collation"),
61 ),
62 })
63 }
64}
65
66impl ExpressionSchema for ColumnTypeSchema<'_> {
67 fn column_reference(
68 &self,
69 name: &str,
70 qualifier: Option<&str>,
71 ) -> Result<ColumnReference<'_>, SQLError> {
72 if qualifier.is_some_and(|qualifier| !self.has_qualifier(qualifier)) {
73 return Err(SQLError::UnknownColumn(name.into()));
74 }
75 let mut matching = self
76 .columns()
77 .iter()
78 .enumerate()
79 .filter(|(_, column)| column.name == name);
80 let Some((position, column)) = matching.next() else {
81 if let Some(ty) = self.system_column_type(name) {
82 return Ok(ColumnReference {
83 attribute_number: -6,
84 ty,
85 collation_oid: 0,
86 });
87 }
88 if qualifier.is_none() && self.has_qualifier(name) {
89 return self.whole_row_reference(name);
90 }
91 return Err(SQLError::UnknownColumn(name.into()));
92 };
93 if matching.next().is_some() {
94 return Err(SQLError::UnknownColumn(name.into()));
95 }
96 let attribute_number = column.attribute_number.map_or_else(
97 || {
98 i64::try_from(position + 1)
99 .map_err(|_| SQLError::Internal("column ordinal overflow".into()))
100 },
101 |number| Ok(i64::from(number)),
102 )?;
103 if attribute_number <= 0 {
104 return Err(SQLError::Internal(
105 "invalid catalog attribute number".into(),
106 ));
107 }
108 Ok(ColumnReference {
109 attribute_number,
110 ty: &column.ty,
111 collation_oid: crate::catalog::collations::declarations::column_oid(column),
112 })
113 }
114}