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