risingwave_frontend/binder/expr/column.rs
1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use risingwave_common::types::DataType;
16use risingwave_sqlparser::ast::Ident;
17
18use crate::binder::{Binder, Clause};
19use crate::error::{ErrorCode, Result};
20use crate::expr::{CorrelatedInputRef, ExprImpl, ExprType, FunctionCall, InputRef, Literal};
21
22impl Binder {
23 pub fn bind_column(&mut self, idents: &[Ident]) -> Result<ExprImpl> {
24 // TODO: check quote style of `ident`.
25 let (schema_name, table_name, column_name) = match idents {
26 [column] => (None, None, column.real_value()),
27 [table, column] => (None, Some(table.real_value()), column.real_value()),
28 [schema, table, column] => (
29 Some(schema.real_value()),
30 Some(table.real_value()),
31 column.real_value(),
32 ),
33 _ => {
34 return Err(
35 ErrorCode::InternalError(format!("Too many idents: {:?}", idents)).into(),
36 );
37 }
38 };
39
40 // If we find `sql_udf_arguments` in the current context, it means we're binding an inline SQL UDF
41 // (without a layer of subquery). This only happens when the function body is a trivial `SELECT`
42 // statement without any `FROM` clause etc. In this case, the column must be a UDF parameter.
43 if self.is_binding_inline_sql_udf() {
44 return self.bind_sql_udf_parameter(&column_name);
45 }
46
47 match self
48 .context
49 .get_column_binding_indices(&schema_name, &table_name, &column_name)
50 {
51 Ok(mut indices) => {
52 match indices.len() {
53 0 => unreachable!(),
54 1 => {
55 let index = indices[0];
56 let column = &self.context.columns[index];
57 return Ok(
58 InputRef::new(column.index, column.field.data_type.clone()).into()
59 );
60 }
61 _ => {
62 indices.sort(); // make sure we have a consistent result
63 let inputs = indices
64 .iter()
65 .map(|index| {
66 let column = &self.context.columns[*index];
67 InputRef::new(column.index, column.field.data_type.clone()).into()
68 })
69 .collect::<Vec<_>>();
70 return Ok(FunctionCall::new(ExprType::Coalesce, inputs)?.into());
71 }
72 }
73 }
74 Err(e) => {
75 // If a column is referenced using three-level qualification and the table has an alias,
76 // prompt the user to use the table alias instead.
77 if let ErrorCode::ItemNotFound(_) = e {
78 if let (Some(schema), Some(table)) = (&schema_name, &table_name)
79 && let Some(index) =
80 self.context.get_table_alias(schema, table, &column_name)?
81 {
82 let column = &self.context.columns[index];
83 return Err(ErrorCode::InvalidReference(format!(
84 "missing FROM-clause entry for table \"{}\"\n\
85 HINT: Perhaps you meant to reference the table alias \"{}\".",
86 table, column.table_name
87 ))
88 .into());
89 };
90 } else {
91 // If the error message is not that the column is not found, throw the error
92 return Err(e.into());
93 }
94 }
95 }
96
97 // Try to find a correlated column in the enclosing scopes, starting from the innermost one.
98 let mut err = ErrorCode::ItemNotFound(format!("Invalid column: {}", column_name));
99
100 for scope in self.correlation_scopes() {
101 let mut found = None;
102 for (context, depth) in scope {
103 if matches!(context.clause, Some(Clause::Insert)) {
104 continue;
105 }
106 match context.get_column_binding_indices(&schema_name, &table_name, &column_name) {
107 Ok(indices) => {
108 // All `FROM` items of a query level share one namespace, even when the
109 // binder keeps the left inputs of a lateral factor in separate contexts.
110 if found.is_some() {
111 return Err(match &table_name {
112 Some(table_name) => ErrorCode::InvalidReference(format!(
113 "table reference \"{}\" is ambiguous",
114 table_name
115 )),
116 None => ErrorCode::InvalidReference(format!(
117 "column reference \"{}\" is ambiguous",
118 column_name
119 )),
120 }
121 .into());
122 }
123 found = Some((context, indices, depth));
124 }
125 Err(e @ ErrorCode::ItemNotFound(_)) => err = e,
126 // An ambiguous name must not fall through to an outer scope.
127 Err(e) => return Err(e.into()),
128 }
129 }
130
131 if let Some((context, mut indices, depth)) = found {
132 indices.sort(); // make sure we have a consistent result
133 let mut inputs = indices
134 .iter()
135 .map(|index| {
136 let column = &context.columns[*index];
137 CorrelatedInputRef::new(column.index, column.field.data_type.clone(), depth)
138 .into()
139 })
140 .collect::<Vec<ExprImpl>>();
141 return if inputs.len() == 1 {
142 Ok(inputs.pop().unwrap())
143 } else {
144 // An unqualified reference to a column merged by `NATURAL`/`USING` join.
145 Ok(FunctionCall::new(ExprType::Coalesce, inputs)?.into())
146 };
147 }
148 }
149
150 // `CTID` is a system column in postgres.
151 // https://www.postgresql.org/docs/current/ddl-system-columns.html
152 //
153 // We return an empty string here to support some tools such as DataGrip.
154 //
155 // FIXME: The type of `CTID` should be `tid`.
156 // FIXME: The `CTID` column should be unique, so literal may break something.
157 // FIXME: At least we should add a notice here.
158 if let ErrorCode::ItemNotFound(_) = err
159 && column_name == "ctid"
160 {
161 return Ok(Literal::new(Some("".into()), DataType::Varchar).into());
162 }
163
164 // Failed to resolve the column in current context. Now check if it's a sql udf parameter.
165 if let ErrorCode::ItemNotFound(_) = err
166 && self.is_binding_subquery_sql_udf()
167 {
168 return self.bind_sql_udf_parameter(&column_name);
169 }
170
171 Err(err.into())
172 }
173
174 /// Return visible outer column contexts grouped by name-resolution scope, innermost first.
175 /// Each context is paired with the semantic correlation depth at which it is owned.
176 ///
177 /// An upper query context and its visible lateral contexts are the `FROM` items of one query
178 /// level, so they form one scope: a name found in more than one of them is ambiguous rather
179 /// than resolved to whichever context comes first.
180 ///
181 /// A non-empty lateral context represents the left input of a potential `Apply`, so it adds a
182 /// depth boundary. Empty contexts are parser/binder isolation frames and do not. An upper
183 /// query or table-function context always contributes at least one boundary, even if its local
184 /// `FROM` context is empty.
185 fn correlation_scopes(&self) -> Vec<Vec<(&crate::binder::BindContext, usize)>> {
186 let mut scopes = vec![];
187 let mut depth = 1;
188
189 let mut scope = vec![];
190 for lateral_context in self.lateral_contexts.iter().rev() {
191 if lateral_context.is_visible {
192 scope.push((&lateral_context.context, depth));
193 }
194 if !lateral_context.context.columns.is_empty() {
195 depth += 1;
196 }
197 }
198 scopes.push(scope);
199
200 for (context, lateral_contexts) in self.visible_upper_subquery_contexts_rev() {
201 let entry_depth = depth;
202 let mut scope = vec![(context, depth)];
203 if !context.columns.is_empty() {
204 depth += 1;
205 }
206
207 for lateral_context in lateral_contexts.iter().rev() {
208 if lateral_context.is_visible {
209 scope.push((&lateral_context.context, depth));
210 }
211 if !lateral_context.context.columns.is_empty() {
212 depth += 1;
213 }
214 }
215
216 depth = depth.max(entry_depth + 1);
217 scopes.push(scope);
218 }
219
220 scopes
221 }
222}