1use std::collections::hash_map::Entry;
16use std::ops::Deref;
17
18use itertools::{EitherOrBoth, Itertools};
19use risingwave_common::bail;
20use risingwave_common::catalog::{Field, TableId};
21use risingwave_sqlparser::ast::{
22 AsOf, Expr as ParserExpr, FunctionArg, FunctionArgExpr, Ident, ObjectName, TableAlias,
23 TableFactor,
24};
25use thiserror::Error;
26use thiserror_ext::AsReport;
27
28use super::bind_context::ColumnBinding;
29use super::statement::RewriteExprsRecursive;
30use crate::binder::Binder;
31use crate::binder::bind_context::{BindingCte, BindingCteState};
32use crate::error::{ErrorCode, Result, RwError};
33use crate::expr::{ExprImpl, InputRef};
34
35mod gap_fill;
36mod join;
37mod share;
38mod subquery;
39mod table_function;
40mod table_or_source;
41mod watermark;
42mod window_table_function;
43
44pub use gap_fill::BoundGapFill;
45pub use join::BoundJoin;
46pub use share::{BoundShare, BoundShareInput};
47pub use subquery::BoundSubquery;
48pub use table_or_source::{
49 BoundBaseTable, BoundIcebergMetadataTable, BoundSource, BoundSystemTable,
50};
51pub use watermark::BoundWatermark;
52pub use window_table_function::{BoundWindowTableFunction, WindowTableFunctionKind};
53
54use crate::expr::{CorrelatedId, Depth};
55
56#[derive(Debug, Clone)]
59pub enum Relation {
60 Source(Box<BoundSource>),
61 BaseTable(Box<BoundBaseTable>),
62 SystemTable(Box<BoundSystemTable>),
63 IcebergMetadataTable(Box<BoundIcebergMetadataTable>),
64 Subquery(Box<BoundSubquery>),
65 Join(Box<BoundJoin>),
66 Apply(Box<BoundJoin>),
67 WindowTableFunction(Box<BoundWindowTableFunction>),
68 TableFunction {
70 expr: ExprImpl,
71 with_ordinality: bool,
72 },
73 Watermark(Box<BoundWatermark>),
74 Share(Box<BoundShare>),
75 GapFill(Box<BoundGapFill>),
76}
77
78impl RewriteExprsRecursive for Relation {
79 fn rewrite_exprs_recursive(&mut self, rewriter: &mut impl crate::expr::ExprRewriter) {
80 match self {
81 Relation::Subquery(inner) => inner.rewrite_exprs_recursive(rewriter),
82 Relation::Join(inner) => inner.rewrite_exprs_recursive(rewriter),
83 Relation::Apply(inner) => inner.rewrite_exprs_recursive(rewriter),
84 Relation::WindowTableFunction(inner) => inner.rewrite_exprs_recursive(rewriter),
85 Relation::Watermark(inner) => inner.rewrite_exprs_recursive(rewriter),
86 Relation::Share(inner) => inner.rewrite_exprs_recursive(rewriter),
87 Relation::TableFunction { expr: inner, .. } => {
88 *inner = rewriter.rewrite_expr(inner.take())
89 }
90 _ => {}
91 }
92 }
93}
94
95impl Relation {
96 pub fn is_correlated_by_depth(&self, depth: Depth) -> bool {
97 match self {
98 Relation::Subquery(subquery) => subquery.query.is_correlated_by_depth(depth),
99 Relation::Join(join) => {
100 join.cond.has_correlated_input_ref_by_depth(depth)
101 || join.left.is_correlated_by_depth(depth)
102 || join.right.is_correlated_by_depth(depth)
103 }
104 Relation::Apply(join) => {
107 join.cond.has_correlated_input_ref_by_depth(depth)
108 || join.left.is_correlated_by_depth(depth)
109 || join.right.is_correlated_by_depth(depth + 1)
110 }
111 Relation::TableFunction {
112 expr: table_function,
113 with_ordinality: _,
114 } => table_function.has_correlated_input_ref_by_depth(depth + 1),
115 Relation::Share(share) => match &share.input {
116 BoundShareInput::Query(query) => query.is_correlated_by_depth(depth),
117 BoundShareInput::ChangeLog(change_log) => change_log.is_correlated_by_depth(depth),
118 },
119 _ => false,
120 }
121 }
122
123 pub fn is_correlated_by_correlated_id(&self, correlated_id: CorrelatedId) -> bool {
124 match self {
125 Relation::Subquery(subquery) => {
126 subquery.query.is_correlated_by_correlated_id(correlated_id)
127 }
128 Relation::Join(join) | Relation::Apply(join) => {
129 join.cond
130 .has_correlated_input_ref_by_correlated_id(correlated_id)
131 || join.left.is_correlated_by_correlated_id(correlated_id)
132 || join.right.is_correlated_by_correlated_id(correlated_id)
133 }
134 Relation::TableFunction {
135 expr: table_function,
136 with_ordinality: _,
137 } => table_function.has_correlated_input_ref_by_correlated_id(correlated_id),
138 Relation::Share(share) => match &share.input {
139 BoundShareInput::Query(query) => {
140 query.is_correlated_by_correlated_id(correlated_id)
141 }
142 BoundShareInput::ChangeLog(change_log) => {
143 change_log.is_correlated_by_correlated_id(correlated_id)
144 }
145 },
146 _ => false,
147 }
148 }
149
150 pub fn collect_correlated_indices_by_depth_and_assign_id(
151 &mut self,
152 depth: Depth,
153 correlated_id: CorrelatedId,
154 ) -> Vec<usize> {
155 match self {
156 Relation::Subquery(subquery) => subquery
157 .query
158 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
159 Relation::Join(join) => {
160 let mut correlated_indices = vec![];
161 correlated_indices.extend(
162 join.cond
163 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
164 );
165 correlated_indices.extend(
166 join.left
167 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
168 );
169 correlated_indices.extend(
170 join.right
171 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
172 );
173 correlated_indices
174 }
175 Relation::Apply(join) => {
176 let mut correlated_indices = vec![];
177 correlated_indices.extend(
178 join.cond
179 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
180 );
181 correlated_indices.extend(
182 join.left
183 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
184 );
185 correlated_indices.extend(
186 join.right
187 .collect_correlated_indices_by_depth_and_assign_id(
188 depth + 1,
189 correlated_id,
190 ),
191 );
192 correlated_indices
193 }
194 Relation::TableFunction {
195 expr: table_function,
196 with_ordinality: _,
197 } => table_function
198 .collect_correlated_indices_by_depth_and_assign_id(depth + 1, correlated_id),
199 Relation::Share(share) => match &mut share.input {
200 BoundShareInput::Query(query) => {
201 query.collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id)
202 }
203 BoundShareInput::ChangeLog(change_log) => change_log
204 .collect_correlated_indices_by_depth_and_assign_id(depth, correlated_id),
205 },
206 _ => vec![],
207 }
208 }
209}
210
211#[derive(Debug)]
212#[non_exhaustive]
213pub enum ResolveQualifiedNameErrorKind {
214 QualifiedNameTooLong,
215 NotCurrentDatabase,
216}
217
218#[derive(Debug, Error)]
219pub struct ResolveQualifiedNameError {
220 qualified: String,
221 kind: ResolveQualifiedNameErrorKind,
222}
223
224impl std::fmt::Display for ResolveQualifiedNameError {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 match self.kind {
227 ResolveQualifiedNameErrorKind::QualifiedNameTooLong => write!(
228 f,
229 "improper qualified name (too many dotted names): {}",
230 self.qualified
231 ),
232 ResolveQualifiedNameErrorKind::NotCurrentDatabase => write!(
233 f,
234 "cross-database references are not implemented: \"{}\"",
235 self.qualified
236 ),
237 }
238 }
239}
240
241impl ResolveQualifiedNameError {
242 pub fn new(qualified: String, kind: ResolveQualifiedNameErrorKind) -> Self {
243 Self { qualified, kind }
244 }
245}
246
247impl From<ResolveQualifiedNameError> for RwError {
248 fn from(e: ResolveQualifiedNameError) -> Self {
249 ErrorCode::InvalidInputSyntax(format!("{}", e.as_report())).into()
250 }
251}
252
253impl Binder {
254 pub fn resolve_schema_qualified_name(
256 db_name: &str,
257 name: &ObjectName,
258 ) -> std::result::Result<(Option<String>, String), ResolveQualifiedNameError> {
259 let formatted_name = name.to_string();
260 let mut identifiers = name.0.clone();
261
262 if identifiers.len() > 3 {
263 return Err(ResolveQualifiedNameError::new(
264 formatted_name,
265 ResolveQualifiedNameErrorKind::QualifiedNameTooLong,
266 ));
267 }
268
269 let name = identifiers.pop().unwrap().real_value();
270
271 let schema_name = identifiers.pop().map(|ident| ident.real_value());
272 let database_name = identifiers.pop().map(|ident| ident.real_value());
273
274 if let Some(database_name) = database_name
275 && database_name != db_name
276 {
277 return Err(ResolveQualifiedNameError::new(
278 formatted_name,
279 ResolveQualifiedNameErrorKind::NotCurrentDatabase,
280 ));
281 }
282
283 Ok((schema_name, name))
284 }
285
286 pub fn validate_cross_db_reference(
288 db_name: &str,
289 name: &ObjectName,
290 ) -> std::result::Result<(), ResolveQualifiedNameError> {
291 let formatted_name = name.to_string();
292 let identifiers = &name.0;
293 if identifiers.len() > 3 {
294 return Err(ResolveQualifiedNameError::new(
295 formatted_name,
296 ResolveQualifiedNameErrorKind::QualifiedNameTooLong,
297 ));
298 }
299
300 if identifiers.len() == 3 && identifiers[0].real_value() != db_name {
301 return Err(ResolveQualifiedNameError::new(
302 formatted_name,
303 ResolveQualifiedNameErrorKind::NotCurrentDatabase,
304 ));
305 }
306
307 Ok(())
308 }
309
310 pub fn resolve_db_schema_qualified_name(
312 name: &ObjectName,
313 ) -> std::result::Result<(Option<String>, Option<String>, String), ResolveQualifiedNameError>
314 {
315 let formatted_name = name.to_string();
316 let mut identifiers = name.0.clone();
317
318 if identifiers.len() > 3 {
319 return Err(ResolveQualifiedNameError::new(
320 formatted_name,
321 ResolveQualifiedNameErrorKind::QualifiedNameTooLong,
322 ));
323 }
324
325 let name = identifiers.pop().unwrap().real_value();
326 let schema_name = identifiers.pop().map(|ident| ident.real_value());
327 let database_name = identifiers.pop().map(|ident| ident.real_value());
328
329 Ok((database_name, schema_name, name))
330 }
331
332 fn resolve_single_name(mut identifiers: Vec<Ident>, ident_desc: &str) -> Result<String> {
334 if identifiers.len() > 1 {
335 bail!("{} must contain 1 argument", ident_desc);
336 }
337 let name = identifiers.pop().unwrap().real_value();
338
339 Ok(name)
340 }
341
342 pub fn resolve_database_name(name: ObjectName) -> Result<String> {
344 Self::resolve_single_name(name.0, "database name")
345 }
346
347 pub fn resolve_schema_name(name: ObjectName) -> Result<String> {
349 Self::resolve_single_name(name.0, "schema name")
350 }
351
352 pub fn resolve_index_name(name: ObjectName) -> Result<String> {
354 Self::resolve_single_name(name.0, "index name")
355 }
356
357 pub fn resolve_view_name(name: ObjectName) -> Result<String> {
359 Self::resolve_single_name(name.0, "view name")
360 }
361
362 pub fn resolve_sink_name(name: ObjectName) -> Result<String> {
364 Self::resolve_single_name(name.0, "sink name")
365 }
366
367 pub fn resolve_subscription_name(name: ObjectName) -> Result<String> {
369 Self::resolve_single_name(name.0, "subscription name")
370 }
371
372 pub fn resolve_table_name(name: ObjectName) -> Result<String> {
374 Self::resolve_single_name(name.0, "table name")
375 }
376
377 pub fn resolve_source_name(name: ObjectName) -> Result<String> {
379 Self::resolve_single_name(name.0, "source name")
380 }
381
382 pub fn resolve_user_name(name: ObjectName) -> Result<String> {
384 Self::resolve_single_name(name.0, "user name")
385 }
386
387 pub(super) fn bind_table_to_context(
389 &mut self,
390 columns: impl IntoIterator<Item = (bool, Field)>, table_name: String,
392 schema_name: Option<String>,
393 alias: Option<&TableAlias>,
394 ) -> Result<()> {
395 const EMPTY: [Ident; 0] = [];
396 let (resolved_schema_name, table_name, column_aliases, table_alias) = match alias {
397 None => (schema_name.clone(), table_name, &EMPTY[..], None),
398 Some(TableAlias { name, columns }) => (
399 None,
400 name.real_value(),
401 columns.as_slice(),
402 Some(table_name),
403 ),
404 };
405
406 let num_col_aliases = column_aliases.len();
407
408 let begin = self.context.columns.len();
409 let mut alias_iter = column_aliases.iter().fuse();
412 let mut index = 0;
413 columns.into_iter().for_each(|(is_hidden, mut field)| {
414 let name = match is_hidden {
415 true => field.name.clone(),
416 false => alias_iter
417 .next()
418 .map(|t| t.real_value())
419 .unwrap_or_else(|| field.name.clone()),
420 };
421 field.name.clone_from(&name);
422 self.context.columns.push(ColumnBinding::new(
423 table_name.clone(),
424 schema_name.clone(),
425 table_alias.clone(),
426 begin + index,
427 is_hidden,
428 field,
429 ));
430 self.context
431 .indices_of
432 .entry(name)
433 .or_default()
434 .push(self.context.columns.len() - 1);
435 index += 1;
436 });
437
438 let num_cols = index;
439 if num_cols < num_col_aliases {
440 return Err(ErrorCode::BindError(format!(
441 "table \"{table_name}\" has {num_cols} columns available but {num_col_aliases} column aliases specified",
442 ))
443 .into());
444 }
445
446 match self
447 .context
448 .range_of
449 .entry((resolved_schema_name, table_name.clone()))
450 {
451 Entry::Occupied(_) => Err(ErrorCode::InternalError(format!(
452 "Duplicated table name while binding table to context: {}",
453 table_name
454 ))
455 .into()),
456 Entry::Vacant(entry) => {
457 entry.insert((begin, self.context.columns.len()));
458 Ok(())
459 }
460 }
461 }
462
463 pub fn bind_relation_by_name(
468 &mut self,
469 name: &ObjectName,
470 alias: Option<&TableAlias>,
471 as_of: Option<&AsOf>,
472 allow_cross_db: bool,
473 ) -> Result<Relation> {
474 let (db_name, schema_name, table_name) = if allow_cross_db {
475 Self::resolve_db_schema_qualified_name(name)?
476 } else {
477 let (schema_name, table_name) =
478 Self::resolve_schema_qualified_name(&self.db_name, name)?;
479 (None, schema_name, table_name)
480 };
481
482 if schema_name.is_none()
483 && let Some(item) = self.context.cte_to_relation.get(&table_name)
485 {
486 if as_of.is_some() {
489 return Err(ErrorCode::BindError(
490 "Right table of a temporal join should not be a CTE. \
491 It should be a table, index, or materialized view"
492 .to_owned(),
493 )
494 .into());
495 }
496
497 let BindingCte {
498 share_id,
499 state: cte_state,
500 alias: mut original_alias,
501 } = item.deref().borrow().clone();
502
503 debug_assert_eq!(original_alias.name.real_value(), table_name);
505
506 if let Some(from_alias) = alias {
507 original_alias.name = from_alias.name.clone();
508 original_alias.columns = original_alias
509 .columns
510 .into_iter()
511 .zip_longest(from_alias.columns.iter().cloned())
512 .map(EitherOrBoth::into_right)
513 .collect();
514 }
515
516 let exposed_table_name = original_alias.name.real_value();
517 self.context
518 .check_relation_name_conflict(&exposed_table_name)?;
519
520 match cte_state {
521 BindingCteState::Bound { query } => {
522 let input = BoundShareInput::Query(query);
523 self.bind_table_to_context(
524 input.fields()?,
525 table_name,
526 None,
527 Some(&original_alias),
528 )?;
529 self.context.add_cte_name(exposed_table_name);
530 Ok(Relation::Share(Box::new(BoundShare { share_id, input })))
533 }
534 BindingCteState::ChangeLog { table } => {
535 let input = BoundShareInput::ChangeLog(table);
536 self.bind_table_to_context(
537 input.fields()?,
538 table_name,
539 None,
540 Some(&original_alias),
541 )?;
542 self.context.add_cte_name(exposed_table_name);
543 Ok(Relation::Share(Box::new(BoundShare { share_id, input })))
544 }
545 }
546 } else {
547 let exposed_table_name = alias
548 .map(|alias| alias.name.real_value())
549 .unwrap_or_else(|| table_name.clone());
550 self.context.check_catalog_name(&exposed_table_name)?;
551 self.bind_catalog_relation_by_name(
552 db_name.as_deref(),
553 schema_name.as_deref(),
554 &table_name,
555 alias,
556 as_of,
557 false,
558 )
559 }
560 }
561
562 fn bind_relation_by_function_arg(
564 &mut self,
565 arg: Option<&FunctionArg>,
566 err_msg: &str,
567 ) -> Result<(Relation, ObjectName)> {
568 let Some(FunctionArg::Unnamed(FunctionArgExpr::Expr(expr))) = arg else {
569 return Err(ErrorCode::BindError(err_msg.to_owned()).into());
570 };
571 let table_name = match expr {
572 ParserExpr::Identifier(ident) => Ok::<_, RwError>(ObjectName(vec![ident.clone()])),
573 ParserExpr::CompoundIdentifier(idents) => Ok(ObjectName(idents.clone())),
574 _ => Err(ErrorCode::BindError(err_msg.to_owned()).into()),
575 }?;
576
577 Ok((
578 self.bind_relation_by_name(&table_name, None, None, true)?,
579 table_name,
580 ))
581 }
582
583 fn bind_column_by_function_args(
585 &mut self,
586 arg: Option<&FunctionArg>,
587 err_msg: &str,
588 ) -> Result<Box<InputRef>> {
589 if let Some(time_col_arg) = arg
590 && let Some(ExprImpl::InputRef(time_col)) =
591 self.bind_function_arg(time_col_arg)?.into_iter().next()
592 {
593 Ok(time_col)
594 } else {
595 Err(ErrorCode::BindError(err_msg.to_owned()).into())
596 }
597 }
598
599 fn bind_internal_table(
601 &mut self,
602 args: &[FunctionArg],
603 alias: Option<&TableAlias>,
604 ) -> Result<Relation> {
605 if args.is_empty() || args.len() > 2 {
606 return Err(
607 ErrorCode::BindError("usage: rw_table(table_id[,schema_name])".to_owned()).into(),
608 );
609 }
610
611 let table_id: TableId = args[0]
612 .to_string()
613 .parse::<u32>()
614 .map_err(|err| {
615 RwError::from(ErrorCode::BindError(format!(
616 "invalid table id: {}",
617 err.as_report()
618 )))
619 })?
620 .into();
621
622 let schema = args.get(1).map(|arg| arg.to_string());
623
624 let table_name = self.catalog.get_table_name_by_id(table_id)?;
625 self.bind_catalog_relation_by_name(None, schema.as_deref(), &table_name, alias, None, false)
626 }
627
628 pub(super) fn bind_table_factor(&mut self, table_factor: &TableFactor) -> Result<Relation> {
629 match table_factor {
630 TableFactor::Table { name, alias, as_of } => {
631 self.bind_relation_by_name(name, alias.as_ref(), as_of.as_ref(), true)
632 }
633 TableFactor::TableFunction {
634 name,
635 alias,
636 args,
637 with_ordinality,
638 } => {
639 let visibility = self.mark_lateral_contexts_visible();
640 let result = self.bind_table_function(name, alias.as_ref(), args, *with_ordinality);
641 self.restore_lateral_contexts_visibility(visibility);
642 result
643 }
644 TableFactor::Derived {
645 lateral,
646 subquery,
647 alias,
648 } => {
649 if *lateral {
650 let visibility = self.mark_lateral_contexts_visible();
651
652 let result = self.bind_subquery_relation(subquery, alias.as_ref(), true);
654
655 self.restore_lateral_contexts_visibility(visibility);
656 result.map(|subquery| Relation::Subquery(Box::new(subquery)))
657 } else {
658 self.push_lateral_context();
660 let bound_subquery =
661 self.bind_subquery_relation(subquery, alias.as_ref(), false)?;
662 self.pop_and_merge_lateral_context()?;
663 Ok(Relation::Subquery(Box::new(bound_subquery)))
664 }
665 }
666 TableFactor::NestedJoin(table_with_joins) => {
667 self.push_lateral_context();
668 let bound_join = self.bind_table_with_joins(table_with_joins)?;
669 self.pop_and_merge_lateral_context()?;
670 Ok(bound_join)
671 }
672 }
673 }
674}