1use super::{
10 Arc, ColumnIdentity, ColumnType, HashMap, HashSet, RowSchema, SchemaBuildMetadata,
11 SchemaColdMetadata, SchemaIndex, NULL_SLOT,
12};
13use uqa_sql::ast::InternalRelationId;
14
15impl Default for RowSchema {
16 fn default() -> Self {
17 Self::new(Vec::new())
18 }
19}
20
21impl From<Vec<String>> for RowSchema {
22 fn from(columns: Vec<String>) -> Self {
23 Self::new(columns)
24 }
25}
26
27impl RowSchema {
28 pub fn new(columns: Vec<String>) -> Self {
29 let width = columns.len();
30 let identities = columns
31 .iter()
32 .cloned()
33 .map(ColumnIdentity::unqualified)
34 .collect();
35 Self::from_parts(columns, identities, (0..width).collect(), width)
36 }
37
38 pub fn with_types(columns: Vec<String>, types: Vec<Option<ColumnType>>) -> Self {
40 let width = columns.len();
41 assert_eq!(width, types.len(), "row schema column/type width mismatch");
42 let identities = columns
43 .iter()
44 .cloned()
45 .map(ColumnIdentity::unqualified)
46 .collect();
47 Self::from_typed_parts_with_aliases_and_exact_precedence(
48 columns,
49 identities,
50 types,
51 (0..width).collect(),
52 width,
53 SchemaBuildMetadata::default(),
54 )
55 }
56
57 pub fn with_qualified_types(
59 qualifier: &str,
60 columns: Vec<String>,
61 types: Vec<Option<ColumnType>>,
62 ) -> Self {
63 let identities = columns
64 .iter()
65 .cloned()
66 .map(|column| ColumnIdentity::qualified(qualifier, column))
67 .collect();
68 Self::with_identities(columns, identities, types)
69 }
70
71 pub fn with_identities(
73 columns: Vec<String>,
74 identities: Vec<ColumnIdentity>,
75 types: Vec<Option<ColumnType>>,
76 ) -> Self {
77 let width = columns.len();
78 assert_eq!(
79 width,
80 identities.len(),
81 "row schema column/identity width mismatch"
82 );
83 assert_eq!(width, types.len(), "row schema column/type width mismatch");
84 Self::from_typed_parts_with_aliases_and_exact_precedence(
85 columns,
86 identities,
87 types,
88 (0..width).collect(),
89 width,
90 SchemaBuildMetadata::default(),
91 )
92 }
93
94 pub fn with_internal_relation_types(
98 relation: InternalRelationId,
99 types: Vec<Option<ColumnType>>,
100 ) -> Self {
101 let internal = (0..types.len())
102 .map(|position| (relation.column(position), position))
103 .collect();
104 let internal_types = types
105 .iter()
106 .enumerate()
107 .map(|(position, ty)| (relation.column(position), ty.clone()))
108 .collect();
109 Self::from_typed_parts_with_aliases_and_exact_precedence(
110 Vec::new(),
111 Vec::new(),
112 Vec::new(),
113 Vec::new(),
114 types.len(),
115 SchemaBuildMetadata {
116 internal,
117 internal_types,
118 ..SchemaBuildMetadata::default()
119 },
120 )
121 }
122
123 pub fn from_named_columns(columns: Vec<String>) -> Self {
128 let width = columns.len();
129 let identities = columns
130 .iter()
131 .cloned()
132 .map(ColumnIdentity::unqualified)
133 .collect();
134 Self::from_parts_with_aliases_and_exact_precedence(
135 columns,
136 identities,
137 (0..width).collect(),
138 width,
139 SchemaBuildMetadata {
140 exact_unqualified_precedence: true,
141 ..SchemaBuildMetadata::default()
142 },
143 )
144 }
145
146 fn from_parts(
147 columns: Vec<String>,
148 identities: Vec<ColumnIdentity>,
149 slots: Vec<usize>,
150 physical_width: usize,
151 ) -> Self {
152 Self::from_parts_with_aliases(columns, identities, slots, physical_width, HashMap::new())
153 }
154
155 fn from_parts_with_aliases(
156 columns: Vec<String>,
157 identities: Vec<ColumnIdentity>,
158 slots: Vec<usize>,
159 physical_width: usize,
160 aliases: HashMap<ColumnIdentity, usize>,
161 ) -> Self {
162 Self::from_parts_with_aliases_and_exact_precedence(
163 columns,
164 identities,
165 slots,
166 physical_width,
167 SchemaBuildMetadata {
168 aliases,
169 ..SchemaBuildMetadata::default()
170 },
171 )
172 }
173
174 fn from_parts_with_aliases_and_exact_precedence(
175 columns: Vec<String>,
176 identities: Vec<ColumnIdentity>,
177 slots: Vec<usize>,
178 physical_width: usize,
179 metadata: SchemaBuildMetadata,
180 ) -> Self {
181 let types = vec![None; columns.len()];
182 Self::from_typed_parts_with_aliases_and_exact_precedence(
183 columns,
184 identities,
185 types,
186 slots,
187 physical_width,
188 metadata,
189 )
190 }
191
192 pub(super) fn from_typed_parts_with_aliases_and_exact_precedence(
193 columns: Vec<String>,
194 identities: Vec<ColumnIdentity>,
195 types: Vec<Option<ColumnType>>,
196 slots: Vec<usize>,
197 physical_width: usize,
198 metadata: SchemaBuildMetadata,
199 ) -> Self {
200 let SchemaBuildMetadata {
201 aliases,
202 alias_types,
203 internal,
204 internal_types,
205 score_sources,
206 wildcard_hidden,
207 binding_only,
208 exact_unqualified_precedence,
209 extra_ambiguous_unqualified,
210 extra_ambiguous_qualified,
211 } = metadata;
212 debug_assert_eq!(columns.len(), slots.len());
213 debug_assert_eq!(columns.len(), identities.len());
214 debug_assert_eq!(columns.len(), types.len());
215 debug_assert!(wildcard_hidden
216 .iter()
217 .all(|position| *position < columns.len()));
218 let identity_layout = physical_width == columns.len()
219 && slots
220 .iter()
221 .enumerate()
222 .all(|(position, slot)| position == *slot);
223 let mut exact = HashMap::with_capacity(columns.len());
224 let mut unqualified = HashMap::with_capacity(columns.len());
225 let mut qualified = HashMap::with_capacity(columns.len());
226 let mut unqualified_counts: HashMap<Box<str>, usize> = HashMap::new();
227 let mut qualified_counts: HashMap<ColumnIdentity, usize> = HashMap::new();
228
229 for (logical, (name, identity)) in columns.iter().zip(&identities).enumerate() {
230 exact.insert(Box::<str>::from(name.as_str()), logical);
233 *unqualified_counts
234 .entry(identity.column.clone())
235 .or_default() += 1;
236 unqualified.insert(identity.column.clone(), logical);
237 if identity.qualifier.is_some() {
238 *qualified_counts.entry(identity.clone()).or_default() += 1;
239 qualified.insert(identity.clone(), logical);
240 }
241 }
242 for slot in aliases.values() {
243 debug_assert!(*slot == NULL_SLOT || *slot < physical_width);
244 }
245 for slot in internal.values() {
246 debug_assert!(*slot == NULL_SLOT || *slot < physical_width);
247 }
248 let mut ambiguous_unqualified: HashSet<Box<str>> = unqualified_counts
249 .into_iter()
250 .filter_map(|(column, count)| {
251 (count > 1
252 && !(exact_unqualified_precedence
253 && identities.iter().any(|identity| {
254 identity.qualifier.is_none() && identity.column == column
255 })))
256 .then_some(column)
257 })
258 .collect();
259 ambiguous_unqualified.extend(extra_ambiguous_unqualified);
260 let mut ambiguous_qualified = qualified_counts
261 .into_iter()
262 .filter_map(|(identity, count)| (count > 1).then_some(identity))
263 .collect::<HashSet<_>>();
264 ambiguous_qualified.extend(extra_ambiguous_qualified);
265 Self {
266 index: Arc::new(SchemaIndex {
267 columns: columns.into_boxed_slice(),
268 identities: identities.into_boxed_slice(),
269 slots: slots.into_boxed_slice(),
270 physical_width,
271 exact,
272 unqualified,
273 qualified,
274 aliases,
275 executor_attributes: internal,
276 ambiguous_unqualified,
277 ambiguous_qualified,
278 cold: Box::new(SchemaColdMetadata {
279 columns: types.into_boxed_slice(),
280 aliases: alias_types,
281 executor_attribute_types: internal_types,
282 score_sources,
283 wildcard_hidden,
284 binding_only,
285 identity_layout,
286 }),
287 }),
288 }
289 }
290}