1use std::cmp::Ordering;
21use std::collections::{HashMap, HashSet};
22use std::fmt::{self, Debug, Display, Formatter};
23use std::hash::{Hash, Hasher};
24use std::sync::{Arc, LazyLock};
25
26use super::DdlStatement;
27use super::dml::CopyTo;
28use super::invariants::{
29 InvariantLevel, assert_always_invariants_at_current_node,
30 assert_executable_invariants,
31};
32use crate::builder::{unique_field_aliases, unnest_with_options};
33use crate::expr::{
34 Alias, Placeholder, Sort as SortExpr, WindowFunction, WindowFunctionParams,
35 intersect_metadata_for_union,
36};
37use crate::expr_rewriter::{
38 NamePreserver, create_col_from_scalar_expr, normalize_cols, normalize_sorts,
39};
40use crate::logical_plan::display::{GraphvizVisitor, IndentVisitor};
41use crate::logical_plan::extension::UserDefinedLogicalNode;
42use crate::logical_plan::{DmlStatement, Statement};
43use crate::utils::{
44 enumerate_grouping_sets, exprlist_to_fields, find_out_reference_exprs,
45 grouping_set_expr_count, grouping_set_to_exprlist, merge_schema, split_conjunction,
46};
47use crate::{
48 BinaryExpr, CreateMemoryTable, CreateView, Execute, Expr, ExprSchemable, GroupingSet,
49 LogicalPlanBuilder, Operator, Prepare, TableProviderFilterPushDown, TableSource,
50 WindowFunctionDefinition, build_join_schema, expr_vec_fmt, requalify_sides_if_needed,
51};
52
53use arrow::datatypes::{DataType, Field, FieldRef, Schema, SchemaRef};
54use datafusion_common::cse::{NormalizeEq, Normalizeable};
55use datafusion_common::format::ExplainFormat;
56use datafusion_common::metadata::check_metadata_with_storage_equal;
57use datafusion_common::tree_node::{
58 Transformed, TreeNode, TreeNodeContainer, TreeNodeRecursion,
59};
60use datafusion_common::{
61 Column, Constraints, DFSchema, DFSchemaRef, DataFusionError, Dependency,
62 FunctionalDependence, FunctionalDependencies, NullEquality, ParamValues, Result,
63 ScalarValue, Spans, TableReference, UnnestOptions, aggregate_functional_dependencies,
64 assert_eq_or_internal_err, assert_or_internal_err, internal_err, plan_err,
65};
66use indexmap::IndexSet;
67
68use crate::display::PgJsonVisitor;
70pub use datafusion_common::display::{PlanType, StringifiedPlan, ToStringifiedPlan};
71pub use datafusion_common::{JoinConstraint, JoinType};
72
73#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
206pub enum LogicalPlan {
207 Projection(Projection),
210 Filter(Filter),
219 Window(Window),
225 Aggregate(Aggregate),
231 Sort(Sort),
234 Join(Join),
237 Repartition(Repartition),
241 Union(Union),
245 TableScan(TableScan),
248 EmptyRelation(EmptyRelation),
252 Subquery(Subquery),
255 SubqueryAlias(SubqueryAlias),
257 Limit(Limit),
259 Statement(Statement),
261 Values(Values),
266 Explain(Explain),
269 Analyze(Analyze),
273 Extension(Extension),
276 Distinct(Distinct),
279 Dml(DmlStatement),
281 Ddl(DdlStatement),
283 Copy(CopyTo),
285 DescribeTable(DescribeTable),
288 Unnest(Unnest),
291 RecursiveQuery(RecursiveQuery),
293}
294
295impl Default for LogicalPlan {
296 fn default() -> Self {
297 LogicalPlan::EmptyRelation(EmptyRelation {
301 produce_one_row: false,
302 schema: Arc::clone(DFSchema::empty_ref()),
303 })
304 }
305}
306
307impl<'a> TreeNodeContainer<'a, Self> for LogicalPlan {
308 fn apply_elements<F: FnMut(&'a Self) -> Result<TreeNodeRecursion>>(
309 &'a self,
310 mut f: F,
311 ) -> Result<TreeNodeRecursion> {
312 f(self)
313 }
314
315 fn map_elements<F: FnMut(Self) -> Result<Transformed<Self>>>(
316 self,
317 mut f: F,
318 ) -> Result<Transformed<Self>> {
319 f(self)
320 }
321}
322
323impl LogicalPlan {
324 pub fn schema(&self) -> &DFSchemaRef {
326 match self {
327 LogicalPlan::EmptyRelation(EmptyRelation { schema, .. }) => schema,
328 LogicalPlan::Values(Values { schema, .. }) => schema,
329 LogicalPlan::TableScan(TableScan {
330 projected_schema, ..
331 }) => projected_schema,
332 LogicalPlan::Projection(Projection { schema, .. }) => schema,
333 LogicalPlan::Filter(Filter { input, .. }) => input.schema(),
334 LogicalPlan::Distinct(Distinct::All(input)) => input.schema(),
335 LogicalPlan::Distinct(Distinct::On(DistinctOn { schema, .. })) => schema,
336 LogicalPlan::Window(Window { schema, .. }) => schema,
337 LogicalPlan::Aggregate(Aggregate { schema, .. }) => schema,
338 LogicalPlan::Sort(Sort { input, .. }) => input.schema(),
339 LogicalPlan::Join(Join { schema, .. }) => schema,
340 LogicalPlan::Repartition(Repartition { input, .. }) => input.schema(),
341 LogicalPlan::Limit(Limit { input, .. }) => input.schema(),
342 LogicalPlan::Statement(statement) => statement.schema(),
343 LogicalPlan::Subquery(Subquery { subquery, .. }) => subquery.schema(),
344 LogicalPlan::SubqueryAlias(SubqueryAlias { schema, .. }) => schema,
345 LogicalPlan::Explain(explain) => &explain.schema,
346 LogicalPlan::Analyze(analyze) => &analyze.schema,
347 LogicalPlan::Extension(extension) => extension.node.schema(),
348 LogicalPlan::Union(Union { schema, .. }) => schema,
349 LogicalPlan::DescribeTable(DescribeTable { output_schema, .. }) => {
350 output_schema
351 }
352 LogicalPlan::Dml(DmlStatement { output_schema, .. }) => output_schema,
353 LogicalPlan::Copy(CopyTo { output_schema, .. }) => output_schema,
354 LogicalPlan::Ddl(ddl) => ddl.schema(),
355 LogicalPlan::Unnest(Unnest { schema, .. }) => schema,
356 LogicalPlan::RecursiveQuery(RecursiveQuery { schema, .. }) => schema,
357 }
358 }
359
360 pub fn fallback_normalize_schemas(&self) -> Vec<&DFSchema> {
363 match self {
364 LogicalPlan::Window(_)
365 | LogicalPlan::Projection(_)
366 | LogicalPlan::Aggregate(_)
367 | LogicalPlan::Unnest(_)
368 | LogicalPlan::Join(_) => self
369 .inputs()
370 .iter()
371 .map(|input| input.schema().as_ref())
372 .collect(),
373 _ => vec![],
374 }
375 }
376
377 pub fn explain_schema() -> SchemaRef {
379 SchemaRef::new(Schema::new(vec![
380 Field::new("plan_type", DataType::Utf8, false),
381 Field::new("plan", DataType::Utf8, false),
382 ]))
383 }
384
385 pub fn describe_schema() -> Schema {
387 Schema::new(vec![
388 Field::new("column_name", DataType::Utf8, false),
389 Field::new("data_type", DataType::Utf8, false),
390 Field::new("is_nullable", DataType::Utf8, false),
391 ])
392 }
393
394 pub fn expressions(self: &LogicalPlan) -> Vec<Expr> {
411 let mut exprs = vec![];
412 self.apply_expressions(|e| {
413 exprs.push(e.clone());
414 Ok(TreeNodeRecursion::Continue)
415 })
416 .unwrap();
418 exprs
419 }
420
421 pub fn all_out_ref_exprs(self: &LogicalPlan) -> Vec<Expr> {
424 let mut exprs = vec![];
425 self.apply_expressions(|e| {
426 find_out_reference_exprs(e).into_iter().for_each(|e| {
427 if !exprs.contains(&e) {
428 exprs.push(e)
429 }
430 });
431 Ok(TreeNodeRecursion::Continue)
432 })
433 .unwrap();
435 self.inputs()
436 .into_iter()
437 .flat_map(|child| child.all_out_ref_exprs())
438 .for_each(|e| {
439 if !exprs.contains(&e) {
440 exprs.push(e)
441 }
442 });
443 exprs
444 }
445
446 pub fn inputs(&self) -> Vec<&LogicalPlan> {
450 match self {
451 LogicalPlan::Projection(Projection { input, .. }) => vec![input],
452 LogicalPlan::Filter(Filter { input, .. }) => vec![input],
453 LogicalPlan::Repartition(Repartition { input, .. }) => vec![input],
454 LogicalPlan::Window(Window { input, .. }) => vec![input],
455 LogicalPlan::Aggregate(Aggregate { input, .. }) => vec![input],
456 LogicalPlan::Sort(Sort { input, .. }) => vec![input],
457 LogicalPlan::Join(Join { left, right, .. }) => vec![left, right],
458 LogicalPlan::Limit(Limit { input, .. }) => vec![input],
459 LogicalPlan::Subquery(Subquery { subquery, .. }) => vec![subquery],
460 LogicalPlan::SubqueryAlias(SubqueryAlias { input, .. }) => vec![input],
461 LogicalPlan::Extension(extension) => extension.node.inputs(),
462 LogicalPlan::Union(Union { inputs, .. }) => {
463 inputs.iter().map(|arc| arc.as_ref()).collect()
464 }
465 LogicalPlan::Distinct(
466 Distinct::All(input) | Distinct::On(DistinctOn { input, .. }),
467 ) => vec![input],
468 LogicalPlan::Explain(explain) => vec![&explain.plan],
469 LogicalPlan::Analyze(analyze) => vec![&analyze.input],
470 LogicalPlan::Dml(write) => vec![&write.input],
471 LogicalPlan::Copy(copy) => vec![©.input],
472 LogicalPlan::Ddl(ddl) => ddl.inputs(),
473 LogicalPlan::Unnest(Unnest { input, .. }) => vec![input],
474 LogicalPlan::RecursiveQuery(RecursiveQuery {
475 static_term,
476 recursive_term,
477 ..
478 }) => vec![static_term, recursive_term],
479 LogicalPlan::Statement(stmt) => stmt.inputs(),
480 LogicalPlan::TableScan { .. }
482 | LogicalPlan::EmptyRelation { .. }
483 | LogicalPlan::Values { .. }
484 | LogicalPlan::DescribeTable(_) => vec![],
485 }
486 }
487
488 pub fn using_columns(&self) -> Result<Vec<HashSet<Column>>, DataFusionError> {
490 let mut using_columns: Vec<HashSet<Column>> = vec![];
491
492 self.apply_with_subqueries(|plan| {
493 if let LogicalPlan::Join(Join {
494 join_constraint: JoinConstraint::Using,
495 on,
496 ..
497 }) = plan
498 {
499 let columns =
501 on.iter().try_fold(HashSet::new(), |mut accumu, (l, r)| {
502 let Some(l) = l.get_as_join_column() else {
503 return internal_err!(
504 "Invalid join key. Expected column, found {l:?}"
505 );
506 };
507 let Some(r) = r.get_as_join_column() else {
508 return internal_err!(
509 "Invalid join key. Expected column, found {r:?}"
510 );
511 };
512 accumu.insert(l.to_owned());
513 accumu.insert(r.to_owned());
514 Result::<_, DataFusionError>::Ok(accumu)
515 })?;
516 using_columns.push(columns);
517 }
518 Ok(TreeNodeRecursion::Continue)
519 })?;
520
521 Ok(using_columns)
522 }
523
524 pub fn head_output_expr(&self) -> Result<Option<Expr>> {
526 match self {
527 LogicalPlan::Projection(projection) => {
528 Ok(Some(projection.expr.as_slice()[0].clone()))
529 }
530 LogicalPlan::Aggregate(agg) => {
531 if agg.group_expr.is_empty() {
532 Ok(Some(agg.aggr_expr.as_slice()[0].clone()))
533 } else {
534 Ok(Some(agg.group_expr.as_slice()[0].clone()))
535 }
536 }
537 LogicalPlan::Distinct(Distinct::On(DistinctOn { select_expr, .. })) => {
538 Ok(Some(select_expr[0].clone()))
539 }
540 LogicalPlan::Filter(Filter { input, .. })
541 | LogicalPlan::Distinct(Distinct::All(input))
542 | LogicalPlan::Sort(Sort { input, .. })
543 | LogicalPlan::Limit(Limit { input, .. })
544 | LogicalPlan::Repartition(Repartition { input, .. })
545 | LogicalPlan::Window(Window { input, .. }) => input.head_output_expr(),
546 LogicalPlan::Join(Join {
547 left,
548 right,
549 join_type,
550 ..
551 }) => match join_type {
552 JoinType::Inner | JoinType::Left | JoinType::Right | JoinType::Full => {
553 if left.schema().fields().is_empty() {
554 right.head_output_expr()
555 } else {
556 left.head_output_expr()
557 }
558 }
559 JoinType::LeftSemi | JoinType::LeftAnti | JoinType::LeftMark => {
560 left.head_output_expr()
561 }
562 JoinType::RightSemi | JoinType::RightAnti | JoinType::RightMark => {
563 right.head_output_expr()
564 }
565 },
566 LogicalPlan::RecursiveQuery(RecursiveQuery { static_term, .. }) => {
567 static_term.head_output_expr()
568 }
569 LogicalPlan::Union(union) => Ok(Some(Expr::Column(Column::from(
570 union.schema.qualified_field(0),
571 )))),
572 LogicalPlan::TableScan(table) => Ok(Some(Expr::Column(Column::from(
573 table.projected_schema.qualified_field(0),
574 )))),
575 LogicalPlan::SubqueryAlias(subquery_alias) => {
576 let expr_opt = subquery_alias.input.head_output_expr()?;
577 expr_opt
578 .map(|expr| {
579 Ok(Expr::Column(create_col_from_scalar_expr(
580 &expr,
581 subquery_alias.alias.to_string(),
582 )?))
583 })
584 .map_or(Ok(None), |v| v.map(Some))
585 }
586 LogicalPlan::Subquery(_) => Ok(None),
587 LogicalPlan::EmptyRelation(_)
588 | LogicalPlan::Statement(_)
589 | LogicalPlan::Values(_)
590 | LogicalPlan::Explain(_)
591 | LogicalPlan::Analyze(_)
592 | LogicalPlan::Extension(_)
593 | LogicalPlan::Dml(_)
594 | LogicalPlan::Copy(_)
595 | LogicalPlan::Ddl(_)
596 | LogicalPlan::DescribeTable(_)
597 | LogicalPlan::Unnest(_) => Ok(None),
598 }
599 }
600
601 pub fn recompute_schema(self) -> Result<Self> {
624 match self {
625 LogicalPlan::Projection(Projection {
628 expr,
629 input,
630 schema: _,
631 }) => Projection::try_new(expr, input).map(LogicalPlan::Projection),
632 LogicalPlan::Dml(_) => Ok(self),
633 LogicalPlan::Copy(_) => Ok(self),
634 LogicalPlan::Values(Values { schema, values }) => {
635 Ok(LogicalPlan::Values(Values { schema, values }))
637 }
638 LogicalPlan::Filter(Filter { predicate, input }) => {
639 Filter::try_new(predicate, input).map(LogicalPlan::Filter)
640 }
641 LogicalPlan::Repartition(_) => Ok(self),
642 LogicalPlan::Window(Window {
643 input,
644 window_expr,
645 schema: _,
646 }) => Window::try_new(window_expr, input).map(LogicalPlan::Window),
647 LogicalPlan::Aggregate(Aggregate {
648 input,
649 group_expr,
650 aggr_expr,
651 schema: _,
652 }) => Aggregate::try_new(input, group_expr, aggr_expr)
653 .map(LogicalPlan::Aggregate),
654 LogicalPlan::Sort(_) => Ok(self),
655 LogicalPlan::Join(Join {
656 left,
657 right,
658 filter,
659 join_type,
660 join_constraint,
661 on,
662 schema: _,
663 null_equality,
664 null_aware,
665 }) => {
666 let schema =
667 build_join_schema(left.schema(), right.schema(), &join_type)?;
668
669 let new_on: Vec<_> = on
670 .into_iter()
671 .map(|equi_expr| {
672 (equi_expr.0.unalias(), equi_expr.1.unalias())
674 })
675 .collect();
676
677 Ok(LogicalPlan::Join(Join {
678 left,
679 right,
680 join_type,
681 join_constraint,
682 on: new_on,
683 filter,
684 schema: DFSchemaRef::new(schema),
685 null_equality,
686 null_aware,
687 }))
688 }
689 LogicalPlan::Subquery(_) => Ok(self),
690 LogicalPlan::SubqueryAlias(SubqueryAlias {
691 input,
692 alias,
693 schema: _,
694 }) => SubqueryAlias::try_new(input, alias).map(LogicalPlan::SubqueryAlias),
695 LogicalPlan::Limit(_) => Ok(self),
696 LogicalPlan::Ddl(_) => Ok(self),
697 LogicalPlan::Extension(Extension { node }) => {
698 let expr = node.expressions();
701 let inputs: Vec<_> = node.inputs().into_iter().cloned().collect();
702 Ok(LogicalPlan::Extension(Extension {
703 node: node.with_exprs_and_inputs(expr, inputs)?,
704 }))
705 }
706 LogicalPlan::Union(Union { inputs, schema }) => {
707 let first_input_schema = inputs[0].schema();
708 if schema.fields().len() == first_input_schema.fields().len() {
709 Ok(LogicalPlan::Union(Union { inputs, schema }))
711 } else {
712 Ok(LogicalPlan::Union(Union::try_new(inputs)?))
720 }
721 }
722 LogicalPlan::Distinct(distinct) => {
723 let distinct = match distinct {
724 Distinct::All(input) => Distinct::All(input),
725 Distinct::On(DistinctOn {
726 on_expr,
727 select_expr,
728 sort_expr,
729 input,
730 schema: _,
731 }) => Distinct::On(DistinctOn::try_new(
732 on_expr,
733 select_expr,
734 sort_expr,
735 input,
736 )?),
737 };
738 Ok(LogicalPlan::Distinct(distinct))
739 }
740 LogicalPlan::RecursiveQuery(RecursiveQuery {
741 name,
742 static_term,
743 recursive_term,
744 is_distinct,
745 schema: _,
746 }) => RecursiveQuery::try_new(name, static_term, recursive_term, is_distinct)
747 .map(LogicalPlan::RecursiveQuery),
748 LogicalPlan::Analyze(_) => Ok(self),
749 LogicalPlan::Explain(_) => Ok(self),
750 LogicalPlan::TableScan(_) => Ok(self),
751 LogicalPlan::EmptyRelation(_) => Ok(self),
752 LogicalPlan::Statement(_) => Ok(self),
753 LogicalPlan::DescribeTable(_) => Ok(self),
754 LogicalPlan::Unnest(Unnest {
755 input,
756 exec_columns,
757 options,
758 ..
759 }) => {
760 unnest_with_options(Arc::unwrap_or_clone(input), exec_columns, options)
762 }
763 }
764 }
765
766 pub fn with_new_exprs(
792 &self,
793 mut expr: Vec<Expr>,
794 inputs: Vec<LogicalPlan>,
795 ) -> Result<LogicalPlan> {
796 match self {
797 LogicalPlan::Projection(Projection { .. }) => {
800 let input = self.only_input(inputs)?;
801 Projection::try_new(expr, Arc::new(input)).map(LogicalPlan::Projection)
802 }
803 LogicalPlan::Dml(DmlStatement {
804 table_name,
805 target,
806 op,
807 ..
808 }) => {
809 self.assert_no_expressions(expr)?;
810 let input = self.only_input(inputs)?;
811 Ok(LogicalPlan::Dml(DmlStatement::new(
812 table_name.clone(),
813 Arc::clone(target),
814 op.clone(),
815 Arc::new(input),
816 )))
817 }
818 LogicalPlan::Copy(CopyTo {
819 input: _,
820 output_url,
821 file_type,
822 options,
823 partition_by,
824 output_schema: _,
825 }) => {
826 self.assert_no_expressions(expr)?;
827 let input = self.only_input(inputs)?;
828 Ok(LogicalPlan::Copy(CopyTo::new(
829 Arc::new(input),
830 output_url.clone(),
831 partition_by.clone(),
832 Arc::clone(file_type),
833 options.clone(),
834 )))
835 }
836 LogicalPlan::Values(Values { schema, .. }) => {
837 self.assert_no_inputs(inputs)?;
838 Ok(LogicalPlan::Values(Values {
839 schema: Arc::clone(schema),
840 values: expr
841 .chunks_exact(schema.fields().len())
842 .map(|s| s.to_vec())
843 .collect(),
844 }))
845 }
846 LogicalPlan::Filter { .. } => {
847 let predicate = self.only_expr(expr)?;
848 let input = self.only_input(inputs)?;
849
850 Filter::try_new(predicate, Arc::new(input)).map(LogicalPlan::Filter)
851 }
852 LogicalPlan::Repartition(Repartition {
853 partitioning_scheme,
854 ..
855 }) => match partitioning_scheme {
856 Partitioning::RoundRobinBatch(n) => {
857 self.assert_no_expressions(expr)?;
858 let input = self.only_input(inputs)?;
859 Ok(LogicalPlan::Repartition(Repartition {
860 partitioning_scheme: Partitioning::RoundRobinBatch(*n),
861 input: Arc::new(input),
862 }))
863 }
864 Partitioning::Hash(_, n) => {
865 let input = self.only_input(inputs)?;
866 Ok(LogicalPlan::Repartition(Repartition {
867 partitioning_scheme: Partitioning::Hash(expr, *n),
868 input: Arc::new(input),
869 }))
870 }
871 Partitioning::DistributeBy(_) => {
872 let input = self.only_input(inputs)?;
873 Ok(LogicalPlan::Repartition(Repartition {
874 partitioning_scheme: Partitioning::DistributeBy(expr),
875 input: Arc::new(input),
876 }))
877 }
878 },
879 LogicalPlan::Window(Window { window_expr, .. }) => {
880 assert_eq!(window_expr.len(), expr.len());
881 let input = self.only_input(inputs)?;
882 Window::try_new(expr, Arc::new(input)).map(LogicalPlan::Window)
883 }
884 LogicalPlan::Aggregate(Aggregate { group_expr, .. }) => {
885 let input = self.only_input(inputs)?;
886 let agg_expr = expr.split_off(group_expr.len());
888
889 Aggregate::try_new(Arc::new(input), expr, agg_expr)
890 .map(LogicalPlan::Aggregate)
891 }
892 LogicalPlan::Sort(Sort {
893 expr: sort_expr,
894 fetch,
895 ..
896 }) => {
897 let input = self.only_input(inputs)?;
898 Ok(LogicalPlan::Sort(Sort {
899 expr: expr
900 .into_iter()
901 .zip(sort_expr.iter())
902 .map(|(expr, sort)| sort.with_expr(expr))
903 .collect(),
904 input: Arc::new(input),
905 fetch: *fetch,
906 }))
907 }
908 LogicalPlan::Join(Join {
909 join_type,
910 join_constraint,
911 on,
912 null_equality,
913 null_aware,
914 ..
915 }) => {
916 let (left, right) = self.only_two_inputs(inputs)?;
917 let schema = build_join_schema(left.schema(), right.schema(), join_type)?;
918
919 let equi_expr_count = on.len() * 2;
920 assert!(expr.len() >= equi_expr_count);
921
922 let filter_expr = if expr.len() > equi_expr_count {
925 expr.pop()
926 } else {
927 None
928 };
929
930 assert_eq!(expr.len(), equi_expr_count);
933 let mut new_on = Vec::with_capacity(on.len());
934 let mut iter = expr.into_iter();
935 while let Some(left) = iter.next() {
936 let Some(right) = iter.next() else {
937 internal_err!(
938 "Expected a pair of expressions to construct the join on expression"
939 )?
940 };
941
942 new_on.push((left.unalias(), right.unalias()));
944 }
945
946 Ok(LogicalPlan::Join(Join {
947 left: Arc::new(left),
948 right: Arc::new(right),
949 join_type: *join_type,
950 join_constraint: *join_constraint,
951 on: new_on,
952 filter: filter_expr,
953 schema: DFSchemaRef::new(schema),
954 null_equality: *null_equality,
955 null_aware: *null_aware,
956 }))
957 }
958 LogicalPlan::Subquery(Subquery {
959 outer_ref_columns,
960 spans,
961 ..
962 }) => {
963 self.assert_no_expressions(expr)?;
964 let input = self.only_input(inputs)?;
965 let subquery = LogicalPlanBuilder::from(input).build()?;
966 Ok(LogicalPlan::Subquery(Subquery {
967 subquery: Arc::new(subquery),
968 outer_ref_columns: outer_ref_columns.clone(),
969 spans: spans.clone(),
970 }))
971 }
972 LogicalPlan::SubqueryAlias(SubqueryAlias { alias, .. }) => {
973 self.assert_no_expressions(expr)?;
974 let input = self.only_input(inputs)?;
975 SubqueryAlias::try_new(Arc::new(input), alias.clone())
976 .map(LogicalPlan::SubqueryAlias)
977 }
978 LogicalPlan::Limit(Limit { skip, fetch, .. }) => {
979 let old_expr_len = skip.iter().chain(fetch.iter()).count();
980 assert_eq_or_internal_err!(
981 old_expr_len,
982 expr.len(),
983 "Invalid number of new Limit expressions: expected {}, got {}",
984 old_expr_len,
985 expr.len()
986 );
987 let new_fetch = fetch.as_ref().and_then(|_| expr.pop());
989 let new_skip = skip.as_ref().and_then(|_| expr.pop());
990 let input = self.only_input(inputs)?;
991 Ok(LogicalPlan::Limit(Limit {
992 skip: new_skip.map(Box::new),
993 fetch: new_fetch.map(Box::new),
994 input: Arc::new(input),
995 }))
996 }
997 LogicalPlan::Ddl(DdlStatement::CreateMemoryTable(CreateMemoryTable {
998 name,
999 if_not_exists,
1000 or_replace,
1001 column_defaults,
1002 temporary,
1003 ..
1004 })) => {
1005 self.assert_no_expressions(expr)?;
1006 let input = self.only_input(inputs)?;
1007 Ok(LogicalPlan::Ddl(DdlStatement::CreateMemoryTable(
1008 CreateMemoryTable {
1009 input: Arc::new(input),
1010 constraints: Constraints::default(),
1011 name: name.clone(),
1012 if_not_exists: *if_not_exists,
1013 or_replace: *or_replace,
1014 column_defaults: column_defaults.clone(),
1015 temporary: *temporary,
1016 },
1017 )))
1018 }
1019 LogicalPlan::Ddl(DdlStatement::CreateView(CreateView {
1020 name,
1021 or_replace,
1022 definition,
1023 temporary,
1024 ..
1025 })) => {
1026 self.assert_no_expressions(expr)?;
1027 let input = self.only_input(inputs)?;
1028 Ok(LogicalPlan::Ddl(DdlStatement::CreateView(CreateView {
1029 input: Arc::new(input),
1030 name: name.clone(),
1031 or_replace: *or_replace,
1032 temporary: *temporary,
1033 definition: definition.clone(),
1034 })))
1035 }
1036 LogicalPlan::Extension(e) => Ok(LogicalPlan::Extension(Extension {
1037 node: e.node.with_exprs_and_inputs(expr, inputs)?,
1038 })),
1039 LogicalPlan::Union(Union { schema, .. }) => {
1040 self.assert_no_expressions(expr)?;
1041 let input_schema = inputs[0].schema();
1042 let schema = if schema.fields().len() == input_schema.fields().len() {
1044 Arc::clone(schema)
1045 } else {
1046 Arc::clone(input_schema)
1047 };
1048 Ok(LogicalPlan::Union(Union {
1049 inputs: inputs.into_iter().map(Arc::new).collect(),
1050 schema,
1051 }))
1052 }
1053 LogicalPlan::Distinct(distinct) => {
1054 let distinct = match distinct {
1055 Distinct::All(_) => {
1056 self.assert_no_expressions(expr)?;
1057 let input = self.only_input(inputs)?;
1058 Distinct::All(Arc::new(input))
1059 }
1060 Distinct::On(DistinctOn {
1061 on_expr,
1062 select_expr,
1063 ..
1064 }) => {
1065 let input = self.only_input(inputs)?;
1066 let sort_expr = expr.split_off(on_expr.len() + select_expr.len());
1067 let select_expr = expr.split_off(on_expr.len());
1068 assert!(
1069 sort_expr.is_empty(),
1070 "with_new_exprs for Distinct does not support sort expressions"
1071 );
1072 Distinct::On(DistinctOn::try_new(
1073 expr,
1074 select_expr,
1075 None, Arc::new(input),
1077 )?)
1078 }
1079 };
1080 Ok(LogicalPlan::Distinct(distinct))
1081 }
1082 LogicalPlan::RecursiveQuery(RecursiveQuery {
1083 name, is_distinct, ..
1084 }) => {
1085 self.assert_no_expressions(expr)?;
1086 let (static_term, recursive_term) = self.only_two_inputs(inputs)?;
1087 RecursiveQuery::try_new(
1088 name.clone(),
1089 Arc::new(static_term),
1090 Arc::new(recursive_term),
1091 *is_distinct,
1092 )
1093 .map(LogicalPlan::RecursiveQuery)
1094 }
1095 LogicalPlan::Analyze(a) => {
1096 self.assert_no_expressions(expr)?;
1097 let input = self.only_input(inputs)?;
1098 Ok(LogicalPlan::Analyze(Analyze {
1099 verbose: a.verbose,
1100 schema: Arc::clone(&a.schema),
1101 input: Arc::new(input),
1102 }))
1103 }
1104 LogicalPlan::Explain(e) => {
1105 self.assert_no_expressions(expr)?;
1106 let input = self.only_input(inputs)?;
1107 Ok(LogicalPlan::Explain(Explain {
1108 verbose: e.verbose,
1109 plan: Arc::new(input),
1110 explain_format: e.explain_format.clone(),
1111 stringified_plans: e.stringified_plans.clone(),
1112 schema: Arc::clone(&e.schema),
1113 logical_optimization_succeeded: e.logical_optimization_succeeded,
1114 }))
1115 }
1116 LogicalPlan::Statement(Statement::Prepare(Prepare {
1117 name, fields, ..
1118 })) => {
1119 self.assert_no_expressions(expr)?;
1120 let input = self.only_input(inputs)?;
1121 Ok(LogicalPlan::Statement(Statement::Prepare(Prepare {
1122 name: name.clone(),
1123 fields: fields.clone(),
1124 input: Arc::new(input),
1125 })))
1126 }
1127 LogicalPlan::Statement(Statement::Execute(Execute { name, .. })) => {
1128 self.assert_no_inputs(inputs)?;
1129 Ok(LogicalPlan::Statement(Statement::Execute(Execute {
1130 name: name.clone(),
1131 parameters: expr,
1132 })))
1133 }
1134 LogicalPlan::TableScan(ts) => {
1135 self.assert_no_inputs(inputs)?;
1136 Ok(LogicalPlan::TableScan(TableScan {
1137 filters: expr,
1138 ..ts.clone()
1139 }))
1140 }
1141 LogicalPlan::EmptyRelation(_)
1142 | LogicalPlan::Ddl(_)
1143 | LogicalPlan::Statement(_)
1144 | LogicalPlan::DescribeTable(_) => {
1145 self.assert_no_expressions(expr)?;
1147 self.assert_no_inputs(inputs)?;
1148 Ok(self.clone())
1149 }
1150 LogicalPlan::Unnest(Unnest {
1151 exec_columns: columns,
1152 options,
1153 ..
1154 }) => {
1155 self.assert_no_expressions(expr)?;
1156 let input = self.only_input(inputs)?;
1157 let new_plan =
1159 unnest_with_options(input, columns.clone(), options.clone())?;
1160 Ok(new_plan)
1161 }
1162 }
1163 }
1164
1165 pub fn check_invariants(&self, check: InvariantLevel) -> Result<()> {
1167 match check {
1168 InvariantLevel::Always => assert_always_invariants_at_current_node(self),
1169 InvariantLevel::Executable => assert_executable_invariants(self),
1170 }
1171 }
1172
1173 #[inline]
1175 #[expect(clippy::needless_pass_by_value)] fn assert_no_expressions(&self, expr: Vec<Expr>) -> Result<()> {
1177 assert_or_internal_err!(
1178 expr.is_empty(),
1179 "{self:?} should have no exprs, got {:?}",
1180 expr
1181 );
1182 Ok(())
1183 }
1184
1185 #[inline]
1187 #[expect(clippy::needless_pass_by_value)] fn assert_no_inputs(&self, inputs: Vec<LogicalPlan>) -> Result<()> {
1189 assert_or_internal_err!(
1190 inputs.is_empty(),
1191 "{self:?} should have no inputs, got: {:?}",
1192 inputs
1193 );
1194 Ok(())
1195 }
1196
1197 #[inline]
1199 fn only_expr(&self, mut expr: Vec<Expr>) -> Result<Expr> {
1200 assert_eq_or_internal_err!(
1201 expr.len(),
1202 1,
1203 "{self:?} should have exactly one expr, got {:?}",
1204 &expr
1205 );
1206 Ok(expr.remove(0))
1207 }
1208
1209 #[inline]
1211 fn only_input(&self, mut inputs: Vec<LogicalPlan>) -> Result<LogicalPlan> {
1212 assert_eq_or_internal_err!(
1213 inputs.len(),
1214 1,
1215 "{self:?} should have exactly one input, got {:?}",
1216 &inputs
1217 );
1218 Ok(inputs.remove(0))
1219 }
1220
1221 #[inline]
1223 fn only_two_inputs(
1224 &self,
1225 mut inputs: Vec<LogicalPlan>,
1226 ) -> Result<(LogicalPlan, LogicalPlan)> {
1227 assert_eq_or_internal_err!(
1228 inputs.len(),
1229 2,
1230 "{self:?} should have exactly two inputs, got {:?}",
1231 &inputs
1232 );
1233 let right = inputs.remove(1);
1234 let left = inputs.remove(0);
1235 Ok((left, right))
1236 }
1237
1238 pub fn with_param_values(
1291 self,
1292 param_values: impl Into<ParamValues>,
1293 ) -> Result<LogicalPlan> {
1294 let param_values = param_values.into();
1295 let plan_with_values = self.replace_params_with_values(¶m_values)?;
1296
1297 Ok(
1299 if let LogicalPlan::Statement(Statement::Prepare(prepare_lp)) =
1300 plan_with_values
1301 {
1302 param_values.verify_fields(&prepare_lp.fields)?;
1303 Arc::unwrap_or_clone(prepare_lp.input)
1305 } else {
1306 plan_with_values
1307 },
1308 )
1309 }
1310
1311 pub fn max_rows(self: &LogicalPlan) -> Option<usize> {
1316 match self {
1317 LogicalPlan::Projection(Projection { input, .. }) => input.max_rows(),
1318 LogicalPlan::Filter(filter) => {
1319 if filter.is_scalar() {
1320 Some(1)
1321 } else {
1322 filter.input.max_rows()
1323 }
1324 }
1325 LogicalPlan::Window(Window { input, .. }) => input.max_rows(),
1326 LogicalPlan::Aggregate(Aggregate {
1327 input, group_expr, ..
1328 }) => {
1329 if group_expr
1331 .iter()
1332 .all(|expr| matches!(expr, Expr::Literal(_, _)))
1333 {
1334 Some(1)
1335 } else {
1336 input.max_rows()
1337 }
1338 }
1339 LogicalPlan::Sort(Sort { input, fetch, .. }) => {
1340 match (fetch, input.max_rows()) {
1341 (Some(fetch_limit), Some(input_max)) => {
1342 Some(input_max.min(*fetch_limit))
1343 }
1344 (Some(fetch_limit), None) => Some(*fetch_limit),
1345 (None, Some(input_max)) => Some(input_max),
1346 (None, None) => None,
1347 }
1348 }
1349 LogicalPlan::Join(Join {
1350 left,
1351 right,
1352 join_type,
1353 ..
1354 }) => match join_type {
1355 JoinType::Inner => Some(left.max_rows()? * right.max_rows()?),
1356 JoinType::Left | JoinType::Right | JoinType::Full => {
1357 match (left.max_rows()?, right.max_rows()?, join_type) {
1358 (0, 0, _) => Some(0),
1359 (max_rows, 0, JoinType::Left | JoinType::Full) => Some(max_rows),
1360 (0, max_rows, JoinType::Right | JoinType::Full) => Some(max_rows),
1361 (left_max, right_max, _) => Some(left_max * right_max),
1362 }
1363 }
1364 JoinType::LeftSemi | JoinType::LeftAnti | JoinType::LeftMark => {
1365 left.max_rows()
1366 }
1367 JoinType::RightSemi | JoinType::RightAnti | JoinType::RightMark => {
1368 right.max_rows()
1369 }
1370 },
1371 LogicalPlan::Repartition(Repartition { input, .. }) => input.max_rows(),
1372 LogicalPlan::Union(Union { inputs, .. }) => {
1373 inputs.iter().try_fold(0usize, |mut acc, plan| {
1374 acc += plan.max_rows()?;
1375 Some(acc)
1376 })
1377 }
1378 LogicalPlan::TableScan(TableScan { fetch, .. }) => *fetch,
1379 LogicalPlan::EmptyRelation(_) => Some(0),
1380 LogicalPlan::RecursiveQuery(_) => None,
1381 LogicalPlan::Subquery(_) => None,
1382 LogicalPlan::SubqueryAlias(SubqueryAlias { input, .. }) => input.max_rows(),
1383 LogicalPlan::Limit(limit) => match limit.get_fetch_type() {
1384 Ok(FetchType::Literal(s)) => s,
1385 _ => None,
1386 },
1387 LogicalPlan::Distinct(
1388 Distinct::All(input) | Distinct::On(DistinctOn { input, .. }),
1389 ) => input.max_rows(),
1390 LogicalPlan::Values(v) => Some(v.values.len()),
1391 LogicalPlan::Unnest(_) => None,
1392 LogicalPlan::Ddl(_)
1393 | LogicalPlan::Explain(_)
1394 | LogicalPlan::Analyze(_)
1395 | LogicalPlan::Dml(_)
1396 | LogicalPlan::Copy(_)
1397 | LogicalPlan::DescribeTable(_)
1398 | LogicalPlan::Statement(_)
1399 | LogicalPlan::Extension(_) => None,
1400 }
1401 }
1402
1403 pub fn skip(&self) -> Result<Option<usize>> {
1408 match self {
1409 LogicalPlan::Limit(limit) => match limit.get_skip_type()? {
1410 SkipType::Literal(0) => Ok(None),
1411 SkipType::Literal(n) => Ok(Some(n)),
1412 SkipType::UnsupportedExpr => Ok(None),
1413 },
1414 LogicalPlan::Sort(_) => Ok(None),
1415 LogicalPlan::TableScan(_) => Ok(None),
1416 LogicalPlan::Projection(_) => Ok(None),
1417 LogicalPlan::Filter(_) => Ok(None),
1418 LogicalPlan::Window(_) => Ok(None),
1419 LogicalPlan::Aggregate(_) => Ok(None),
1420 LogicalPlan::Join(_) => Ok(None),
1421 LogicalPlan::Repartition(_) => Ok(None),
1422 LogicalPlan::Union(_) => Ok(None),
1423 LogicalPlan::EmptyRelation(_) => Ok(None),
1424 LogicalPlan::Subquery(_) => Ok(None),
1425 LogicalPlan::SubqueryAlias(_) => Ok(None),
1426 LogicalPlan::Statement(_) => Ok(None),
1427 LogicalPlan::Values(_) => Ok(None),
1428 LogicalPlan::Explain(_) => Ok(None),
1429 LogicalPlan::Analyze(_) => Ok(None),
1430 LogicalPlan::Extension(_) => Ok(None),
1431 LogicalPlan::Distinct(_) => Ok(None),
1432 LogicalPlan::Dml(_) => Ok(None),
1433 LogicalPlan::Ddl(_) => Ok(None),
1434 LogicalPlan::Copy(_) => Ok(None),
1435 LogicalPlan::DescribeTable(_) => Ok(None),
1436 LogicalPlan::Unnest(_) => Ok(None),
1437 LogicalPlan::RecursiveQuery(_) => Ok(None),
1438 }
1439 }
1440
1441 pub fn fetch(&self) -> Result<Option<usize>> {
1447 match self {
1448 LogicalPlan::Sort(Sort { fetch, .. }) => Ok(*fetch),
1449 LogicalPlan::TableScan(TableScan { fetch, .. }) => Ok(*fetch),
1450 LogicalPlan::Limit(limit) => match limit.get_fetch_type()? {
1451 FetchType::Literal(s) => Ok(s),
1452 FetchType::UnsupportedExpr => Ok(None),
1453 },
1454 LogicalPlan::Projection(_) => Ok(None),
1455 LogicalPlan::Filter(_) => Ok(None),
1456 LogicalPlan::Window(_) => Ok(None),
1457 LogicalPlan::Aggregate(_) => Ok(None),
1458 LogicalPlan::Join(_) => Ok(None),
1459 LogicalPlan::Repartition(_) => Ok(None),
1460 LogicalPlan::Union(_) => Ok(None),
1461 LogicalPlan::EmptyRelation(_) => Ok(None),
1462 LogicalPlan::Subquery(_) => Ok(None),
1463 LogicalPlan::SubqueryAlias(_) => Ok(None),
1464 LogicalPlan::Statement(_) => Ok(None),
1465 LogicalPlan::Values(_) => Ok(None),
1466 LogicalPlan::Explain(_) => Ok(None),
1467 LogicalPlan::Analyze(_) => Ok(None),
1468 LogicalPlan::Extension(_) => Ok(None),
1469 LogicalPlan::Distinct(_) => Ok(None),
1470 LogicalPlan::Dml(_) => Ok(None),
1471 LogicalPlan::Ddl(_) => Ok(None),
1472 LogicalPlan::Copy(_) => Ok(None),
1473 LogicalPlan::DescribeTable(_) => Ok(None),
1474 LogicalPlan::Unnest(_) => Ok(None),
1475 LogicalPlan::RecursiveQuery(_) => Ok(None),
1476 }
1477 }
1478
1479 pub fn contains_outer_reference(&self) -> bool {
1481 let mut contains = false;
1482 self.apply_expressions(|expr| {
1483 Ok(if expr.contains_outer() {
1484 contains = true;
1485 TreeNodeRecursion::Stop
1486 } else {
1487 TreeNodeRecursion::Continue
1488 })
1489 })
1490 .unwrap();
1491 contains
1492 }
1493
1494 pub fn columnized_output_exprs(&self) -> Result<Vec<(&Expr, Column)>> {
1502 match self {
1503 LogicalPlan::Aggregate(aggregate) => Ok(aggregate
1504 .output_expressions()?
1505 .into_iter()
1506 .zip(self.schema().columns())
1507 .collect()),
1508 LogicalPlan::Window(Window {
1509 window_expr,
1510 input,
1511 schema,
1512 }) => {
1513 let mut output_exprs = input.columnized_output_exprs()?;
1521 let input_len = input.schema().fields().len();
1522 output_exprs.extend(
1523 window_expr
1524 .iter()
1525 .zip(schema.columns().into_iter().skip(input_len)),
1526 );
1527 Ok(output_exprs)
1528 }
1529 _ => Ok(vec![]),
1530 }
1531 }
1532}
1533
1534impl LogicalPlan {
1535 pub fn replace_params_with_values(
1542 self,
1543 param_values: &ParamValues,
1544 ) -> Result<LogicalPlan> {
1545 self.transform_up_with_subqueries(|plan| {
1546 let schema = Arc::clone(plan.schema());
1547 let name_preserver = NamePreserver::new(&plan);
1548 plan.map_expressions(|e| {
1549 let (e, has_placeholder) = e.infer_placeholder_types(&schema)?;
1550 if !has_placeholder {
1551 Ok(Transformed::no(e))
1555 } else {
1556 let original_name = name_preserver.save(&e);
1557 let transformed_expr = e.transform_up(|e| {
1558 if let Expr::Placeholder(Placeholder { id, .. }) = e {
1559 let (value, metadata) = param_values
1560 .get_placeholders_with_values(&id)?
1561 .into_inner();
1562 Ok(Transformed::yes(Expr::Literal(value, metadata)))
1563 } else {
1564 Ok(Transformed::no(e))
1565 }
1566 })?;
1567 Ok(transformed_expr.update_data(|expr| original_name.restore(expr)))
1569 }
1570 })?
1571 .map_data(|plan| plan.update_schema_data_type())
1572 })
1573 .map(|res| res.data)
1574 }
1575
1576 fn update_schema_data_type(self) -> Result<LogicalPlan> {
1582 match self {
1583 LogicalPlan::Values(Values { values, schema: _ }) => {
1587 LogicalPlanBuilder::values(values)?.build()
1588 }
1589 plan => plan.recompute_schema(),
1591 }
1592 }
1593
1594 pub fn get_parameter_names(&self) -> Result<HashSet<String>> {
1596 let mut param_names = HashSet::new();
1597 self.apply_with_subqueries(|plan| {
1598 plan.apply_expressions(|expr| {
1599 expr.apply(|expr| {
1600 if let Expr::Placeholder(Placeholder { id, .. }) = expr {
1601 param_names.insert(id.clone());
1602 }
1603 Ok(TreeNodeRecursion::Continue)
1604 })
1605 })
1606 })
1607 .map(|_| param_names)
1608 }
1609
1610 pub fn get_parameter_types(
1615 &self,
1616 ) -> Result<HashMap<String, Option<DataType>>, DataFusionError> {
1617 let mut parameter_fields = self.get_parameter_fields()?;
1618 Ok(parameter_fields
1619 .drain()
1620 .map(|(name, maybe_field)| {
1621 (name, maybe_field.map(|field| field.data_type().clone()))
1622 })
1623 .collect())
1624 }
1625
1626 pub fn get_parameter_fields(
1628 &self,
1629 ) -> Result<HashMap<String, Option<FieldRef>>, DataFusionError> {
1630 let mut param_types: HashMap<String, Option<FieldRef>> = HashMap::new();
1631
1632 self.apply_with_subqueries(|plan| {
1633 plan.apply_expressions(|expr| {
1634 expr.apply(|expr| {
1635 if let Expr::Placeholder(Placeholder { id, field }) = expr {
1636 let prev = param_types.get(id);
1637 match (prev, field) {
1638 (Some(Some(prev)), Some(field)) => {
1639 check_metadata_with_storage_equal(
1640 (field.data_type(), Some(field.metadata())),
1641 (prev.data_type(), Some(prev.metadata())),
1642 "parameter",
1643 &format!(": Conflicting types for id {id}"),
1644 )?;
1645 }
1646 (_, Some(field)) => {
1647 param_types.insert(id.clone(), Some(Arc::clone(field)));
1648 }
1649 _ => {
1650 param_types.insert(id.clone(), None);
1651 }
1652 }
1653 }
1654 Ok(TreeNodeRecursion::Continue)
1655 })
1656 })
1657 })
1658 .map(|_| param_types)
1659 }
1660
1661 pub fn display_indent(&self) -> impl Display + '_ {
1693 struct Wrapper<'a>(&'a LogicalPlan);
1696 impl Display for Wrapper<'_> {
1697 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1698 let with_schema = false;
1699 let mut visitor = IndentVisitor::new(f, with_schema);
1700 match self.0.visit_with_subqueries(&mut visitor) {
1701 Ok(_) => Ok(()),
1702 Err(_) => Err(fmt::Error),
1703 }
1704 }
1705 }
1706 Wrapper(self)
1707 }
1708
1709 pub fn display_indent_schema(&self) -> impl Display + '_ {
1739 struct Wrapper<'a>(&'a LogicalPlan);
1742 impl Display for Wrapper<'_> {
1743 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1744 let with_schema = true;
1745 let mut visitor = IndentVisitor::new(f, with_schema);
1746 match self.0.visit_with_subqueries(&mut visitor) {
1747 Ok(_) => Ok(()),
1748 Err(_) => Err(fmt::Error),
1749 }
1750 }
1751 }
1752 Wrapper(self)
1753 }
1754
1755 pub fn display_pg_json(&self) -> impl Display + '_ {
1759 struct Wrapper<'a>(&'a LogicalPlan);
1762 impl Display for Wrapper<'_> {
1763 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1764 let mut visitor = PgJsonVisitor::new(f);
1765 visitor.with_schema(true);
1766 match self.0.visit_with_subqueries(&mut visitor) {
1767 Ok(_) => Ok(()),
1768 Err(_) => Err(fmt::Error),
1769 }
1770 }
1771 }
1772 Wrapper(self)
1773 }
1774
1775 pub fn display_graphviz(&self) -> impl Display + '_ {
1805 struct Wrapper<'a>(&'a LogicalPlan);
1808 impl Display for Wrapper<'_> {
1809 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1810 let mut visitor = GraphvizVisitor::new(f);
1811
1812 visitor.start_graph()?;
1813
1814 visitor.pre_visit_plan("LogicalPlan")?;
1815 self.0
1816 .visit_with_subqueries(&mut visitor)
1817 .map_err(|_| fmt::Error)?;
1818 visitor.post_visit_plan()?;
1819
1820 visitor.set_with_schema(true);
1821 visitor.pre_visit_plan("Detailed LogicalPlan")?;
1822 self.0
1823 .visit_with_subqueries(&mut visitor)
1824 .map_err(|_| fmt::Error)?;
1825 visitor.post_visit_plan()?;
1826
1827 visitor.end_graph()?;
1828 Ok(())
1829 }
1830 }
1831 Wrapper(self)
1832 }
1833
1834 pub fn display(&self) -> impl Display + '_ {
1856 struct Wrapper<'a>(&'a LogicalPlan);
1859 impl Display for Wrapper<'_> {
1860 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1861 match self.0 {
1862 LogicalPlan::EmptyRelation(EmptyRelation {
1863 produce_one_row,
1864 schema: _,
1865 }) => {
1866 let rows = if *produce_one_row { 1 } else { 0 };
1867 write!(f, "EmptyRelation: rows={rows}")
1868 }
1869 LogicalPlan::RecursiveQuery(RecursiveQuery {
1870 is_distinct, ..
1871 }) => {
1872 write!(f, "RecursiveQuery: is_distinct={is_distinct}")
1873 }
1874 LogicalPlan::Values(Values { values, .. }) => {
1875 let str_values: Vec<_> = values
1876 .iter()
1877 .take(5)
1879 .map(|row| {
1880 let item = row
1881 .iter()
1882 .map(|expr| expr.to_string())
1883 .collect::<Vec<_>>()
1884 .join(", ");
1885 format!("({item})")
1886 })
1887 .collect();
1888
1889 let eclipse = if values.len() > 5 { "..." } else { "" };
1890 write!(f, "Values: {}{}", str_values.join(", "), eclipse)
1891 }
1892
1893 LogicalPlan::TableScan(TableScan {
1894 source,
1895 table_name,
1896 projection,
1897 filters,
1898 fetch,
1899 ..
1900 }) => {
1901 let projected_fields = match projection {
1902 Some(indices) => {
1903 let schema = source.schema();
1904 let names: Vec<&str> = indices
1905 .iter()
1906 .map(|i| schema.field(*i).name().as_str())
1907 .collect();
1908 format!(" projection=[{}]", names.join(", "))
1909 }
1910 _ => "".to_string(),
1911 };
1912
1913 write!(f, "TableScan: {table_name}{projected_fields}")?;
1914
1915 if !filters.is_empty() {
1916 let mut full_filter = vec![];
1917 let mut partial_filter = vec![];
1918 let mut unsupported_filters = vec![];
1919 let filters: Vec<&Expr> = filters.iter().collect();
1920
1921 if let Ok(results) =
1922 source.supports_filters_pushdown(&filters)
1923 {
1924 filters.iter().zip(results.iter()).for_each(
1925 |(x, res)| match res {
1926 TableProviderFilterPushDown::Exact => {
1927 full_filter.push(x)
1928 }
1929 TableProviderFilterPushDown::Inexact => {
1930 partial_filter.push(x)
1931 }
1932 TableProviderFilterPushDown::Unsupported => {
1933 unsupported_filters.push(x)
1934 }
1935 },
1936 );
1937 }
1938
1939 if !full_filter.is_empty() {
1940 write!(
1941 f,
1942 ", full_filters=[{}]",
1943 expr_vec_fmt!(full_filter)
1944 )?;
1945 };
1946 if !partial_filter.is_empty() {
1947 write!(
1948 f,
1949 ", partial_filters=[{}]",
1950 expr_vec_fmt!(partial_filter)
1951 )?;
1952 }
1953 if !unsupported_filters.is_empty() {
1954 write!(
1955 f,
1956 ", unsupported_filters=[{}]",
1957 expr_vec_fmt!(unsupported_filters)
1958 )?;
1959 }
1960 }
1961
1962 if let Some(n) = fetch {
1963 write!(f, ", fetch={n}")?;
1964 }
1965
1966 Ok(())
1967 }
1968 LogicalPlan::Projection(Projection { expr, .. }) => {
1969 write!(f, "Projection:")?;
1970 for (i, expr_item) in expr.iter().enumerate() {
1971 if i > 0 {
1972 write!(f, ",")?;
1973 }
1974 write!(f, " {expr_item}")?;
1975 }
1976 Ok(())
1977 }
1978 LogicalPlan::Dml(DmlStatement { table_name, op, .. }) => {
1979 write!(f, "Dml: op=[{op}] table=[{table_name}]")
1980 }
1981 LogicalPlan::Copy(CopyTo {
1982 input: _,
1983 output_url,
1984 file_type,
1985 options,
1986 ..
1987 }) => {
1988 let op_str = options
1989 .iter()
1990 .map(|(k, v)| format!("{k} {v}"))
1991 .collect::<Vec<String>>()
1992 .join(", ");
1993
1994 write!(
1995 f,
1996 "CopyTo: format={} output_url={output_url} options: ({op_str})",
1997 file_type.get_ext()
1998 )
1999 }
2000 LogicalPlan::Ddl(ddl) => {
2001 write!(f, "{}", ddl.display())
2002 }
2003 LogicalPlan::Filter(Filter {
2004 predicate: expr, ..
2005 }) => write!(f, "Filter: {expr}"),
2006 LogicalPlan::Window(Window { window_expr, .. }) => {
2007 write!(
2008 f,
2009 "WindowAggr: windowExpr=[[{}]]",
2010 expr_vec_fmt!(window_expr)
2011 )
2012 }
2013 LogicalPlan::Aggregate(Aggregate {
2014 group_expr,
2015 aggr_expr,
2016 ..
2017 }) => write!(
2018 f,
2019 "Aggregate: groupBy=[[{}]], aggr=[[{}]]",
2020 expr_vec_fmt!(group_expr),
2021 expr_vec_fmt!(aggr_expr)
2022 ),
2023 LogicalPlan::Sort(Sort { expr, fetch, .. }) => {
2024 write!(f, "Sort: ")?;
2025 for (i, expr_item) in expr.iter().enumerate() {
2026 if i > 0 {
2027 write!(f, ", ")?;
2028 }
2029 write!(f, "{expr_item}")?;
2030 }
2031 if let Some(a) = fetch {
2032 write!(f, ", fetch={a}")?;
2033 }
2034
2035 Ok(())
2036 }
2037 LogicalPlan::Join(Join {
2038 on: keys,
2039 filter,
2040 join_constraint,
2041 join_type,
2042 ..
2043 }) => {
2044 let join_expr: Vec<String> =
2045 keys.iter().map(|(l, r)| format!("{l} = {r}")).collect();
2046 let filter_expr = filter
2047 .as_ref()
2048 .map(|expr| format!(" Filter: {expr}"))
2049 .unwrap_or_else(|| "".to_string());
2050 let join_type = if filter.is_none()
2051 && keys.is_empty()
2052 && *join_type == JoinType::Inner
2053 {
2054 "Cross".to_string()
2055 } else {
2056 join_type.to_string()
2057 };
2058 match join_constraint {
2059 JoinConstraint::On => {
2060 write!(f, "{join_type} Join:",)?;
2061 if !join_expr.is_empty() || !filter_expr.is_empty() {
2062 write!(
2063 f,
2064 " {}{}",
2065 join_expr.join(", "),
2066 filter_expr
2067 )?;
2068 }
2069 Ok(())
2070 }
2071 JoinConstraint::Using => {
2072 write!(
2073 f,
2074 "{} Join: Using {}{}",
2075 join_type,
2076 join_expr.join(", "),
2077 filter_expr,
2078 )
2079 }
2080 }
2081 }
2082 LogicalPlan::Repartition(Repartition {
2083 partitioning_scheme,
2084 ..
2085 }) => match partitioning_scheme {
2086 Partitioning::RoundRobinBatch(n) => {
2087 write!(f, "Repartition: RoundRobinBatch partition_count={n}")
2088 }
2089 Partitioning::Hash(expr, n) => {
2090 let hash_expr: Vec<String> =
2091 expr.iter().map(|e| format!("{e}")).collect();
2092 write!(
2093 f,
2094 "Repartition: Hash({}) partition_count={}",
2095 hash_expr.join(", "),
2096 n
2097 )
2098 }
2099 Partitioning::DistributeBy(expr) => {
2100 let dist_by_expr: Vec<String> =
2101 expr.iter().map(|e| format!("{e}")).collect();
2102 write!(
2103 f,
2104 "Repartition: DistributeBy({})",
2105 dist_by_expr.join(", "),
2106 )
2107 }
2108 },
2109 LogicalPlan::Limit(limit) => {
2110 let skip_str = match limit.get_skip_type() {
2112 Ok(SkipType::Literal(n)) => n.to_string(),
2113 _ => limit
2114 .skip
2115 .as_ref()
2116 .map_or_else(|| "None".to_string(), |x| x.to_string()),
2117 };
2118 let fetch_str = match limit.get_fetch_type() {
2119 Ok(FetchType::Literal(Some(n))) => n.to_string(),
2120 Ok(FetchType::Literal(None)) => "None".to_string(),
2121 _ => limit
2122 .fetch
2123 .as_ref()
2124 .map_or_else(|| "None".to_string(), |x| x.to_string()),
2125 };
2126 write!(f, "Limit: skip={skip_str}, fetch={fetch_str}",)
2127 }
2128 LogicalPlan::Subquery(Subquery { .. }) => {
2129 write!(f, "Subquery:")
2130 }
2131 LogicalPlan::SubqueryAlias(SubqueryAlias { alias, .. }) => {
2132 write!(f, "SubqueryAlias: {alias}")
2133 }
2134 LogicalPlan::Statement(statement) => {
2135 write!(f, "{}", statement.display())
2136 }
2137 LogicalPlan::Distinct(distinct) => match distinct {
2138 Distinct::All(_) => write!(f, "Distinct:"),
2139 Distinct::On(DistinctOn {
2140 on_expr,
2141 select_expr,
2142 sort_expr,
2143 ..
2144 }) => write!(
2145 f,
2146 "DistinctOn: on_expr=[[{}]], select_expr=[[{}]], sort_expr=[[{}]]",
2147 expr_vec_fmt!(on_expr),
2148 expr_vec_fmt!(select_expr),
2149 if let Some(sort_expr) = sort_expr {
2150 expr_vec_fmt!(sort_expr)
2151 } else {
2152 "".to_string()
2153 },
2154 ),
2155 },
2156 LogicalPlan::Explain { .. } => write!(f, "Explain"),
2157 LogicalPlan::Analyze { .. } => write!(f, "Analyze"),
2158 LogicalPlan::Union(_) => write!(f, "Union"),
2159 LogicalPlan::Extension(e) => e.node.fmt_for_explain(f),
2160 LogicalPlan::DescribeTable(DescribeTable { .. }) => {
2161 write!(f, "DescribeTable")
2162 }
2163 LogicalPlan::Unnest(Unnest {
2164 input: plan,
2165 list_type_columns: list_col_indices,
2166 struct_type_columns: struct_col_indices,
2167 ..
2168 }) => {
2169 let input_columns = plan.schema().columns();
2170 let list_type_columns = list_col_indices
2171 .iter()
2172 .map(|(i, unnest_info)| {
2173 format!(
2174 "{}|depth={}",
2175 &input_columns[*i].to_string(),
2176 unnest_info.depth
2177 )
2178 })
2179 .collect::<Vec<String>>();
2180 let struct_type_columns = struct_col_indices
2181 .iter()
2182 .map(|i| &input_columns[*i])
2183 .collect::<Vec<&Column>>();
2184 write!(
2186 f,
2187 "Unnest: lists[{}] structs[{}]",
2188 expr_vec_fmt!(list_type_columns),
2189 expr_vec_fmt!(struct_type_columns)
2190 )
2191 }
2192 }
2193 }
2194 }
2195 Wrapper(self)
2196 }
2197
2198 pub fn resolve_lambda_variables(self) -> Result<Transformed<LogicalPlan>> {
2202 self.transform_with_subqueries(|plan| {
2203 let schema = merge_schema(&plan.inputs());
2204
2205 plan.map_expressions(|expr| expr.resolve_lambda_variables(&schema))
2206 })
2207 }
2208}
2209
2210impl Display for LogicalPlan {
2211 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2212 self.display_indent().fmt(f)
2213 }
2214}
2215
2216impl ToStringifiedPlan for LogicalPlan {
2217 fn to_stringified(&self, plan_type: PlanType) -> StringifiedPlan {
2218 StringifiedPlan::new(plan_type, self.display_indent().to_string())
2219 }
2220}
2221
2222#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2226pub struct EmptyRelation {
2227 pub produce_one_row: bool,
2229 pub schema: DFSchemaRef,
2231}
2232
2233impl PartialOrd for EmptyRelation {
2235 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2236 self.produce_one_row
2237 .partial_cmp(&other.produce_one_row)
2238 .filter(|cmp| *cmp != Ordering::Equal || self == other)
2240 }
2241}
2242
2243#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2266pub struct RecursiveQuery {
2267 pub name: String,
2269 pub static_term: Arc<LogicalPlan>,
2271 pub recursive_term: Arc<LogicalPlan>,
2274 pub is_distinct: bool,
2277 pub schema: DFSchemaRef,
2279}
2280
2281impl PartialOrd for RecursiveQuery {
2282 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2283 match self.name.partial_cmp(&other.name) {
2284 Some(Ordering::Equal) => {
2285 match self.static_term.partial_cmp(&other.static_term) {
2286 Some(Ordering::Equal) => {
2287 match self.recursive_term.partial_cmp(&other.recursive_term) {
2288 Some(Ordering::Equal) => {
2289 self.is_distinct.partial_cmp(&other.is_distinct)
2290 }
2291 cmp => cmp,
2292 }
2293 }
2294 cmp => cmp,
2295 }
2296 }
2297 cmp => cmp,
2298 }
2299 .filter(|cmp| *cmp != Ordering::Equal || self == other)
2303 }
2304}
2305
2306impl RecursiveQuery {
2307 pub fn try_new(
2308 name: String,
2309 static_term: Arc<LogicalPlan>,
2310 recursive_term: Arc<LogicalPlan>,
2311 is_distinct: bool,
2312 ) -> Result<Self> {
2313 let schema =
2314 recursive_query_output_schema(static_term.schema(), recursive_term.schema())?;
2315 Ok(Self {
2316 name,
2317 static_term,
2318 recursive_term,
2319 is_distinct,
2320 schema,
2321 })
2322 }
2323}
2324
2325fn recursive_query_output_schema(
2336 static_schema: &DFSchemaRef,
2337 recursive_schema: &DFSchemaRef,
2338) -> Result<DFSchemaRef> {
2339 if static_schema.fields().len() != recursive_schema.fields().len() {
2340 return Err(DataFusionError::Plan(format!(
2341 "Non-recursive term and recursive term must have the same number of columns ({} != {})",
2342 static_schema.fields().len(),
2343 recursive_schema.fields().len()
2344 )));
2345 }
2346
2347 let fields = static_schema
2348 .iter()
2349 .zip(recursive_schema.fields())
2350 .map(|((qualifier, static_field), recursive_field)| {
2351 let nullable = static_field.is_nullable() || recursive_field.is_nullable();
2352 (
2353 qualifier.cloned(),
2354 static_field.as_ref().clone().with_nullable(nullable).into(),
2355 )
2356 })
2357 .collect::<Vec<_>>();
2358
2359 DFSchema::new_with_metadata(fields, static_schema.metadata().clone())
2360 .map(DFSchemaRef::new)
2361}
2362
2363#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2367pub struct Values {
2368 pub schema: DFSchemaRef,
2370 pub values: Vec<Vec<Expr>>,
2372}
2373
2374impl PartialOrd for Values {
2376 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2377 self.values
2378 .partial_cmp(&other.values)
2379 .filter(|cmp| *cmp != Ordering::Equal || self == other)
2381 }
2382}
2383
2384#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2387#[non_exhaustive]
2389pub struct Projection {
2390 pub expr: Vec<Expr>,
2392 pub input: Arc<LogicalPlan>,
2394 pub schema: DFSchemaRef,
2396}
2397
2398impl PartialOrd for Projection {
2400 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2401 match self.expr.partial_cmp(&other.expr) {
2402 Some(Ordering::Equal) => self.input.partial_cmp(&other.input),
2403 cmp => cmp,
2404 }
2405 .filter(|cmp| *cmp != Ordering::Equal || self == other)
2407 }
2408}
2409
2410impl Projection {
2411 pub fn try_new(expr: Vec<Expr>, input: Arc<LogicalPlan>) -> Result<Self> {
2413 let projection_schema = projection_schema(&input, &expr)?;
2414 Self::try_new_with_schema(expr, input, projection_schema)
2415 }
2416
2417 pub fn try_new_with_schema(
2419 expr: Vec<Expr>,
2420 input: Arc<LogicalPlan>,
2421 schema: DFSchemaRef,
2422 ) -> Result<Self> {
2423 #[expect(deprecated)]
2424 if !expr.iter().any(|e| matches!(e, Expr::Wildcard { .. }))
2425 && expr.len() != schema.fields().len()
2426 {
2427 return plan_err!(
2428 "Projection has mismatch between number of expressions ({}) and number of fields in schema ({})",
2429 expr.len(),
2430 schema.fields().len()
2431 );
2432 }
2433 Ok(Self {
2434 expr,
2435 input,
2436 schema,
2437 })
2438 }
2439
2440 pub fn new_from_schema(input: Arc<LogicalPlan>, schema: DFSchemaRef) -> Self {
2442 let expr: Vec<Expr> = schema.columns().into_iter().map(Expr::Column).collect();
2443 Self {
2444 expr,
2445 input,
2446 schema,
2447 }
2448 }
2449}
2450
2451pub fn projection_schema(input: &LogicalPlan, exprs: &[Expr]) -> Result<Arc<DFSchema>> {
2471 let metadata = input.schema().metadata().clone();
2473
2474 let schema =
2476 DFSchema::new_with_metadata(exprlist_to_fields(exprs, input)?, metadata)?
2477 .with_functional_dependencies(calc_func_dependencies_for_project(
2478 exprs, input,
2479 )?)?;
2480
2481 Ok(Arc::new(schema))
2482}
2483
2484#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2486#[non_exhaustive]
2488pub struct SubqueryAlias {
2489 pub input: Arc<LogicalPlan>,
2491 pub alias: TableReference,
2493 pub schema: DFSchemaRef,
2495}
2496
2497impl SubqueryAlias {
2498 pub fn try_new(
2499 plan: Arc<LogicalPlan>,
2500 alias: impl Into<TableReference>,
2501 ) -> Result<Self> {
2502 let alias = alias.into();
2503
2504 let aliases = unique_field_aliases(plan.schema().fields());
2510 let is_projection_needed = aliases.iter().any(Option::is_some);
2511
2512 let plan = if is_projection_needed {
2514 let projection_expressions = aliases
2515 .iter()
2516 .zip(plan.schema().iter())
2517 .map(|(alias, (qualifier, field))| {
2518 let column =
2519 Expr::Column(Column::new(qualifier.cloned(), field.name()));
2520 match alias {
2521 None => column,
2522 Some(alias) => {
2523 Expr::Alias(Alias::new(column, qualifier.cloned(), alias))
2524 }
2525 }
2526 })
2527 .collect();
2528 let projection = Projection::try_new(projection_expressions, plan)?;
2529 Arc::new(LogicalPlan::Projection(projection))
2530 } else {
2531 plan
2532 };
2533
2534 let fields = plan.schema().fields().clone();
2536 let meta_data = plan.schema().metadata().clone();
2537 let func_dependencies = plan.schema().functional_dependencies().clone();
2538
2539 let schema = DFSchema::from_unqualified_fields(fields, meta_data)?;
2540 let schema = schema.as_arrow();
2541
2542 let schema = DFSchemaRef::new(
2543 DFSchema::try_from_qualified_schema(alias.clone(), schema)?
2544 .with_functional_dependencies(func_dependencies)?,
2545 );
2546 Ok(SubqueryAlias {
2547 input: plan,
2548 alias,
2549 schema,
2550 })
2551 }
2552}
2553
2554impl PartialOrd for SubqueryAlias {
2556 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2557 match self.input.partial_cmp(&other.input) {
2558 Some(Ordering::Equal) => self.alias.partial_cmp(&other.alias),
2559 cmp => cmp,
2560 }
2561 .filter(|cmp| *cmp != Ordering::Equal || self == other)
2563 }
2564}
2565
2566#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
2578#[non_exhaustive]
2579pub struct Filter {
2580 pub predicate: Expr,
2582 pub input: Arc<LogicalPlan>,
2584}
2585
2586impl Filter {
2587 pub fn try_new(predicate: Expr, input: Arc<LogicalPlan>) -> Result<Self> {
2592 Self::try_new_internal(predicate, input)
2593 }
2594
2595 #[deprecated(since = "48.0.0", note = "Use `try_new` instead")]
2598 pub fn try_new_with_having(predicate: Expr, input: Arc<LogicalPlan>) -> Result<Self> {
2599 Self::try_new_internal(predicate, input)
2600 }
2601
2602 fn is_allowed_filter_type(data_type: &DataType) -> bool {
2603 match data_type {
2604 DataType::Boolean | DataType::Null => true,
2606 DataType::Dictionary(_, value_type) => {
2607 Filter::is_allowed_filter_type(value_type.as_ref())
2608 }
2609 _ => false,
2610 }
2611 }
2612
2613 fn try_new_internal(predicate: Expr, input: Arc<LogicalPlan>) -> Result<Self> {
2614 if let Ok(predicate_type) = predicate.get_type(input.schema())
2619 && !Filter::is_allowed_filter_type(&predicate_type)
2620 {
2621 return plan_err!(
2622 "Cannot create filter with non-boolean predicate '{predicate}' returning {predicate_type}"
2623 );
2624 }
2625
2626 Ok(Self {
2627 predicate: predicate.unalias_nested().data,
2628 input,
2629 })
2630 }
2631
2632 fn is_scalar(&self) -> bool {
2648 let schema = self.input.schema();
2649
2650 let functional_dependencies = self.input.schema().functional_dependencies();
2651 let unique_keys = functional_dependencies.iter().filter(|dep| {
2652 let nullable = dep.nullable
2653 && dep
2654 .source_indices
2655 .iter()
2656 .any(|&source| schema.field(source).is_nullable());
2657 !nullable
2658 && dep.mode == Dependency::Single
2659 && dep.target_indices.len() == schema.fields().len()
2660 });
2661
2662 let exprs = split_conjunction(&self.predicate);
2663 let eq_pred_cols: HashSet<_> = exprs
2664 .iter()
2665 .filter_map(|expr| {
2666 let Expr::BinaryExpr(BinaryExpr {
2667 left,
2668 op: Operator::Eq,
2669 right,
2670 }) = expr
2671 else {
2672 return None;
2673 };
2674 if left == right {
2676 return None;
2677 }
2678
2679 match (left.as_ref(), right.as_ref()) {
2680 (Expr::Column(_), Expr::Column(_)) => None,
2681 (Expr::Column(c), _) | (_, Expr::Column(c)) => {
2682 Some(schema.index_of_column(c).unwrap())
2683 }
2684 _ => None,
2685 }
2686 })
2687 .collect();
2688
2689 for key in unique_keys {
2692 if key.source_indices.iter().all(|c| eq_pred_cols.contains(c)) {
2693 return true;
2694 }
2695 }
2696 false
2697 }
2698}
2699
2700#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2715pub struct Window {
2716 pub input: Arc<LogicalPlan>,
2718 pub window_expr: Vec<Expr>,
2720 pub schema: DFSchemaRef,
2722}
2723
2724impl Window {
2725 pub fn try_new(window_expr: Vec<Expr>, input: Arc<LogicalPlan>) -> Result<Self> {
2727 let fields: Vec<(Option<TableReference>, Arc<Field>)> = input
2728 .schema()
2729 .iter()
2730 .map(|(q, f)| (q.cloned(), Arc::clone(f)))
2731 .collect();
2732 let input_len = fields.len();
2733 let mut window_fields = fields;
2734 let expr_fields = exprlist_to_fields(window_expr.as_slice(), &input)?;
2735 window_fields.extend_from_slice(expr_fields.as_slice());
2736 let metadata = input.schema().metadata().clone();
2737
2738 let mut window_func_dependencies =
2740 input.schema().functional_dependencies().clone();
2741 window_func_dependencies.extend_target_indices(window_fields.len());
2742
2743 let mut new_dependencies = window_expr
2747 .iter()
2748 .enumerate()
2749 .filter_map(|(idx, expr)| {
2750 let Expr::WindowFunction(window_fun) = expr else {
2751 return None;
2752 };
2753 let WindowFunction {
2754 fun: WindowFunctionDefinition::WindowUDF(udwf),
2755 params: WindowFunctionParams { partition_by, .. },
2756 } = window_fun.as_ref()
2757 else {
2758 return None;
2759 };
2760 if udwf.name() == "row_number" && partition_by.is_empty() {
2763 Some(idx + input_len)
2764 } else {
2765 None
2766 }
2767 })
2768 .map(|idx| {
2769 FunctionalDependence::new(vec![idx], vec![], false)
2770 .with_mode(Dependency::Single)
2771 })
2772 .collect::<Vec<_>>();
2773
2774 if !new_dependencies.is_empty() {
2775 for dependence in new_dependencies.iter_mut() {
2776 dependence.target_indices = (0..window_fields.len()).collect();
2777 }
2778 let new_deps = FunctionalDependencies::new(new_dependencies);
2780 window_func_dependencies.extend(new_deps);
2781 }
2782
2783 if let Some(e) = window_expr.iter().find(|e| {
2785 matches!(
2786 e,
2787 Expr::WindowFunction(wf)
2788 if !matches!(wf.fun, WindowFunctionDefinition::AggregateUDF(_))
2789 && wf.params.filter.is_some()
2790 )
2791 }) {
2792 return plan_err!(
2793 "FILTER clause can only be used with aggregate window functions. Found in '{e}'"
2794 );
2795 }
2796
2797 Self::try_new_with_schema(
2798 window_expr,
2799 input,
2800 Arc::new(
2801 DFSchema::new_with_metadata(window_fields, metadata)?
2802 .with_functional_dependencies(window_func_dependencies)?,
2803 ),
2804 )
2805 }
2806
2807 pub fn try_new_with_schema(
2813 window_expr: Vec<Expr>,
2814 input: Arc<LogicalPlan>,
2815 schema: DFSchemaRef,
2816 ) -> Result<Self> {
2817 let input_fields_count = input.schema().fields().len();
2818 if schema.fields().len() != input_fields_count + window_expr.len() {
2819 return plan_err!(
2820 "Window schema has wrong number of fields. Expected {} got {}",
2821 input_fields_count + window_expr.len(),
2822 schema.fields().len()
2823 );
2824 }
2825
2826 Ok(Window {
2827 input,
2828 window_expr,
2829 schema,
2830 })
2831 }
2832}
2833
2834impl PartialOrd for Window {
2836 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2837 match self.input.partial_cmp(&other.input)? {
2838 Ordering::Equal => {} not_equal => return Some(not_equal),
2840 }
2841
2842 match self.window_expr.partial_cmp(&other.window_expr)? {
2843 Ordering::Equal => {} not_equal => return Some(not_equal),
2845 }
2846
2847 if self == other {
2850 Some(Ordering::Equal)
2851 } else {
2852 None
2853 }
2854 }
2855}
2856
2857#[derive(Clone)]
2859pub struct TableScan {
2860 pub table_name: TableReference,
2862 pub source: Arc<dyn TableSource>,
2864 pub projection: Option<Vec<usize>>,
2866 pub projected_schema: DFSchemaRef,
2868 pub filters: Vec<Expr>,
2870 pub fetch: Option<usize>,
2872}
2873
2874impl Debug for TableScan {
2875 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2876 f.debug_struct("TableScan")
2877 .field("table_name", &self.table_name)
2878 .field("source", &"...")
2879 .field("projection", &self.projection)
2880 .field("projected_schema", &self.projected_schema)
2881 .field("filters", &self.filters)
2882 .field("fetch", &self.fetch)
2883 .finish_non_exhaustive()
2884 }
2885}
2886
2887impl PartialEq for TableScan {
2888 fn eq(&self, other: &Self) -> bool {
2889 self.table_name == other.table_name
2890 && self.projection == other.projection
2891 && self.projected_schema == other.projected_schema
2892 && self.filters == other.filters
2893 && self.fetch == other.fetch
2894 }
2895}
2896
2897impl Eq for TableScan {}
2898
2899impl PartialOrd for TableScan {
2902 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2903 #[derive(PartialEq, PartialOrd)]
2904 struct ComparableTableScan<'a> {
2905 pub table_name: &'a TableReference,
2907 pub projection: &'a Option<Vec<usize>>,
2909 pub filters: &'a Vec<Expr>,
2911 pub fetch: &'a Option<usize>,
2913 }
2914 let comparable_self = ComparableTableScan {
2915 table_name: &self.table_name,
2916 projection: &self.projection,
2917 filters: &self.filters,
2918 fetch: &self.fetch,
2919 };
2920 let comparable_other = ComparableTableScan {
2921 table_name: &other.table_name,
2922 projection: &other.projection,
2923 filters: &other.filters,
2924 fetch: &other.fetch,
2925 };
2926 comparable_self
2927 .partial_cmp(&comparable_other)
2928 .filter(|cmp| *cmp != Ordering::Equal || self == other)
2930 }
2931}
2932
2933impl Hash for TableScan {
2934 fn hash<H: Hasher>(&self, state: &mut H) {
2935 self.table_name.hash(state);
2936 self.projection.hash(state);
2937 self.projected_schema.hash(state);
2938 self.filters.hash(state);
2939 self.fetch.hash(state);
2940 }
2941}
2942
2943impl TableScan {
2944 pub fn try_new(
2947 table_name: impl Into<TableReference>,
2948 table_source: Arc<dyn TableSource>,
2949 projection: Option<Vec<usize>>,
2950 filters: Vec<Expr>,
2951 fetch: Option<usize>,
2952 ) -> Result<Self> {
2953 let table_name = table_name.into();
2954
2955 if table_name.table().is_empty() {
2956 return plan_err!("table_name cannot be empty");
2957 }
2958 let schema = table_source.schema();
2959 let func_dependencies = FunctionalDependencies::new_from_constraints(
2960 table_source.constraints(),
2961 schema.fields.len(),
2962 );
2963 let projected_schema = projection
2964 .as_ref()
2965 .map(|p| {
2966 let projected_func_dependencies =
2967 func_dependencies.project_functional_dependencies(p, p.len());
2968
2969 let df_schema = DFSchema::new_with_metadata(
2970 p.iter()
2971 .map(|i| {
2972 (Some(table_name.clone()), Arc::clone(&schema.fields()[*i]))
2973 })
2974 .collect(),
2975 schema.metadata.clone(),
2976 )?;
2977 df_schema.with_functional_dependencies(projected_func_dependencies)
2978 })
2979 .unwrap_or_else(|| {
2980 let df_schema =
2981 DFSchema::try_from_qualified_schema(table_name.clone(), &schema)?;
2982 df_schema.with_functional_dependencies(func_dependencies)
2983 })?;
2984 let projected_schema = Arc::new(projected_schema);
2985
2986 Ok(Self {
2987 table_name,
2988 source: table_source,
2989 projection,
2990 projected_schema,
2991 filters,
2992 fetch,
2993 })
2994 }
2995}
2996
2997#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
2999pub struct Repartition {
3000 pub input: Arc<LogicalPlan>,
3002 pub partitioning_scheme: Partitioning,
3004}
3005
3006#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3008pub struct Union {
3009 pub inputs: Vec<Arc<LogicalPlan>>,
3011 pub schema: DFSchemaRef,
3013}
3014
3015impl Union {
3016 pub fn try_new(inputs: Vec<Arc<LogicalPlan>>) -> Result<Self> {
3019 let schema = Self::derive_schema_from_inputs(&inputs, false, false)?;
3020 Ok(Union { inputs, schema })
3021 }
3022
3023 pub fn try_new_with_loose_types(inputs: Vec<Arc<LogicalPlan>>) -> Result<Self> {
3028 let schema = Self::derive_schema_from_inputs(&inputs, true, false)?;
3029 Ok(Union { inputs, schema })
3030 }
3031
3032 pub fn try_new_by_name(inputs: Vec<Arc<LogicalPlan>>) -> Result<Self> {
3036 let schema = Self::derive_schema_from_inputs(&inputs, true, true)?;
3037 let inputs = Self::rewrite_inputs_from_schema(&schema, inputs)?;
3038
3039 Ok(Union { inputs, schema })
3040 }
3041
3042 fn rewrite_inputs_from_schema(
3046 schema: &Arc<DFSchema>,
3047 inputs: Vec<Arc<LogicalPlan>>,
3048 ) -> Result<Vec<Arc<LogicalPlan>>> {
3049 let schema_width = schema.iter().count();
3050 let mut wrapped_inputs = Vec::with_capacity(inputs.len());
3051 for input in inputs {
3052 let mut expr = Vec::with_capacity(schema_width);
3056 for column in schema.columns() {
3057 if input
3058 .schema()
3059 .has_column_with_unqualified_name(column.name())
3060 {
3061 expr.push(Expr::Column(column));
3062 } else {
3063 expr.push(
3064 Expr::Literal(ScalarValue::Null, None).alias(column.name()),
3065 );
3066 }
3067 }
3068 wrapped_inputs.push(Arc::new(LogicalPlan::Projection(
3069 Projection::try_new_with_schema(expr, input, Arc::clone(schema))?,
3070 )));
3071 }
3072
3073 Ok(wrapped_inputs)
3074 }
3075
3076 fn derive_schema_from_inputs(
3085 inputs: &[Arc<LogicalPlan>],
3086 loose_types: bool,
3087 by_name: bool,
3088 ) -> Result<DFSchemaRef> {
3089 if inputs.len() < 2 {
3090 return plan_err!("UNION requires at least two inputs");
3091 }
3092
3093 if by_name {
3094 Self::derive_schema_from_inputs_by_name(inputs, loose_types)
3095 } else {
3096 Self::derive_schema_from_inputs_by_position(inputs, loose_types)
3097 }
3098 }
3099
3100 fn derive_schema_from_inputs_by_name(
3101 inputs: &[Arc<LogicalPlan>],
3102 loose_types: bool,
3103 ) -> Result<DFSchemaRef> {
3104 type FieldData<'a> =
3105 (&'a DataType, bool, Vec<&'a HashMap<String, String>>, usize);
3106 let mut cols: Vec<(&str, FieldData)> = Vec::new();
3107 for input in inputs.iter() {
3108 for field in input.schema().fields() {
3109 if let Some((_, (data_type, is_nullable, metadata, occurrences))) =
3110 cols.iter_mut().find(|(name, _)| name == field.name())
3111 {
3112 if !loose_types && *data_type != field.data_type() {
3113 return plan_err!(
3114 "Found different types for field {}",
3115 field.name()
3116 );
3117 }
3118
3119 metadata.push(field.metadata());
3120 *is_nullable |= field.is_nullable();
3123 *occurrences += 1;
3124 } else {
3125 cols.push((
3126 field.name(),
3127 (
3128 field.data_type(),
3129 field.is_nullable(),
3130 vec![field.metadata()],
3131 1,
3132 ),
3133 ));
3134 }
3135 }
3136 }
3137
3138 let union_fields = cols
3139 .into_iter()
3140 .map(
3141 |(name, (data_type, is_nullable, unmerged_metadata, occurrences))| {
3142 let final_is_nullable = if occurrences == inputs.len() {
3146 is_nullable
3147 } else {
3148 true
3149 };
3150
3151 let mut field =
3152 Field::new(name, data_type.clone(), final_is_nullable);
3153 field.set_metadata(intersect_metadata_for_union(unmerged_metadata));
3154
3155 (None, Arc::new(field))
3156 },
3157 )
3158 .collect::<Vec<(Option<TableReference>, _)>>();
3159
3160 let union_schema_metadata = intersect_metadata_for_union(
3161 inputs.iter().map(|input| input.schema().metadata()),
3162 );
3163
3164 let schema = DFSchema::new_with_metadata(union_fields, union_schema_metadata)?;
3166 let schema = Arc::new(schema);
3167
3168 Ok(schema)
3169 }
3170
3171 fn derive_schema_from_inputs_by_position(
3172 inputs: &[Arc<LogicalPlan>],
3173 loose_types: bool,
3174 ) -> Result<DFSchemaRef> {
3175 let first_schema = inputs[0].schema();
3176 let fields_count = first_schema.fields().len();
3177 for input in inputs.iter().skip(1) {
3178 if fields_count != input.schema().fields().len() {
3179 return plan_err!(
3180 "UNION queries have different number of columns: \
3181 left has {} columns whereas right has {} columns",
3182 fields_count,
3183 input.schema().fields().len()
3184 );
3185 }
3186 }
3187
3188 let mut name_counts: HashMap<String, usize> = HashMap::new();
3189 let union_fields = (0..fields_count)
3190 .map(|i| {
3191 let fields = inputs
3192 .iter()
3193 .map(|input| input.schema().field(i))
3194 .collect::<Vec<_>>();
3195 let first_field = fields[0];
3196 let base_name = first_field.name().to_string();
3197
3198 let data_type = if loose_types {
3199 first_field.data_type()
3203 } else {
3204 fields.iter().skip(1).try_fold(
3205 first_field.data_type(),
3206 |acc, field| {
3207 if acc != field.data_type() {
3208 return plan_err!(
3209 "UNION field {i} have different type in inputs: \
3210 left has {} whereas right has {}",
3211 first_field.data_type(),
3212 field.data_type()
3213 );
3214 }
3215 Ok(acc)
3216 },
3217 )?
3218 };
3219 let nullable = fields.iter().any(|field| field.is_nullable());
3220
3221 let name = if let Some(count) = name_counts.get_mut(&base_name) {
3223 *count += 1;
3224 format!("{base_name}_{count}")
3225 } else {
3226 name_counts.insert(base_name.clone(), 0);
3227 base_name
3228 };
3229
3230 let mut field = Field::new(&name, data_type.clone(), nullable);
3231 let field_metadata = intersect_metadata_for_union(
3232 fields.iter().map(|field| field.metadata()),
3233 );
3234 field.set_metadata(field_metadata);
3235 Ok((None, Arc::new(field)))
3236 })
3237 .collect::<Result<_>>()?;
3238 let union_schema_metadata = intersect_metadata_for_union(
3239 inputs.iter().map(|input| input.schema().metadata()),
3240 );
3241
3242 let schema = DFSchema::new_with_metadata(union_fields, union_schema_metadata)?;
3244 let schema = Arc::new(schema);
3245
3246 Ok(schema)
3247 }
3248}
3249
3250impl PartialOrd for Union {
3252 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3253 self.inputs
3254 .partial_cmp(&other.inputs)
3255 .filter(|cmp| *cmp != Ordering::Equal || self == other)
3257 }
3258}
3259
3260#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3283pub struct DescribeTable {
3284 pub schema: Arc<Schema>,
3286 pub output_schema: DFSchemaRef,
3288}
3289
3290impl PartialOrd for DescribeTable {
3293 fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
3294 None
3296 }
3297}
3298
3299#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3301pub struct ExplainOption {
3302 pub verbose: bool,
3304 pub analyze: bool,
3306 pub format: ExplainFormat,
3308}
3309
3310impl Default for ExplainOption {
3311 fn default() -> Self {
3312 ExplainOption {
3313 verbose: false,
3314 analyze: false,
3315 format: ExplainFormat::Indent,
3316 }
3317 }
3318}
3319
3320impl ExplainOption {
3321 pub fn with_verbose(mut self, verbose: bool) -> Self {
3323 self.verbose = verbose;
3324 self
3325 }
3326
3327 pub fn with_analyze(mut self, analyze: bool) -> Self {
3329 self.analyze = analyze;
3330 self
3331 }
3332
3333 pub fn with_format(mut self, format: ExplainFormat) -> Self {
3335 self.format = format;
3336 self
3337 }
3338}
3339
3340#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3347pub struct Explain {
3348 pub verbose: bool,
3350 pub explain_format: ExplainFormat,
3353 pub plan: Arc<LogicalPlan>,
3355 pub stringified_plans: Vec<StringifiedPlan>,
3357 pub schema: DFSchemaRef,
3359 pub logical_optimization_succeeded: bool,
3361}
3362
3363impl PartialOrd for Explain {
3365 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3366 #[derive(PartialEq, PartialOrd)]
3367 struct ComparableExplain<'a> {
3368 pub verbose: &'a bool,
3370 pub plan: &'a Arc<LogicalPlan>,
3372 pub stringified_plans: &'a Vec<StringifiedPlan>,
3374 pub logical_optimization_succeeded: &'a bool,
3376 }
3377 let comparable_self = ComparableExplain {
3378 verbose: &self.verbose,
3379 plan: &self.plan,
3380 stringified_plans: &self.stringified_plans,
3381 logical_optimization_succeeded: &self.logical_optimization_succeeded,
3382 };
3383 let comparable_other = ComparableExplain {
3384 verbose: &other.verbose,
3385 plan: &other.plan,
3386 stringified_plans: &other.stringified_plans,
3387 logical_optimization_succeeded: &other.logical_optimization_succeeded,
3388 };
3389 comparable_self
3390 .partial_cmp(&comparable_other)
3391 .filter(|cmp| *cmp != Ordering::Equal || self == other)
3393 }
3394}
3395
3396#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3399pub struct Analyze {
3400 pub verbose: bool,
3402 pub input: Arc<LogicalPlan>,
3404 pub schema: DFSchemaRef,
3406}
3407
3408impl PartialOrd for Analyze {
3410 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3411 match self.verbose.partial_cmp(&other.verbose) {
3412 Some(Ordering::Equal) => self.input.partial_cmp(&other.input),
3413 cmp => cmp,
3414 }
3415 .filter(|cmp| *cmp != Ordering::Equal || self == other)
3417 }
3418}
3419
3420#[allow(clippy::allow_attributes)]
3425#[allow(clippy::derived_hash_with_manual_eq)]
3426#[derive(Debug, Clone, Eq, Hash)]
3427pub struct Extension {
3428 pub node: Arc<dyn UserDefinedLogicalNode>,
3430}
3431
3432impl PartialEq for Extension {
3436 fn eq(&self, other: &Self) -> bool {
3437 self.node.eq(&other.node)
3438 }
3439}
3440
3441impl PartialOrd for Extension {
3442 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3443 self.node.partial_cmp(&other.node)
3444 }
3445}
3446
3447#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
3449pub struct Limit {
3450 pub skip: Option<Box<Expr>>,
3452 pub fetch: Option<Box<Expr>>,
3455 pub input: Arc<LogicalPlan>,
3457}
3458
3459pub enum SkipType {
3461 Literal(usize),
3463 UnsupportedExpr,
3465}
3466
3467pub enum FetchType {
3469 Literal(Option<usize>),
3472 UnsupportedExpr,
3474}
3475
3476impl Limit {
3477 pub fn get_skip_type(&self) -> Result<SkipType> {
3479 match self.skip.as_deref() {
3480 Some(expr) => match *expr {
3481 Expr::Literal(ScalarValue::Int64(s), _) => {
3482 let s = s.unwrap_or(0);
3484 if s >= 0 {
3485 Ok(SkipType::Literal(s as usize))
3486 } else {
3487 plan_err!("OFFSET must be >=0, '{}' was provided", s)
3488 }
3489 }
3490 _ => Ok(SkipType::UnsupportedExpr),
3491 },
3492 None => Ok(SkipType::Literal(0)),
3494 }
3495 }
3496
3497 pub fn get_fetch_type(&self) -> Result<FetchType> {
3499 match self.fetch.as_deref() {
3500 Some(expr) => match *expr {
3501 Expr::Literal(ScalarValue::Int64(Some(s)), _) => {
3502 if s >= 0 {
3503 Ok(FetchType::Literal(Some(s as usize)))
3504 } else {
3505 plan_err!("LIMIT must be >= 0, '{}' was provided", s)
3506 }
3507 }
3508 Expr::Literal(ScalarValue::Int64(None), _) => {
3509 Ok(FetchType::Literal(None))
3510 }
3511 _ => Ok(FetchType::UnsupportedExpr),
3512 },
3513 None => Ok(FetchType::Literal(None)),
3514 }
3515 }
3516}
3517
3518#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
3520pub enum Distinct {
3521 All(Arc<LogicalPlan>),
3523 On(DistinctOn),
3525}
3526
3527impl Distinct {
3528 pub fn input(&self) -> &Arc<LogicalPlan> {
3530 match self {
3531 Distinct::All(input) => input,
3532 Distinct::On(DistinctOn { input, .. }) => input,
3533 }
3534 }
3535}
3536
3537#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3539pub struct DistinctOn {
3540 pub on_expr: Vec<Expr>,
3542 pub select_expr: Vec<Expr>,
3544 pub sort_expr: Option<Vec<SortExpr>>,
3548 pub input: Arc<LogicalPlan>,
3550 pub schema: DFSchemaRef,
3552}
3553
3554impl DistinctOn {
3555 pub fn try_new(
3557 on_expr: Vec<Expr>,
3558 select_expr: Vec<Expr>,
3559 sort_expr: Option<Vec<SortExpr>>,
3560 input: Arc<LogicalPlan>,
3561 ) -> Result<Self> {
3562 if on_expr.is_empty() {
3563 return plan_err!("No `ON` expressions provided");
3564 }
3565
3566 let on_expr = normalize_cols(on_expr, input.as_ref())?;
3567 let qualified_fields = exprlist_to_fields(select_expr.as_slice(), &input)?
3568 .into_iter()
3569 .collect();
3570
3571 let dfschema = DFSchema::new_with_metadata(
3572 qualified_fields,
3573 input.schema().metadata().clone(),
3574 )?;
3575
3576 let mut distinct_on = DistinctOn {
3577 on_expr,
3578 select_expr,
3579 sort_expr: None,
3580 input,
3581 schema: Arc::new(dfschema),
3582 };
3583
3584 if let Some(sort_expr) = sort_expr {
3585 distinct_on = distinct_on.with_sort_expr(sort_expr)?;
3586 }
3587
3588 Ok(distinct_on)
3589 }
3590
3591 pub fn with_sort_expr(mut self, sort_expr: Vec<SortExpr>) -> Result<Self> {
3595 let sort_expr = normalize_sorts(sort_expr, self.input.as_ref())?;
3596
3597 let mut matched = true;
3599 for (on, sort) in self.on_expr.iter().zip(sort_expr.iter()) {
3600 if on != &sort.expr {
3601 matched = false;
3602 break;
3603 }
3604 }
3605
3606 if self.on_expr.len() > sort_expr.len() || !matched {
3607 return plan_err!(
3608 "SELECT DISTINCT ON expressions must match initial ORDER BY expressions"
3609 );
3610 }
3611
3612 self.sort_expr = Some(sort_expr);
3613 Ok(self)
3614 }
3615}
3616
3617impl PartialOrd for DistinctOn {
3619 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3620 #[derive(PartialEq, PartialOrd)]
3621 struct ComparableDistinctOn<'a> {
3622 pub on_expr: &'a Vec<Expr>,
3624 pub select_expr: &'a Vec<Expr>,
3626 pub sort_expr: &'a Option<Vec<SortExpr>>,
3630 pub input: &'a Arc<LogicalPlan>,
3632 }
3633 let comparable_self = ComparableDistinctOn {
3634 on_expr: &self.on_expr,
3635 select_expr: &self.select_expr,
3636 sort_expr: &self.sort_expr,
3637 input: &self.input,
3638 };
3639 let comparable_other = ComparableDistinctOn {
3640 on_expr: &other.on_expr,
3641 select_expr: &other.select_expr,
3642 sort_expr: &other.sort_expr,
3643 input: &other.input,
3644 };
3645 comparable_self
3646 .partial_cmp(&comparable_other)
3647 .filter(|cmp| *cmp != Ordering::Equal || self == other)
3649 }
3650}
3651
3652#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3665#[non_exhaustive]
3667pub struct Aggregate {
3668 pub input: Arc<LogicalPlan>,
3670 pub group_expr: Vec<Expr>,
3672 pub aggr_expr: Vec<Expr>,
3676 pub schema: DFSchemaRef,
3678}
3679
3680impl Aggregate {
3681 pub fn try_new(
3683 input: Arc<LogicalPlan>,
3684 group_expr: Vec<Expr>,
3685 aggr_expr: Vec<Expr>,
3686 ) -> Result<Self> {
3687 let group_expr = enumerate_grouping_sets(group_expr)?;
3688
3689 let is_grouping_set = matches!(group_expr.as_slice(), [Expr::GroupingSet(_)]);
3690
3691 let grouping_expr: Vec<&Expr> = grouping_set_to_exprlist(group_expr.as_slice())?;
3692
3693 let mut qualified_fields = exprlist_to_fields(grouping_expr, &input)?;
3694
3695 if is_grouping_set {
3697 qualified_fields = qualified_fields
3698 .into_iter()
3699 .map(|(q, f)| (q, f.as_ref().clone().with_nullable(true).into()))
3700 .collect::<Vec<_>>();
3701 let max_ordinal = max_grouping_set_duplicate_ordinal(&group_expr);
3702 qualified_fields.push((
3703 None,
3704 Field::new(
3705 Self::INTERNAL_GROUPING_ID,
3706 Self::grouping_id_type(qualified_fields.len(), max_ordinal),
3707 false,
3708 )
3709 .into(),
3710 ));
3711 }
3712
3713 qualified_fields.extend(exprlist_to_fields(aggr_expr.as_slice(), &input)?);
3714
3715 let schema = DFSchema::new_with_metadata(
3716 qualified_fields,
3717 input.schema().metadata().clone(),
3718 )?;
3719
3720 Self::try_new_with_schema(input, group_expr, aggr_expr, Arc::new(schema))
3721 }
3722
3723 pub fn try_new_with_schema(
3729 input: Arc<LogicalPlan>,
3730 group_expr: Vec<Expr>,
3731 aggr_expr: Vec<Expr>,
3732 schema: DFSchemaRef,
3733 ) -> Result<Self> {
3734 if group_expr.is_empty() && aggr_expr.is_empty() {
3735 return plan_err!(
3736 "Aggregate requires at least one grouping or aggregate expression. \
3737 Aggregate without grouping expressions nor aggregate expressions is \
3738 logically equivalent to, but less efficient than, VALUES producing \
3739 single row. Please use VALUES instead."
3740 );
3741 }
3742 let group_expr_count = grouping_set_expr_count(&group_expr)?;
3743 if schema.fields().len() != group_expr_count + aggr_expr.len() {
3744 return plan_err!(
3745 "Aggregate schema has wrong number of fields. Expected {} got {}",
3746 group_expr_count + aggr_expr.len(),
3747 schema.fields().len()
3748 );
3749 }
3750
3751 let aggregate_func_dependencies =
3752 calc_func_dependencies_for_aggregate(&group_expr, &input, &schema)?;
3753 let new_schema = Arc::unwrap_or_clone(schema);
3754 let schema = Arc::new(
3755 new_schema.with_functional_dependencies(aggregate_func_dependencies)?,
3756 );
3757 Ok(Self {
3758 input,
3759 group_expr,
3760 aggr_expr,
3761 schema,
3762 })
3763 }
3764
3765 fn is_grouping_set(&self) -> bool {
3766 matches!(self.group_expr.as_slice(), [Expr::GroupingSet(_)])
3767 }
3768
3769 fn output_expressions(&self) -> Result<Vec<&Expr>> {
3771 static INTERNAL_ID_EXPR: LazyLock<Expr> = LazyLock::new(|| {
3772 Expr::Column(Column::from_name(Aggregate::INTERNAL_GROUPING_ID))
3773 });
3774 let mut exprs = grouping_set_to_exprlist(self.group_expr.as_slice())?;
3775 if self.is_grouping_set() {
3776 exprs.push(&INTERNAL_ID_EXPR);
3777 }
3778 exprs.extend(self.aggr_expr.iter());
3779 debug_assert!(exprs.len() == self.schema.fields().len());
3780 Ok(exprs)
3781 }
3782
3783 pub fn group_expr_len(&self) -> Result<usize> {
3787 grouping_set_expr_count(&self.group_expr)
3788 }
3789
3790 pub fn grouping_id_type(group_exprs: usize, max_ordinal: usize) -> DataType {
3802 let ordinal_bits = usize::BITS as usize - max_ordinal.leading_zeros() as usize;
3803 let total_bits = group_exprs + ordinal_bits;
3804 if total_bits <= 8 {
3805 DataType::UInt8
3806 } else if total_bits <= 16 {
3807 DataType::UInt16
3808 } else if total_bits <= 32 {
3809 DataType::UInt32
3810 } else {
3811 DataType::UInt64
3812 }
3813 }
3814
3815 pub const INTERNAL_GROUPING_ID: &'static str = "__grouping_id";
3848}
3849
3850impl PartialOrd for Aggregate {
3852 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3853 match self.input.partial_cmp(&other.input) {
3854 Some(Ordering::Equal) => {
3855 match self.group_expr.partial_cmp(&other.group_expr) {
3856 Some(Ordering::Equal) => self.aggr_expr.partial_cmp(&other.aggr_expr),
3857 cmp => cmp,
3858 }
3859 }
3860 cmp => cmp,
3861 }
3862 .filter(|cmp| *cmp != Ordering::Equal || self == other)
3864 }
3865}
3866
3867#[allow(clippy::allow_attributes, clippy::mutable_key_type)] fn max_grouping_set_duplicate_ordinal(group_expr: &[Expr]) -> usize {
3875 if let Some(Expr::GroupingSet(GroupingSet::GroupingSets(sets))) = group_expr.first() {
3876 let mut counts: HashMap<&[Expr], usize> = HashMap::new();
3877 for set in sets {
3878 *counts.entry(set).or_insert(0) += 1;
3879 }
3880 counts.into_values().max().unwrap_or(0).saturating_sub(1)
3881 } else {
3882 0
3883 }
3884}
3885
3886fn contains_grouping_set(group_expr: &[Expr]) -> bool {
3888 group_expr
3889 .iter()
3890 .any(|expr| matches!(expr, Expr::GroupingSet(_)))
3891}
3892
3893fn calc_func_dependencies_for_aggregate(
3895 group_expr: &[Expr],
3897 input: &LogicalPlan,
3899 aggr_schema: &DFSchema,
3901) -> Result<FunctionalDependencies> {
3902 if !contains_grouping_set(group_expr) {
3908 let group_by_expr_names = group_expr
3909 .iter()
3910 .map(|item| item.schema_name().to_string())
3911 .collect::<IndexSet<_>>()
3912 .into_iter()
3913 .collect::<Vec<_>>();
3914 let aggregate_func_dependencies = aggregate_functional_dependencies(
3915 input.schema(),
3916 &group_by_expr_names,
3917 aggr_schema,
3918 );
3919 Ok(aggregate_func_dependencies)
3920 } else {
3921 Ok(FunctionalDependencies::empty())
3922 }
3923}
3924
3925fn calc_func_dependencies_for_project(
3928 exprs: &[Expr],
3929 input: &LogicalPlan,
3930) -> Result<FunctionalDependencies> {
3931 let input_fields = input.schema().field_names();
3932 let proj_indices = exprs
3934 .iter()
3935 .map(|expr| match expr {
3936 #[expect(deprecated)]
3937 Expr::Wildcard { qualifier, options } => {
3938 let wildcard_fields = exprlist_to_fields(
3939 vec![&Expr::Wildcard {
3940 qualifier: qualifier.clone(),
3941 options: options.clone(),
3942 }],
3943 input,
3944 )?;
3945 Ok::<_, DataFusionError>(
3946 wildcard_fields
3947 .into_iter()
3948 .filter_map(|(qualifier, f)| {
3949 let flat_name = qualifier
3950 .map(|t| format!("{}.{}", t, f.name()))
3951 .unwrap_or_else(|| f.name().clone());
3952 input_fields.iter().position(|item| *item == flat_name)
3953 })
3954 .collect::<Vec<_>>(),
3955 )
3956 }
3957 Expr::Alias(alias) => {
3958 let name = format!("{}", alias.expr);
3959 Ok(input_fields
3960 .iter()
3961 .position(|item| *item == name)
3962 .map(|i| vec![i])
3963 .unwrap_or(vec![]))
3964 }
3965 _ => {
3966 let name = format!("{expr}");
3967 Ok(input_fields
3968 .iter()
3969 .position(|item| *item == name)
3970 .map(|i| vec![i])
3971 .unwrap_or(vec![]))
3972 }
3973 })
3974 .collect::<Result<Vec<_>>>()?
3975 .into_iter()
3976 .flatten()
3977 .collect::<Vec<_>>();
3978
3979 Ok(input
3980 .schema()
3981 .functional_dependencies()
3982 .project_functional_dependencies(&proj_indices, exprs.len()))
3983}
3984
3985#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
3987pub struct Sort {
3988 pub expr: Vec<SortExpr>,
3990 pub input: Arc<LogicalPlan>,
3992 pub fetch: Option<usize>,
3994}
3995
3996#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3998pub struct Join {
3999 pub left: Arc<LogicalPlan>,
4001 pub right: Arc<LogicalPlan>,
4003 pub on: Vec<(Expr, Expr)>,
4005 pub filter: Option<Expr>,
4007 pub join_type: JoinType,
4009 pub join_constraint: JoinConstraint,
4011 pub schema: DFSchemaRef,
4013 pub null_equality: NullEquality,
4015 pub null_aware: bool,
4023}
4024
4025impl Join {
4026 #[expect(clippy::too_many_arguments)]
4046 pub fn try_new(
4047 left: Arc<LogicalPlan>,
4048 right: Arc<LogicalPlan>,
4049 on: Vec<(Expr, Expr)>,
4050 filter: Option<Expr>,
4051 join_type: JoinType,
4052 join_constraint: JoinConstraint,
4053 null_equality: NullEquality,
4054 null_aware: bool,
4055 ) -> Result<Self> {
4056 let join_schema = build_join_schema(left.schema(), right.schema(), &join_type)?;
4057
4058 Ok(Join {
4059 left,
4060 right,
4061 on,
4062 filter,
4063 join_type,
4064 join_constraint,
4065 schema: Arc::new(join_schema),
4066 null_equality,
4067 null_aware,
4068 })
4069 }
4070
4071 pub fn try_new_with_project_input(
4074 original: &LogicalPlan,
4075 left: Arc<LogicalPlan>,
4076 right: Arc<LogicalPlan>,
4077 column_on: (Vec<Column>, Vec<Column>),
4078 ) -> Result<(Self, bool)> {
4079 let original_join = match original {
4080 LogicalPlan::Join(join) => join,
4081 _ => return plan_err!("Could not create join with project input"),
4082 };
4083
4084 let mut left_sch = LogicalPlanBuilder::from(Arc::clone(&left));
4085 let mut right_sch = LogicalPlanBuilder::from(Arc::clone(&right));
4086
4087 let mut requalified = false;
4088
4089 if original_join.join_type == JoinType::Inner
4092 || original_join.join_type == JoinType::Left
4093 || original_join.join_type == JoinType::Right
4094 || original_join.join_type == JoinType::Full
4095 {
4096 (left_sch, right_sch, requalified) =
4097 requalify_sides_if_needed(left_sch.clone(), right_sch.clone())?;
4098 }
4099
4100 let on: Vec<(Expr, Expr)> = column_on
4101 .0
4102 .into_iter()
4103 .zip(column_on.1)
4104 .map(|(l, r)| (Expr::Column(l), Expr::Column(r)))
4105 .collect();
4106
4107 let join_schema = build_join_schema(
4108 left_sch.schema(),
4109 right_sch.schema(),
4110 &original_join.join_type,
4111 )?;
4112
4113 Ok((
4114 Join {
4115 left,
4116 right,
4117 on,
4118 filter: original_join.filter.clone(),
4119 join_type: original_join.join_type,
4120 join_constraint: original_join.join_constraint,
4121 schema: Arc::new(join_schema),
4122 null_equality: original_join.null_equality,
4123 null_aware: original_join.null_aware,
4124 },
4125 requalified,
4126 ))
4127 }
4128}
4129
4130impl PartialOrd for Join {
4132 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
4133 #[derive(PartialEq, PartialOrd)]
4134 struct ComparableJoin<'a> {
4135 pub left: &'a Arc<LogicalPlan>,
4137 pub right: &'a Arc<LogicalPlan>,
4139 pub on: &'a Vec<(Expr, Expr)>,
4141 pub filter: &'a Option<Expr>,
4143 pub join_type: &'a JoinType,
4145 pub join_constraint: &'a JoinConstraint,
4147 pub null_equality: &'a NullEquality,
4149 }
4150 let comparable_self = ComparableJoin {
4151 left: &self.left,
4152 right: &self.right,
4153 on: &self.on,
4154 filter: &self.filter,
4155 join_type: &self.join_type,
4156 join_constraint: &self.join_constraint,
4157 null_equality: &self.null_equality,
4158 };
4159 let comparable_other = ComparableJoin {
4160 left: &other.left,
4161 right: &other.right,
4162 on: &other.on,
4163 filter: &other.filter,
4164 join_type: &other.join_type,
4165 join_constraint: &other.join_constraint,
4166 null_equality: &other.null_equality,
4167 };
4168 comparable_self
4169 .partial_cmp(&comparable_other)
4170 .filter(|cmp| *cmp != Ordering::Equal || self == other)
4172 }
4173}
4174
4175#[derive(Clone, PartialEq, Eq, PartialOrd, Hash)]
4177pub struct Subquery {
4178 pub subquery: Arc<LogicalPlan>,
4180 pub outer_ref_columns: Vec<Expr>,
4182 pub spans: Spans,
4184}
4185
4186impl Normalizeable for Subquery {
4187 fn can_normalize(&self) -> bool {
4188 false
4189 }
4190}
4191
4192impl NormalizeEq for Subquery {
4193 fn normalize_eq(&self, other: &Self) -> bool {
4194 *self.subquery == *other.subquery
4196 && self.outer_ref_columns.len() == other.outer_ref_columns.len()
4197 && self
4198 .outer_ref_columns
4199 .iter()
4200 .zip(other.outer_ref_columns.iter())
4201 .all(|(a, b)| a.normalize_eq(b))
4202 }
4203}
4204
4205impl Subquery {
4206 pub fn try_from_expr(plan: &Expr) -> Result<&Subquery> {
4207 match plan {
4208 Expr::ScalarSubquery(it) => Ok(it),
4209 Expr::Cast(cast) => Subquery::try_from_expr(cast.expr.as_ref()),
4210 _ => plan_err!("Could not coerce into ScalarSubquery!"),
4211 }
4212 }
4213
4214 pub fn with_plan(&self, plan: Arc<LogicalPlan>) -> Subquery {
4215 Subquery {
4216 subquery: plan,
4217 outer_ref_columns: self.outer_ref_columns.clone(),
4218 spans: Spans::new(),
4219 }
4220 }
4221}
4222
4223impl Debug for Subquery {
4224 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4225 write!(f, "<subquery>")
4226 }
4227}
4228
4229#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
4235pub enum Partitioning {
4236 RoundRobinBatch(usize),
4238 Hash(Vec<Expr>, usize),
4241 DistributeBy(Vec<Expr>),
4243}
4244
4245#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd)]
4265pub struct ColumnUnnestList {
4266 pub output_column: Column,
4267 pub depth: usize,
4268}
4269
4270impl Display for ColumnUnnestList {
4271 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4272 write!(f, "{}|depth={}", self.output_column, self.depth)
4273 }
4274}
4275
4276#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4279pub struct Unnest {
4280 pub input: Arc<LogicalPlan>,
4282 pub exec_columns: Vec<Column>,
4284 pub list_type_columns: Vec<(usize, ColumnUnnestList)>,
4287 pub struct_type_columns: Vec<usize>,
4290 pub dependency_indices: Vec<usize>,
4293 pub schema: DFSchemaRef,
4295 pub options: UnnestOptions,
4297}
4298
4299impl PartialOrd for Unnest {
4301 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
4302 #[derive(PartialEq, PartialOrd)]
4303 struct ComparableUnnest<'a> {
4304 pub input: &'a Arc<LogicalPlan>,
4306 pub exec_columns: &'a Vec<Column>,
4308 pub list_type_columns: &'a Vec<(usize, ColumnUnnestList)>,
4311 pub struct_type_columns: &'a Vec<usize>,
4314 pub dependency_indices: &'a Vec<usize>,
4317 pub options: &'a UnnestOptions,
4319 }
4320 let comparable_self = ComparableUnnest {
4321 input: &self.input,
4322 exec_columns: &self.exec_columns,
4323 list_type_columns: &self.list_type_columns,
4324 struct_type_columns: &self.struct_type_columns,
4325 dependency_indices: &self.dependency_indices,
4326 options: &self.options,
4327 };
4328 let comparable_other = ComparableUnnest {
4329 input: &other.input,
4330 exec_columns: &other.exec_columns,
4331 list_type_columns: &other.list_type_columns,
4332 struct_type_columns: &other.struct_type_columns,
4333 dependency_indices: &other.dependency_indices,
4334 options: &other.options,
4335 };
4336 comparable_self
4337 .partial_cmp(&comparable_other)
4338 .filter(|cmp| *cmp != Ordering::Equal || self == other)
4340 }
4341}
4342
4343impl Unnest {
4344 pub fn try_new(
4345 input: Arc<LogicalPlan>,
4346 exec_columns: Vec<Column>,
4347 options: UnnestOptions,
4348 ) -> Result<Self> {
4349 if exec_columns.is_empty() {
4350 return plan_err!("unnest plan requires at least 1 column to unnest");
4351 }
4352
4353 let mut list_columns: Vec<(usize, ColumnUnnestList)> = vec![];
4354 let mut struct_columns = vec![];
4355 let indices_to_unnest = exec_columns
4356 .iter()
4357 .map(|c| Ok((input.schema().index_of_column(c)?, c)))
4358 .collect::<Result<HashMap<usize, &Column>>>()?;
4359
4360 let input_schema = input.schema();
4361
4362 let mut dependency_indices = vec![];
4363 let fields = input_schema
4379 .iter()
4380 .enumerate()
4381 .map(|(index, (original_qualifier, original_field))| {
4382 match indices_to_unnest.get(&index) {
4383 Some(column_to_unnest) => {
4384 let recursions_on_column = options
4385 .recursions
4386 .iter()
4387 .filter(|p| -> bool { &p.input_column == *column_to_unnest })
4388 .collect::<Vec<_>>();
4389 let mut transformed_columns = recursions_on_column
4390 .iter()
4391 .map(|r| {
4392 list_columns.push((
4393 index,
4394 ColumnUnnestList {
4395 output_column: r.output_column.clone(),
4396 depth: r.depth,
4397 },
4398 ));
4399 Ok(get_unnested_columns(
4400 &r.output_column.name,
4401 original_field.data_type(),
4402 r.depth,
4403 )?
4404 .into_iter()
4405 .next()
4406 .unwrap()) })
4408 .collect::<Result<Vec<(Column, Arc<Field>)>>>()?;
4409 if transformed_columns.is_empty() {
4410 transformed_columns = get_unnested_columns(
4411 &column_to_unnest.name,
4412 original_field.data_type(),
4413 1,
4414 )?;
4415 match original_field.data_type() {
4416 DataType::Struct(_) => {
4417 struct_columns.push(index);
4418 }
4419 DataType::List(_)
4420 | DataType::FixedSizeList(_, _)
4421 | DataType::LargeList(_)
4422 | DataType::ListView(_)
4423 | DataType::LargeListView(_) => {
4424 list_columns.push((
4425 index,
4426 ColumnUnnestList {
4427 output_column: Column::from_name(
4428 &column_to_unnest.name,
4429 ),
4430 depth: 1,
4431 },
4432 ));
4433 }
4434 _ => {}
4435 };
4436 }
4437
4438 dependency_indices.extend(std::iter::repeat_n(
4440 index,
4441 transformed_columns.len(),
4442 ));
4443 Ok(transformed_columns
4444 .iter()
4445 .map(|(col, field)| {
4446 (col.relation.to_owned(), field.to_owned())
4447 })
4448 .collect())
4449 }
4450 None => {
4451 dependency_indices.push(index);
4452 Ok(vec![(
4453 original_qualifier.cloned(),
4454 Arc::clone(original_field),
4455 )])
4456 }
4457 }
4458 })
4459 .collect::<Result<Vec<_>>>()?
4460 .into_iter()
4461 .flatten()
4462 .collect::<Vec<_>>();
4463
4464 let metadata = input_schema.metadata().clone();
4465 let df_schema = DFSchema::new_with_metadata(fields, metadata)?;
4466 let deps = input_schema.functional_dependencies().clone();
4468 let schema = Arc::new(df_schema.with_functional_dependencies(deps)?);
4469
4470 Ok(Unnest {
4471 input,
4472 exec_columns,
4473 list_type_columns: list_columns,
4474 struct_type_columns: struct_columns,
4475 dependency_indices,
4476 schema,
4477 options,
4478 })
4479 }
4480}
4481
4482fn get_unnested_columns(
4491 col_name: &String,
4492 data_type: &DataType,
4493 depth: usize,
4494) -> Result<Vec<(Column, Arc<Field>)>> {
4495 let mut qualified_columns = Vec::with_capacity(1);
4496
4497 match data_type {
4498 DataType::List(_)
4499 | DataType::FixedSizeList(_, _)
4500 | DataType::LargeList(_)
4501 | DataType::ListView(_)
4502 | DataType::LargeListView(_) => {
4503 let data_type = get_unnested_list_datatype_recursive(data_type, depth)?;
4504 let new_field = Arc::new(Field::new(
4505 col_name, data_type,
4506 true,
4509 ));
4510 let column = Column::from_name(col_name);
4511 qualified_columns.push((column, new_field));
4513 }
4514 DataType::Struct(fields) => {
4515 qualified_columns.extend(fields.iter().map(|f| {
4516 let new_name = format!("{}.{}", col_name, f.name());
4517 let column = Column::from_name(&new_name);
4518 let new_field = f.as_ref().clone().with_name(new_name);
4519 (column, Arc::new(new_field))
4521 }))
4522 }
4523 _ => {
4524 return internal_err!("trying to unnest on invalid data type {data_type}");
4525 }
4526 };
4527 Ok(qualified_columns)
4528}
4529
4530fn get_unnested_list_datatype_recursive(
4533 data_type: &DataType,
4534 depth: usize,
4535) -> Result<DataType> {
4536 match data_type {
4537 DataType::List(field)
4538 | DataType::FixedSizeList(field, _)
4539 | DataType::LargeList(field)
4540 | DataType::ListView(field)
4541 | DataType::LargeListView(field) => {
4542 if depth == 1 {
4543 return Ok(field.data_type().clone());
4544 }
4545 return get_unnested_list_datatype_recursive(field.data_type(), depth - 1);
4546 }
4547 _ => {}
4548 };
4549
4550 internal_err!("trying to unnest on invalid data type {data_type}")
4551}
4552
4553#[cfg(test)]
4554mod tests {
4555 use super::*;
4556 use crate::builder::LogicalTableSource;
4557 use crate::logical_plan::table_scan;
4558 use crate::select_expr::SelectExpr;
4559 use crate::test::function_stub::{count, count_udaf};
4560 use crate::{
4561 GroupingSet, binary_expr, col, exists, in_subquery, lit, placeholder,
4562 scalar_subquery,
4563 };
4564 use datafusion_common::metadata::ScalarAndMetadata;
4565 use datafusion_common::tree_node::{
4566 TransformedResult, TreeNodeRewriter, TreeNodeVisitor,
4567 };
4568 use datafusion_common::{Constraint, not_impl_err};
4569 use insta::{assert_debug_snapshot, assert_snapshot};
4570 use std::hash::DefaultHasher;
4571
4572 fn employee_schema() -> Schema {
4573 Schema::new(vec![
4574 Field::new("id", DataType::Int32, false),
4575 Field::new("first_name", DataType::Utf8, false),
4576 Field::new("last_name", DataType::Utf8, false),
4577 Field::new("state", DataType::Utf8, false),
4578 Field::new("salary", DataType::Int32, false),
4579 ])
4580 }
4581
4582 fn display_plan() -> Result<LogicalPlan> {
4583 let plan1 = table_scan(Some("employee_csv"), &employee_schema(), Some(vec![3]))?
4584 .build()?;
4585
4586 table_scan(Some("employee_csv"), &employee_schema(), Some(vec![0, 3]))?
4587 .filter(in_subquery(col("state"), Arc::new(plan1)))?
4588 .project(vec![col("id")])?
4589 .build()
4590 }
4591
4592 fn recursive_term_scan(name: &str, fields: Vec<Field>) -> Result<Arc<LogicalPlan>> {
4593 Ok(Arc::new(
4594 table_scan(Some(name), &Schema::new(fields), None)?.build()?,
4595 ))
4596 }
4597
4598 #[test]
4599 fn recursive_query_widens_nullability_per_column() -> Result<()> {
4600 let static_term = recursive_term_scan(
4604 "static",
4605 vec![
4606 Field::new("a", DataType::Int32, false),
4607 Field::new("b", DataType::Int32, false),
4608 ],
4609 )?;
4610 let recursive_term = recursive_term_scan(
4611 "rec",
4612 vec![
4613 Field::new("a", DataType::Int32, false),
4614 Field::new("b", DataType::Int32, true),
4615 ],
4616 )?;
4617
4618 let query =
4619 RecursiveQuery::try_new("t".to_string(), static_term, recursive_term, false)?;
4620
4621 assert_eq!(query.schema.field(0).name(), "a");
4623 assert_eq!(query.schema.field(1).name(), "b");
4624 assert_eq!(query.schema.field(0).data_type(), &DataType::Int32);
4625 assert_eq!(query.schema.field(1).data_type(), &DataType::Int32);
4626 assert!(!query.schema.field(0).is_nullable());
4628 assert!(query.schema.field(1).is_nullable());
4629 assert_eq!(
4631 LogicalPlan::RecursiveQuery(query.clone()).schema(),
4632 &query.schema
4633 );
4634 Ok(())
4635 }
4636
4637 #[test]
4638 fn recursive_query_rejects_column_count_mismatch() -> Result<()> {
4639 let static_term =
4640 recursive_term_scan("static", vec![Field::new("a", DataType::Int32, false)])?;
4641 let recursive_term = recursive_term_scan(
4642 "rec",
4643 vec![
4644 Field::new("a", DataType::Int32, false),
4645 Field::new("b", DataType::Int32, false),
4646 ],
4647 )?;
4648
4649 let err =
4650 RecursiveQuery::try_new("t".to_string(), static_term, recursive_term, false)
4651 .unwrap_err();
4652 assert!(
4653 err.strip_backtrace()
4654 .contains("must have the same number of columns"),
4655 "unexpected error: {err}"
4656 );
4657 Ok(())
4658 }
4659
4660 #[test]
4661 fn test_display_indent() -> Result<()> {
4662 let plan = display_plan()?;
4663
4664 assert_snapshot!(plan.display_indent(), @r"
4665 Projection: employee_csv.id
4666 Filter: employee_csv.state IN (<subquery>)
4667 Subquery:
4668 TableScan: employee_csv projection=[state]
4669 TableScan: employee_csv projection=[id, state]
4670 ");
4671 Ok(())
4672 }
4673
4674 #[test]
4675 fn test_display_indent_schema() -> Result<()> {
4676 let plan = display_plan()?;
4677
4678 assert_snapshot!(plan.display_indent_schema(), @r"
4679 Projection: employee_csv.id [id:Int32]
4680 Filter: employee_csv.state IN (<subquery>) [id:Int32, state:Utf8]
4681 Subquery: [state:Utf8]
4682 TableScan: employee_csv projection=[state] [state:Utf8]
4683 TableScan: employee_csv projection=[id, state] [id:Int32, state:Utf8]
4684 ");
4685 Ok(())
4686 }
4687
4688 #[test]
4689 fn test_display_subquery_alias() -> Result<()> {
4690 let plan1 = table_scan(Some("employee_csv"), &employee_schema(), Some(vec![3]))?
4691 .build()?;
4692 let plan1 = Arc::new(plan1);
4693
4694 let plan =
4695 table_scan(Some("employee_csv"), &employee_schema(), Some(vec![0, 3]))?
4696 .project(vec![col("id"), exists(plan1).alias("exists")])?
4697 .build();
4698
4699 assert_snapshot!(plan?.display_indent(), @r"
4700 Projection: employee_csv.id, EXISTS (<subquery>) AS exists
4701 Subquery:
4702 TableScan: employee_csv projection=[state]
4703 TableScan: employee_csv projection=[id, state]
4704 ");
4705 Ok(())
4706 }
4707
4708 #[test]
4709 fn test_display_graphviz() -> Result<()> {
4710 let plan = display_plan()?;
4711
4712 assert_snapshot!(plan.display_graphviz(), @r#"
4715 // Begin DataFusion GraphViz Plan,
4716 // display it online here: https://dreampuf.github.io/GraphvizOnline
4717
4718 digraph {
4719 subgraph cluster_1
4720 {
4721 graph[label="LogicalPlan"]
4722 2[shape=box label="Projection: employee_csv.id"]
4723 3[shape=box label="Filter: employee_csv.state IN (<subquery>)"]
4724 2 -> 3 [arrowhead=none, arrowtail=normal, dir=back]
4725 4[shape=box label="Subquery:"]
4726 3 -> 4 [arrowhead=none, arrowtail=normal, dir=back]
4727 5[shape=box label="TableScan: employee_csv projection=[state]"]
4728 4 -> 5 [arrowhead=none, arrowtail=normal, dir=back]
4729 6[shape=box label="TableScan: employee_csv projection=[id, state]"]
4730 3 -> 6 [arrowhead=none, arrowtail=normal, dir=back]
4731 }
4732 subgraph cluster_7
4733 {
4734 graph[label="Detailed LogicalPlan"]
4735 8[shape=box label="Projection: employee_csv.id\nSchema: [id:Int32]"]
4736 9[shape=box label="Filter: employee_csv.state IN (<subquery>)\nSchema: [id:Int32, state:Utf8]"]
4737 8 -> 9 [arrowhead=none, arrowtail=normal, dir=back]
4738 10[shape=box label="Subquery:\nSchema: [state:Utf8]"]
4739 9 -> 10 [arrowhead=none, arrowtail=normal, dir=back]
4740 11[shape=box label="TableScan: employee_csv projection=[state]\nSchema: [state:Utf8]"]
4741 10 -> 11 [arrowhead=none, arrowtail=normal, dir=back]
4742 12[shape=box label="TableScan: employee_csv projection=[id, state]\nSchema: [id:Int32, state:Utf8]"]
4743 9 -> 12 [arrowhead=none, arrowtail=normal, dir=back]
4744 }
4745 }
4746 // End DataFusion GraphViz Plan
4747 "#);
4748 Ok(())
4749 }
4750
4751 #[test]
4752 fn test_display_pg_json() -> Result<()> {
4753 let plan = display_plan()?;
4754
4755 assert_snapshot!(plan.display_pg_json(), @r#"
4756 [
4757 {
4758 "Plan": {
4759 "Node Type": "Projection",
4760 "Expressions": [
4761 "employee_csv.id"
4762 ],
4763 "Plans": [
4764 {
4765 "Node Type": "Filter",
4766 "Condition": "employee_csv.state IN (<subquery>)",
4767 "Plans": [
4768 {
4769 "Node Type": "Subquery",
4770 "Plans": [
4771 {
4772 "Node Type": "TableScan",
4773 "Relation Name": "employee_csv",
4774 "Plans": [],
4775 "Output": [
4776 "state"
4777 ]
4778 }
4779 ],
4780 "Output": [
4781 "state"
4782 ]
4783 },
4784 {
4785 "Node Type": "TableScan",
4786 "Relation Name": "employee_csv",
4787 "Plans": [],
4788 "Output": [
4789 "id",
4790 "state"
4791 ]
4792 }
4793 ],
4794 "Output": [
4795 "id",
4796 "state"
4797 ]
4798 }
4799 ],
4800 "Output": [
4801 "id"
4802 ]
4803 }
4804 }
4805 ]
4806 "#);
4807 Ok(())
4808 }
4809
4810 #[derive(Debug, Default)]
4812 struct OkVisitor {
4813 strings: Vec<String>,
4814 }
4815
4816 impl<'n> TreeNodeVisitor<'n> for OkVisitor {
4817 type Node = LogicalPlan;
4818
4819 fn f_down(&mut self, plan: &'n LogicalPlan) -> Result<TreeNodeRecursion> {
4820 let s = match plan {
4821 LogicalPlan::Projection { .. } => "pre_visit Projection",
4822 LogicalPlan::Filter { .. } => "pre_visit Filter",
4823 LogicalPlan::TableScan { .. } => "pre_visit TableScan",
4824 _ => {
4825 return not_impl_err!("unknown plan type");
4826 }
4827 };
4828
4829 self.strings.push(s.into());
4830 Ok(TreeNodeRecursion::Continue)
4831 }
4832
4833 fn f_up(&mut self, plan: &'n LogicalPlan) -> Result<TreeNodeRecursion> {
4834 let s = match plan {
4835 LogicalPlan::Projection { .. } => "post_visit Projection",
4836 LogicalPlan::Filter { .. } => "post_visit Filter",
4837 LogicalPlan::TableScan { .. } => "post_visit TableScan",
4838 _ => {
4839 return not_impl_err!("unknown plan type");
4840 }
4841 };
4842
4843 self.strings.push(s.into());
4844 Ok(TreeNodeRecursion::Continue)
4845 }
4846 }
4847
4848 #[test]
4849 fn visit_order() {
4850 let mut visitor = OkVisitor::default();
4851 let plan = test_plan();
4852 let res = plan.visit_with_subqueries(&mut visitor);
4853 assert!(res.is_ok());
4854
4855 assert_debug_snapshot!(visitor.strings, @r#"
4856 [
4857 "pre_visit Projection",
4858 "pre_visit Filter",
4859 "pre_visit TableScan",
4860 "post_visit TableScan",
4861 "post_visit Filter",
4862 "post_visit Projection",
4863 ]
4864 "#);
4865 }
4866
4867 #[derive(Debug, Default)]
4868 struct OptionalCounter {
4870 val: Option<usize>,
4871 }
4872
4873 impl OptionalCounter {
4874 fn new(val: usize) -> Self {
4875 Self { val: Some(val) }
4876 }
4877 fn dec(&mut self) -> bool {
4879 if Some(0) == self.val {
4880 true
4881 } else {
4882 self.val = self.val.take().map(|i| i - 1);
4883 false
4884 }
4885 }
4886 }
4887
4888 #[derive(Debug, Default)]
4889 struct StoppingVisitor {
4891 inner: OkVisitor,
4892 return_false_from_pre_in: OptionalCounter,
4894 return_false_from_post_in: OptionalCounter,
4896 }
4897
4898 impl<'n> TreeNodeVisitor<'n> for StoppingVisitor {
4899 type Node = LogicalPlan;
4900
4901 fn f_down(&mut self, plan: &'n LogicalPlan) -> Result<TreeNodeRecursion> {
4902 if self.return_false_from_pre_in.dec() {
4903 return Ok(TreeNodeRecursion::Stop);
4904 }
4905 self.inner.f_down(plan)?;
4906
4907 Ok(TreeNodeRecursion::Continue)
4908 }
4909
4910 fn f_up(&mut self, plan: &'n LogicalPlan) -> Result<TreeNodeRecursion> {
4911 if self.return_false_from_post_in.dec() {
4912 return Ok(TreeNodeRecursion::Stop);
4913 }
4914
4915 self.inner.f_up(plan)
4916 }
4917 }
4918
4919 #[test]
4921 fn early_stopping_pre_visit() {
4922 let mut visitor = StoppingVisitor {
4923 return_false_from_pre_in: OptionalCounter::new(2),
4924 ..Default::default()
4925 };
4926 let plan = test_plan();
4927 let res = plan.visit_with_subqueries(&mut visitor);
4928 assert!(res.is_ok());
4929
4930 assert_debug_snapshot!(
4931 visitor.inner.strings,
4932 @r#"
4933 [
4934 "pre_visit Projection",
4935 "pre_visit Filter",
4936 ]
4937 "#
4938 );
4939 }
4940
4941 #[test]
4942 fn early_stopping_post_visit() {
4943 let mut visitor = StoppingVisitor {
4944 return_false_from_post_in: OptionalCounter::new(1),
4945 ..Default::default()
4946 };
4947 let plan = test_plan();
4948 let res = plan.visit_with_subqueries(&mut visitor);
4949 assert!(res.is_ok());
4950
4951 assert_debug_snapshot!(
4952 visitor.inner.strings,
4953 @r#"
4954 [
4955 "pre_visit Projection",
4956 "pre_visit Filter",
4957 "pre_visit TableScan",
4958 "post_visit TableScan",
4959 ]
4960 "#
4961 );
4962 }
4963
4964 #[derive(Debug, Default)]
4965 struct ErrorVisitor {
4967 inner: OkVisitor,
4968 return_error_from_pre_in: OptionalCounter,
4970 return_error_from_post_in: OptionalCounter,
4972 }
4973
4974 impl<'n> TreeNodeVisitor<'n> for ErrorVisitor {
4975 type Node = LogicalPlan;
4976
4977 fn f_down(&mut self, plan: &'n LogicalPlan) -> Result<TreeNodeRecursion> {
4978 if self.return_error_from_pre_in.dec() {
4979 return not_impl_err!("Error in pre_visit");
4980 }
4981
4982 self.inner.f_down(plan)
4983 }
4984
4985 fn f_up(&mut self, plan: &'n LogicalPlan) -> Result<TreeNodeRecursion> {
4986 if self.return_error_from_post_in.dec() {
4987 return not_impl_err!("Error in post_visit");
4988 }
4989
4990 self.inner.f_up(plan)
4991 }
4992 }
4993
4994 #[test]
4995 fn error_pre_visit() {
4996 let mut visitor = ErrorVisitor {
4997 return_error_from_pre_in: OptionalCounter::new(2),
4998 ..Default::default()
4999 };
5000 let plan = test_plan();
5001 let res = plan.visit_with_subqueries(&mut visitor).unwrap_err();
5002 assert_snapshot!(
5003 res.strip_backtrace(),
5004 @"This feature is not implemented: Error in pre_visit"
5005 );
5006 assert_debug_snapshot!(
5007 visitor.inner.strings,
5008 @r#"
5009 [
5010 "pre_visit Projection",
5011 "pre_visit Filter",
5012 ]
5013 "#
5014 );
5015 }
5016
5017 #[test]
5018 fn error_post_visit() {
5019 let mut visitor = ErrorVisitor {
5020 return_error_from_post_in: OptionalCounter::new(1),
5021 ..Default::default()
5022 };
5023 let plan = test_plan();
5024 let res = plan.visit_with_subqueries(&mut visitor).unwrap_err();
5025 assert_snapshot!(
5026 res.strip_backtrace(),
5027 @"This feature is not implemented: Error in post_visit"
5028 );
5029 assert_debug_snapshot!(
5030 visitor.inner.strings,
5031 @r#"
5032 [
5033 "pre_visit Projection",
5034 "pre_visit Filter",
5035 "pre_visit TableScan",
5036 "post_visit TableScan",
5037 ]
5038 "#
5039 );
5040 }
5041
5042 #[test]
5043 fn test_partial_eq_hash_and_partial_ord() {
5044 let empty_values = Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
5045 produce_one_row: true,
5046 schema: Arc::new(DFSchema::empty()),
5047 }));
5048
5049 let count_window_function = |schema| {
5050 Window::try_new_with_schema(
5051 vec![Expr::WindowFunction(Box::new(WindowFunction::new(
5052 WindowFunctionDefinition::AggregateUDF(count_udaf()),
5053 vec![],
5054 )))],
5055 Arc::clone(&empty_values),
5056 Arc::new(schema),
5057 )
5058 .unwrap()
5059 };
5060
5061 let schema_without_metadata = || {
5062 DFSchema::from_unqualified_fields(
5063 vec![Field::new("count", DataType::Int64, false)].into(),
5064 HashMap::new(),
5065 )
5066 .unwrap()
5067 };
5068
5069 let schema_with_metadata = || {
5070 DFSchema::from_unqualified_fields(
5071 vec![Field::new("count", DataType::Int64, false)].into(),
5072 [("key".to_string(), "value".to_string())].into(),
5073 )
5074 .unwrap()
5075 };
5076
5077 let f = count_window_function(schema_without_metadata());
5079
5080 let f2 = count_window_function(schema_without_metadata());
5082 assert_eq!(f, f2);
5083 assert_eq!(hash(&f), hash(&f2));
5084 assert_eq!(f.partial_cmp(&f2), Some(Ordering::Equal));
5085
5086 let o = count_window_function(schema_with_metadata());
5088 assert_ne!(f, o);
5089 assert_ne!(hash(&f), hash(&o)); assert_eq!(f.partial_cmp(&o), None);
5091 }
5092
5093 fn hash<T: Hash>(value: &T) -> u64 {
5094 let hasher = &mut DefaultHasher::new();
5095 value.hash(hasher);
5096 hasher.finish()
5097 }
5098
5099 #[test]
5100 fn projection_expr_schema_mismatch() -> Result<()> {
5101 let empty_schema = Arc::new(DFSchema::empty());
5102 let p = Projection::try_new_with_schema(
5103 vec![col("a")],
5104 Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
5105 produce_one_row: false,
5106 schema: Arc::clone(&empty_schema),
5107 })),
5108 empty_schema,
5109 );
5110 assert_snapshot!(p.unwrap_err().strip_backtrace(), @"Error during planning: Projection has mismatch between number of expressions (1) and number of fields in schema (0)");
5111 Ok(())
5112 }
5113
5114 fn test_plan() -> LogicalPlan {
5115 let schema = Schema::new(vec![
5116 Field::new("id", DataType::Int32, false),
5117 Field::new("state", DataType::Utf8, false),
5118 ]);
5119
5120 table_scan(TableReference::none(), &schema, Some(vec![0, 1]))
5121 .unwrap()
5122 .filter(col("state").eq(lit("CO")))
5123 .unwrap()
5124 .project(vec![col("id")])
5125 .unwrap()
5126 .build()
5127 .unwrap()
5128 }
5129
5130 #[test]
5131 fn test_replace_invalid_placeholder() {
5132 let schema = Schema::new(vec![Field::new("id", DataType::Int32, false)]);
5134
5135 let plan = table_scan(TableReference::none(), &schema, None)
5136 .unwrap()
5137 .filter(col("id").eq(placeholder("")))
5138 .unwrap()
5139 .build()
5140 .unwrap();
5141
5142 let param_values = vec![ScalarValue::Int32(Some(42))];
5143 plan.replace_params_with_values(¶m_values.clone().into())
5144 .expect_err("unexpectedly succeeded to replace an invalid placeholder");
5145
5146 let schema = Schema::new(vec![Field::new("id", DataType::Int32, false)]);
5148
5149 let plan = table_scan(TableReference::none(), &schema, None)
5150 .unwrap()
5151 .filter(col("id").eq(placeholder("$0")))
5152 .unwrap()
5153 .build()
5154 .unwrap();
5155
5156 plan.replace_params_with_values(¶m_values.clone().into())
5157 .expect_err("unexpectedly succeeded to replace an invalid placeholder");
5158
5159 let schema = Schema::new(vec![Field::new("id", DataType::Int32, false)]);
5161
5162 let plan = table_scan(TableReference::none(), &schema, None)
5163 .unwrap()
5164 .filter(col("id").eq(placeholder("$00")))
5165 .unwrap()
5166 .build()
5167 .unwrap();
5168
5169 plan.replace_params_with_values(¶m_values.into())
5170 .expect_err("unexpectedly succeeded to replace an invalid placeholder");
5171 }
5172
5173 #[test]
5174 fn test_replace_placeholder_mismatched_metadata() {
5175 let schema = Schema::new(vec![Field::new("id", DataType::Int32, false)]);
5176
5177 let plan = table_scan(TableReference::none(), &schema, None)
5179 .unwrap()
5180 .filter(col("id").eq(placeholder("$1")))
5181 .unwrap()
5182 .build()
5183 .unwrap();
5184 let prepared_builder = LogicalPlanBuilder::new(plan)
5185 .prepare(
5186 "".to_string(),
5187 vec![Field::new("", DataType::Int32, true).into()],
5188 )
5189 .unwrap();
5190
5191 let mut scalar_meta = HashMap::new();
5193 scalar_meta.insert("some_key".to_string(), "some_value".to_string());
5194 let param_values = ParamValues::List(vec![ScalarAndMetadata::new(
5195 ScalarValue::Int32(Some(42)),
5196 Some(scalar_meta.into()),
5197 )]);
5198 prepared_builder
5199 .plan()
5200 .clone()
5201 .with_param_values(param_values)
5202 .expect_err("prepared field metadata mismatch unexpectedly succeeded");
5203 }
5204
5205 #[test]
5206 fn test_replace_placeholder_empty_relation_valid_schema() {
5207 let plan = LogicalPlanBuilder::empty(false)
5209 .project(vec![
5210 SelectExpr::from(placeholder("$1")),
5211 SelectExpr::from(placeholder("$2")),
5212 ])
5213 .unwrap()
5214 .build()
5215 .unwrap();
5216
5217 assert_snapshot!(plan.display_indent_schema(), @r"
5219 Projection: $1, $2 [$1:Null;N, $2:Null;N]
5220 EmptyRelation: rows=0 []
5221 ");
5222
5223 let plan = plan
5224 .with_param_values(vec![ScalarValue::from(1i32), ScalarValue::from("s")])
5225 .unwrap();
5226
5227 assert_snapshot!(plan.display_indent_schema(), @r#"
5229 Projection: Int32(1) AS $1, Utf8("s") AS $2 [$1:Int32, $2:Utf8]
5230 EmptyRelation: rows=0 []
5231 "#);
5232 }
5233
5234 #[test]
5235 fn test_nullable_schema_after_grouping_set() {
5236 let schema = Schema::new(vec![
5237 Field::new("foo", DataType::Int32, false),
5238 Field::new("bar", DataType::Int32, false),
5239 ]);
5240
5241 let plan = table_scan(TableReference::none(), &schema, None)
5242 .unwrap()
5243 .aggregate(
5244 vec![Expr::GroupingSet(GroupingSet::GroupingSets(vec![
5245 vec![col("foo")],
5246 vec![col("bar")],
5247 ]))],
5248 vec![count(lit(true))],
5249 )
5250 .unwrap()
5251 .build()
5252 .unwrap();
5253
5254 let output_schema = plan.schema();
5255
5256 assert!(
5257 output_schema
5258 .field_with_name(None, "foo")
5259 .unwrap()
5260 .is_nullable(),
5261 );
5262 assert!(
5263 output_schema
5264 .field_with_name(None, "bar")
5265 .unwrap()
5266 .is_nullable()
5267 );
5268 }
5269
5270 #[test]
5271 fn grouping_id_type_accounts_for_duplicate_ordinal_bits() {
5272 assert_eq!(Aggregate::grouping_id_type(8, 0), DataType::UInt8);
5275 assert_eq!(Aggregate::grouping_id_type(8, 1), DataType::UInt16);
5276 }
5277
5278 #[test]
5279 fn test_filter_is_scalar() {
5280 let schema =
5282 Arc::new(Schema::new(vec![Field::new("id", DataType::Int32, false)]));
5283
5284 let source = Arc::new(LogicalTableSource::new(schema));
5285 let schema = Arc::new(
5286 DFSchema::try_from_qualified_schema(
5287 TableReference::bare("tab"),
5288 &source.schema(),
5289 )
5290 .unwrap(),
5291 );
5292 let scan = Arc::new(LogicalPlan::TableScan(TableScan {
5293 table_name: TableReference::bare("tab"),
5294 source: Arc::clone(&source) as Arc<dyn TableSource>,
5295 projection: None,
5296 projected_schema: Arc::clone(&schema),
5297 filters: vec![],
5298 fetch: None,
5299 }));
5300 let col = schema.field_names()[0].clone();
5301
5302 let filter = Filter::try_new(
5303 Expr::Column(col.into()).eq(Expr::Literal(ScalarValue::Int32(Some(1)), None)),
5304 scan,
5305 )
5306 .unwrap();
5307 assert!(!filter.is_scalar());
5308 let unique_schema = Arc::new(
5309 schema
5310 .as_ref()
5311 .clone()
5312 .with_functional_dependencies(
5313 FunctionalDependencies::new_from_constraints(
5314 Some(&Constraints::new_unverified(vec![Constraint::Unique(
5315 vec![0],
5316 )])),
5317 1,
5318 ),
5319 )
5320 .unwrap(),
5321 );
5322 let scan = Arc::new(LogicalPlan::TableScan(TableScan {
5323 table_name: TableReference::bare("tab"),
5324 source,
5325 projection: None,
5326 projected_schema: Arc::clone(&unique_schema),
5327 filters: vec![],
5328 fetch: None,
5329 }));
5330 let col = schema.field_names()[0].clone();
5331
5332 let filter =
5333 Filter::try_new(Expr::Column(col.into()).eq(lit(1i32)), scan).unwrap();
5334 assert!(filter.is_scalar());
5335 }
5336
5337 #[test]
5338 fn test_transform_explain() {
5339 let schema = Schema::new(vec![
5340 Field::new("foo", DataType::Int32, false),
5341 Field::new("bar", DataType::Int32, false),
5342 ]);
5343
5344 let plan = table_scan(TableReference::none(), &schema, None)
5345 .unwrap()
5346 .explain(false, false)
5347 .unwrap()
5348 .build()
5349 .unwrap();
5350
5351 let external_filter = col("foo").eq(lit(true));
5352
5353 let plan = plan
5356 .transform(|plan| match plan {
5357 LogicalPlan::TableScan(table) => {
5358 let filter = Filter::try_new(
5359 external_filter.clone(),
5360 Arc::new(LogicalPlan::TableScan(table)),
5361 )
5362 .unwrap();
5363 Ok(Transformed::yes(LogicalPlan::Filter(filter)))
5364 }
5365 x => Ok(Transformed::no(x)),
5366 })
5367 .data()
5368 .unwrap();
5369
5370 let actual = format!("{}", plan.display_indent());
5371 assert_snapshot!(actual, @r"
5372 Explain
5373 Filter: foo = Boolean(true)
5374 TableScan: ?table?
5375 ")
5376 }
5377
5378 #[test]
5379 fn test_plan_partial_ord() {
5380 let empty_relation = LogicalPlan::EmptyRelation(EmptyRelation {
5381 produce_one_row: false,
5382 schema: Arc::new(DFSchema::empty()),
5383 });
5384
5385 let describe_table = LogicalPlan::DescribeTable(DescribeTable {
5386 schema: Arc::new(Schema::new(vec![Field::new(
5387 "foo",
5388 DataType::Int32,
5389 false,
5390 )])),
5391 output_schema: DFSchemaRef::new(DFSchema::empty()),
5392 });
5393
5394 let describe_table_clone = LogicalPlan::DescribeTable(DescribeTable {
5395 schema: Arc::new(Schema::new(vec![Field::new(
5396 "foo",
5397 DataType::Int32,
5398 false,
5399 )])),
5400 output_schema: DFSchemaRef::new(DFSchema::empty()),
5401 });
5402
5403 assert_eq!(
5404 empty_relation.partial_cmp(&describe_table),
5405 Some(Ordering::Less)
5406 );
5407 assert_eq!(
5408 describe_table.partial_cmp(&empty_relation),
5409 Some(Ordering::Greater)
5410 );
5411 assert_eq!(describe_table.partial_cmp(&describe_table_clone), None);
5412 }
5413
5414 #[test]
5415 fn test_limit_with_new_children() {
5416 let input = Arc::new(LogicalPlan::Values(Values {
5417 schema: Arc::new(DFSchema::empty()),
5418 values: vec![vec![]],
5419 }));
5420 let cases = [
5421 LogicalPlan::Limit(Limit {
5422 skip: None,
5423 fetch: None,
5424 input: Arc::clone(&input),
5425 }),
5426 LogicalPlan::Limit(Limit {
5427 skip: None,
5428 fetch: Some(Box::new(Expr::Literal(
5429 ScalarValue::new_ten(&DataType::UInt32).unwrap(),
5430 None,
5431 ))),
5432 input: Arc::clone(&input),
5433 }),
5434 LogicalPlan::Limit(Limit {
5435 skip: Some(Box::new(Expr::Literal(
5436 ScalarValue::new_ten(&DataType::UInt32).unwrap(),
5437 None,
5438 ))),
5439 fetch: None,
5440 input: Arc::clone(&input),
5441 }),
5442 LogicalPlan::Limit(Limit {
5443 skip: Some(Box::new(Expr::Literal(
5444 ScalarValue::new_one(&DataType::UInt32).unwrap(),
5445 None,
5446 ))),
5447 fetch: Some(Box::new(Expr::Literal(
5448 ScalarValue::new_ten(&DataType::UInt32).unwrap(),
5449 None,
5450 ))),
5451 input,
5452 }),
5453 ];
5454
5455 for limit in cases {
5456 let new_limit = limit
5457 .with_new_exprs(
5458 limit.expressions(),
5459 limit.inputs().into_iter().cloned().collect(),
5460 )
5461 .unwrap();
5462 assert_eq!(limit, new_limit);
5463 }
5464 }
5465
5466 #[test]
5467 fn test_with_subqueries_jump() {
5468 let subquery_schema =
5473 Schema::new(vec![Field::new("sub_id", DataType::Int32, false)]);
5474
5475 let subquery_plan =
5476 table_scan(TableReference::none(), &subquery_schema, Some(vec![0]))
5477 .unwrap()
5478 .filter(col("sub_id").eq(lit(0)))
5479 .unwrap()
5480 .build()
5481 .unwrap();
5482
5483 let schema = Schema::new(vec![Field::new("id", DataType::Int32, false)]);
5484
5485 let plan = table_scan(TableReference::none(), &schema, Some(vec![0]))
5486 .unwrap()
5487 .filter(col("id").eq(lit(0)))
5488 .unwrap()
5489 .project(vec![col("id"), scalar_subquery(Arc::new(subquery_plan))])
5490 .unwrap()
5491 .build()
5492 .unwrap();
5493
5494 let mut filter_found = false;
5495 plan.apply_with_subqueries(|plan| {
5496 match plan {
5497 LogicalPlan::Projection(..) => return Ok(TreeNodeRecursion::Jump),
5498 LogicalPlan::Filter(..) => filter_found = true,
5499 _ => {}
5500 }
5501 Ok(TreeNodeRecursion::Continue)
5502 })
5503 .unwrap();
5504 assert!(!filter_found);
5505
5506 struct ProjectJumpVisitor {
5507 filter_found: bool,
5508 }
5509
5510 impl ProjectJumpVisitor {
5511 fn new() -> Self {
5512 Self {
5513 filter_found: false,
5514 }
5515 }
5516 }
5517
5518 impl<'n> TreeNodeVisitor<'n> for ProjectJumpVisitor {
5519 type Node = LogicalPlan;
5520
5521 fn f_down(&mut self, node: &'n Self::Node) -> Result<TreeNodeRecursion> {
5522 match node {
5523 LogicalPlan::Projection(..) => return Ok(TreeNodeRecursion::Jump),
5524 LogicalPlan::Filter(..) => self.filter_found = true,
5525 _ => {}
5526 }
5527 Ok(TreeNodeRecursion::Continue)
5528 }
5529 }
5530
5531 let mut visitor = ProjectJumpVisitor::new();
5532 plan.visit_with_subqueries(&mut visitor).unwrap();
5533 assert!(!visitor.filter_found);
5534
5535 let mut filter_found = false;
5536 plan.clone()
5537 .transform_down_with_subqueries(|plan| {
5538 match plan {
5539 LogicalPlan::Projection(..) => {
5540 return Ok(Transformed::new(
5541 plan,
5542 false,
5543 TreeNodeRecursion::Jump,
5544 ));
5545 }
5546 LogicalPlan::Filter(..) => filter_found = true,
5547 _ => {}
5548 }
5549 Ok(Transformed::no(plan))
5550 })
5551 .unwrap();
5552 assert!(!filter_found);
5553
5554 let mut filter_found = false;
5555 plan.clone()
5556 .transform_down_up_with_subqueries(
5557 |plan| {
5558 match plan {
5559 LogicalPlan::Projection(..) => {
5560 return Ok(Transformed::new(
5561 plan,
5562 false,
5563 TreeNodeRecursion::Jump,
5564 ));
5565 }
5566 LogicalPlan::Filter(..) => filter_found = true,
5567 _ => {}
5568 }
5569 Ok(Transformed::no(plan))
5570 },
5571 |plan| Ok(Transformed::no(plan)),
5572 )
5573 .unwrap();
5574 assert!(!filter_found);
5575
5576 struct ProjectJumpRewriter {
5577 filter_found: bool,
5578 }
5579
5580 impl ProjectJumpRewriter {
5581 fn new() -> Self {
5582 Self {
5583 filter_found: false,
5584 }
5585 }
5586 }
5587
5588 impl TreeNodeRewriter for ProjectJumpRewriter {
5589 type Node = LogicalPlan;
5590
5591 fn f_down(&mut self, node: Self::Node) -> Result<Transformed<Self::Node>> {
5592 match node {
5593 LogicalPlan::Projection(..) => {
5594 return Ok(Transformed::new(
5595 node,
5596 false,
5597 TreeNodeRecursion::Jump,
5598 ));
5599 }
5600 LogicalPlan::Filter(..) => self.filter_found = true,
5601 _ => {}
5602 }
5603 Ok(Transformed::no(node))
5604 }
5605 }
5606
5607 let mut rewriter = ProjectJumpRewriter::new();
5608 plan.rewrite_with_subqueries(&mut rewriter).unwrap();
5609 assert!(!rewriter.filter_found);
5610 }
5611
5612 #[test]
5613 fn test_with_unresolved_placeholders() {
5614 let field_name = "id";
5615 let placeholder_value = "$1";
5616 let schema = Schema::new(vec![Field::new(field_name, DataType::Int32, false)]);
5617
5618 let plan = table_scan(TableReference::none(), &schema, None)
5619 .unwrap()
5620 .filter(col(field_name).eq(placeholder(placeholder_value)))
5621 .unwrap()
5622 .build()
5623 .unwrap();
5624
5625 let params = plan.get_parameter_fields().unwrap();
5627 assert_eq!(params.len(), 1);
5628
5629 let parameter_type = params.clone().get(placeholder_value).unwrap().clone();
5630 assert_eq!(parameter_type, None);
5631 }
5632
5633 #[test]
5634 fn test_join_with_new_exprs() -> Result<()> {
5635 fn create_test_join(
5636 on: Vec<(Expr, Expr)>,
5637 filter: Option<Expr>,
5638 ) -> Result<LogicalPlan> {
5639 let schema = Schema::new(vec![
5640 Field::new("a", DataType::Int32, false),
5641 Field::new("b", DataType::Int32, false),
5642 ]);
5643
5644 let left_schema = DFSchema::try_from_qualified_schema("t1", &schema)?;
5645 let right_schema = DFSchema::try_from_qualified_schema("t2", &schema)?;
5646
5647 Ok(LogicalPlan::Join(Join {
5648 left: Arc::new(
5649 table_scan(Some("t1"), left_schema.as_arrow(), None)?.build()?,
5650 ),
5651 right: Arc::new(
5652 table_scan(Some("t2"), right_schema.as_arrow(), None)?.build()?,
5653 ),
5654 on,
5655 filter,
5656 join_type: JoinType::Inner,
5657 join_constraint: JoinConstraint::On,
5658 schema: Arc::new(left_schema.join(&right_schema)?),
5659 null_equality: NullEquality::NullEqualsNothing,
5660 null_aware: false,
5661 }))
5662 }
5663
5664 {
5665 let join = create_test_join(vec![(col("t1.a"), (col("t2.a")))], None)?;
5666 let LogicalPlan::Join(join) = join.with_new_exprs(
5667 join.expressions(),
5668 join.inputs().into_iter().cloned().collect(),
5669 )?
5670 else {
5671 unreachable!()
5672 };
5673 assert_eq!(join.on, vec![(col("t1.a"), (col("t2.a")))]);
5674 assert_eq!(join.filter, None);
5675 }
5676
5677 {
5678 let join = create_test_join(vec![], Some(col("t1.a").gt(col("t2.a"))))?;
5679 let LogicalPlan::Join(join) = join.with_new_exprs(
5680 join.expressions(),
5681 join.inputs().into_iter().cloned().collect(),
5682 )?
5683 else {
5684 unreachable!()
5685 };
5686 assert_eq!(join.on, vec![]);
5687 assert_eq!(join.filter, Some(col("t1.a").gt(col("t2.a"))));
5688 }
5689
5690 {
5691 let join = create_test_join(
5692 vec![(col("t1.a"), (col("t2.a")))],
5693 Some(col("t1.b").gt(col("t2.b"))),
5694 )?;
5695 let LogicalPlan::Join(join) = join.with_new_exprs(
5696 join.expressions(),
5697 join.inputs().into_iter().cloned().collect(),
5698 )?
5699 else {
5700 unreachable!()
5701 };
5702 assert_eq!(join.on, vec![(col("t1.a"), (col("t2.a")))]);
5703 assert_eq!(join.filter, Some(col("t1.b").gt(col("t2.b"))));
5704 }
5705
5706 {
5707 let join = create_test_join(
5708 vec![(col("t1.a"), (col("t2.a"))), (col("t1.b"), (col("t2.b")))],
5709 None,
5710 )?;
5711 let LogicalPlan::Join(join) = join.with_new_exprs(
5712 vec![
5713 binary_expr(col("t1.a"), Operator::Plus, lit(1)),
5714 binary_expr(col("t2.a"), Operator::Plus, lit(2)),
5715 col("t1.b"),
5716 col("t2.b"),
5717 lit(true),
5718 ],
5719 join.inputs().into_iter().cloned().collect(),
5720 )?
5721 else {
5722 unreachable!()
5723 };
5724 assert_eq!(
5725 join.on,
5726 vec![
5727 (
5728 binary_expr(col("t1.a"), Operator::Plus, lit(1)),
5729 binary_expr(col("t2.a"), Operator::Plus, lit(2))
5730 ),
5731 (col("t1.b"), (col("t2.b")))
5732 ]
5733 );
5734 assert_eq!(join.filter, Some(lit(true)));
5735 }
5736
5737 Ok(())
5738 }
5739
5740 #[test]
5741 fn test_join_try_new() -> Result<()> {
5742 let schema = Schema::new(vec![
5743 Field::new("a", DataType::Int32, false),
5744 Field::new("b", DataType::Int32, false),
5745 ]);
5746
5747 let left_scan = table_scan(Some("t1"), &schema, None)?.build()?;
5748
5749 let right_scan = table_scan(Some("t2"), &schema, None)?.build()?;
5750
5751 let join_types = vec![
5752 JoinType::Inner,
5753 JoinType::Left,
5754 JoinType::Right,
5755 JoinType::Full,
5756 JoinType::LeftSemi,
5757 JoinType::LeftAnti,
5758 JoinType::RightSemi,
5759 JoinType::RightAnti,
5760 JoinType::LeftMark,
5761 ];
5762
5763 for join_type in join_types {
5764 let join = Join::try_new(
5765 Arc::new(left_scan.clone()),
5766 Arc::new(right_scan.clone()),
5767 vec![(col("t1.a"), col("t2.a"))],
5768 Some(col("t1.b").gt(col("t2.b"))),
5769 join_type,
5770 JoinConstraint::On,
5771 NullEquality::NullEqualsNothing,
5772 false,
5773 )?;
5774
5775 match join_type {
5776 JoinType::LeftSemi | JoinType::LeftAnti => {
5777 assert_eq!(join.schema.fields().len(), 2);
5778
5779 let fields = join.schema.fields();
5780 assert_eq!(
5781 fields[0].name(),
5782 "a",
5783 "First field should be 'a' from left table"
5784 );
5785 assert_eq!(
5786 fields[1].name(),
5787 "b",
5788 "Second field should be 'b' from left table"
5789 );
5790 }
5791 JoinType::RightSemi | JoinType::RightAnti => {
5792 assert_eq!(join.schema.fields().len(), 2);
5793
5794 let fields = join.schema.fields();
5795 assert_eq!(
5796 fields[0].name(),
5797 "a",
5798 "First field should be 'a' from right table"
5799 );
5800 assert_eq!(
5801 fields[1].name(),
5802 "b",
5803 "Second field should be 'b' from right table"
5804 );
5805 }
5806 JoinType::LeftMark => {
5807 assert_eq!(join.schema.fields().len(), 3);
5808
5809 let fields = join.schema.fields();
5810 assert_eq!(
5811 fields[0].name(),
5812 "a",
5813 "First field should be 'a' from left table"
5814 );
5815 assert_eq!(
5816 fields[1].name(),
5817 "b",
5818 "Second field should be 'b' from left table"
5819 );
5820 assert_eq!(
5821 fields[2].name(),
5822 "mark",
5823 "Third field should be the mark column"
5824 );
5825
5826 assert!(!fields[0].is_nullable());
5827 assert!(!fields[1].is_nullable());
5828 assert!(!fields[2].is_nullable());
5829 }
5830 _ => {
5831 assert_eq!(join.schema.fields().len(), 4);
5832
5833 let fields = join.schema.fields();
5834 assert_eq!(
5835 fields[0].name(),
5836 "a",
5837 "First field should be 'a' from left table"
5838 );
5839 assert_eq!(
5840 fields[1].name(),
5841 "b",
5842 "Second field should be 'b' from left table"
5843 );
5844 assert_eq!(
5845 fields[2].name(),
5846 "a",
5847 "Third field should be 'a' from right table"
5848 );
5849 assert_eq!(
5850 fields[3].name(),
5851 "b",
5852 "Fourth field should be 'b' from right table"
5853 );
5854
5855 if join_type == JoinType::Left {
5856 assert!(!fields[0].is_nullable());
5858 assert!(!fields[1].is_nullable());
5859 assert!(fields[2].is_nullable());
5861 assert!(fields[3].is_nullable());
5862 } else if join_type == JoinType::Right {
5863 assert!(fields[0].is_nullable());
5865 assert!(fields[1].is_nullable());
5866 assert!(!fields[2].is_nullable());
5868 assert!(!fields[3].is_nullable());
5869 } else if join_type == JoinType::Full {
5870 assert!(fields[0].is_nullable());
5871 assert!(fields[1].is_nullable());
5872 assert!(fields[2].is_nullable());
5873 assert!(fields[3].is_nullable());
5874 }
5875 }
5876 }
5877
5878 assert_eq!(join.on, vec![(col("t1.a"), col("t2.a"))]);
5879 assert_eq!(join.filter, Some(col("t1.b").gt(col("t2.b"))));
5880 assert_eq!(join.join_type, join_type);
5881 assert_eq!(join.join_constraint, JoinConstraint::On);
5882 assert_eq!(join.null_equality, NullEquality::NullEqualsNothing);
5883 }
5884
5885 Ok(())
5886 }
5887
5888 #[test]
5889 fn test_join_try_new_with_using_constraint_and_overlapping_columns() -> Result<()> {
5890 let left_schema = Schema::new(vec![
5891 Field::new("id", DataType::Int32, false), Field::new("name", DataType::Utf8, false), Field::new("value", DataType::Int32, false), ]);
5895
5896 let right_schema = Schema::new(vec![
5897 Field::new("id", DataType::Int32, false), Field::new("category", DataType::Utf8, false), Field::new("value", DataType::Float64, true), ]);
5901
5902 let left_plan = table_scan(Some("t1"), &left_schema, None)?.build()?;
5903
5904 let right_plan = table_scan(Some("t2"), &right_schema, None)?.build()?;
5905
5906 {
5908 let join = Join::try_new(
5911 Arc::new(left_plan.clone()),
5912 Arc::new(right_plan.clone()),
5913 vec![(col("t1.id"), col("t2.id"))],
5914 None,
5915 JoinType::Inner,
5916 JoinConstraint::Using,
5917 NullEquality::NullEqualsNothing,
5918 false,
5919 )?;
5920
5921 let fields = join.schema.fields();
5922
5923 assert_eq!(fields.len(), 6);
5924
5925 assert_eq!(
5926 fields[0].name(),
5927 "id",
5928 "First field should be 'id' from left table"
5929 );
5930 assert_eq!(
5931 fields[1].name(),
5932 "name",
5933 "Second field should be 'name' from left table"
5934 );
5935 assert_eq!(
5936 fields[2].name(),
5937 "value",
5938 "Third field should be 'value' from left table"
5939 );
5940 assert_eq!(
5941 fields[3].name(),
5942 "id",
5943 "Fourth field should be 'id' from right table"
5944 );
5945 assert_eq!(
5946 fields[4].name(),
5947 "category",
5948 "Fifth field should be 'category' from right table"
5949 );
5950 assert_eq!(
5951 fields[5].name(),
5952 "value",
5953 "Sixth field should be 'value' from right table"
5954 );
5955
5956 assert_eq!(join.join_constraint, JoinConstraint::Using);
5957 }
5958
5959 {
5961 let join = Join::try_new(
5963 Arc::new(left_plan.clone()),
5964 Arc::new(right_plan.clone()),
5965 vec![(col("t1.id"), col("t2.id"))], Some(col("t1.value").lt(col("t2.value"))), JoinType::Inner,
5968 JoinConstraint::On,
5969 NullEquality::NullEqualsNothing,
5970 false,
5971 )?;
5972
5973 let fields = join.schema.fields();
5974 assert_eq!(fields.len(), 6);
5975
5976 assert_eq!(
5977 fields[0].name(),
5978 "id",
5979 "First field should be 'id' from left table"
5980 );
5981 assert_eq!(
5982 fields[1].name(),
5983 "name",
5984 "Second field should be 'name' from left table"
5985 );
5986 assert_eq!(
5987 fields[2].name(),
5988 "value",
5989 "Third field should be 'value' from left table"
5990 );
5991 assert_eq!(
5992 fields[3].name(),
5993 "id",
5994 "Fourth field should be 'id' from right table"
5995 );
5996 assert_eq!(
5997 fields[4].name(),
5998 "category",
5999 "Fifth field should be 'category' from right table"
6000 );
6001 assert_eq!(
6002 fields[5].name(),
6003 "value",
6004 "Sixth field should be 'value' from right table"
6005 );
6006
6007 assert_eq!(join.filter, Some(col("t1.value").lt(col("t2.value"))));
6008 }
6009
6010 {
6012 let join = Join::try_new(
6013 Arc::new(left_plan.clone()),
6014 Arc::new(right_plan.clone()),
6015 vec![(col("t1.id"), col("t2.id"))],
6016 None,
6017 JoinType::Inner,
6018 JoinConstraint::On,
6019 NullEquality::NullEqualsNull,
6020 false,
6021 )?;
6022
6023 assert_eq!(join.null_equality, NullEquality::NullEqualsNull);
6024 }
6025
6026 Ok(())
6027 }
6028
6029 #[test]
6030 fn test_join_try_new_schema_validation() -> Result<()> {
6031 let left_schema = Schema::new(vec![
6032 Field::new("id", DataType::Int32, false),
6033 Field::new("name", DataType::Utf8, false),
6034 Field::new("value", DataType::Float64, true),
6035 ]);
6036
6037 let right_schema = Schema::new(vec![
6038 Field::new("id", DataType::Int32, false),
6039 Field::new("category", DataType::Utf8, true),
6040 Field::new("code", DataType::Int16, false),
6041 ]);
6042
6043 let left_plan = table_scan(Some("t1"), &left_schema, None)?.build()?;
6044
6045 let right_plan = table_scan(Some("t2"), &right_schema, None)?.build()?;
6046
6047 let join_types = vec![
6048 JoinType::Inner,
6049 JoinType::Left,
6050 JoinType::Right,
6051 JoinType::Full,
6052 ];
6053
6054 for join_type in join_types {
6055 let join = Join::try_new(
6056 Arc::new(left_plan.clone()),
6057 Arc::new(right_plan.clone()),
6058 vec![(col("t1.id"), col("t2.id"))],
6059 Some(col("t1.value").gt(lit(5.0))),
6060 join_type,
6061 JoinConstraint::On,
6062 NullEquality::NullEqualsNothing,
6063 false,
6064 )?;
6065
6066 let fields = join.schema.fields();
6067 assert_eq!(fields.len(), 6, "Expected 6 fields for {join_type} join");
6068
6069 for (i, field) in fields.iter().enumerate() {
6070 let expected_nullable = match (i, &join_type) {
6071 (0, JoinType::Right | JoinType::Full) => true, (1, JoinType::Right | JoinType::Full) => true, (2, _) => true, (3, JoinType::Left | JoinType::Full) => true, (4, _) => true, (5, JoinType::Left | JoinType::Full) => true, _ => false,
6082 };
6083
6084 assert_eq!(
6085 field.is_nullable(),
6086 expected_nullable,
6087 "Field {} ({}) nullability incorrect for {:?} join",
6088 i,
6089 field.name(),
6090 join_type
6091 );
6092 }
6093 }
6094
6095 let using_join = Join::try_new(
6096 Arc::new(left_plan.clone()),
6097 Arc::new(right_plan.clone()),
6098 vec![(col("t1.id"), col("t2.id"))],
6099 None,
6100 JoinType::Inner,
6101 JoinConstraint::Using,
6102 NullEquality::NullEqualsNothing,
6103 false,
6104 )?;
6105
6106 assert_eq!(
6107 using_join.schema.fields().len(),
6108 6,
6109 "USING join should have all fields"
6110 );
6111 assert_eq!(using_join.join_constraint, JoinConstraint::Using);
6112
6113 Ok(())
6114 }
6115}