uqa_execution/batch/
schema_layout.rs1use super::{ColumnIdentity, ColumnType, HashSet, RowSchema, NULL_SLOT};
10
11impl RowSchema {
12 #[must_use]
14 pub fn wildcard_position_visible(&self, position: usize) -> bool {
15 position < self.len() && !self.index.cold.wildcard_hidden.contains(&position)
16 }
17
18 pub fn columns(&self) -> &[String] {
19 &self.index.columns
20 }
21
22 pub fn len(&self) -> usize {
23 self.index.columns.len()
24 }
25
26 pub fn is_empty(&self) -> bool {
27 self.index.columns.is_empty()
28 }
29
30 pub fn iter(&self) -> std::slice::Iter<'_, String> {
31 self.index.columns.iter()
32 }
33
34 pub fn column_type(&self, logical: usize) -> Option<&ColumnType> {
36 self.index
37 .cold
38 .columns
39 .get(logical)
40 .and_then(Option::as_ref)
41 }
42
43 pub fn column_types(&self) -> &[Option<ColumnType>] {
45 &self.index.cold.columns
46 }
47
48 pub fn identities(&self) -> &[ColumnIdentity] {
50 &self.index.identities
51 }
52
53 pub fn identity(&self, logical: usize) -> Option<&ColumnIdentity> {
54 self.index.identities.get(logical)
55 }
56
57 pub fn public_name(&self, logical: usize) -> Option<&str> {
58 self.identity(logical).map(ColumnIdentity::column)
59 }
60
61 pub fn position(&self, name: &str) -> Option<usize> {
62 self.index.exact.get(name).copied()
63 }
64
65 pub fn unqualified_position(&self, column: &str) -> Option<usize> {
67 if self.index.ambiguous_unqualified.contains(column) {
68 return None;
69 }
70 self.index.unqualified.get(column).copied()
71 }
72
73 pub fn qualified_position(&self, qualifier: &str, column: &str) -> Option<usize> {
75 let identity = ColumnIdentity::qualified(qualifier, column);
76 if self.index.ambiguous_qualified.contains(&identity) {
77 return None;
78 }
79 self.index.qualified.get(&identity).copied()
80 }
81
82 pub fn physical_width(&self) -> usize {
83 self.index.physical_width
84 }
85
86 pub fn physical_slot(&self, logical: usize) -> Option<usize> {
88 self.slot(logical)
89 }
90
91 pub fn physical_type(&self, physical: usize) -> Option<&ColumnType> {
94 self.index
95 .slots
96 .iter()
97 .position(|slot| *slot == physical)
98 .and_then(|logical| self.column_type(logical))
99 .or_else(|| {
100 self.index.aliases.iter().find_map(|(identity, slot)| {
101 (*slot == physical)
102 .then(|| {
103 self.index
104 .cold
105 .aliases
106 .get(identity)
107 .and_then(Option::as_ref)
108 })
109 .flatten()
110 })
111 })
112 .or_else(|| {
113 self.index
114 .executor_attributes
115 .iter()
116 .find_map(|(column, slot)| {
117 (*slot == physical)
118 .then(|| {
119 self.index
120 .cold
121 .executor_attribute_types
122 .get(column)
123 .and_then(Option::as_ref)
124 })
125 .flatten()
126 })
127 })
128 }
129
130 pub fn physical_slot_for_identity(&self, identity: &ColumnIdentity) -> Option<usize> {
132 match identity.qualifier() {
133 Some(qualifier) => self.qualified_slot(qualifier, identity.column()),
134 None => self.column_slot(identity.column()),
135 }
136 }
137
138 pub(crate) fn slot(&self, logical: usize) -> Option<usize> {
139 self.index
140 .slots
141 .get(logical)
142 .copied()
143 .filter(|slot| *slot != NULL_SLOT)
144 }
145
146 pub(super) fn exact_slot(&self, name: &str) -> Option<usize> {
147 self.index
148 .exact
149 .get(name)
150 .and_then(|logical| self.slot(*logical))
151 .filter(|slot| *slot != NULL_SLOT)
152 }
153
154 pub(super) fn exact_type(&self, name: &str) -> Option<&ColumnType> {
155 self.index
156 .exact
157 .get(name)
158 .and_then(|logical| self.column_type(*logical))
159 }
160
161 pub(super) fn column_slot(&self, name: &str) -> Option<usize> {
162 if self.index.ambiguous_unqualified.contains(name) {
163 return None;
164 }
165 self.index
166 .unqualified
167 .get(name)
168 .and_then(|logical| self.slot(*logical))
169 .or_else(|| {
170 self.index
171 .aliases
172 .get(&ColumnIdentity::unqualified(name))
173 .copied()
174 })
175 .filter(|slot| *slot != NULL_SLOT)
176 }
177
178 pub fn qualified_star_layout(
180 &self,
181 qualifier: &str,
182 ) -> Vec<(String, usize, Option<ColumnType>)> {
183 self.qualified_star_position_layout(qualifier)
184 .into_iter()
185 .map(|(column, _, slot, ty)| (column, slot, ty))
186 .collect()
187 }
188
189 pub fn qualified_star_position_layout(
191 &self,
192 qualifier: &str,
193 ) -> Vec<(String, Option<usize>, usize, Option<ColumnType>)> {
194 let mut entries = Vec::new();
195 let mut visible_layout = HashSet::new();
196 for (logical, identity) in self.identities().iter().enumerate() {
197 if identity.qualifier() == Some(qualifier) {
198 let slot = self.slot(logical).unwrap_or(NULL_SLOT);
199 visible_layout.insert((identity.clone(), slot));
200 entries.push((
201 identity.clone(),
202 Some(logical),
203 slot,
204 self.column_type(logical).cloned(),
205 ));
206 }
207 }
208 for (identity, slot) in &self.index.aliases {
209 if identity.qualifier() == Some(qualifier)
210 && !visible_layout.contains(&(identity.clone(), *slot))
211 {
212 entries.push((
213 identity.clone(),
214 None,
215 *slot,
216 self.index.cold.aliases.get(identity).cloned().flatten(),
217 ));
218 }
219 }
220 entries.sort_by_key(|(_, _, slot, _)| *slot);
221 entries
222 .into_iter()
223 .map(|(identity, logical, slot, ty)| (identity.column().to_string(), logical, slot, ty))
224 .collect()
225 }
226
227 pub(super) fn qualified_slot(&self, qualifier: &str, column: &str) -> Option<usize> {
228 let identity = ColumnIdentity::qualified(qualifier, column);
229 if self.index.ambiguous_qualified.contains(&identity) {
230 return None;
231 }
232 self.index
233 .qualified
234 .get(&identity)
235 .and_then(|logical| self.slot(*logical))
236 .or_else(|| self.index.aliases.get(&identity).copied())
237 .filter(|slot| *slot != NULL_SLOT)
238 }
239}