1mod analysis;
15pub mod catalog_sources;
16mod command_scopes;
17mod commands;
18pub mod composite_dependencies;
19mod composite_inputs;
20pub mod composite_rename;
21mod cte_controls;
22mod ctes;
23mod dependencies;
24pub mod legacy_patterns;
25mod merge_scopes;
26mod ordered_calls;
27mod preparation;
28mod projection;
29mod record_fields;
30mod routine_binding;
31mod routine_parameters;
32mod scope;
33mod source_schemas;
34mod sources;
35pub mod statements;
36mod type_resolution;
37mod variable_sites;
38
39pub use commands::analyze_prepared_command_schema;
40pub use preparation::{analyze_column_type_transform, infer_prepared_parameter_types};
41pub(crate) use preparation::{
42 analyze_default_inputs, analyze_routine_body_argument, analyze_routine_body_inputs,
43 prepare_routine_body_inputs,
44};
45pub(crate) use preparation::{
46 analyze_domain_check, analyze_stored_expression_inputs, analyze_table_check,
47 read_prepared_inputs,
48};
49
50#[cfg(test)]
51mod tests;
52
53pub use cte_controls::{analyze_recursive_control_step, extend_cte_generated_schema};
54pub use projection::{
55 analyze_projection_output_schema, bind_projection_output_schema,
56 validate_query_block_expression_types, validate_query_block_references,
57};
58pub use routine_binding::{
59 bind_expression_plan_routines_for_storage, bind_query_plan_routines_for_storage,
60 bind_syntax_query_plan_routines,
61};
62pub use routine_parameters::{bind_routine_parameter_references, RoutineParameterScope};
63pub use scope::{
64 analyze_expression_plan_type, analyze_query_plan_schema,
65 analyze_query_plan_schema_with_catalog, bind_expression_plan_type, bind_query_plan_schema,
66};
67pub use scope::{overlay_outer_schema, values_schema_in_scope, values_types_in_scope};
68pub use sources::{
69 analyze_source_plan_schema, bind_source_plan_schema, bind_source_plan_schema_for_execution,
70 with_query_table_pseudo_columns,
71};
72pub use variable_sites::{resolve_variable_sites, VariableSiteResolution};
73
74use catalog_sources::operator_join_relation_schemas;
75use cte_controls::extend_recursive_cte_binding_schema;
76pub use cte_controls::hide_recursive_generated_schema;
77use projection::{projection_star_columns, rename_schema};
78use sources::{alias_table_schema, table_function_member_source, JoinSchemaBinding};
79use type_resolution::QueryFunctionTypeResolver;
80
81use crate::plan::{QueryBlockPlan, QueryPlan, RelationalPlan, SourcePlan};
82use crate::semantics::{cte_references_own_name, expr_contains_subquery, projection_columns};
83use crate::{SQLError, SQLParam, ScalarExpr};
84use catalog_sources::user_function_output_columns;
85pub use context::BindingContext;
86
87pub mod context;
88mod rule_inputs;
89use crate::ast::ColumnType;
90use crate::catalog::analysis::CatalogReadView;
91use crate::catalog::resolution::RelationNameResolution;
92use crate::routines::RoutineResolution;
93use crate::semantics::{
94 apply_table_function_aliases, table_function_column_types, table_function_empty_schema,
95 validate_table_function_alias_count, validate_table_function_column_definition,
96 TableFunctionTypeRequest,
97};
98use crate::RowSchema;
99use std::collections::{BTreeMap, BTreeSet};
100
101#[derive(Clone, Copy)]
102enum ScalarBindingMode {
103 References,
104 Stored,
105 CompositeInputs,
106}
107
108struct SchemaScope {
109 collations: preparation::PendingCollations,
110 catalog: CatalogReadView,
111 resolution: RelationNameResolution,
112 ctes: BTreeMap<String, RowSchema>,
113 deferred_ctes: BTreeMap<String, crate::plan::CtePlan>,
114 non_returning_ctes: BTreeSet<String>,
115 visiting_views: BTreeSet<String>,
116 validate_references: bool,
117 stored_expression_outer: Option<RowSchema>,
118 rule_condition_event: Option<crate::ast::RuleEvent>,
119 merge_returning: bool,
121 stored_whole_rows: BTreeMap<String, ScalarExpr>,
122 routine_parameters: Option<RoutineParameterScope>,
124 scalar_binding: ScalarBindingMode,
126 variable_sites: Option<variable_sites::VariableSites>,
128 preserve_syntax_shape: bool,
130 prepared_dependencies: Option<crate::prepared::dependencies::PreparedAnalysisDependencies>,
131 composite_dependencies: Option<Vec<crate::catalog::dependencies::ObjectAddress>>,
132}
133
134fn non_returning_cte_error(name: &str) -> SQLError {
135 SQLError::Unsupported(format!(
136 "WITH query \"{name}\" does not have a RETURNING clause"
137 ))
138}
139
140impl SchemaScope {
141 fn from_context(ctes: &BindingContext) -> Result<Self, SQLError> {
142 Ok(Self {
143 collations: preparation::PendingCollations::default(),
144 catalog: ctes.catalog.clone(),
145 resolution: ctes.resolution.clone(),
146 ctes: ctes.ctes.clone(),
147 deferred_ctes: ctes.deferred_ctes.clone(),
148 non_returning_ctes: ctes.non_returning_ctes.clone(),
149 visiting_views: BTreeSet::new(),
150 validate_references: false,
151 stored_expression_outer: None,
152 rule_condition_event: None,
153 merge_returning: false,
154 stored_whole_rows: BTreeMap::new(),
155 routine_parameters: None,
156 scalar_binding: ScalarBindingMode::Stored,
157 variable_sites: None,
158 preserve_syntax_shape: false,
159 prepared_dependencies: None,
160 composite_dependencies: None,
161 })
162 }
163
164 fn for_analysis(ctes: &BindingContext) -> Result<Self, SQLError> {
165 let mut scope = Self::from_context(ctes)?;
166 scope.validate_references = true;
167 Ok(scope)
168 }
169
170 fn for_catalog_analysis(catalog: CatalogReadView, resolution: RelationNameResolution) -> Self {
171 Self {
172 collations: preparation::PendingCollations::default(),
173 catalog,
174 resolution,
175 ctes: BTreeMap::new(),
176 deferred_ctes: BTreeMap::new(),
177 non_returning_ctes: BTreeSet::new(),
178 visiting_views: BTreeSet::new(),
179 validate_references: true,
180 stored_expression_outer: None,
181 rule_condition_event: None,
182 merge_returning: false,
183 stored_whole_rows: BTreeMap::new(),
184 routine_parameters: None,
185 scalar_binding: ScalarBindingMode::Stored,
186 variable_sites: None,
187 preserve_syntax_shape: false,
188 prepared_dependencies: None,
189 composite_dependencies: None,
190 }
191 }
192
193 fn bind_query(
194 &mut self,
195 routines: &dyn RoutineResolution,
196 plan: &QueryPlan,
197 params: &[SQLParam],
198 outer: Option<&RowSchema>,
199 ) -> Result<RowSchema, SQLError> {
200 let lookup_mode = if plan.relations_bound {
201 crate::catalog::resolution::RelationLookupMode::Bound
202 } else {
203 crate::catalog::resolution::RelationLookupMode::Dynamic
204 };
205 let previous = self.resolution.set_lookup_mode(lookup_mode);
206 let result = self.bind_query_inner(routines, plan, params, outer);
207 self.resolution.set_lookup_mode(previous);
208 result
209 }
210
211 fn bind_query_inner(
212 &mut self,
213 routines: &dyn RoutineResolution,
214 plan: &QueryPlan,
215 params: &[SQLParam],
216 outer: Option<&RowSchema>,
217 ) -> Result<RowSchema, SQLError> {
218 let previous = self.bind_cte_schemas(routines, &plan.ctes, params, outer)?;
219
220 let result = self.bind_root(routines, &plan.root, params, outer);
221 self.restore_cte_schemas(previous);
222 let output = result?;
223 self.collations.validate_query(plan)?;
224 Ok(output)
225 }
226
227 fn bind_recursive_seed(
228 &mut self,
229 routines: &dyn RoutineResolution,
230 plan: &QueryPlan,
231 params: &[SQLParam],
232 outer: Option<&RowSchema>,
233 ) -> Result<RowSchema, SQLError> {
234 match &plan.root {
235 RelationalPlan::SetOp { left, .. } => self.bind_query(routines, left, params, outer),
236 _ => self.bind_root(routines, &plan.root, params, outer),
237 }
238 }
239
240 fn bind_root(
241 &mut self,
242 routines: &dyn RoutineResolution,
243 root: &RelationalPlan,
244 params: &[SQLParam],
245 outer: Option<&RowSchema>,
246 ) -> Result<RowSchema, SQLError> {
247 match root {
248 RelationalPlan::QueryBlock(block) => {
249 self.bind_query_block(routines, block, params, outer)
250 }
251 RelationalPlan::SetOp { .. } => {
252 preparation::set_metadata(self, routines, root, outer, params)
253 }
254 RelationalPlan::Values { rows, subqueries } => {
255 self.bind_values_schema(routines, rows, subqueries, outer, params)
256 }
257 }
258 }
259
260 fn bind_query_block(
261 &mut self,
262 routines: &dyn RoutineResolution,
263 block: &QueryBlockPlan,
264 params: &[SQLParam],
265 outer: Option<&RowSchema>,
266 ) -> Result<RowSchema, SQLError> {
267 let source = block.from.as_ref().map_or_else(
268 || Ok(RowSchema::default()),
269 |source| self.bind_source(routines, source, &block.subqueries, params, outer),
270 )?;
271 let source = if self.validate_references {
272 analysis::with_query_source_columns(&source, block)
273 } else {
274 source
275 };
276 let expression_schema = overlay_outer_schema(&source, outer);
277 let output = preparation::block_metadata(self, routines, block, &source, outer, params)?;
278 let output = analysis::with_projected_open_columns(&output, &block.projections, &source);
279 if self.validate_references {
280 self.validate_query_block_clauses(
281 routines,
282 block,
283 &expression_schema,
284 &output,
285 params,
286 outer,
287 )?;
288 }
289 Ok(output)
290 }
291
292 fn bind_expression_type(
293 &mut self,
294 routines: &dyn RoutineResolution,
295 expression: &ScalarExpr,
296 schema: &RowSchema,
297 subqueries: &[QueryPlan],
298 params: &[SQLParam],
299 ) -> Result<Option<ColumnType>, SQLError> {
300 if let ScalarExpr::ScalarSubquery(index) = expression {
301 let plan = subqueries.get(*index).ok_or_else(|| {
302 SQLError::Internal(format!("scalar subquery slot {index} is out of bounds"))
303 })?;
304 let subquery_outer = Some(schema);
306 let output = self.bind_query(routines, plan, params, subquery_outer)?;
307 return Ok(output.column_type(0).cloned());
308 }
309 let schema = self.with_stored_outer_internal_aliases(schema);
310 let schema = &schema;
311 let resolver =
312 self.query_function_type_resolver(routines, expression, schema, subqueries, params)?;
313 if self.validate_references {
314 Self::validate_expression_references_with_resolver(
315 self.rule_condition_event,
316 routines,
317 expression,
318 schema,
319 None,
320 params,
321 &resolver,
322 )?;
323 }
324 crate::type_resolution::validate_catalog_literals(expression, schema, params, &resolver)?;
325 crate::scalar_type_with_resolver(expression, schema, params, &resolver)
326 }
327
328 fn bind_projection_metadata(
329 &mut self,
330 routines: &dyn RoutineResolution,
331 expression: &ScalarExpr,
332 schema: &RowSchema,
333 subqueries: &[QueryPlan],
334 params: &[SQLParam],
335 ) -> Result<projection::ProjectionMetadata, SQLError> {
336 let schema = self.with_stored_outer_internal_aliases(schema);
337 preparation::projection_metadata(self, routines, expression, &schema, subqueries, params)
338 }
339
340 #[expect(
341 clippy::too_many_lines,
342 reason = "preserves SELECT schema and row identity"
343 )]
344 fn bind_source_inner(
345 &mut self,
346 routines: &dyn RoutineResolution,
347 source: &SourcePlan,
348 subqueries: &[QueryPlan],
349 params: &[SQLParam],
350 outer: Option<&RowSchema>,
351 ) -> Result<RowSchema, SQLError> {
352 match source {
353 SourcePlan::Table {
354 name,
355 qualifier,
356 alias,
357 column_aliases,
358 bound_columns,
359 ..
360 } => {
361 let qualifier = alias.as_deref().unwrap_or(qualifier);
362 let cte_name = crate::semantics::cte_reference_name(name);
363 if let Some(schema) = cte_name.as_ref().and_then(|name| self.ctes.get(name)) {
364 if let Some(name) = cte_name
365 .as_ref()
366 .filter(|name| self.non_returning_ctes.contains(*name))
367 {
368 return Err(non_returning_cte_error(name));
369 }
370 return alias_table_schema(schema, qualifier, column_aliases);
371 }
372 if let Some(plan) = cte_name
373 .as_ref()
374 .and_then(|name| self.deferred_ctes.get(name))
375 {
376 if !plan.body.returns_rows() {
377 return Err(non_returning_cte_error(&plan.name));
378 }
379 }
380 if let Some(plan) = cte_name.and_then(|name| self.deferred_ctes.remove(&name)) {
381 let result = self
382 .bind_cte_body(routines, &plan.body, params, outer)
383 .and_then(|schema| {
384 let schema = rename_schema(&schema, &plan.columns, Some(qualifier));
385 alias_table_schema(&schema, qualifier, column_aliases)
386 });
387 self.deferred_ctes.insert(plan.name.clone(), plan);
388 return result;
389 }
390 if self.catalog.sequence_exists(&self.resolution, name)? {
391 self.record_relation_dependency(name)?;
392 let schema = RowSchema::with_qualified_types(
393 qualifier,
394 vec!["last_value".into(), "log_cnt".into(), "is_called".into()],
395 vec![
396 Some(ColumnType::BigInteger),
397 Some(ColumnType::BigInteger),
398 Some(ColumnType::Boolean),
399 ],
400 );
401 return self.alias_relation_schema(&schema, name, qualifier, column_aliases);
402 }
403 let view = self.catalog.view_resolved(&self.resolution, name)?;
404 if let Some(view) = view {
405 self.record_relation_dependency(name)?;
406 if view.materialized {
407 let columns = view.output_columns.unwrap_or_default();
408 if columns.len() != view.materialized_column_types.len() {
409 return Err(SQLError::Internal(format!(
410 "materialized view `{name}` has {} columns but {} stored column types",
411 columns.len(),
412 view.materialized_column_types.len()
413 )));
414 }
415 let schema = crate::catalog::view::materialized_view_schema(
416 &columns,
417 &view.materialized_column_types,
418 view.materialized_column_collations.as_deref(),
419 )?;
420 let schema = RowSchema::with_relation_qualifier(&schema, qualifier);
421 return self.alias_relation_schema(
422 &schema,
423 name,
424 qualifier,
425 column_aliases,
426 );
427 }
428 let key = name.to_ascii_lowercase();
429 if !self.visiting_views.insert(key.clone()) {
430 return Err(SQLError::Internal(format!(
431 "view `{name}` has a recursive schema dependency"
432 )));
433 }
434 self.record_stored_query_dependencies(&view.query);
435 let result = self
436 .bind_query(routines, &view.query, params, outer)
437 .and_then(|schema| {
438 let schema = rename_schema(
439 &schema,
440 view.output_columns.as_deref().unwrap_or(&[]),
441 Some(qualifier),
442 );
443 self.alias_relation_schema(&schema, name, qualifier, column_aliases)
444 });
445 self.visiting_views.remove(&key);
446 return result;
447 }
448 let table = self.catalog.table_resolved(&self.resolution, name)?;
449 if let Some(table) = table {
450 self.record_relation_dependency(name)?;
451 let schema =
452 RowSchema::with_column_definitions(Some(qualifier), &table.columns);
453 let schema =
454 crate::semantics::bound_source_schema(&schema, bound_columns.as_deref())?;
455 let schema =
456 self.alias_relation_schema(&schema, name, qualifier, column_aliases)?;
457 let schema = if table.columns.is_empty() && !table.columns_declared {
458 RowSchema::with_open_columns(&schema, Some(qualifier))
459 } else {
460 schema
461 };
462 return Ok(analysis::with_table_pseudo_columns(&schema, qualifier));
463 }
464 let foreign_table = self
465 .catalog
466 .foreign_table_resolved(&self.resolution, name)?;
467 if let Some(foreign_table) = foreign_table {
468 self.record_relation_dependency(name)?;
469 let schema =
470 RowSchema::with_column_definitions(Some(qualifier), &foreign_table.columns);
471 let schema =
472 crate::semantics::bound_source_schema(&schema, bound_columns.as_deref())?;
473 return self.alias_relation_schema(&schema, name, qualifier, column_aliases);
474 }
475 if let Some(schema) = self
476 .catalog
477 .virtual_relation_schema(&self.resolution, name)?
478 {
479 self.record_relation_dependency(name)?;
480 let (columns, types): (Vec<_>, Vec<_>) = schema
481 .into_iter()
482 .map(|(column, ty)| (column, Some(ty)))
483 .unzip();
484 let schema = RowSchema::with_qualified_types(qualifier, columns, types);
485 return self.alias_relation_schema(&schema, name, qualifier, column_aliases);
486 }
487 if let Some(relation) = self.catalog.unopenable_relation(&self.resolution, name)? {
488 return Err(relation.error());
489 }
490 Err(SQLError::UnknownTable(name.clone()))
491 }
492 SourcePlan::Values {
493 rows,
494 alias,
495 column_aliases,
496 ..
497 } => {
498 if let Some(schema) = source.internal_values_schema()? {
499 return Ok(schema);
500 }
501 let schema = self.bind_values_schema(routines, rows, subqueries, outer, params)?;
502 Ok(rename_schema(&schema, column_aliases, alias.as_deref()))
503 }
504 SourcePlan::Function {
505 name,
506 binding,
507 output_name,
508 relations,
509 args,
510 alias,
511 column_aliases,
512 ordinality,
513 column_types,
514 ..
515 } => {
516 let lower = crate::semantics::builtin_function_dispatch_name(name);
517 let operator_join = crate::registry::is_operator_join_table_function(&lower);
518 let operator_inputs = operator_join
519 .then(|| {
520 operator_join_relation_schemas(
521 &self.catalog,
522 &self.resolution,
523 relations.as_ref(),
524 )
525 })
526 .transpose()?;
527 let input = outer.cloned().unwrap_or_default();
528 let type_resolver = self.query_function_type_resolver_for_subqueries(
529 routines, args, &input, subqueries, params,
530 )?;
531 let user_function = if let Some((left, right)) = operator_inputs.as_ref() {
532 if self.validate_references {
533 let constant = RowSchema::default();
534 for (position, argument) in args.iter().enumerate() {
535 let schema = match position {
536 0 => left,
537 1 => right,
538 _ => &constant,
539 };
540 self.validate_expression_references(
541 routines, argument, schema, None, subqueries, params,
542 )?;
543 }
544 }
545 None
546 } else if self.validate_references {
547 self.validate_table_function_source(
548 routines,
549 analysis::TableFunctionSourceValidation {
550 name,
551 binding: binding.as_ref(),
552 args,
553 subqueries,
554 input: &input,
555 params,
556 },
557 )?
558 } else {
559 crate::semantics::resolve_user_table_function(
560 routines,
561 name,
562 binding.as_ref(),
563 args,
564 &input,
565 params,
566 &type_resolver,
567 )?
568 };
569 validate_table_function_column_definition(
570 name,
571 binding.as_ref(),
572 user_function
573 .as_ref()
574 .map(|resolved| resolved.function.as_ref()),
575 column_types,
576 )?;
577 if let Some(function) = &user_function {
578 self.record_routine_dependency(&function.binding);
579 }
580 let catalog_columns = if !self.validate_references && user_function.is_none() {
581 user_function_output_columns(self.catalog.as_ref(), &self.resolution, name)?
582 } else {
583 None
584 };
585 let columns = user_function
586 .as_ref()
587 .map(|resolved| {
588 crate::semantics::user_function_composite_result(
589 routines,
590 &resolved.function,
591 resolved.binding.invocation.as_deref(),
592 )
593 .map(|descriptor| {
594 descriptor
595 .map(|descriptor| {
596 descriptor
597 .attributes
598 .iter()
599 .map(|attribute| attribute.name.clone())
600 .collect()
601 })
602 .or_else(|| {
603 crate::semantics::user_function_output_columns_for(
604 &resolved.function,
605 )
606 })
607 })
608 })
609 .transpose()?
610 .flatten()
611 .or(catalog_columns)
612 .map_or_else(
613 || {
614 table_function_empty_schema(
615 name,
616 output_name,
617 alias.as_deref(),
618 column_aliases,
619 args.len(),
620 *ordinality,
621 )
622 },
623 |columns| {
624 apply_table_function_aliases(columns, column_aliases, *ordinality)
625 },
626 );
627 validate_table_function_alias_count(
628 alias.as_deref().unwrap_or(output_name),
629 columns.len(),
630 column_aliases.len(),
631 )?;
632 let types = table_function_column_types(
633 routines,
634 TableFunctionTypeRequest {
635 name,
636 binding: binding.as_ref(),
637 args,
638 user_function: user_function
639 .as_ref()
640 .map(|resolved| resolved.function.as_ref()),
641 user_invocation: user_function
642 .as_ref()
643 .and_then(|resolved| resolved.binding.invocation.as_deref()),
644 declared_types: column_types,
645 columns: &columns,
646 ordinality: *ordinality,
647 },
648 &input,
649 params,
650 &type_resolver,
651 );
652 let qualifier = alias.as_deref().unwrap_or(output_name);
653 let schema = RowSchema::with_qualified_types(qualifier, columns, types);
654 Ok(
655 if user_function.is_none()
656 && column_types.is_empty()
657 && routines.has_registered_table_function(name)
658 {
659 RowSchema::with_open_columns(&schema, Some(qualifier))
660 } else {
661 schema
662 },
663 )
664 }
665 SourcePlan::FunctionGroup {
666 functions,
667 alias,
668 column_aliases,
669 ordinality,
670 } => {
671 let first = functions
672 .first()
673 .ok_or_else(|| SQLError::Internal("ROWS FROM group has no functions".into()))?;
674 let mut columns = Vec::new();
675 let mut types = Vec::new();
676 let mut open = false;
677 for function in functions {
678 let member = table_function_member_source(function);
679 let schema = self.bind_source(routines, &member, subqueries, params, outer)?;
680 open |= schema.columns_are_open(None);
681 columns.extend(schema.iter().enumerate().map(|(position, column)| {
682 schema.public_name(position).unwrap_or(column).to_string()
683 }));
684 types.extend(schema.column_types().iter().cloned());
685 }
686 if *ordinality {
687 columns.push("ordinality".into());
688 types.push(Some(ColumnType::BigInteger));
689 }
690 let qualifier = alias.as_deref().unwrap_or(&first.output_name);
691 validate_table_function_alias_count(
692 qualifier,
693 columns.len(),
694 column_aliases.len(),
695 )?;
696 for (column, alias) in columns.iter_mut().zip(column_aliases) {
697 column.clone_from(alias);
698 }
699 let schema = RowSchema::with_qualified_types(qualifier, columns, types);
700 Ok(if open {
701 RowSchema::with_open_columns(&schema, Some(qualifier))
702 } else {
703 schema
704 })
705 }
706 SourcePlan::Subquery {
707 body,
708 alias,
709 column_aliases,
710 } => {
711 let schema = self.bind_query(routines, body, params, outer)?;
712 Ok(rename_schema(&schema, column_aliases, alias.as_deref()))
713 }
714 SourcePlan::Join {
715 left,
716 right,
717 kind,
718 on,
719 using,
720 natural,
721 alias,
722 column_aliases,
723 lateral,
724 ..
725 } => {
726 let left_schema = self.bind_source(routines, left, subqueries, params, outer)?;
727 let implicit_lateral_function = matches!(
728 right.as_ref(),
729 SourcePlan::Function { .. } | SourcePlan::FunctionGroup { .. }
730 );
731 let right_scope = (*lateral || implicit_lateral_function)
732 .then(|| overlay_outer_schema(&left_schema, outer));
733 let right_schema = self.bind_source(
734 routines,
735 right,
736 subqueries,
737 params,
738 right_scope.as_ref().or(outer),
739 )?;
740 self.bind_join_output_schema(JoinSchemaBinding {
741 routines,
742 kind: *kind,
743 on: on.as_ref(),
744 using: using.as_ref(),
745 natural: *natural,
746 alias: alias.as_deref(),
747 column_aliases,
748 left: &left_schema,
749 right: &right_schema,
750 subqueries,
751 params,
752 outer,
753 })
754 }
755 }
756 }
757}
758
759#[cfg(test)]
760pub(crate) mod fixture;
761
762pub mod correlation;
763
764pub mod stored_columns;
765pub mod stored_relations;
766pub mod stored_routines;
767pub mod stored_types;
768pub mod syntax_sites;
769
770pub mod scoped_types;
771pub mod snapshot;
772
773pub mod view_dependencies;
774
775pub mod portals;