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