uqa_sql/binding/
sources.rs1use crate::ast::{JoinKind, JoinUsing};
10use crate::plan::{QueryPlan, SourcePlan, TableFunctionPlan};
11use crate::RowSchema;
12use crate::{SQLError, SQLParam};
13
14use super::{analysis, projection::rename_schema, BindingContext, ScalarExpr, SchemaScope};
15use crate::routines::RoutineResolution;
16
17pub(super) fn alias_table_schema(
18 schema: &RowSchema,
19 qualifier: &str,
20 column_aliases: &[String],
21) -> Result<RowSchema, SQLError> {
22 if column_aliases.len() > schema.len() {
23 return Err(SQLError::Routine {
24 sqlstate: "42P10".into(),
25 message: format!(
26 "table \"{qualifier}\" has {} columns available but {} columns specified",
27 schema.len(),
28 column_aliases.len()
29 ),
30 });
31 }
32 Ok(rename_schema(schema, column_aliases, Some(qualifier)))
33}
34
35pub(super) struct JoinSchemaBinding<'a> {
36 pub(super) routines: &'a dyn RoutineResolution,
37 pub(super) kind: JoinKind,
38 pub(super) on: Option<&'a ScalarExpr>,
39 pub(super) using: Option<&'a JoinUsing>,
40 pub(super) natural: bool,
41 pub(super) alias: Option<&'a str>,
42 pub(super) column_aliases: &'a [String],
43 pub(super) left: &'a RowSchema,
44 pub(super) right: &'a RowSchema,
45 pub(super) subqueries: &'a [QueryPlan],
46 pub(super) params: &'a [SQLParam],
47 pub(super) outer: Option<&'a RowSchema>,
48}
49
50pub(super) fn table_function_member_source(function: &TableFunctionPlan) -> SourcePlan {
51 SourcePlan::Function {
52 name: function.name.clone(),
53 binding: function.binding.clone(),
54 output_name: function.output_name.clone(),
55 relations: function.relations.clone(),
56 args: function.args.clone(),
57 alias: None,
58 column_aliases: function.column_aliases.clone(),
59 ordinality: false,
60 column_types: function.column_types.clone(),
61 }
62}
63
64pub fn bind_source_plan_schema(
66 routines: &dyn RoutineResolution,
67 source: &SourcePlan,
68 params: &[SQLParam],
69 ctes: &BindingContext,
70 outer: Option<&RowSchema>,
71) -> Result<RowSchema, SQLError> {
72 SchemaScope::from_context(ctes)?.bind_source(
73 routines,
74 source,
75 ctes.scalar_subqueries,
76 params,
77 outer,
78 )
79}
80
81pub fn with_query_table_pseudo_columns(schema: &RowSchema) -> RowSchema {
83 analysis::with_unqualified_table_pseudo_columns(schema)
84}
85
86pub fn analyze_source_plan_schema(
88 routines: &dyn RoutineResolution,
89 source: &SourcePlan,
90 params: &[SQLParam],
91 ctes: &BindingContext,
92 outer: Option<&RowSchema>,
93) -> Result<RowSchema, SQLError> {
94 SchemaScope::for_analysis(ctes)?.bind_source(
95 routines,
96 source,
97 ctes.scalar_subqueries,
98 params,
99 outer,
100 )
101}
102
103pub fn bind_source_plan_schema_for_execution(
105 routines: &dyn RoutineResolution,
106 source: &mut SourcePlan,
107 params: &[SQLParam],
108 ctes: &BindingContext,
109 outer: Option<&RowSchema>,
110) -> Result<RowSchema, SQLError> {
111 SchemaScope::from_context(ctes)?.bind_source_for_execution(
112 routines,
113 source,
114 ctes.scalar_subqueries,
115 params,
116 outer,
117 )
118}
119
120impl SchemaScope {
121 pub(super) fn bind_source(
122 &mut self,
123 routines: &dyn RoutineResolution,
124 source: &SourcePlan,
125 subqueries: &[QueryPlan],
126 params: &[SQLParam],
127 outer: Option<&RowSchema>,
128 ) -> Result<RowSchema, SQLError> {
129 let bound = matches!(
130 source,
131 SourcePlan::Table {
132 bound_columns: Some(_),
133 ..
134 }
135 );
136 let previous = bound.then(|| {
137 self.resolution
138 .set_lookup_mode(crate::catalog::resolution::RelationLookupMode::Bound)
139 });
140 let result = self.bind_source_inner(routines, source, subqueries, params, outer);
141 if let Some(previous) = previous {
142 self.resolution.set_lookup_mode(previous);
143 }
144 result
145 }
146}