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