1use super::{
10 Arc, ColumnIdentity, ColumnType, HashMap, HashSet, RowSchema, SchemaBuildMetadata,
11 SchemaColdMetadata, SchemaIndex, NULL_SLOT,
12};
13use crate::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 record_fields,
202 aliases,
203 alias_types,
204 internal,
205 internal_types,
206 score_sources,
207 wildcard_hidden,
208 binding_only,
209 open_qualifiers,
210 exact_unqualified_precedence,
211 extra_ambiguous_unqualified,
212 extra_ambiguous_qualified,
213 local_width,
214 } = metadata;
215 debug_assert_eq!(columns.len(), slots.len());
216 debug_assert_eq!(columns.len(), identities.len());
217 debug_assert_eq!(columns.len(), types.len());
218 debug_assert!(wildcard_hidden
219 .iter()
220 .all(|position| *position < columns.len()));
221 let identity_layout = physical_width == columns.len()
222 && slots
223 .iter()
224 .enumerate()
225 .all(|(position, slot)| position == *slot);
226 let mut exact = HashMap::with_capacity(columns.len());
227 let mut unqualified = HashMap::with_capacity(columns.len());
228 let mut qualified = HashMap::with_capacity(columns.len());
229 let mut unqualified_counts: HashMap<Box<str>, usize> = HashMap::new();
230 let mut qualified_counts: HashMap<ColumnIdentity, usize> = HashMap::new();
231
232 for (logical, (name, identity)) in columns.iter().zip(&identities).enumerate() {
233 exact.insert(Box::<str>::from(name.as_str()), logical);
236 *unqualified_counts
237 .entry(identity.column.clone())
238 .or_default() += 1;
239 unqualified.insert(identity.column.clone(), logical);
240 if identity.qualifier.is_some() {
241 *qualified_counts.entry(identity.clone()).or_default() += 1;
242 qualified.insert(identity.clone(), logical);
243 }
244 }
245 for slot in aliases.values() {
246 debug_assert!(*slot == NULL_SLOT || *slot < physical_width);
247 }
248 for slot in internal.values() {
249 debug_assert!(*slot == NULL_SLOT || *slot < physical_width);
250 }
251 let mut ambiguous_unqualified: HashSet<Box<str>> = unqualified_counts
252 .into_iter()
253 .filter_map(|(column, count)| {
254 (count > 1
255 && !(exact_unqualified_precedence
256 && identities.iter().any(|identity| {
257 identity.qualifier.is_none() && identity.column == column
258 })))
259 .then_some(column)
260 })
261 .collect();
262 ambiguous_unqualified.extend(extra_ambiguous_unqualified);
263 let mut ambiguous_qualified = qualified_counts
264 .into_iter()
265 .filter_map(|(identity, count)| (count > 1).then_some(identity))
266 .collect::<HashSet<_>>();
267 ambiguous_qualified.extend(extra_ambiguous_qualified);
268 Self {
269 index: Arc::new(SchemaIndex {
270 columns: columns.into_boxed_slice(),
271 identities: identities.into_boxed_slice(),
272 slots: slots.into_boxed_slice(),
273 physical_width,
274 exact,
275 unqualified,
276 qualified,
277 aliases,
278 executor_attributes: internal,
279 ambiguous_unqualified,
280 ambiguous_qualified,
281 cold: Box::new(SchemaColdMetadata {
282 record_fields,
283 columns: types.into_boxed_slice(),
284 aliases: alias_types,
285 executor_attribute_types: internal_types,
286 score_sources,
287 wildcard_hidden,
288 binding_only,
289 open_qualifiers,
290 identity_layout,
291 local_width,
292 }),
293 }),
294 }
295 }
296}