1use crate::ast::ColumnType;
10use crate::plan::{ProjectionPlan, QueryBlockPlan, QueryPlan};
11use crate::RowSchema;
12use crate::{SQLError, SQLParam};
13
14use super::{
15 bind_query_plan_schema, projection_columns, BindingContext, QueryFunctionTypeResolver,
16 ScalarExpr, SchemaScope,
17};
18use crate::routines::RoutineResolution;
19
20type ProjectionStarColumn = (String, Option<ColumnType>);
21
22pub fn bind_projection_output_schema(
24 routines: &dyn RoutineResolution,
25 projections: &[ProjectionPlan],
26 expression_schema: &RowSchema,
27 star_schema: &RowSchema,
28 subqueries: &[QueryPlan],
29 params: &[SQLParam],
30 ctes: &BindingContext,
31) -> Result<RowSchema, SQLError> {
32 projection_output_schema(
33 SchemaScope::from_context(ctes)?,
34 routines,
35 projections,
36 expression_schema,
37 star_schema,
38 subqueries,
39 params,
40 )
41}
42
43pub fn analyze_projection_output_schema(
45 routines: &dyn RoutineResolution,
46 projections: &[ProjectionPlan],
47 expression_schema: &RowSchema,
48 star_schema: &RowSchema,
49 subqueries: &[QueryPlan],
50 params: &[SQLParam],
51 ctes: &BindingContext,
52) -> Result<RowSchema, SQLError> {
53 projection_output_schema(
54 SchemaScope::for_analysis(ctes)?,
55 routines,
56 projections,
57 expression_schema,
58 star_schema,
59 subqueries,
60 params,
61 )
62}
63
64fn projection_output_schema(
65 mut scope: SchemaScope,
66 routines: &dyn RoutineResolution,
67 projections: &[ProjectionPlan],
68 expression_schema: &RowSchema,
69 star_schema: &RowSchema,
70 subqueries: &[QueryPlan],
71 params: &[SQLParam],
72) -> Result<RowSchema, SQLError> {
73 let labels = projection_columns(projections);
74 let mut columns = Vec::new();
75 let mut types = Vec::new();
76 for (position, projection) in projections.iter().enumerate() {
77 let expansion_schema = match projection.expr {
78 ScalarExpr::QualifiedStar(_) => expression_schema,
79 _ => star_schema,
80 };
81 if let Some(star_columns) = projection_star_columns(&projection.expr, expansion_schema)? {
82 for (column, ty) in star_columns {
83 columns.push(column);
84 types.push(ty);
85 }
86 continue;
87 }
88 columns.push(labels[position].clone());
89 types.push(scope.bind_expression_type(
90 routines,
91 &projection.expr,
92 expression_schema,
93 subqueries,
94 params,
95 Some(expression_schema),
96 )?);
97 }
98 Ok(RowSchema::with_types(columns, types))
99}
100
101pub fn validate_query_block_expression_types(
103 routines: &dyn RoutineResolution,
104 statement: &QueryBlockPlan,
105 schema: &RowSchema,
106 params: &[SQLParam],
107 ctes: &BindingContext,
108) -> Result<(), SQLError> {
109 let scalar_subquery_types = statement
110 .subqueries
111 .iter()
112 .map(|plan| {
113 bind_query_plan_schema(routines, plan, params, ctes, Some(schema))
114 .map(|output| output.column_type(0).cloned())
115 })
116 .collect::<Result<Vec<_>, _>>()?;
117 let resolver = QueryFunctionTypeResolver {
118 routines,
119 scalar_subquery_types: Some(scalar_subquery_types),
120 defer_routine_namespace_errors: true,
121 };
122 for expression in statement
123 .projections
124 .iter()
125 .map(|projection| &projection.expr)
126 .chain(statement.group_by.iter())
127 .chain(statement.grouping_sets.iter().flatten())
128 .chain(statement.order_by.iter().map(|order| &order.expr))
129 .chain(statement.distinct_on.iter())
130 .chain(statement.r#where.iter())
131 .chain(statement.having.iter())
132 .chain(statement.limit.iter())
133 .chain(statement.offset.iter())
134 {
135 crate::scalar_type_with_resolver(expression, schema, params, &resolver)?;
136 }
137 for expression in statement
138 .group_by
139 .iter()
140 .chain(statement.grouping_sets.iter().flatten())
141 .chain(statement.distinct_on.iter())
142 {
143 if let Some(ty) = crate::scalar_type_with_resolver(expression, schema, params, &resolver)? {
144 crate::require_equality_operator(&ty)?;
145 }
146 }
147 for order in &statement.order_by {
148 if let Some(ty) = crate::scalar_type_with_resolver(&order.expr, schema, params, &resolver)?
149 {
150 crate::require_ordering_operator(&ty)?;
151 }
152 }
153 Ok(())
154}
155
156pub fn validate_query_block_references(
158 routines: &dyn RoutineResolution,
159 statement: &QueryBlockPlan,
160 schema: &RowSchema,
161 params: &[SQLParam],
162 ctes: &BindingContext,
163) -> Result<(), SQLError> {
164 let output = analyze_projection_output_schema(
165 routines,
166 &statement.projections,
167 schema,
168 schema,
169 &statement.subqueries,
170 params,
171 ctes,
172 )?;
173 if statement.distinct && statement.distinct_on.is_empty() {
174 for ty in output.column_types().iter().flatten() {
175 crate::require_equality_operator(ty)?;
176 }
177 }
178 SchemaScope::for_analysis(ctes)?
179 .validate_query_block_clauses(routines, statement, schema, &output, params)
180}
181
182pub(super) fn projection_star_columns(
183 expression: &ScalarExpr,
184 schema: &RowSchema,
185) -> Result<Option<Vec<ProjectionStarColumn>>, SQLError> {
186 match expression {
187 ScalarExpr::Star => Ok(Some(
188 schema
189 .columns()
190 .iter()
191 .enumerate()
192 .map(|(position, column)| {
193 (
194 schema.public_name(position).unwrap_or(column).to_string(),
195 schema.column_type(position).cloned(),
196 )
197 })
198 .collect(),
199 )),
200 ScalarExpr::QualifiedStar(qualifier) => {
201 let columns = schema
202 .qualified_star_layout(qualifier)
203 .into_iter()
204 .map(|(column, _, ty)| (column, ty))
205 .collect::<Vec<_>>();
206 if columns.is_empty() {
207 return Err(SQLError::UnknownTable(qualifier.clone()));
208 }
209 Ok(Some(columns))
210 }
211 _ => Ok(None),
212 }
213}
214
215pub(super) fn rename_schema(
216 schema: &RowSchema,
217 aliases: &[String],
218 qualifier: Option<&str>,
219) -> RowSchema {
220 let columns = schema
221 .columns()
222 .iter()
223 .enumerate()
224 .map(|(position, column)| {
225 aliases
226 .get(position)
227 .cloned()
228 .unwrap_or_else(|| schema.public_name(position).unwrap_or(column).to_string())
229 })
230 .collect();
231 let renamed = match qualifier {
232 Some(qualifier) => {
233 RowSchema::with_qualified_types(qualifier, columns, schema.column_types().to_vec())
234 }
235 None => RowSchema::with_types(columns, schema.column_types().to_vec()),
236 };
237 let renamed = if schema.columns_are_open(None) {
238 RowSchema::with_open_columns(&renamed, qualifier)
239 } else {
240 renamed
241 };
242 let mut hidden = Vec::new();
243 let mut conflicting = Vec::new();
244 for (identity, ty) in schema.typed_virtual_identities() {
245 let conflicts = match identity.qualifier() {
246 Some(source) => schema.qualified_column_is_ambiguous(source, identity.column()),
247 None => schema.column_is_ambiguous(identity.column()),
248 };
249 let mapped = qualifier.map_or_else(
250 || vec![identity.clone()],
251 |qualifier| {
252 vec![
253 crate::ColumnIdentity::unqualified(identity.column()),
254 crate::ColumnIdentity::qualified(qualifier, identity.column()),
255 ]
256 },
257 );
258 for identity in mapped {
259 if conflicts {
260 conflicting.push((identity, ty.cloned()));
261 } else {
262 hidden.push((identity, ty.cloned()));
263 }
264 }
265 }
266 let renamed = RowSchema::with_typed_virtual_identities(&renamed, &hidden);
267 RowSchema::with_typed_conflicting_virtual_identities(&renamed, &conflicting)
268}