1use super::{
10 cte_references_own_name, extend_cte_generated_schema, extend_recursive_cte_binding_schema,
11 operator_join_relation_schemas, overlay_outer_schema, rename_schema, BindingContext,
12 ColumnType, QueryPlan, RelationalPlan, RowSchema, SQLError, SQLParam, ScalarExpr, SchemaScope,
13 SourcePlan,
14};
15use crate::ast::FunctionBinding;
16use crate::plan::ExpressionPlan;
17use crate::routines::RoutineResolution;
18use crate::{ColumnIdentity, FunctionTypeResolver};
19
20impl SchemaScope {
21 pub(super) fn with_stored_outer_internal_aliases(&self, schema: &RowSchema) -> RowSchema {
22 self.stored_expression_outer.as_ref().map_or_else(
23 || schema.clone(),
24 |outer| {
25 if schema.physical_width() < outer.physical_width() {
26 schema.clone()
27 } else {
28 RowSchema::with_trailing_internal_aliases(schema, outer)
29 }
30 },
31 )
32 }
33
34 fn canonicalize_stored_outer_columns(&self, expression: &mut ScalarExpr, schema: &RowSchema) {
35 let Some(outer) = self.stored_expression_outer.as_ref() else {
36 return;
37 };
38 let Some(outer_start) = schema.physical_width().checked_sub(outer.physical_width()) else {
39 return;
40 };
41 crate::plan::rewrite_scalar_expression(expression, &mut |node| {
42 let lookup = match node {
43 ScalarExpr::Column(column) => ColumnIdentity::unqualified(column.as_str()),
44 ScalarExpr::QualifiedColumn { qualifier, column } => {
45 ColumnIdentity::qualified(qualifier.as_str(), column.as_str())
46 }
47 _ => return,
48 };
49 let Some(slot) = schema.physical_slot_for_identity(&lookup) else {
50 return;
51 };
52 if slot < outer_start {
53 return;
54 }
55 let outer_slot = slot - outer_start;
56 let Some(column) = outer.unique_internal_column_for_slot(outer_slot) else {
57 return;
58 };
59 *node = ScalarExpr::InternalColumn(column);
60 });
61 }
62
63 fn bind_cte_routines_for_storage(
64 &mut self,
65 routines: &dyn RoutineResolution,
66 body: &mut crate::plan::CtePlanBody,
67 params: &[SQLParam],
68 outer: Option<&RowSchema>,
69 ) -> Result<RowSchema, SQLError> {
70 let crate::plan::CtePlanBody::Command(command) = body else {
71 return self.bind_query_routines_for_storage(
72 routines,
73 body.query_mut().expect("query CTE body"),
74 params,
75 outer,
76 );
77 };
78 self.bind_command_routines_for_storage(routines, command, params, outer)?;
79 self.bind_command_returning(routines, command, params)
80 }
81
82 pub(super) fn bind_cte_routine_schemas(
83 &mut self,
84 routines: &dyn RoutineResolution,
85 ctes: &mut [crate::plan::CtePlan],
86 params: &[SQLParam],
87 outer: Option<&RowSchema>,
88 ) -> Result<Vec<(String, bool, Option<RowSchema>)>, SQLError> {
89 let ordered_names = crate::semantics::ordered_cte_plans(ctes)?
90 .into_iter()
91 .map(|cte| cte.name.clone())
92 .collect::<Vec<_>>();
93 let mut previous = Vec::with_capacity(ordered_names.len());
94 for name in ordered_names {
95 let position = ctes
96 .iter()
97 .position(|cte| cte.name == name)
98 .ok_or_else(|| SQLError::Internal(format!("ordered CTE `{name}` disappeared")))?;
99 let self_recursive = cte_references_own_name(&ctes[position]);
100 if let Some(cycle) = ctes[position].cycle.as_mut() {
101 let schema = RowSchema::default();
102 self.bind_scalar_routines_for_storage(
103 routines,
104 &mut cycle.mark_value,
105 &schema,
106 &[],
107 params,
108 )?;
109 self.bind_scalar_routines_for_storage(
110 routines,
111 &mut cycle.mark_default,
112 &schema,
113 &[],
114 params,
115 )?;
116 }
117 let provisional = if self_recursive {
118 self.bind_recursive_seed(
119 routines,
120 ctes[position]
121 .body
122 .query()
123 .ok_or_else(|| SQLError::Routine {
124 sqlstate: "42P19".into(),
125 message: format!(
126 "recursive query \"{}\" must not contain data-modifying statements",
127 ctes[position].name
128 ),
129 })?,
130 params,
131 outer,
132 )?
133 } else {
134 self.bind_cte_routines_for_storage(
135 routines,
136 &mut ctes[position].body,
137 params,
138 outer,
139 )?
140 };
141 let columns = ctes[position].columns.clone();
142 let provisional = rename_schema(&provisional, &columns, None);
143 let provisional = if self_recursive {
144 extend_recursive_cte_binding_schema(routines, &ctes[position], provisional, params)?
145 } else {
146 extend_cte_generated_schema(routines, &ctes[position], provisional, params)?
147 };
148 previous.push((
149 name.clone(),
150 self.set_cte_returning(&ctes[position]),
151 self.ctes.insert(name.clone(), provisional),
152 ));
153 if self_recursive {
154 let complete = self.bind_cte_routines_for_storage(
155 routines,
156 &mut ctes[position].body,
157 params,
158 outer,
159 )?;
160 let complete = rename_schema(&complete, &columns, None);
161 let complete =
162 extend_cte_generated_schema(routines, &ctes[position], complete, params)?;
163 self.ctes.insert(name, complete);
164 }
165 }
166
167 Ok(previous)
168 }
169
170 pub(super) fn bind_query_routines_for_storage(
171 &mut self,
172 routines: &dyn RoutineResolution,
173 plan: &mut QueryPlan,
174 params: &[SQLParam],
175 outer: Option<&RowSchema>,
176 ) -> Result<RowSchema, SQLError> {
177 let previous = self.bind_cte_routine_schemas(routines, &mut plan.ctes, params, outer)?;
178
179 let result = self.bind_root_routines_for_storage(routines, &mut plan.root, params, outer);
180 self.restore_cte_schemas(previous);
181 result
182 }
183
184 #[expect(
185 clippy::too_many_lines,
186 reason = "preserves SELECT schema and row identity"
187 )]
188 fn bind_root_routines_for_storage(
189 &mut self,
190 routines: &dyn RoutineResolution,
191 root: &mut RelationalPlan,
192 params: &[SQLParam],
193 outer: Option<&RowSchema>,
194 ) -> Result<RowSchema, SQLError> {
195 match root {
196 RelationalPlan::QueryBlock(block) => {
197 if let Some(source) = block.from.as_mut() {
199 self.bind_source_routines_for_storage(
200 routines,
201 source,
202 &block.subqueries,
203 params,
204 outer,
205 )?;
206 }
207 let source_schema = match block.from.as_mut() {
208 Some(source) => self.bind_source_for_execution(
209 routines,
210 source,
211 &block.subqueries,
212 params,
213 outer,
214 )?,
215 None => RowSchema::default(),
216 };
217 let expression_schema = overlay_outer_schema(&source_schema, outer);
218 for subquery in &mut block.subqueries {
219 self.bind_query_routines_for_storage(
220 routines,
221 subquery,
222 params,
223 Some(&expression_schema),
224 )?;
225 }
226 }
227 RelationalPlan::SetOp {
228 left,
229 right,
230 subqueries,
231 ..
232 } => {
233 self.bind_query_routines_for_storage(routines, left, params, outer)?;
234 self.bind_query_routines_for_storage(routines, right, params, outer)?;
235 for subquery in subqueries {
236 self.bind_query_routines_for_storage(routines, subquery, params, outer)?;
237 }
238 }
239 RelationalPlan::Values { subqueries, .. } => {
240 for subquery in subqueries {
241 self.bind_query_routines_for_storage(routines, subquery, params, outer)?;
242 }
243 }
244 }
245
246 let set_output = match &*root {
247 RelationalPlan::SetOp { .. } => {
248 Some(self.bind_root(routines, root, params, outer, false)?)
249 }
250 RelationalPlan::QueryBlock(_) | RelationalPlan::Values { .. } => None,
251 };
252 match root {
253 RelationalPlan::QueryBlock(block) => {
254 if block.from.is_none()
255 && block
256 .projections
257 .iter()
258 .any(|projection| matches!(projection.expr, ScalarExpr::Star))
259 && outer.is_none()
260 {
261 return Err(SQLError::Routine {
262 sqlstate: "42601".into(),
263 message: "SELECT * with no tables specified is not valid".into(),
264 });
265 }
266 let source_schema = block.from.as_ref().map_or_else(
267 || Ok(RowSchema::default()),
268 |source| self.bind_source(routines, source, &block.subqueries, params, outer),
269 )?;
270 let expression_schema = overlay_outer_schema(&source_schema, outer);
271 if let Some(filter) = block.r#where.as_mut() {
272 self.bind_scalar_routines_for_storage(
273 routines,
274 filter,
275 &expression_schema,
276 &block.subqueries,
277 params,
278 )?;
279 }
280 let labels = super::routine_parameters::column_labels(&block.projections);
281 for projection in &mut block.projections {
282 self.bind_scalar_routines_for_storage(
283 routines,
284 &mut projection.expr,
285 &expression_schema,
286 &block.subqueries,
287 params,
288 )?;
289 }
290 super::routine_parameters::keep_column_labels(&mut block.projections, labels);
291 if self.preserve_syntax_shape {
292 let mut expanded = (**block).clone();
294 expanded.projections = crate::semantics::expand_bound_projection_stars(
295 &block.projections,
296 &source_schema,
297 )?;
298 self.bind_grouping_variable_sites(&mut expanded, &source_schema);
299 crate::semantics::grouping_sets::bind_grouping_names(
300 routines,
301 &mut expanded,
302 &source_schema,
303 None,
304 params,
305 )?;
306 } else {
307 block.projections = crate::semantics::expand_bound_projection_stars(
308 &block.projections,
309 &source_schema,
310 )?;
311 self.bind_grouping_variable_sites(block, &source_schema);
312 crate::semantics::grouping_sets::bind_grouping_names(
313 routines,
314 block,
315 &source_schema,
316 None,
317 params,
318 )?;
319 }
320 let output_names = self.output_names(&block.projections);
321 for expression in block
322 .group_by
323 .iter_mut()
324 .chain(block.grouping_sets.iter_mut().flatten())
325 {
326 if self.preserve_syntax_shape
328 && matches!(expression, ScalarExpr::Column(name)
329 if !source_schema.has_unqualified_column(name)
330 && !source_schema.column_is_ambiguous(name)
331 && output_names.contains(name))
332 {
333 continue;
334 }
335 self.bind_scalar_routines_for_storage(
336 routines,
337 expression,
338 &expression_schema,
339 &block.subqueries,
340 params,
341 )?;
342 }
343 if let Some(having) = block.having.as_mut() {
344 self.bind_scalar_routines_for_storage(
345 routines,
346 having,
347 &expression_schema,
348 &block.subqueries,
349 params,
350 )?;
351 }
352 let names_output = |expression: &ScalarExpr| match expression {
354 ScalarExpr::Column(name) => output_names.contains(name),
355 _ => false,
356 };
357 for order in &mut block.order_by {
358 if names_output(&order.expr)
359 || self.output_takes_variable_site(&order.expr, &output_names)
360 {
361 continue;
362 }
363 self.bind_scalar_routines_for_storage(
364 routines,
365 &mut order.expr,
366 &expression_schema,
367 &block.subqueries,
368 params,
369 )?;
370 }
371 if let Some(limit) = block.limit.as_mut() {
372 self.bind_scalar_routines_for_storage(
373 routines,
374 limit,
375 &expression_schema,
376 &block.subqueries,
377 params,
378 )?;
379 }
380 if let Some(offset) = block.offset.as_mut() {
381 self.bind_scalar_routines_for_storage(
382 routines,
383 offset,
384 &expression_schema,
385 &block.subqueries,
386 params,
387 )?;
388 }
389 for expression in &mut block.distinct_on {
390 if names_output(expression)
391 || self.output_takes_variable_site(expression, &output_names)
392 {
393 continue;
394 }
395 self.bind_scalar_routines_for_storage(
396 routines,
397 expression,
398 &expression_schema,
399 &block.subqueries,
400 params,
401 )?;
402 }
403 for expression in block
404 .windows
405 .iter_mut()
406 .flat_map(|window| window.spec.expressions_mut())
407 {
408 self.bind_scalar_routines_for_storage(
409 routines,
410 expression,
411 &expression_schema,
412 &block.subqueries,
413 params,
414 )?;
415 }
416 }
417 RelationalPlan::SetOp {
418 order_by,
419 limit,
420 offset,
421 subqueries,
422 ..
423 } => {
424 let output = overlay_outer_schema(
425 set_output
426 .as_ref()
427 .expect("set-operation output schema was bound before routine expressions"),
428 outer,
429 );
430 let output = &output;
431 for order in order_by {
432 self.bind_scalar_routines_for_storage(
433 routines,
434 &mut order.expr,
435 output,
436 subqueries,
437 params,
438 )?;
439 }
440 if let Some(limit) = limit {
441 self.bind_scalar_routines_for_storage(
442 routines, limit, output, subqueries, params,
443 )?;
444 }
445 if let Some(offset) = offset {
446 self.bind_scalar_routines_for_storage(
447 routines, offset, output, subqueries, params,
448 )?;
449 }
450 }
451 RelationalPlan::Values { rows, subqueries } => {
452 let input = outer.cloned().unwrap_or_default();
453 for expression in rows.iter_mut().flatten() {
454 self.bind_scalar_routines_for_storage(
455 routines, expression, &input, subqueries, params,
456 )?;
457 }
458 }
459 }
460 self.bind_root(routines, root, params, outer, false)
461 }
462
463 #[expect(
464 clippy::too_many_lines,
465 reason = "preserves SELECT schema and row identity"
466 )]
467 pub(super) fn bind_source_routines_for_storage(
468 &mut self,
469 engine: &dyn RoutineResolution,
470 source: &mut SourcePlan,
471 subqueries: &[QueryPlan],
472 params: &[SQLParam],
473 outer: Option<&RowSchema>,
474 ) -> Result<(), SQLError> {
475 match source {
476 SourcePlan::Join {
477 left,
478 right,
479 on,
480 lateral,
481 ..
482 } => {
483 self.bind_source_routines_for_storage(engine, left, subqueries, params, outer)?;
484 let left_schema = self.bind_source(engine, left, subqueries, params, outer)?;
485 let implicit_lateral_function = matches!(
486 right.as_ref(),
487 SourcePlan::Function { .. } | SourcePlan::FunctionGroup { .. }
488 );
489 let right_scope = (*lateral || implicit_lateral_function)
490 .then(|| overlay_outer_schema(&left_schema, outer));
491 let right_outer = right_scope.as_ref().or(outer);
492 self.bind_source_routines_for_storage(
493 engine,
494 right,
495 subqueries,
496 params,
497 right_outer,
498 )?;
499 if let Some(on) = on {
500 let right_schema =
501 self.bind_source(engine, right, subqueries, params, right_outer)?;
502 let input = RowSchema::join(&left_schema, &right_schema, std::iter::empty());
503 let input = overlay_outer_schema(&input, outer);
504 self.bind_scalar_routines_for_storage(engine, on, &input, subqueries, params)?;
505 }
506 Ok(())
507 }
508 SourcePlan::Subquery { body, .. } => self
509 .bind_query_routines_for_storage(engine, body, params, outer)
510 .map(|_| ()),
511 SourcePlan::Values { rows, .. } => {
512 let input = outer.cloned().unwrap_or_default();
513 for expression in rows.iter_mut().flatten() {
514 self.bind_scalar_routines_for_storage(
515 engine, expression, &input, subqueries, params,
516 )?;
517 }
518 Ok(())
519 }
520 SourcePlan::Function {
521 name,
522 relations,
523 args,
524 ..
525 } => {
526 let local = crate::semantics::builtin_function_dispatch_name(name);
527 if crate::registry::is_operator_join_table_function(&local) {
528 let (left, right) = operator_join_relation_schemas(
529 &self.catalog,
530 &self.resolution,
531 relations.as_ref(),
532 )?;
533 let constant = RowSchema::default();
534 for (position, expression) in args.iter_mut().enumerate() {
535 let input = match position {
536 0 => &left,
537 1 => &right,
538 _ => &constant,
539 };
540 self.bind_scalar_routines_for_storage(
541 engine, expression, input, subqueries, params,
542 )?;
543 }
544 return Ok(());
545 }
546 let input = outer.cloned().unwrap_or_default();
547 for expression in args {
548 self.bind_scalar_routines_for_storage(
549 engine, expression, &input, subqueries, params,
550 )?;
551 }
552 Ok(())
553 }
554 SourcePlan::FunctionGroup { functions, .. } => {
555 for function in functions {
556 let local = crate::semantics::builtin_function_dispatch_name(&function.name);
557 if crate::registry::is_operator_join_table_function(&local) {
558 let (left, right) = operator_join_relation_schemas(
559 &self.catalog,
560 &self.resolution,
561 function.relations.as_ref(),
562 )?;
563 let constant = RowSchema::default();
564 for (position, expression) in function.args.iter_mut().enumerate() {
565 let input = match position {
566 0 => &left,
567 1 => &right,
568 _ => &constant,
569 };
570 self.bind_scalar_routines_for_storage(
571 engine, expression, input, subqueries, params,
572 )?;
573 }
574 continue;
575 }
576 let input = outer.cloned().unwrap_or_default();
577 for expression in &mut function.args {
578 self.bind_scalar_routines_for_storage(
579 engine, expression, &input, subqueries, params,
580 )?;
581 }
582 }
583 Ok(())
584 }
585 SourcePlan::Table { .. } => Ok(()),
586 }
587 }
588
589 pub(super) fn bind_scalar_routines_for_storage(
590 &mut self,
591 engine: &dyn RoutineResolution,
592 expression: &mut ScalarExpr,
593 schema: &RowSchema,
594 subqueries: &[QueryPlan],
595 params: &[SQLParam],
596 ) -> Result<(), SQLError> {
597 let schema = self.with_stored_outer_internal_aliases(schema);
598 let schema = &schema;
599 self.canonicalize_stored_outer_columns(expression, schema);
600 self.expand_stored_whole_rows(expression, schema);
601 self.canonicalize_routine_parameters(expression, schema);
602 self.resolve_variable_sites(expression, schema);
603 match self.scalar_binding {
604 super::ScalarBindingMode::References => return Ok(()),
605 super::ScalarBindingMode::CompositeInputs => {
606 return self.retain_composite_inputs_in_scope(
607 engine, expression, schema, subqueries, params,
608 )
609 }
610 super::ScalarBindingMode::Stored => {}
611 }
612 let mut failure = None;
613 crate::plan::rewrite_scalar_expression(expression, &mut |expression| {
614 if failure.is_some() {
615 return;
616 }
617 if matches!(expression, ScalarExpr::Func { order_syntax, name, binding, order_by, .. }
618 if super::ordered_calls::uses_ordered_arguments(*order_syntax, name, binding.as_ref(), order_by.len())
619 || super::ordered_calls::is_ordered_set(name))
620 {
621 if let Err(error) = self.bind_ordered_function_for_storage(
622 engine, expression, schema, subqueries, params,
623 ) {
624 failure = Some(error);
625 }
626 return;
627 }
628 let ScalarExpr::Func {
629 name,
630 binding,
631 args,
632 ..
633 } = expression
634 else {
635 return;
636 };
637 if let Some(dispatch) = binding.as_ref().and_then(|binding| binding.dispatch) {
638 if let crate::ast::FunctionDispatch::NumericOperator(operator) = dispatch {
639 let selected = (|| {
640 let resolver = self.query_function_type_resolver_for_subqueries(
641 engine, args, schema, subqueries, params,
642 )?;
643 let (_, types, _) = crate::function_call_argument_signature(
644 args,
645 schema,
646 params,
647 Some(&resolver),
648 )?;
649 crate::type_resolution::numeric_operator_types(operator, &types)
650 })();
651 match selected {
652 Ok(selected) => {
653 binding
654 .as_mut()
655 .expect("structural operator binding")
656 .argument_types = selected
657 .arguments
658 .iter()
659 .map(crate::ColumnType::sql_name)
660 .collect();
661 }
662 Err(error) => failure = Some(error),
663 }
664 }
665 return;
666 }
667 if let Err(error) = self.bind_scalar_function_for_storage(
668 engine, name, binding, args, schema, subqueries, params,
669 ) {
670 failure = Some(error);
671 }
672 });
673 failure.map_or(Ok(()), Err)?;
674 self.bind_stored_scalar_types(engine, expression, schema, subqueries, params)?;
675 self.record_composite_dependencies(engine, expression, schema, subqueries, params)
676 }
677
678 fn bind_stored_scalar_types(
680 &mut self,
681 engine: &dyn RoutineResolution,
682 expression: &mut ScalarExpr,
683 schema: &RowSchema,
684 subqueries: &[QueryPlan],
685 params: &[SQLParam],
686 ) -> Result<(), SQLError> {
687 super::stored_types::bind_scalar_type_identities(expression, &mut |name| {
688 engine.resolve_type_name(name)
689 })?;
690 let resolver = self.query_function_type_resolver_for_subqueries(
691 engine,
692 std::slice::from_ref(expression),
693 schema,
694 subqueries,
695 params,
696 )?;
697 crate::type_resolution::store_operand_coercions(expression, schema, params, &resolver)?;
699 if !crate::type_resolution::contains_unknown_literal(expression) {
700 return Ok(());
701 }
702 crate::type_resolution::fold_stored_enum_constants(expression, schema, params, &resolver)
703 .map(drop)
704 }
705
706 #[expect(
707 clippy::too_many_arguments,
708 reason = "keeps execution context inputs aligned"
709 )]
710 fn bind_scalar_function_for_storage(
711 &mut self,
712 engine: &dyn RoutineResolution,
713 name: &str,
714 binding: &mut Option<FunctionBinding>,
715 args: &[ScalarExpr],
716 schema: &RowSchema,
717 subqueries: &[QueryPlan],
718 params: &[SQLParam],
719 ) -> Result<(), SQLError> {
720 let resolver = self.query_function_type_resolver_for_subqueries(
721 engine, args, schema, subqueries, params,
722 )?;
723 let (argument_names, argument_types, explicit_variadic) =
724 crate::function_call_argument_signature(args, schema, params, Some(&resolver))?;
725 let selected = if crate::is_fixed_builtin(name) {
726 crate::resolve_fixed_builtin_call(
727 name,
728 binding.as_ref(),
729 &argument_names,
730 &argument_types,
731 explicit_variadic,
732 Some(&resolver),
733 )?
734 .map(|resolved| resolved.selected)
735 } else if let Some(array) = crate::type_resolution::resolve_array_transform_call(
736 name,
737 binding.as_ref(),
738 args,
739 &argument_types,
740 explicit_variadic,
741 &resolver,
742 )? {
743 array.overload
744 } else {
745 resolver.resolve_function_overload(
746 name,
747 binding.as_ref(),
748 &argument_names,
749 &argument_types,
750 explicit_variadic,
751 )?
752 };
753 if let Some(selected) = selected {
754 *binding = Some(selected.binding);
755 }
756 Ok(())
757 }
758}
759
760pub fn bind_query_plan_routines_for_storage(
761 engine: &dyn RoutineResolution,
762 plan: &mut QueryPlan,
763 params: &[SQLParam],
764 ctes: &BindingContext,
765 outer: Option<&RowSchema>,
766) -> Result<RowSchema, SQLError> {
767 SchemaScope::for_analysis(ctes)?.bind_query_routines_for_storage(engine, plan, params, outer)
768}
769
770pub fn bind_syntax_query_plan_routines(
772 engine: &dyn RoutineResolution,
773 plan: &mut QueryPlan,
774 params: &[SQLParam],
775 ctes: &BindingContext,
776 outer: Option<&RowSchema>,
777) -> Result<RowSchema, SQLError> {
778 let mut scope = SchemaScope::for_analysis(ctes)?;
779 scope.preserve_syntax_shape = true;
780 scope.bind_query_routines_for_storage(engine, plan, params, outer)
781}
782
783pub fn bind_expression_plan_routines_for_storage(
785 engine: &dyn RoutineResolution,
786 plan: &mut ExpressionPlan,
787 params: &[SQLParam],
788 ctes: &BindingContext,
789 schema: &RowSchema,
790) -> Result<Option<ColumnType>, SQLError> {
791 let mut scope = SchemaScope::for_analysis(ctes)?;
792 scope.preserve_syntax_shape = true;
793 scope.stored_expression_outer = Some(schema.clone());
794 for subquery in &mut plan.subqueries {
795 scope.bind_query_routines_for_storage(engine, subquery, params, Some(schema))?;
796 }
797 scope.bind_scalar_routines_for_storage(
798 engine,
799 &mut plan.scalar,
800 schema,
801 &plan.subqueries,
802 params,
803 )?;
804 scope.bind_expression_type(engine, &plan.scalar, schema, &plan.subqueries, params)
805}