1use std::cmp::Ordering;
21use std::collections::HashSet;
22use std::fmt::{self, Display, Formatter, Write};
23use std::hash::{Hash, Hasher};
24use std::mem;
25use std::sync::Arc;
26
27use crate::expr_fn::binary_expr;
28use crate::function::WindowFunctionSimplification;
29use crate::higher_order_function::{HigherOrderUDF, resolve_lambda_variables};
30use crate::logical_plan::Subquery;
31use crate::type_coercion::functions::value_fields_with_higher_order_udf;
32use crate::{AggregateUDF, LambdaParametersProgress, ValueOrLambda, Volatility};
33use crate::{ExprSchemable, Operator, Signature, WindowFrame, WindowUDF};
34
35use arrow::datatypes::{DataType, Field, FieldRef};
36use datafusion_common::cse::{HashNode, NormalizeEq, Normalizeable};
37use datafusion_common::datatype::DataTypeExt;
38use datafusion_common::metadata::format_type_and_metadata;
39use datafusion_common::tree_node::{
40 Transformed, TransformedResult, TreeNode, TreeNodeContainer, TreeNodeRecursion,
41};
42use datafusion_common::{
43 Column, DFSchema, ExprSchema, HashMap, Result, ScalarValue, Spans, TableReference,
44 plan_err,
45};
46use datafusion_expr_common::placement::ExpressionPlacement;
47use datafusion_functions_window_common::field::WindowUDFFieldArgs;
48#[cfg(feature = "sql")]
49pub use sqlparser::ast::{
50 ExceptSelectItem, ExcludeSelectItem, IlikeSelectItem, RenameSelectItem,
51 ReplaceSelectElement,
52};
53#[cfg(not(feature = "sql"))]
55pub use crate::sql::{
56 ExceptSelectItem, ExcludeSelectItem, IlikeSelectItem, RenameSelectItem,
57 ReplaceSelectElement,
58};
59
60pub use datafusion_common::metadata::FieldMetadata;
62use datafusion_common::metadata::ScalarAndMetadata;
63
64#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
67pub enum NullTreatment {
68 IgnoreNulls,
69 RespectNulls,
70}
71
72impl Display for NullTreatment {
73 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
74 f.write_str(match self {
75 NullTreatment::IgnoreNulls => "IGNORE NULLS",
76 NullTreatment::RespectNulls => "RESPECT NULLS",
77 })
78 }
79}
80
81#[cfg(feature = "sql")]
82impl From<sqlparser::ast::NullTreatment> for NullTreatment {
83 fn from(value: sqlparser::ast::NullTreatment) -> Self {
84 match value {
85 sqlparser::ast::NullTreatment::IgnoreNulls => Self::IgnoreNulls,
86 sqlparser::ast::NullTreatment::RespectNulls => Self::RespectNulls,
87 }
88 }
89}
90
91#[derive(Clone, PartialEq, PartialOrd, Eq, Debug, Hash)]
326pub enum Expr {
327 Alias(Alias),
329 Column(Column),
331 ScalarVariable(FieldRef, Vec<String>),
333 Literal(ScalarValue, Option<FieldMetadata>),
335 BinaryExpr(BinaryExpr),
337 Like(Like),
339 SimilarTo(Like),
341 Not(Box<Expr>),
343 IsNotNull(Box<Expr>),
345 IsNull(Box<Expr>),
347 IsTrue(Box<Expr>),
349 IsFalse(Box<Expr>),
351 IsUnknown(Box<Expr>),
353 IsNotTrue(Box<Expr>),
355 IsNotFalse(Box<Expr>),
357 IsNotUnknown(Box<Expr>),
359 Negative(Box<Expr>),
361 Between(Between),
363 Case(Case),
365 Cast(Cast),
368 TryCast(TryCast),
371 ScalarFunction(ScalarFunction),
373 AggregateFunction(AggregateFunction),
380 WindowFunction(Box<WindowFunction>),
382 InList(InList),
384 Exists(Exists),
386 InSubquery(InSubquery),
388 SetComparison(SetComparison),
390 ScalarSubquery(Subquery),
392 #[deprecated(
398 since = "46.0.0",
399 note = "A wildcard needs to be resolved to concrete expressions when constructing the logical plan. See https://github.com/apache/datafusion/issues/7765"
400 )]
401 Wildcard {
402 qualifier: Option<TableReference>,
403 options: Box<WildcardOptions>,
404 },
405 GroupingSet(GroupingSet),
408 Placeholder(Placeholder),
411 OuterReferenceColumn(FieldRef, Column),
414 Unnest(Unnest),
416 HigherOrderFunction(HigherOrderFunction),
430 Lambda(Lambda),
432 LambdaVariable(LambdaVariable),
434}
435
436#[derive(Clone, Eq, PartialOrd, Debug)]
438pub struct HigherOrderFunction {
439 pub func: Arc<HigherOrderUDF>,
441 pub args: Vec<Expr>,
443}
444
445impl HigherOrderFunction {
446 pub fn new(func: Arc<HigherOrderUDF>, args: Vec<Expr>) -> Self {
448 Self { func, args }
449 }
450
451 pub fn name(&self) -> &str {
452 self.func.name()
453 }
454
455 pub fn lambda_parameters(
463 &self,
464 schema: &dyn ExprSchema,
465 ) -> Result<Vec<Vec<FieldRef>>> {
466 let args = self
467 .args
468 .iter()
469 .map(|e| match e {
470 Expr::Lambda(lambda) => {
471 Ok(ValueOrLambda::Lambda(Some(lambda.body.to_field(schema)?.1)))
472 }
473 _ => Ok(ValueOrLambda::Value(e.to_field(schema)?.1)),
474 })
475 .collect::<Result<Vec<_>>>()?;
476
477 let coerced_fields =
478 value_fields_with_higher_order_udf(&args, self.func.as_ref())?;
479
480 match self.func.lambda_parameters(0, &coerced_fields)? {
481 LambdaParametersProgress::Partial(_) => plan_err!(
482 "{} lambda_parameters returned a partial result when the return type of all it's lambdas were provided",
483 self.name()
484 ),
485 LambdaParametersProgress::Complete(items) => Ok(items),
486 }
487 }
488}
489
490impl Hash for HigherOrderFunction {
491 fn hash<H: Hasher>(&self, state: &mut H) {
492 self.func.hash(state);
493 self.args.hash(state);
494 }
495}
496
497impl PartialEq for HigherOrderFunction {
498 fn eq(&self, other: &Self) -> bool {
499 self.func.as_ref() == other.func.as_ref() && self.args == other.args
500 }
501}
502
503#[derive(Clone, PartialEq, PartialOrd, Eq, Debug, Hash)]
519pub struct LambdaVariable {
520 pub name: String,
521 pub field: Option<FieldRef>,
522 pub spans: Spans,
523}
524
525impl LambdaVariable {
526 pub fn new(name: String, field: Option<FieldRef>) -> Self {
533 Self {
534 name,
535 field,
536 spans: Spans::new(),
537 }
538 }
539
540 pub fn spans_mut(&mut self) -> &mut Spans {
541 &mut self.spans
542 }
543}
544
545impl Default for Expr {
546 fn default() -> Self {
547 Expr::Literal(ScalarValue::Null, None)
548 }
549}
550
551impl AsRef<Expr> for Expr {
552 fn as_ref(&self) -> &Expr {
553 self
554 }
555}
556
557impl From<Column> for Expr {
559 fn from(value: Column) -> Self {
560 Expr::Column(value)
561 }
562}
563
564impl From<WindowFunction> for Expr {
566 fn from(value: WindowFunction) -> Self {
567 Expr::WindowFunction(Box::new(value))
568 }
569}
570
571impl From<ScalarAndMetadata> for Expr {
573 fn from(value: ScalarAndMetadata) -> Self {
574 let (value, metadata) = value.into_inner();
575 Expr::Literal(value, metadata)
576 }
577}
578
579impl<'a> From<(Option<&'a TableReference>, &'a FieldRef)> for Expr {
584 fn from(value: (Option<&'a TableReference>, &'a FieldRef)) -> Self {
585 Expr::from(Column::from(value))
586 }
587}
588
589impl<'a> TreeNodeContainer<'a, Self> for Expr {
590 fn apply_elements<F: FnMut(&'a Self) -> Result<TreeNodeRecursion>>(
591 &'a self,
592 mut f: F,
593 ) -> Result<TreeNodeRecursion> {
594 f(self)
595 }
596
597 fn map_elements<F: FnMut(Self) -> Result<Transformed<Self>>>(
598 self,
599 mut f: F,
600 ) -> Result<Transformed<Self>> {
601 f(self)
602 }
603}
604
605pub type SchemaFieldMetadata = std::collections::HashMap<String, String>;
626
627pub fn intersect_metadata_for_union<'a>(
649 metadatas: impl IntoIterator<Item = &'a SchemaFieldMetadata>,
650) -> SchemaFieldMetadata {
651 let mut intersected: Option<SchemaFieldMetadata> = None;
652
653 for metadata in metadatas {
654 if metadata.is_empty() {
657 continue;
658 }
659 match &mut intersected {
660 None => {
661 intersected = Some(metadata.clone());
662 }
663 Some(current) => {
664 current.retain(|k, v| metadata.get(k) == Some(&*v));
666 }
667 }
668 }
669
670 intersected.unwrap_or_default()
671}
672
673#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
680pub struct Unnest {
681 pub expr: Box<Expr>,
682 pub outer: bool,
685}
686
687impl Unnest {
688 pub fn new(expr: Expr) -> Self {
690 Self {
691 expr: Box::new(expr),
692 outer: false,
693 }
694 }
695
696 pub fn new_boxed(boxed: Box<Expr>) -> Self {
698 Self {
699 expr: boxed,
700 outer: false,
701 }
702 }
703
704 pub fn new_outer(expr: Expr) -> Self {
707 Self {
708 expr: Box::new(expr),
709 outer: true,
710 }
711 }
712}
713
714#[derive(Clone, PartialEq, Eq, Debug)]
716pub struct Alias {
717 pub expr: Box<Expr>,
718 pub relation: Option<TableReference>,
719 pub name: String,
720 pub metadata: Option<FieldMetadata>,
721}
722
723impl Hash for Alias {
724 fn hash<H: Hasher>(&self, state: &mut H) {
725 self.expr.hash(state);
726 self.relation.hash(state);
727 self.name.hash(state);
728 }
729}
730
731impl PartialOrd for Alias {
732 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
733 let cmp = self.expr.partial_cmp(&other.expr);
734 let Some(Ordering::Equal) = cmp else {
735 return cmp;
736 };
737 let cmp = self.relation.partial_cmp(&other.relation);
738 let Some(Ordering::Equal) = cmp else {
739 return cmp;
740 };
741 self.name
742 .partial_cmp(&other.name)
743 .filter(|cmp| *cmp != Ordering::Equal || self == other)
745 }
746}
747
748impl Alias {
749 pub fn new(
751 expr: Expr,
752 relation: Option<impl Into<TableReference>>,
753 name: impl Into<String>,
754 ) -> Self {
755 Self {
756 expr: Box::new(expr),
757 relation: relation.map(|r| r.into()),
758 name: name.into(),
759 metadata: None,
760 }
761 }
762
763 pub fn with_metadata(mut self, metadata: Option<FieldMetadata>) -> Self {
764 self.metadata = metadata;
765 self
766 }
767
768 #[doc(hidden)]
769 pub fn with_expr(mut self, expr: Expr) -> Self {
770 self.expr = Box::new(expr);
771 self
772 }
773
774 #[doc(hidden)]
775 pub fn try_map_expr(self, f: impl FnOnce(Expr) -> Result<Expr>) -> Result<Expr> {
776 let Alias {
777 expr,
778 relation,
779 name,
780 metadata,
781 } = self;
782 Ok(Expr::Alias(Alias {
783 expr: Box::new(f(*expr)?),
784 relation,
785 name,
786 metadata,
787 }))
788 }
789}
790
791#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
793pub struct BinaryExpr {
794 pub left: Box<Expr>,
796 pub op: Operator,
798 pub right: Box<Expr>,
800}
801
802impl BinaryExpr {
803 pub fn new(left: Box<Expr>, op: Operator, right: Box<Expr>) -> Self {
805 Self { left, op, right }
806 }
807}
808
809impl Display for BinaryExpr {
810 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
811 fn write_child(
817 f: &mut Formatter<'_>,
818 expr: &Expr,
819 precedence: u8,
820 ) -> fmt::Result {
821 match expr {
822 Expr::BinaryExpr(child) => {
823 let p = child.op.precedence();
824 if p == 0 || p < precedence {
825 write!(f, "({child})")?;
826 } else {
827 write!(f, "{child}")?;
828 }
829 }
830 _ => write!(f, "{expr}")?,
831 }
832 Ok(())
833 }
834
835 let precedence = self.op.precedence();
836 write_child(f, self.left.as_ref(), precedence)?;
837 write!(f, " {} ", self.op)?;
838 write_child(f, self.right.as_ref(), precedence)
839 }
840}
841
842#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
866pub struct Case {
867 pub expr: Option<Box<Expr>>,
869 pub when_then_expr: Vec<(Box<Expr>, Box<Expr>)>,
871 pub else_expr: Option<Box<Expr>>,
873}
874
875impl Case {
876 pub fn new(
878 expr: Option<Box<Expr>>,
879 when_then_expr: Vec<(Box<Expr>, Box<Expr>)>,
880 else_expr: Option<Box<Expr>>,
881 ) -> Self {
882 Self {
883 expr,
884 when_then_expr,
885 else_expr,
886 }
887 }
888}
889
890#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
892pub struct Like {
893 pub negated: bool,
894 pub expr: Box<Expr>,
895 pub pattern: Box<Expr>,
896 pub escape_char: Option<char>,
897 pub case_insensitive: bool,
899}
900
901impl Like {
902 pub fn new(
904 negated: bool,
905 expr: Box<Expr>,
906 pattern: Box<Expr>,
907 escape_char: Option<char>,
908 case_insensitive: bool,
909 ) -> Self {
910 Self {
911 negated,
912 expr,
913 pattern,
914 escape_char,
915 case_insensitive,
916 }
917 }
918}
919
920#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
922pub struct Between {
923 pub expr: Box<Expr>,
925 pub negated: bool,
927 pub low: Box<Expr>,
929 pub high: Box<Expr>,
931}
932
933impl Between {
934 pub fn new(expr: Box<Expr>, negated: bool, low: Box<Expr>, high: Box<Expr>) -> Self {
936 Self {
937 expr,
938 negated,
939 low,
940 high,
941 }
942 }
943}
944
945#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
949pub struct ScalarFunction {
950 pub func: Arc<crate::ScalarUDF>,
952 pub args: Vec<Expr>,
954}
955
956impl ScalarFunction {
957 pub fn name(&self) -> &str {
959 self.func.name()
960 }
961}
962
963impl ScalarFunction {
964 pub fn new_udf(udf: Arc<crate::ScalarUDF>, args: Vec<Expr>) -> Self {
968 Self { func: udf, args }
969 }
970}
971
972#[derive(Clone, PartialEq, Eq, Hash, Debug)]
974pub enum GetFieldAccess {
975 NamedStructField { name: ScalarValue },
977 ListIndex { key: Box<Expr> },
979 ListRange {
981 start: Box<Expr>,
982 stop: Box<Expr>,
983 stride: Box<Expr>,
984 },
985}
986
987#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
989pub struct Cast {
990 pub expr: Box<Expr>,
992 pub field: FieldRef,
994}
995
996impl Cast {
997 pub fn new(expr: Box<Expr>, data_type: DataType) -> Self {
999 Self {
1000 expr,
1001 field: data_type.into_nullable_field_ref(),
1002 }
1003 }
1004
1005 pub fn new_from_field(expr: Box<Expr>, field: FieldRef) -> Self {
1006 Self { expr, field }
1007 }
1008}
1009
1010#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1012pub struct TryCast {
1013 pub expr: Box<Expr>,
1015 pub field: FieldRef,
1017}
1018
1019impl TryCast {
1020 pub fn new(expr: Box<Expr>, data_type: DataType) -> Self {
1022 Self {
1023 expr,
1024 field: data_type.into_nullable_field_ref(),
1025 }
1026 }
1027
1028 pub fn new_from_field(expr: Box<Expr>, field: FieldRef) -> Self {
1029 Self { expr, field }
1030 }
1031}
1032
1033#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1035pub struct Sort {
1036 pub expr: Expr,
1038 pub asc: bool,
1040 pub nulls_first: bool,
1042}
1043
1044impl Sort {
1045 pub fn new(expr: Expr, asc: bool, nulls_first: bool) -> Self {
1047 Self {
1048 expr,
1049 asc,
1050 nulls_first,
1051 }
1052 }
1053
1054 pub fn reverse(&self) -> Self {
1056 Self {
1057 expr: self.expr.clone(),
1058 asc: !self.asc,
1059 nulls_first: !self.nulls_first,
1060 }
1061 }
1062
1063 pub fn with_expr(&self, expr: Expr) -> Self {
1065 Self {
1066 expr,
1067 asc: self.asc,
1068 nulls_first: self.nulls_first,
1069 }
1070 }
1071}
1072
1073impl Display for Sort {
1074 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1075 write!(f, "{}", self.expr)?;
1076 if self.asc {
1077 write!(f, " ASC")?;
1078 } else {
1079 write!(f, " DESC")?;
1080 }
1081 if self.nulls_first {
1082 write!(f, " NULLS FIRST")?;
1083 } else {
1084 write!(f, " NULLS LAST")?;
1085 }
1086 Ok(())
1087 }
1088}
1089
1090impl<'a> TreeNodeContainer<'a, Expr> for Sort {
1091 fn apply_elements<F: FnMut(&'a Expr) -> Result<TreeNodeRecursion>>(
1092 &'a self,
1093 f: F,
1094 ) -> Result<TreeNodeRecursion> {
1095 self.expr.apply_elements(f)
1096 }
1097
1098 fn map_elements<F: FnMut(Expr) -> Result<Transformed<Expr>>>(
1099 self,
1100 f: F,
1101 ) -> Result<Transformed<Self>> {
1102 self.expr
1103 .map_elements(f)?
1104 .map_data(|expr| Ok(Self { expr, ..self }))
1105 }
1106}
1107
1108#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1114pub struct AggregateFunction {
1115 pub func: Arc<AggregateUDF>,
1117 pub params: AggregateFunctionParams,
1118}
1119
1120#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1121pub struct AggregateFunctionParams {
1122 pub args: Vec<Expr>,
1123 pub distinct: bool,
1125 pub filter: Option<Box<Expr>>,
1127 pub order_by: Vec<Sort>,
1129 pub null_treatment: Option<NullTreatment>,
1130}
1131
1132impl AggregateFunction {
1133 pub fn new_udf(
1135 func: Arc<AggregateUDF>,
1136 args: Vec<Expr>,
1137 distinct: bool,
1138 filter: Option<Box<Expr>>,
1139 order_by: Vec<Sort>,
1140 null_treatment: Option<NullTreatment>,
1141 ) -> Self {
1142 Self {
1143 func,
1144 params: AggregateFunctionParams {
1145 args,
1146 distinct,
1147 filter,
1148 order_by,
1149 null_treatment,
1150 },
1151 }
1152 }
1153}
1154
1155#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
1161pub enum WindowFunctionDefinition {
1162 AggregateUDF(Arc<AggregateUDF>),
1164 WindowUDF(Arc<WindowUDF>),
1166}
1167
1168impl WindowFunctionDefinition {
1169 pub fn return_field(
1171 &self,
1172 input_expr_fields: &[FieldRef],
1173 display_name: &str,
1174 ) -> Result<FieldRef> {
1175 match self {
1176 WindowFunctionDefinition::AggregateUDF(fun) => {
1177 fun.return_field(input_expr_fields)
1178 }
1179 WindowFunctionDefinition::WindowUDF(fun) => {
1180 fun.field(WindowUDFFieldArgs::new(input_expr_fields, display_name))
1181 }
1182 }
1183 }
1184
1185 pub fn signature(&self) -> Signature {
1187 match self {
1188 WindowFunctionDefinition::AggregateUDF(fun) => fun.signature().clone(),
1189 WindowFunctionDefinition::WindowUDF(fun) => fun.signature().clone(),
1190 }
1191 }
1192
1193 pub fn name(&self) -> &str {
1195 match self {
1196 WindowFunctionDefinition::WindowUDF(fun) => fun.name(),
1197 WindowFunctionDefinition::AggregateUDF(fun) => fun.name(),
1198 }
1199 }
1200
1201 pub fn simplify(&self) -> Option<WindowFunctionSimplification> {
1205 match self {
1206 WindowFunctionDefinition::AggregateUDF(_) => None,
1207 WindowFunctionDefinition::WindowUDF(udwf) => udwf.simplify(),
1208 }
1209 }
1210}
1211
1212impl Display for WindowFunctionDefinition {
1213 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1214 match self {
1215 WindowFunctionDefinition::AggregateUDF(fun) => Display::fmt(fun, f),
1216 WindowFunctionDefinition::WindowUDF(fun) => Display::fmt(fun, f),
1217 }
1218 }
1219}
1220
1221impl From<Arc<AggregateUDF>> for WindowFunctionDefinition {
1222 fn from(value: Arc<AggregateUDF>) -> Self {
1223 Self::AggregateUDF(value)
1224 }
1225}
1226
1227impl From<Arc<WindowUDF>> for WindowFunctionDefinition {
1228 fn from(value: Arc<WindowUDF>) -> Self {
1229 Self::WindowUDF(value)
1230 }
1231}
1232
1233#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1246pub struct WindowFunction {
1247 pub fun: WindowFunctionDefinition,
1249 pub params: WindowFunctionParams,
1250}
1251
1252#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1253pub struct WindowFunctionParams {
1254 pub args: Vec<Expr>,
1256 pub partition_by: Vec<Expr>,
1258 pub order_by: Vec<Sort>,
1260 pub window_frame: WindowFrame,
1262 pub filter: Option<Box<Expr>>,
1264 pub null_treatment: Option<NullTreatment>,
1266 pub distinct: bool,
1268}
1269
1270impl WindowFunction {
1271 pub fn new(fun: impl Into<WindowFunctionDefinition>, args: Vec<Expr>) -> Self {
1274 Self {
1275 fun: fun.into(),
1276 params: WindowFunctionParams {
1277 args,
1278 partition_by: Vec::default(),
1279 order_by: Vec::default(),
1280 window_frame: WindowFrame::new(None),
1281 filter: None,
1282 null_treatment: None,
1283 distinct: false,
1284 },
1285 }
1286 }
1287
1288 pub fn simplify(&self) -> Option<WindowFunctionSimplification> {
1292 self.fun.simplify()
1293 }
1294}
1295
1296#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1298pub struct Exists {
1299 pub subquery: Subquery,
1301 pub negated: bool,
1303}
1304
1305impl Exists {
1306 pub fn new(subquery: Subquery, negated: bool) -> Self {
1308 Self { subquery, negated }
1309 }
1310}
1311
1312#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Debug)]
1314pub enum SetQuantifier {
1315 Any,
1317 All,
1319}
1320
1321impl Display for SetQuantifier {
1322 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1323 match self {
1324 SetQuantifier::Any => write!(f, "ANY"),
1325 SetQuantifier::All => write!(f, "ALL"),
1326 }
1327 }
1328}
1329
1330#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1332pub struct SetComparison {
1333 pub expr: Box<Expr>,
1335 pub subquery: Subquery,
1337 pub op: Operator,
1339 pub quantifier: SetQuantifier,
1341}
1342
1343impl SetComparison {
1344 pub fn new(
1346 expr: Box<Expr>,
1347 subquery: Subquery,
1348 op: Operator,
1349 quantifier: SetQuantifier,
1350 ) -> Self {
1351 Self {
1352 expr,
1353 subquery,
1354 op,
1355 quantifier,
1356 }
1357 }
1358}
1359
1360#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1362pub struct InList {
1363 pub expr: Box<Expr>,
1365 pub list: Vec<Expr>,
1367 pub negated: bool,
1369}
1370
1371impl InList {
1372 pub fn new(expr: Box<Expr>, list: Vec<Expr>, negated: bool) -> Self {
1374 Self {
1375 expr,
1376 list,
1377 negated,
1378 }
1379 }
1380}
1381
1382#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1384pub struct InSubquery {
1385 pub expr: Box<Expr>,
1387 pub subquery: Subquery,
1389 pub negated: bool,
1391}
1392
1393impl InSubquery {
1394 pub fn new(expr: Box<Expr>, subquery: Subquery, negated: bool) -> Self {
1396 Self {
1397 expr,
1398 subquery,
1399 negated,
1400 }
1401 }
1402}
1403
1404#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1409pub struct Placeholder {
1410 pub id: String,
1412 pub field: Option<FieldRef>,
1414}
1415
1416impl Placeholder {
1417 #[deprecated(since = "51.0.0", note = "Use new_with_field instead")]
1419 pub fn new(id: String, data_type: Option<DataType>) -> Self {
1420 Self {
1421 id,
1422 field: data_type.map(|dt| Arc::new(Field::new("", dt, true))),
1423 }
1424 }
1425
1426 pub fn new_with_field(id: String, field: Option<FieldRef>) -> Self {
1428 Self { id, field }
1429 }
1430}
1431
1432#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1439pub enum GroupingSet {
1440 Rollup(Vec<Expr>),
1442 Cube(Vec<Expr>),
1444 GroupingSets(Vec<Vec<Expr>>),
1446}
1447
1448impl GroupingSet {
1449 pub fn distinct_expr(&self) -> Vec<&Expr> {
1453 match self {
1454 GroupingSet::Rollup(exprs) | GroupingSet::Cube(exprs) => {
1455 exprs.iter().collect()
1456 }
1457 GroupingSet::GroupingSets(groups) => {
1458 let mut exprs: Vec<&Expr> = vec![];
1459 for exp in groups.iter().flatten() {
1460 if !exprs.contains(&exp) {
1461 exprs.push(exp);
1462 }
1463 }
1464 exprs
1465 }
1466 }
1467 }
1468}
1469
1470#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
1472pub struct Lambda {
1473 pub params: Vec<String>,
1475 pub body: Box<Expr>,
1477}
1478
1479impl Lambda {
1480 pub fn new(params: Vec<String>, body: Expr) -> Self {
1482 Self {
1483 params,
1484 body: Box::new(body),
1485 }
1486 }
1487}
1488
1489pub fn display_comma_separated<T>(slice: &[T]) -> String
1490where
1491 T: Display,
1492{
1493 use itertools::Itertools;
1494 slice.iter().map(|v| format!("{v}")).join(", ")
1495}
1496
1497#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Default)]
1499pub struct WildcardOptions {
1500 pub ilike: Option<IlikeSelectItem>,
1503 pub exclude: Option<ExcludeSelectItem>,
1506 pub except: Option<ExceptSelectItem>,
1510 pub replace: Option<PlannedReplaceSelectItem>,
1515 pub rename: Option<RenameSelectItem>,
1518}
1519
1520impl WildcardOptions {
1521 pub fn with_replace(self, replace: PlannedReplaceSelectItem) -> Self {
1522 WildcardOptions {
1523 ilike: self.ilike,
1524 exclude: self.exclude,
1525 except: self.except,
1526 replace: Some(replace),
1527 rename: self.rename,
1528 }
1529 }
1530}
1531
1532impl Display for WildcardOptions {
1533 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1534 if let Some(ilike) = &self.ilike {
1535 write!(f, " {ilike}")?;
1536 }
1537 if let Some(exclude) = &self.exclude {
1538 write!(f, " {exclude}")?;
1539 }
1540 if let Some(except) = &self.except {
1541 write!(f, " {except}")?;
1542 }
1543 if let Some(replace) = &self.replace {
1544 write!(f, " {replace}")?;
1545 }
1546 if let Some(rename) = &self.rename {
1547 write!(f, " {rename}")?;
1548 }
1549 Ok(())
1550 }
1551}
1552
1553#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Default)]
1555pub struct PlannedReplaceSelectItem {
1556 pub items: Vec<ReplaceSelectElement>,
1558 pub planned_expressions: Vec<Expr>,
1560}
1561
1562impl Display for PlannedReplaceSelectItem {
1563 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1564 write!(f, "REPLACE")?;
1565 write!(f, " ({})", display_comma_separated(&self.items))?;
1566 Ok(())
1567 }
1568}
1569
1570impl PlannedReplaceSelectItem {
1571 pub fn items(&self) -> &[ReplaceSelectElement] {
1572 &self.items
1573 }
1574
1575 pub fn expressions(&self) -> &[Expr] {
1576 &self.planned_expressions
1577 }
1578}
1579
1580impl Expr {
1581 pub fn schema_name(&self) -> impl Display + '_ {
1604 SchemaDisplay(self)
1605 }
1606
1607 pub fn human_display(&self) -> impl Display + '_ {
1629 SqlDisplay(self)
1630 }
1631
1632 pub fn qualified_name(&self) -> (Option<TableReference>, String) {
1638 match self {
1639 Expr::Column(Column {
1640 relation,
1641 name,
1642 spans: _,
1643 }) => (relation.clone(), name.clone()),
1644 Expr::Alias(Alias { relation, name, .. }) => (relation.clone(), name.clone()),
1645 _ => (None, self.schema_name().to_string()),
1646 }
1647 }
1648
1649 pub fn placement(&self) -> ExpressionPlacement {
1654 match self {
1655 Expr::Column(_) => ExpressionPlacement::Column,
1656 Expr::Literal(_, _) => ExpressionPlacement::Literal,
1657 Expr::Alias(inner) => inner.expr.placement(),
1658 Expr::ScalarFunction(func) => {
1659 let arg_placements: Vec<_> =
1660 func.args.iter().map(|arg| arg.placement()).collect();
1661 func.func.placement(&arg_placements)
1662 }
1663 _ => ExpressionPlacement::KeepInPlace,
1664 }
1665 }
1666
1667 pub fn variant_name(&self) -> &str {
1670 match self {
1671 Expr::AggregateFunction { .. } => "AggregateFunction",
1672 Expr::Alias(..) => "Alias",
1673 Expr::Between { .. } => "Between",
1674 Expr::BinaryExpr { .. } => "BinaryExpr",
1675 Expr::Case { .. } => "Case",
1676 Expr::Cast { .. } => "Cast",
1677 Expr::Column(..) => "Column",
1678 Expr::OuterReferenceColumn(_, _) => "Outer",
1679 Expr::Exists { .. } => "Exists",
1680 Expr::GroupingSet(..) => "GroupingSet",
1681 Expr::InList { .. } => "InList",
1682 Expr::InSubquery(..) => "InSubquery",
1683 Expr::SetComparison(..) => "SetComparison",
1684 Expr::IsNotNull(..) => "IsNotNull",
1685 Expr::IsNull(..) => "IsNull",
1686 Expr::Like { .. } => "Like",
1687 Expr::SimilarTo { .. } => "RLike",
1688 Expr::IsTrue(..) => "IsTrue",
1689 Expr::IsFalse(..) => "IsFalse",
1690 Expr::IsUnknown(..) => "IsUnknown",
1691 Expr::IsNotTrue(..) => "IsNotTrue",
1692 Expr::IsNotFalse(..) => "IsNotFalse",
1693 Expr::IsNotUnknown(..) => "IsNotUnknown",
1694 Expr::Literal(..) => "Literal",
1695 Expr::Negative(..) => "Negative",
1696 Expr::Not(..) => "Not",
1697 Expr::Placeholder(_) => "Placeholder",
1698 Expr::ScalarFunction(..) => "ScalarFunction",
1699 Expr::ScalarSubquery { .. } => "ScalarSubquery",
1700 Expr::ScalarVariable(..) => "ScalarVariable",
1701 Expr::TryCast { .. } => "TryCast",
1702 Expr::WindowFunction { .. } => "WindowFunction",
1703 #[expect(deprecated)]
1704 Expr::Wildcard { .. } => "Wildcard",
1705 Expr::Unnest { .. } => "Unnest",
1706 Expr::HigherOrderFunction { .. } => "HigherOrderFunction",
1707 Expr::Lambda { .. } => "Lambda",
1708 Expr::LambdaVariable { .. } => "LambdaVariable",
1709 }
1710 }
1711
1712 pub fn eq(self, other: Expr) -> Expr {
1714 binary_expr(self, Operator::Eq, other)
1715 }
1716
1717 pub fn not_eq(self, other: Expr) -> Expr {
1719 binary_expr(self, Operator::NotEq, other)
1720 }
1721
1722 pub fn gt(self, other: Expr) -> Expr {
1724 binary_expr(self, Operator::Gt, other)
1725 }
1726
1727 pub fn gt_eq(self, other: Expr) -> Expr {
1729 binary_expr(self, Operator::GtEq, other)
1730 }
1731
1732 pub fn lt(self, other: Expr) -> Expr {
1734 binary_expr(self, Operator::Lt, other)
1735 }
1736
1737 pub fn lt_eq(self, other: Expr) -> Expr {
1739 binary_expr(self, Operator::LtEq, other)
1740 }
1741
1742 pub fn and(self, other: Expr) -> Expr {
1744 binary_expr(self, Operator::And, other)
1745 }
1746
1747 pub fn or(self, other: Expr) -> Expr {
1749 binary_expr(self, Operator::Or, other)
1750 }
1751
1752 pub fn like(self, other: Expr) -> Expr {
1754 Expr::Like(Like::new(
1755 false,
1756 Box::new(self),
1757 Box::new(other),
1758 None,
1759 false,
1760 ))
1761 }
1762
1763 pub fn not_like(self, other: Expr) -> Expr {
1765 Expr::Like(Like::new(
1766 true,
1767 Box::new(self),
1768 Box::new(other),
1769 None,
1770 false,
1771 ))
1772 }
1773
1774 pub fn ilike(self, other: Expr) -> Expr {
1776 Expr::Like(Like::new(
1777 false,
1778 Box::new(self),
1779 Box::new(other),
1780 None,
1781 true,
1782 ))
1783 }
1784
1785 pub fn not_ilike(self, other: Expr) -> Expr {
1787 Expr::Like(Like::new(true, Box::new(self), Box::new(other), None, true))
1788 }
1789
1790 pub fn name_for_alias(&self) -> Result<String> {
1792 Ok(self.schema_name().to_string())
1793 }
1794
1795 pub fn alias_if_changed(self, original_name: String) -> Result<Expr> {
1798 let new_name = self.name_for_alias()?;
1799 if new_name == original_name {
1800 return Ok(self);
1801 }
1802
1803 Ok(self.alias(original_name))
1804 }
1805
1806 pub fn alias(self, name: impl Into<String>) -> Expr {
1808 Expr::Alias(Alias::new(self, None::<&str>, name.into()))
1809 }
1810
1811 pub fn alias_with_metadata(
1826 self,
1827 name: impl Into<String>,
1828 metadata: Option<FieldMetadata>,
1829 ) -> Expr {
1830 Expr::Alias(Alias::new(self, None::<&str>, name.into()).with_metadata(metadata))
1831 }
1832
1833 pub fn alias_qualified(
1835 self,
1836 relation: Option<impl Into<TableReference>>,
1837 name: impl Into<String>,
1838 ) -> Expr {
1839 Expr::Alias(Alias::new(self, relation, name.into()))
1840 }
1841
1842 pub fn alias_qualified_with_metadata(
1858 self,
1859 relation: Option<impl Into<TableReference>>,
1860 name: impl Into<String>,
1861 metadata: Option<FieldMetadata>,
1862 ) -> Expr {
1863 Expr::Alias(Alias::new(self, relation, name.into()).with_metadata(metadata))
1864 }
1865
1866 pub fn unalias(self) -> Expr {
1887 match self {
1888 Expr::Alias(alias) => *alias.expr,
1889 _ => self,
1890 }
1891 }
1892
1893 pub fn unalias_nested(self) -> Transformed<Expr> {
1914 self.transform_down_up(
1915 |expr| {
1916 let recursion = if matches!(
1918 expr,
1919 Expr::Exists { .. } | Expr::ScalarSubquery(_) | Expr::InSubquery(_)
1920 ) {
1921 TreeNodeRecursion::Jump
1923 } else {
1924 TreeNodeRecursion::Continue
1925 };
1926 Ok(Transformed::new(expr, false, recursion))
1927 },
1928 |expr| {
1929 if let Expr::Alias(alias) = expr {
1932 match alias
1933 .metadata
1934 .as_ref()
1935 .map(|h| h.is_empty())
1936 .unwrap_or(true)
1937 {
1938 true => Ok(Transformed::yes(*alias.expr)),
1939 false => Ok(Transformed::no(Expr::Alias(alias))),
1940 }
1941 } else {
1942 Ok(Transformed::no(expr))
1943 }
1944 },
1945 )
1946 .unwrap()
1948 }
1949
1950 pub fn in_list(self, list: Vec<Expr>, negated: bool) -> Expr {
1953 Expr::InList(InList::new(Box::new(self), list, negated))
1954 }
1955
1956 pub fn is_null(self) -> Expr {
1958 Expr::IsNull(Box::new(self))
1959 }
1960
1961 pub fn is_not_null(self) -> Expr {
1963 Expr::IsNotNull(Box::new(self))
1964 }
1965
1966 pub fn sort(self, asc: bool, nulls_first: bool) -> Sort {
1973 Sort::new(self, asc, nulls_first)
1974 }
1975
1976 pub fn is_true(self) -> Expr {
1978 Expr::IsTrue(Box::new(self))
1979 }
1980
1981 pub fn is_not_true(self) -> Expr {
1983 Expr::IsNotTrue(Box::new(self))
1984 }
1985
1986 pub fn is_false(self) -> Expr {
1988 Expr::IsFalse(Box::new(self))
1989 }
1990
1991 pub fn is_not_false(self) -> Expr {
1993 Expr::IsNotFalse(Box::new(self))
1994 }
1995
1996 pub fn is_unknown(self) -> Expr {
1998 Expr::IsUnknown(Box::new(self))
1999 }
2000
2001 pub fn is_not_unknown(self) -> Expr {
2003 Expr::IsNotUnknown(Box::new(self))
2004 }
2005
2006 pub fn between(self, low: Expr, high: Expr) -> Expr {
2008 Expr::Between(Between::new(
2009 Box::new(self),
2010 false,
2011 Box::new(low),
2012 Box::new(high),
2013 ))
2014 }
2015
2016 pub fn not_between(self, low: Expr, high: Expr) -> Expr {
2018 Expr::Between(Between::new(
2019 Box::new(self),
2020 true,
2021 Box::new(low),
2022 Box::new(high),
2023 ))
2024 }
2025 pub fn try_as_col(&self) -> Option<&Column> {
2043 if let Expr::Column(it) = self {
2044 Some(it)
2045 } else {
2046 None
2047 }
2048 }
2049
2050 pub fn get_as_join_column(&self) -> Option<&Column> {
2057 match self {
2058 Expr::Column(c) => Some(c),
2059 Expr::Cast(Cast { expr, .. }) => match &**expr {
2060 Expr::Column(c) => Some(c),
2061 _ => None,
2062 },
2063 _ => None,
2064 }
2065 }
2066
2067 pub fn column_refs(&self) -> HashSet<&Column> {
2083 let mut using_columns = HashSet::new();
2084 self.add_column_refs(&mut using_columns);
2085 using_columns
2086 }
2087
2088 pub fn add_column_refs<'a>(&'a self, set: &mut HashSet<&'a Column>) {
2092 self.apply(|expr| {
2093 if let Expr::Column(col) = expr {
2094 set.insert(col);
2095 }
2096 Ok(TreeNodeRecursion::Continue)
2097 })
2098 .expect("traversal is infallible");
2099 }
2100
2101 pub fn column_refs_counts(&self) -> HashMap<&Column, usize> {
2117 let mut map = HashMap::new();
2118 self.add_column_ref_counts(&mut map);
2119 map
2120 }
2121
2122 pub fn add_column_ref_counts<'a>(&'a self, map: &mut HashMap<&'a Column, usize>) {
2127 self.apply(|expr| {
2128 if let Expr::Column(col) = expr {
2129 *map.entry(col).or_default() += 1;
2130 }
2131 Ok(TreeNodeRecursion::Continue)
2132 })
2133 .expect("traversal is infallible");
2134 }
2135
2136 pub fn any_column_refs(&self) -> bool {
2138 self.exists(|expr| Ok(matches!(expr, Expr::Column(_))))
2139 .expect("exists closure is infallible")
2140 }
2141
2142 pub fn contains_outer(&self) -> bool {
2144 self.exists(|expr| Ok(matches!(expr, Expr::OuterReferenceColumn { .. })))
2145 .expect("exists closure is infallible")
2146 }
2147
2148 pub fn contains_scalar_subquery(&self) -> bool {
2150 self.exists(|expr| Ok(matches!(expr, Expr::ScalarSubquery(_))))
2151 .expect("exists closure is infallible")
2152 }
2153
2154 pub fn is_volatile_node(&self) -> bool {
2160 matches!(self, Expr::ScalarFunction(func) if func.func.signature().volatility == Volatility::Volatile)
2161 }
2162
2163 pub fn is_volatile(&self) -> bool {
2171 self.exists(|expr| Ok(expr.is_volatile_node()))
2172 .expect("exists closure is infallible")
2173 }
2174
2175 pub fn infer_placeholder_types(self, schema: &DFSchema) -> Result<(Expr, bool)> {
2184 let mut has_placeholder = false;
2185 self.transform(|mut expr| {
2186 match &mut expr {
2187 Expr::BinaryExpr(BinaryExpr { left, op: _, right }) => {
2189 rewrite_placeholder(left.as_mut(), right.as_ref(), schema)?;
2190 rewrite_placeholder(right.as_mut(), left.as_ref(), schema)?;
2191 }
2192 Expr::Between(Between {
2193 expr,
2194 negated: _,
2195 low,
2196 high,
2197 }) => {
2198 rewrite_placeholder(low.as_mut(), expr.as_ref(), schema)?;
2199 rewrite_placeholder(high.as_mut(), expr.as_ref(), schema)?;
2200 }
2201 Expr::InList(InList {
2202 expr,
2203 list,
2204 negated: _,
2205 }) => {
2206 for item in list.iter_mut() {
2207 rewrite_placeholder(item, expr.as_ref(), schema)?;
2208 }
2209 }
2210 Expr::InSubquery(InSubquery {
2211 expr,
2212 subquery,
2213 negated: _,
2214 }) => {
2215 rewrite_placeholder_from_subquery(
2216 "InSubquery",
2217 expr.as_mut(),
2218 subquery,
2219 )?;
2220 }
2221 Expr::SetComparison(SetComparison {
2222 expr,
2223 subquery,
2224 op: _,
2225 quantifier: _,
2226 }) => {
2227 rewrite_placeholder_from_subquery(
2228 "SetComparison",
2229 expr.as_mut(),
2230 subquery,
2231 )?;
2232 }
2233 Expr::Like(Like { expr, pattern, .. })
2234 | Expr::SimilarTo(Like { expr, pattern, .. }) => {
2235 rewrite_placeholder(pattern.as_mut(), expr.as_ref(), schema)?;
2236 }
2237 Expr::Placeholder(_) => {
2238 has_placeholder = true;
2239 }
2240 _ => {}
2241 }
2242 Ok(Transformed::yes(expr))
2243 })
2244 .data()
2245 .map(|data| (data, has_placeholder))
2246 }
2247
2248 pub fn short_circuits(&self) -> bool {
2251 match self {
2252 Expr::ScalarFunction(ScalarFunction { func, .. }) => func.short_circuits(),
2253 Expr::HigherOrderFunction(HigherOrderFunction { func, .. }) => {
2254 func.short_circuits()
2255 }
2256 Expr::BinaryExpr(BinaryExpr { op, .. }) => {
2257 matches!(op, Operator::And | Operator::Or)
2258 }
2259 Expr::Case { .. } => true,
2260 #[expect(deprecated)]
2265 Expr::AggregateFunction(..)
2266 | Expr::Alias(..)
2267 | Expr::Between(..)
2268 | Expr::Cast(..)
2269 | Expr::Column(..)
2270 | Expr::Exists(..)
2271 | Expr::GroupingSet(..)
2272 | Expr::InList(..)
2273 | Expr::InSubquery(..)
2274 | Expr::SetComparison(..)
2275 | Expr::IsFalse(..)
2276 | Expr::IsNotFalse(..)
2277 | Expr::IsNotNull(..)
2278 | Expr::IsNotTrue(..)
2279 | Expr::IsNotUnknown(..)
2280 | Expr::IsNull(..)
2281 | Expr::IsTrue(..)
2282 | Expr::IsUnknown(..)
2283 | Expr::Like(..)
2284 | Expr::ScalarSubquery(..)
2285 | Expr::ScalarVariable(_, _)
2286 | Expr::SimilarTo(..)
2287 | Expr::Not(..)
2288 | Expr::Negative(..)
2289 | Expr::OuterReferenceColumn(_, _)
2290 | Expr::TryCast(..)
2291 | Expr::Unnest(..)
2292 | Expr::Wildcard { .. }
2293 | Expr::WindowFunction(..)
2294 | Expr::Literal(..)
2295 | Expr::Placeholder(..)
2296 | Expr::Lambda(..)
2297 | Expr::LambdaVariable(..) => false,
2298 }
2299 }
2300
2301 pub fn spans(&self) -> Option<&Spans> {
2305 match self {
2306 Expr::Column(col) => Some(&col.spans),
2307 Expr::Not(inner) | Expr::Negative(inner) => inner.spans(),
2308 _ => None,
2309 }
2310 }
2311
2312 pub fn as_literal(&self) -> Option<&ScalarValue> {
2314 if let Expr::Literal(lit, _) = self {
2315 Some(lit)
2316 } else {
2317 None
2318 }
2319 }
2320
2321 pub fn resolve_lambda_variables(
2325 self,
2326 schema: &DFSchema,
2327 ) -> Result<Transformed<Expr>> {
2328 resolve_lambda_variables(self, schema, &mut HashMap::new())
2329 }
2330}
2331
2332impl Normalizeable for Expr {
2333 fn can_normalize(&self) -> bool {
2334 #[expect(clippy::match_like_matches_macro)]
2335 match self {
2336 Expr::BinaryExpr(BinaryExpr {
2337 op:
2338 _op @ (Operator::Plus
2339 | Operator::Multiply
2340 | Operator::BitwiseAnd
2341 | Operator::BitwiseOr
2342 | Operator::BitwiseXor
2343 | Operator::Eq
2344 | Operator::NotEq),
2345 ..
2346 }) => true,
2347 _ => false,
2348 }
2349 }
2350}
2351
2352impl NormalizeEq for Expr {
2353 fn normalize_eq(&self, other: &Self) -> bool {
2354 match (self, other) {
2355 (
2356 Expr::BinaryExpr(BinaryExpr {
2357 left: self_left,
2358 op: self_op,
2359 right: self_right,
2360 }),
2361 Expr::BinaryExpr(BinaryExpr {
2362 left: other_left,
2363 op: other_op,
2364 right: other_right,
2365 }),
2366 ) => {
2367 if self_op != other_op {
2368 return false;
2369 }
2370
2371 if matches!(
2372 self_op,
2373 Operator::Plus
2374 | Operator::Multiply
2375 | Operator::BitwiseAnd
2376 | Operator::BitwiseOr
2377 | Operator::BitwiseXor
2378 | Operator::Eq
2379 | Operator::NotEq
2380 ) {
2381 (self_left.normalize_eq(other_left)
2382 && self_right.normalize_eq(other_right))
2383 || (self_left.normalize_eq(other_right)
2384 && self_right.normalize_eq(other_left))
2385 } else {
2386 self_left.normalize_eq(other_left)
2387 && self_right.normalize_eq(other_right)
2388 }
2389 }
2390 (
2391 Expr::Alias(Alias {
2392 expr: self_expr,
2393 relation: self_relation,
2394 name: self_name,
2395 ..
2396 }),
2397 Expr::Alias(Alias {
2398 expr: other_expr,
2399 relation: other_relation,
2400 name: other_name,
2401 ..
2402 }),
2403 ) => {
2404 self_name == other_name
2405 && self_relation == other_relation
2406 && self_expr.normalize_eq(other_expr)
2407 }
2408 (
2409 Expr::Like(Like {
2410 negated: self_negated,
2411 expr: self_expr,
2412 pattern: self_pattern,
2413 escape_char: self_escape_char,
2414 case_insensitive: self_case_insensitive,
2415 }),
2416 Expr::Like(Like {
2417 negated: other_negated,
2418 expr: other_expr,
2419 pattern: other_pattern,
2420 escape_char: other_escape_char,
2421 case_insensitive: other_case_insensitive,
2422 }),
2423 )
2424 | (
2425 Expr::SimilarTo(Like {
2426 negated: self_negated,
2427 expr: self_expr,
2428 pattern: self_pattern,
2429 escape_char: self_escape_char,
2430 case_insensitive: self_case_insensitive,
2431 }),
2432 Expr::SimilarTo(Like {
2433 negated: other_negated,
2434 expr: other_expr,
2435 pattern: other_pattern,
2436 escape_char: other_escape_char,
2437 case_insensitive: other_case_insensitive,
2438 }),
2439 ) => {
2440 self_negated == other_negated
2441 && self_escape_char == other_escape_char
2442 && self_case_insensitive == other_case_insensitive
2443 && self_expr.normalize_eq(other_expr)
2444 && self_pattern.normalize_eq(other_pattern)
2445 }
2446 (Expr::Not(self_expr), Expr::Not(other_expr))
2447 | (Expr::IsNull(self_expr), Expr::IsNull(other_expr))
2448 | (Expr::IsTrue(self_expr), Expr::IsTrue(other_expr))
2449 | (Expr::IsFalse(self_expr), Expr::IsFalse(other_expr))
2450 | (Expr::IsUnknown(self_expr), Expr::IsUnknown(other_expr))
2451 | (Expr::IsNotNull(self_expr), Expr::IsNotNull(other_expr))
2452 | (Expr::IsNotTrue(self_expr), Expr::IsNotTrue(other_expr))
2453 | (Expr::IsNotFalse(self_expr), Expr::IsNotFalse(other_expr))
2454 | (Expr::IsNotUnknown(self_expr), Expr::IsNotUnknown(other_expr))
2455 | (Expr::Negative(self_expr), Expr::Negative(other_expr)) => {
2456 self_expr.normalize_eq(other_expr)
2457 }
2458 (
2459 Expr::Unnest(Unnest {
2460 expr: self_expr,
2461 outer: self_outer,
2462 }),
2463 Expr::Unnest(Unnest {
2464 expr: other_expr,
2465 outer: other_outer,
2466 }),
2467 ) => self_outer == other_outer && self_expr.normalize_eq(other_expr),
2468 (
2469 Expr::Between(Between {
2470 expr: self_expr,
2471 negated: self_negated,
2472 low: self_low,
2473 high: self_high,
2474 }),
2475 Expr::Between(Between {
2476 expr: other_expr,
2477 negated: other_negated,
2478 low: other_low,
2479 high: other_high,
2480 }),
2481 ) => {
2482 self_negated == other_negated
2483 && self_expr.normalize_eq(other_expr)
2484 && self_low.normalize_eq(other_low)
2485 && self_high.normalize_eq(other_high)
2486 }
2487 (
2488 Expr::Cast(Cast {
2489 expr: self_expr,
2490 field: self_field,
2491 }),
2492 Expr::Cast(Cast {
2493 expr: other_expr,
2494 field: other_field,
2495 }),
2496 )
2497 | (
2498 Expr::TryCast(TryCast {
2499 expr: self_expr,
2500 field: self_field,
2501 }),
2502 Expr::TryCast(TryCast {
2503 expr: other_expr,
2504 field: other_field,
2505 }),
2506 ) => self_field == other_field && self_expr.normalize_eq(other_expr),
2507 (
2508 Expr::ScalarFunction(ScalarFunction {
2509 func: self_func,
2510 args: self_args,
2511 }),
2512 Expr::ScalarFunction(ScalarFunction {
2513 func: other_func,
2514 args: other_args,
2515 }),
2516 ) => {
2517 self_func.name() == other_func.name()
2518 && self_args.len() == other_args.len()
2519 && self_args
2520 .iter()
2521 .zip(other_args.iter())
2522 .all(|(a, b)| a.normalize_eq(b))
2523 }
2524 (
2525 Expr::AggregateFunction(AggregateFunction {
2526 func: self_func,
2527 params:
2528 AggregateFunctionParams {
2529 args: self_args,
2530 distinct: self_distinct,
2531 filter: self_filter,
2532 order_by: self_order_by,
2533 null_treatment: self_null_treatment,
2534 },
2535 }),
2536 Expr::AggregateFunction(AggregateFunction {
2537 func: other_func,
2538 params:
2539 AggregateFunctionParams {
2540 args: other_args,
2541 distinct: other_distinct,
2542 filter: other_filter,
2543 order_by: other_order_by,
2544 null_treatment: other_null_treatment,
2545 },
2546 }),
2547 ) => {
2548 self_func.name() == other_func.name()
2549 && self_distinct == other_distinct
2550 && self_null_treatment == other_null_treatment
2551 && self_args.len() == other_args.len()
2552 && self_args
2553 .iter()
2554 .zip(other_args.iter())
2555 .all(|(a, b)| a.normalize_eq(b))
2556 && match (self_filter, other_filter) {
2557 (Some(self_filter), Some(other_filter)) => {
2558 self_filter.normalize_eq(other_filter)
2559 }
2560 (None, None) => true,
2561 _ => false,
2562 }
2563 && self_order_by
2564 .iter()
2565 .zip(other_order_by.iter())
2566 .all(|(a, b)| {
2567 a.asc == b.asc
2568 && a.nulls_first == b.nulls_first
2569 && a.expr.normalize_eq(&b.expr)
2570 })
2571 && self_order_by.len() == other_order_by.len()
2572 }
2573 (Expr::WindowFunction(left), Expr::WindowFunction(other)) => {
2574 let WindowFunction {
2575 fun: self_fun,
2576 params:
2577 WindowFunctionParams {
2578 args: self_args,
2579 window_frame: self_window_frame,
2580 partition_by: self_partition_by,
2581 order_by: self_order_by,
2582 filter: self_filter,
2583 null_treatment: self_null_treatment,
2584 distinct: self_distinct,
2585 },
2586 } = left.as_ref();
2587 let WindowFunction {
2588 fun: other_fun,
2589 params:
2590 WindowFunctionParams {
2591 args: other_args,
2592 window_frame: other_window_frame,
2593 partition_by: other_partition_by,
2594 order_by: other_order_by,
2595 filter: other_filter,
2596 null_treatment: other_null_treatment,
2597 distinct: other_distinct,
2598 },
2599 } = other.as_ref();
2600
2601 self_fun.name() == other_fun.name()
2602 && self_window_frame == other_window_frame
2603 && match (self_filter, other_filter) {
2604 (Some(a), Some(b)) => a.normalize_eq(b),
2605 (None, None) => true,
2606 _ => false,
2607 }
2608 && self_null_treatment == other_null_treatment
2609 && self_args.len() == other_args.len()
2610 && self_args
2611 .iter()
2612 .zip(other_args.iter())
2613 .all(|(a, b)| a.normalize_eq(b))
2614 && self_partition_by
2615 .iter()
2616 .zip(other_partition_by.iter())
2617 .all(|(a, b)| a.normalize_eq(b))
2618 && self_order_by
2619 .iter()
2620 .zip(other_order_by.iter())
2621 .all(|(a, b)| {
2622 a.asc == b.asc
2623 && a.nulls_first == b.nulls_first
2624 && a.expr.normalize_eq(&b.expr)
2625 })
2626 && self_distinct == other_distinct
2627 }
2628 (
2629 Expr::Exists(Exists {
2630 subquery: self_subquery,
2631 negated: self_negated,
2632 }),
2633 Expr::Exists(Exists {
2634 subquery: other_subquery,
2635 negated: other_negated,
2636 }),
2637 ) => {
2638 self_negated == other_negated
2639 && self_subquery.normalize_eq(other_subquery)
2640 }
2641 (
2642 Expr::InSubquery(InSubquery {
2643 expr: self_expr,
2644 subquery: self_subquery,
2645 negated: self_negated,
2646 }),
2647 Expr::InSubquery(InSubquery {
2648 expr: other_expr,
2649 subquery: other_subquery,
2650 negated: other_negated,
2651 }),
2652 ) => {
2653 self_negated == other_negated
2654 && self_expr.normalize_eq(other_expr)
2655 && self_subquery.normalize_eq(other_subquery)
2656 }
2657 (
2658 Expr::ScalarSubquery(self_subquery),
2659 Expr::ScalarSubquery(other_subquery),
2660 ) => self_subquery.normalize_eq(other_subquery),
2661 (
2662 Expr::GroupingSet(GroupingSet::Rollup(self_exprs)),
2663 Expr::GroupingSet(GroupingSet::Rollup(other_exprs)),
2664 )
2665 | (
2666 Expr::GroupingSet(GroupingSet::Cube(self_exprs)),
2667 Expr::GroupingSet(GroupingSet::Cube(other_exprs)),
2668 ) => {
2669 self_exprs.len() == other_exprs.len()
2670 && self_exprs
2671 .iter()
2672 .zip(other_exprs.iter())
2673 .all(|(a, b)| a.normalize_eq(b))
2674 }
2675 (
2676 Expr::GroupingSet(GroupingSet::GroupingSets(self_exprs)),
2677 Expr::GroupingSet(GroupingSet::GroupingSets(other_exprs)),
2678 ) => {
2679 self_exprs.len() == other_exprs.len()
2680 && self_exprs.iter().zip(other_exprs.iter()).all(|(a, b)| {
2681 a.len() == b.len()
2682 && a.iter().zip(b.iter()).all(|(x, y)| x.normalize_eq(y))
2683 })
2684 }
2685 (
2686 Expr::InList(InList {
2687 expr: self_expr,
2688 list: self_list,
2689 negated: self_negated,
2690 }),
2691 Expr::InList(InList {
2692 expr: other_expr,
2693 list: other_list,
2694 negated: other_negated,
2695 }),
2696 ) => {
2697 self_negated == other_negated
2699 && self_expr.normalize_eq(other_expr)
2700 && self_list.len() == other_list.len()
2701 && self_list
2702 .iter()
2703 .zip(other_list.iter())
2704 .all(|(a, b)| a.normalize_eq(b))
2705 }
2706 (
2707 Expr::Case(Case {
2708 expr: self_expr,
2709 when_then_expr: self_when_then_expr,
2710 else_expr: self_else_expr,
2711 }),
2712 Expr::Case(Case {
2713 expr: other_expr,
2714 when_then_expr: other_when_then_expr,
2715 else_expr: other_else_expr,
2716 }),
2717 ) => {
2718 self_when_then_expr.len() == other_when_then_expr.len()
2721 && self_when_then_expr
2722 .iter()
2723 .zip(other_when_then_expr.iter())
2724 .all(|((self_when, self_then), (other_when, other_then))| {
2725 self_when.normalize_eq(other_when)
2726 && self_then.normalize_eq(other_then)
2727 })
2728 && match (self_expr, other_expr) {
2729 (Some(self_expr), Some(other_expr)) => {
2730 self_expr.normalize_eq(other_expr)
2731 }
2732 (None, None) => true,
2733 (_, _) => false,
2734 }
2735 && match (self_else_expr, other_else_expr) {
2736 (Some(self_else_expr), Some(other_else_expr)) => {
2737 self_else_expr.normalize_eq(other_else_expr)
2738 }
2739 (None, None) => true,
2740 (_, _) => false,
2741 }
2742 }
2743 (_, _) => self == other,
2744 }
2745 }
2746}
2747
2748impl HashNode for Expr {
2749 fn hash_node<H: Hasher>(&self, state: &mut H) {
2753 mem::discriminant(self).hash(state);
2754 match self {
2755 Expr::Alias(Alias {
2756 expr: _expr,
2757 relation,
2758 name,
2759 ..
2760 }) => {
2761 relation.hash(state);
2762 name.hash(state);
2763 }
2764 Expr::Column(column) => {
2765 column.hash(state);
2766 }
2767 Expr::ScalarVariable(field, name) => {
2768 field.hash(state);
2769 name.hash(state);
2770 }
2771 Expr::Literal(scalar_value, _) => {
2772 scalar_value.hash(state);
2773 }
2774 Expr::BinaryExpr(BinaryExpr {
2775 left: _left,
2776 op,
2777 right: _right,
2778 }) => {
2779 op.hash(state);
2780 }
2781 Expr::Like(Like {
2782 negated,
2783 expr: _expr,
2784 pattern: _pattern,
2785 escape_char,
2786 case_insensitive,
2787 })
2788 | Expr::SimilarTo(Like {
2789 negated,
2790 expr: _expr,
2791 pattern: _pattern,
2792 escape_char,
2793 case_insensitive,
2794 }) => {
2795 negated.hash(state);
2796 escape_char.hash(state);
2797 case_insensitive.hash(state);
2798 }
2799 Expr::Not(_expr)
2800 | Expr::IsNotNull(_expr)
2801 | Expr::IsNull(_expr)
2802 | Expr::IsTrue(_expr)
2803 | Expr::IsFalse(_expr)
2804 | Expr::IsUnknown(_expr)
2805 | Expr::IsNotTrue(_expr)
2806 | Expr::IsNotFalse(_expr)
2807 | Expr::IsNotUnknown(_expr)
2808 | Expr::Negative(_expr) => {}
2809 Expr::Between(Between {
2810 expr: _expr,
2811 negated,
2812 low: _low,
2813 high: _high,
2814 }) => {
2815 negated.hash(state);
2816 }
2817 Expr::Case(Case {
2818 expr: _expr,
2819 when_then_expr: _when_then_expr,
2820 else_expr: _else_expr,
2821 }) => {}
2822 Expr::Cast(Cast { expr: _expr, field })
2823 | Expr::TryCast(TryCast { expr: _expr, field }) => {
2824 field.hash(state);
2825 }
2826 Expr::ScalarFunction(ScalarFunction { func, args: _args }) => {
2827 func.hash(state);
2828 }
2829 Expr::AggregateFunction(AggregateFunction {
2830 func,
2831 params:
2832 AggregateFunctionParams {
2833 args: _args,
2834 distinct,
2835 filter: _,
2836 order_by: _,
2837 null_treatment,
2838 },
2839 }) => {
2840 func.hash(state);
2841 distinct.hash(state);
2842 null_treatment.hash(state);
2843 }
2844 Expr::WindowFunction(window_fun) => {
2845 let WindowFunction {
2846 fun,
2847 params:
2848 WindowFunctionParams {
2849 args: _args,
2850 partition_by: _,
2851 order_by: _,
2852 window_frame,
2853 filter,
2854 null_treatment,
2855 distinct,
2856 },
2857 } = window_fun.as_ref();
2858 fun.hash(state);
2859 window_frame.hash(state);
2860 filter.hash(state);
2861 null_treatment.hash(state);
2862 distinct.hash(state);
2863 }
2864 Expr::InList(InList {
2865 expr: _expr,
2866 list: _list,
2867 negated,
2868 }) => {
2869 negated.hash(state);
2870 }
2871 Expr::Exists(Exists { subquery, negated }) => {
2872 subquery.hash(state);
2873 negated.hash(state);
2874 }
2875 Expr::InSubquery(InSubquery {
2876 expr: _expr,
2877 subquery,
2878 negated,
2879 }) => {
2880 subquery.hash(state);
2881 negated.hash(state);
2882 }
2883 Expr::SetComparison(SetComparison {
2884 expr: _,
2885 subquery,
2886 op,
2887 quantifier,
2888 }) => {
2889 subquery.hash(state);
2890 op.hash(state);
2891 quantifier.hash(state);
2892 }
2893 Expr::ScalarSubquery(subquery) => {
2894 subquery.hash(state);
2895 }
2896 #[expect(deprecated)]
2897 Expr::Wildcard { qualifier, options } => {
2898 qualifier.hash(state);
2899 options.hash(state);
2900 }
2901 Expr::GroupingSet(grouping_set) => {
2902 mem::discriminant(grouping_set).hash(state);
2903 match grouping_set {
2904 GroupingSet::Rollup(_exprs) | GroupingSet::Cube(_exprs) => {}
2905 GroupingSet::GroupingSets(_exprs) => {}
2906 }
2907 }
2908 Expr::Placeholder(place_holder) => {
2909 place_holder.hash(state);
2910 }
2911 Expr::OuterReferenceColumn(field, column) => {
2912 field.hash(state);
2913 column.hash(state);
2914 }
2915 Expr::Unnest(Unnest { expr: _expr, outer }) => {
2916 outer.hash(state);
2917 }
2918 Expr::HigherOrderFunction(HigherOrderFunction { func, args: _args }) => {
2919 func.hash(state);
2920 }
2921 Expr::Lambda(Lambda { params, body: _ }) => {
2922 params.hash(state);
2923 }
2924 Expr::LambdaVariable(LambdaVariable {
2925 name,
2926 field,
2927 spans: _,
2928 }) => {
2929 name.hash(state);
2930 field.hash(state);
2931 }
2932 };
2933 }
2934}
2935
2936fn rewrite_placeholder(expr: &mut Expr, other: &Expr, schema: &DFSchema) -> Result<()> {
2939 if let Expr::Placeholder(Placeholder { id: _, field }) = expr
2940 && field.is_none()
2941 {
2942 let other_field = other.to_field(schema);
2943 match other_field {
2944 Err(e) => {
2945 Err(e.context(format!(
2946 "Can not find type of {other} needed to infer type of {expr}"
2947 )))?;
2948 }
2949 Ok((_, other_field)) => {
2950 *field = Some(other_field.as_ref().clone().with_nullable(true).into());
2953 }
2954 }
2955 };
2956 Ok(())
2957}
2958
2959#[macro_export]
2960macro_rules! expr_vec_fmt {
2961 ( $ARRAY:expr ) => {{
2962 $ARRAY
2963 .iter()
2964 .map(|e| format!("{e}"))
2965 .collect::<Vec<String>>()
2966 .join(", ")
2967 }};
2968}
2969fn rewrite_placeholder_from_subquery(
2971 kind: &str,
2972 expr: &mut Expr,
2973 subquery: &Subquery,
2974) -> Result<()> {
2975 let subquery_schema = subquery.subquery.schema();
2976 match &subquery_schema.fields()[..] {
2977 [subquery_field] => {
2978 let column =
2979 Expr::Column(Column::new_unqualified(subquery_field.name().clone()));
2980 rewrite_placeholder(expr, &column, subquery_schema)
2981 }
2982 _ => plan_err!(
2983 "{kind} should only return one column, but found {}: {}",
2984 subquery_schema.fields().len(),
2985 subquery_schema.field_names().join(", ")
2986 ),
2987 }
2988}
2989
2990struct SchemaDisplay<'a>(&'a Expr);
2991impl Display for SchemaDisplay<'_> {
2992 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2993 match self.0 {
2994 #[expect(deprecated)]
2997 Expr::Column(_)
2998 | Expr::Literal(_, _)
2999 | Expr::ScalarVariable(..)
3000 | Expr::OuterReferenceColumn(..)
3001 | Expr::Placeholder(_)
3002 | Expr::Wildcard { .. } => write!(f, "{}", self.0),
3003 Expr::AggregateFunction(AggregateFunction { func, params }) => {
3004 match func.schema_name(params) {
3005 Ok(name) => {
3006 write!(f, "{name}")
3007 }
3008 Err(e) => {
3009 write!(f, "got error from schema_name {e}")
3010 }
3011 }
3012 }
3013 Expr::Alias(Alias {
3015 name,
3016 relation: Some(relation),
3017 ..
3018 }) => write!(f, "{relation}.{name}"),
3019 Expr::Alias(Alias { name, .. }) => write!(f, "{name}"),
3020 Expr::Between(Between {
3021 expr,
3022 negated,
3023 low,
3024 high,
3025 }) => {
3026 if *negated {
3027 write!(
3028 f,
3029 "{} NOT BETWEEN {} AND {}",
3030 SchemaDisplay(expr),
3031 SchemaDisplay(low),
3032 SchemaDisplay(high),
3033 )
3034 } else {
3035 write!(
3036 f,
3037 "{} BETWEEN {} AND {}",
3038 SchemaDisplay(expr),
3039 SchemaDisplay(low),
3040 SchemaDisplay(high),
3041 )
3042 }
3043 }
3044 Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
3045 write!(f, "{} {op} {}", SchemaDisplay(left), SchemaDisplay(right),)
3046 }
3047 Expr::Case(Case {
3048 expr,
3049 when_then_expr,
3050 else_expr,
3051 }) => {
3052 write!(f, "CASE ")?;
3053
3054 if let Some(e) = expr {
3055 write!(f, "{} ", SchemaDisplay(e))?;
3056 }
3057
3058 for (when, then) in when_then_expr {
3059 write!(
3060 f,
3061 "WHEN {} THEN {} ",
3062 SchemaDisplay(when),
3063 SchemaDisplay(then),
3064 )?;
3065 }
3066
3067 if let Some(e) = else_expr {
3068 write!(f, "ELSE {} ", SchemaDisplay(e))?;
3069 }
3070
3071 write!(f, "END")
3072 }
3073 Expr::Cast(Cast { expr, .. }) | Expr::TryCast(TryCast { expr, .. }) => {
3075 write!(f, "{}", SchemaDisplay(expr))
3076 }
3077 Expr::InList(InList {
3078 expr,
3079 list,
3080 negated,
3081 }) => {
3082 let inlist_name = schema_name_from_exprs(list)?;
3083
3084 if *negated {
3085 write!(f, "{} NOT IN {}", SchemaDisplay(expr), inlist_name)
3086 } else {
3087 write!(f, "{} IN {}", SchemaDisplay(expr), inlist_name)
3088 }
3089 }
3090 Expr::Exists(Exists { negated: true, .. }) => write!(f, "NOT EXISTS"),
3091 Expr::Exists(Exists { negated: false, .. }) => write!(f, "EXISTS"),
3092 Expr::GroupingSet(GroupingSet::Cube(exprs)) => {
3093 write!(f, "ROLLUP ({})", schema_name_from_exprs(exprs)?)
3094 }
3095 Expr::GroupingSet(GroupingSet::GroupingSets(lists_of_exprs)) => {
3096 write!(f, "GROUPING SETS (")?;
3097 for exprs in lists_of_exprs.iter() {
3098 write!(f, "({})", schema_name_from_exprs(exprs)?)?;
3099 }
3100 write!(f, ")")
3101 }
3102 Expr::GroupingSet(GroupingSet::Rollup(exprs)) => {
3103 write!(f, "ROLLUP ({})", schema_name_from_exprs(exprs)?)
3104 }
3105 Expr::IsNull(expr) => write!(f, "{} IS NULL", SchemaDisplay(expr)),
3106 Expr::IsNotNull(expr) => {
3107 write!(f, "{} IS NOT NULL", SchemaDisplay(expr))
3108 }
3109 Expr::IsUnknown(expr) => {
3110 write!(f, "{} IS UNKNOWN", SchemaDisplay(expr))
3111 }
3112 Expr::IsNotUnknown(expr) => {
3113 write!(f, "{} IS NOT UNKNOWN", SchemaDisplay(expr))
3114 }
3115 Expr::InSubquery(InSubquery { negated: true, .. }) => {
3116 write!(f, "NOT IN")
3117 }
3118 Expr::InSubquery(InSubquery { negated: false, .. }) => write!(f, "IN"),
3119 Expr::SetComparison(SetComparison {
3120 expr,
3121 op,
3122 quantifier,
3123 ..
3124 }) => write!(f, "{} {op} {quantifier}", SchemaDisplay(expr.as_ref())),
3125 Expr::IsTrue(expr) => write!(f, "{} IS TRUE", SchemaDisplay(expr)),
3126 Expr::IsFalse(expr) => write!(f, "{} IS FALSE", SchemaDisplay(expr)),
3127 Expr::IsNotTrue(expr) => {
3128 write!(f, "{} IS NOT TRUE", SchemaDisplay(expr))
3129 }
3130 Expr::IsNotFalse(expr) => {
3131 write!(f, "{} IS NOT FALSE", SchemaDisplay(expr))
3132 }
3133 Expr::Like(Like {
3134 negated,
3135 expr,
3136 pattern,
3137 escape_char,
3138 case_insensitive,
3139 }) => {
3140 write!(
3141 f,
3142 "{} {}{} {}",
3143 SchemaDisplay(expr),
3144 if *negated { "NOT " } else { "" },
3145 if *case_insensitive { "ILIKE" } else { "LIKE" },
3146 SchemaDisplay(pattern),
3147 )?;
3148
3149 if let Some(char) = escape_char {
3150 write!(f, " CHAR '{char}'")?;
3151 }
3152
3153 Ok(())
3154 }
3155 Expr::Negative(expr) => write!(f, "(- {})", SchemaDisplay(expr)),
3156 Expr::Not(expr) => write!(f, "NOT {}", SchemaDisplay(expr)),
3157 Expr::Unnest(Unnest { expr, outer }) => {
3158 let name = if *outer { "UNNEST_OUTER" } else { "UNNEST" };
3159 write!(f, "{name}({})", SchemaDisplay(expr))
3160 }
3161 Expr::ScalarFunction(ScalarFunction { func, args }) => {
3162 match func.schema_name(args) {
3163 Ok(name) => {
3164 write!(f, "{name}")
3165 }
3166 Err(e) => {
3167 write!(f, "got error from schema_name {e}")
3168 }
3169 }
3170 }
3171 Expr::ScalarSubquery(Subquery { subquery, .. }) => {
3172 write!(f, "{}", subquery.schema().field(0).name())
3173 }
3174 Expr::SimilarTo(Like {
3175 negated,
3176 expr,
3177 pattern,
3178 escape_char,
3179 ..
3180 }) => {
3181 write!(
3182 f,
3183 "{} {} {}",
3184 SchemaDisplay(expr),
3185 if *negated {
3186 "NOT SIMILAR TO"
3187 } else {
3188 "SIMILAR TO"
3189 },
3190 SchemaDisplay(pattern),
3191 )?;
3192 if let Some(char) = escape_char {
3193 write!(f, " CHAR '{char}'")?;
3194 }
3195
3196 Ok(())
3197 }
3198 Expr::WindowFunction(window_fun) => {
3199 let WindowFunction { fun, params } = window_fun.as_ref();
3200 match fun {
3201 WindowFunctionDefinition::AggregateUDF(fun) => {
3202 match fun.window_function_schema_name(params) {
3203 Ok(name) => {
3204 write!(f, "{name}")
3205 }
3206 Err(e) => {
3207 write!(
3208 f,
3209 "got error from window_function_schema_name {e}"
3210 )
3211 }
3212 }
3213 }
3214 _ => {
3215 let WindowFunctionParams {
3216 args,
3217 partition_by,
3218 order_by,
3219 window_frame,
3220 filter,
3221 null_treatment,
3222 distinct,
3223 } = params;
3224
3225 write!(f, "{fun}(")?;
3227
3228 if *distinct {
3230 write!(f, "DISTINCT ")?;
3231 }
3232
3233 write!(
3235 f,
3236 "{}",
3237 schema_name_from_exprs_comma_separated_without_space(args)?
3238 )?;
3239
3240 write!(f, ")")?;
3242
3243 if let Some(null_treatment) = null_treatment {
3244 write!(f, " {null_treatment}")?;
3245 }
3246
3247 if let Some(filter) = filter {
3248 write!(f, " FILTER (WHERE {filter})")?;
3249 }
3250
3251 if !partition_by.is_empty() {
3252 write!(
3253 f,
3254 " PARTITION BY [{}]",
3255 schema_name_from_exprs(partition_by)?
3256 )?;
3257 }
3258
3259 if !order_by.is_empty() {
3260 write!(
3261 f,
3262 " ORDER BY [{}]",
3263 schema_name_from_sorts(order_by)?
3264 )?;
3265 };
3266
3267 write!(f, " {window_frame}")
3268 }
3269 }
3270 }
3271 Expr::HigherOrderFunction(HigherOrderFunction { func, args }) => {
3272 match func.schema_name(args) {
3273 Ok(name) => {
3274 write!(f, "{name}")
3275 }
3276 Err(e) => {
3277 write!(f, "got error from schema_name {e}")
3278 }
3279 }
3280 }
3281 Expr::Lambda(Lambda { params, body }) => {
3282 write!(
3283 f,
3284 "({}) -> {}",
3285 display_comma_separated(params),
3286 SchemaDisplay(body)
3287 )
3288 }
3289 Expr::LambdaVariable(c) => f.write_str(&c.name),
3290 }
3291 }
3292}
3293
3294struct SqlDisplay<'a>(&'a Expr);
3296
3297impl Display for SqlDisplay<'_> {
3298 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
3299 match self.0 {
3300 Expr::Literal(scalar, _) => scalar.fmt(f),
3301 Expr::Alias(Alias { name, .. }) => write!(f, "{name}"),
3302 Expr::Between(Between {
3303 expr,
3304 negated,
3305 low,
3306 high,
3307 }) => {
3308 if *negated {
3309 write!(
3310 f,
3311 "{} NOT BETWEEN {} AND {}",
3312 SqlDisplay(expr),
3313 SqlDisplay(low),
3314 SqlDisplay(high),
3315 )
3316 } else {
3317 write!(
3318 f,
3319 "{} BETWEEN {} AND {}",
3320 SqlDisplay(expr),
3321 SqlDisplay(low),
3322 SqlDisplay(high),
3323 )
3324 }
3325 }
3326 Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
3327 write!(f, "{} {op} {}", SqlDisplay(left), SqlDisplay(right),)
3328 }
3329 Expr::Case(Case {
3330 expr,
3331 when_then_expr,
3332 else_expr,
3333 }) => {
3334 write!(f, "CASE ")?;
3335
3336 if let Some(e) = expr {
3337 write!(f, "{} ", SqlDisplay(e))?;
3338 }
3339
3340 for (when, then) in when_then_expr {
3341 write!(f, "WHEN {} THEN {} ", SqlDisplay(when), SqlDisplay(then),)?;
3342 }
3343
3344 if let Some(e) = else_expr {
3345 write!(f, "ELSE {} ", SqlDisplay(e))?;
3346 }
3347
3348 write!(f, "END")
3349 }
3350 Expr::Cast(Cast { expr, .. }) | Expr::TryCast(TryCast { expr, .. }) => {
3351 write!(f, "{}", SqlDisplay(expr))
3352 }
3353 Expr::InList(InList {
3354 expr,
3355 list,
3356 negated,
3357 }) => {
3358 write!(
3359 f,
3360 "{}{} IN {}",
3361 SqlDisplay(expr),
3362 if *negated { " NOT" } else { "" },
3363 ExprListDisplay::comma_separated(list.as_slice())
3364 )
3365 }
3366 Expr::GroupingSet(GroupingSet::Cube(exprs)) => {
3367 write!(
3368 f,
3369 "ROLLUP ({})",
3370 ExprListDisplay::comma_separated(exprs.as_slice())
3371 )
3372 }
3373 Expr::GroupingSet(GroupingSet::GroupingSets(lists_of_exprs)) => {
3374 write!(f, "GROUPING SETS (")?;
3375 for exprs in lists_of_exprs.iter() {
3376 write!(
3377 f,
3378 "({})",
3379 ExprListDisplay::comma_separated(exprs.as_slice())
3380 )?;
3381 }
3382 write!(f, ")")
3383 }
3384 Expr::GroupingSet(GroupingSet::Rollup(exprs)) => {
3385 write!(
3386 f,
3387 "ROLLUP ({})",
3388 ExprListDisplay::comma_separated(exprs.as_slice())
3389 )
3390 }
3391 Expr::IsNull(expr) => write!(f, "{} IS NULL", SqlDisplay(expr)),
3392 Expr::IsNotNull(expr) => {
3393 write!(f, "{} IS NOT NULL", SqlDisplay(expr))
3394 }
3395 Expr::IsUnknown(expr) => {
3396 write!(f, "{} IS UNKNOWN", SqlDisplay(expr))
3397 }
3398 Expr::IsNotUnknown(expr) => {
3399 write!(f, "{} IS NOT UNKNOWN", SqlDisplay(expr))
3400 }
3401 Expr::IsTrue(expr) => write!(f, "{} IS TRUE", SqlDisplay(expr)),
3402 Expr::IsFalse(expr) => write!(f, "{} IS FALSE", SqlDisplay(expr)),
3403 Expr::IsNotTrue(expr) => {
3404 write!(f, "{} IS NOT TRUE", SqlDisplay(expr))
3405 }
3406 Expr::IsNotFalse(expr) => {
3407 write!(f, "{} IS NOT FALSE", SqlDisplay(expr))
3408 }
3409 Expr::Like(Like {
3410 negated,
3411 expr,
3412 pattern,
3413 escape_char,
3414 case_insensitive,
3415 }) => {
3416 write!(
3417 f,
3418 "{} {}{} {}",
3419 SqlDisplay(expr),
3420 if *negated { "NOT " } else { "" },
3421 if *case_insensitive { "ILIKE" } else { "LIKE" },
3422 SqlDisplay(pattern),
3423 )?;
3424
3425 if let Some(char) = escape_char {
3426 write!(f, " CHAR '{char}'")?;
3427 }
3428
3429 Ok(())
3430 }
3431 Expr::Negative(expr) => write!(f, "(- {})", SqlDisplay(expr)),
3432 Expr::Not(expr) => write!(f, "NOT {}", SqlDisplay(expr)),
3433 Expr::Unnest(Unnest { expr, outer }) => {
3434 let name = if *outer { "UNNEST_OUTER" } else { "UNNEST" };
3435 write!(f, "{name}({})", SqlDisplay(expr))
3436 }
3437 Expr::SimilarTo(Like {
3438 negated,
3439 expr,
3440 pattern,
3441 escape_char,
3442 ..
3443 }) => {
3444 write!(
3445 f,
3446 "{} {} {}",
3447 SqlDisplay(expr),
3448 if *negated {
3449 "NOT SIMILAR TO"
3450 } else {
3451 "SIMILAR TO"
3452 },
3453 SqlDisplay(pattern),
3454 )?;
3455 if let Some(char) = escape_char {
3456 write!(f, " CHAR '{char}'")?;
3457 }
3458
3459 Ok(())
3460 }
3461 Expr::AggregateFunction(AggregateFunction { func, params }) => {
3462 match func.human_display(params) {
3463 Ok(name) => {
3464 write!(f, "{name}")
3465 }
3466 Err(e) => {
3467 write!(f, "got error from schema_name {e}")
3468 }
3469 }
3470 }
3471 Expr::Lambda(Lambda { params, body }) => {
3472 write!(f, "({}) -> {}", params.join(", "), SchemaDisplay(body))
3473 }
3474 _ => write!(f, "{}", self.0),
3475 }
3476 }
3477}
3478
3479pub(crate) fn schema_name_from_exprs_comma_separated_without_space(
3485 exprs: &[Expr],
3486) -> Result<String, fmt::Error> {
3487 schema_name_from_exprs_inner(exprs, ",")
3488}
3489
3490pub struct ExprListDisplay<'a> {
3492 exprs: &'a [Expr],
3493 sep: &'a str,
3494}
3495
3496impl<'a> ExprListDisplay<'a> {
3497 pub fn new(exprs: &'a [Expr], sep: &'a str) -> Self {
3499 Self { exprs, sep }
3500 }
3501
3502 pub fn comma_separated(exprs: &'a [Expr]) -> Self {
3504 Self::new(exprs, ", ")
3505 }
3506}
3507
3508impl Display for ExprListDisplay<'_> {
3509 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
3510 let mut first = true;
3511 for expr in self.exprs {
3512 if !first {
3513 write!(f, "{}", self.sep)?;
3514 }
3515 write!(f, "{}", SqlDisplay(expr))?;
3516 first = false;
3517 }
3518 Ok(())
3519 }
3520}
3521
3522pub fn schema_name_from_exprs(exprs: &[Expr]) -> Result<String, fmt::Error> {
3524 schema_name_from_exprs_inner(exprs, ", ")
3525}
3526
3527fn schema_name_from_exprs_inner(exprs: &[Expr], sep: &str) -> Result<String, fmt::Error> {
3528 let mut s = String::new();
3529 for (i, e) in exprs.iter().enumerate() {
3530 if i > 0 {
3531 write!(&mut s, "{sep}")?;
3532 }
3533 write!(&mut s, "{}", SchemaDisplay(e))?;
3534 }
3535
3536 Ok(s)
3537}
3538
3539pub fn schema_name_from_sorts(sorts: &[Sort]) -> Result<String, fmt::Error> {
3540 let mut s = String::new();
3541 for (i, e) in sorts.iter().enumerate() {
3542 if i > 0 {
3543 write!(&mut s, ", ")?;
3544 }
3545 let ordering = if e.asc { "ASC" } else { "DESC" };
3546 let nulls_ordering = if e.nulls_first {
3547 "NULLS FIRST"
3548 } else {
3549 "NULLS LAST"
3550 };
3551 write!(&mut s, "{} {} {}", e.expr, ordering, nulls_ordering)?;
3552 }
3553
3554 Ok(s)
3555}
3556
3557pub const OUTER_REFERENCE_COLUMN_PREFIX: &str = "outer_ref";
3558pub const UNNEST_COLUMN_PREFIX: &str = "UNNEST";
3559
3560impl Display for Expr {
3563 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
3564 match self {
3565 Expr::Alias(Alias { expr, name, .. }) => write!(f, "{expr} AS {name}"),
3566 Expr::Column(c) => write!(f, "{c}"),
3567 Expr::OuterReferenceColumn(_, c) => {
3568 write!(f, "{OUTER_REFERENCE_COLUMN_PREFIX}({c})")
3569 }
3570 Expr::ScalarVariable(_, var_names) => write!(f, "{}", var_names.join(".")),
3571 Expr::Literal(v, metadata) => {
3572 match metadata.as_ref().map(|m| m.is_empty()).unwrap_or(true) {
3573 false => write!(f, "{v:?} {:?}", metadata.as_ref().unwrap()),
3574 true => write!(f, "{v:?}"),
3575 }
3576 }
3577 Expr::Case(case) => {
3578 write!(f, "CASE ")?;
3579 if let Some(e) = &case.expr {
3580 write!(f, "{e} ")?;
3581 }
3582 for (w, t) in &case.when_then_expr {
3583 write!(f, "WHEN {w} THEN {t} ")?;
3584 }
3585 if let Some(e) = &case.else_expr {
3586 write!(f, "ELSE {e} ")?;
3587 }
3588 write!(f, "END")
3589 }
3590 Expr::Cast(Cast { expr, field }) => {
3591 let formatted =
3592 format_type_and_metadata(field.data_type(), Some(field.metadata()));
3593 write!(f, "CAST({expr} AS {formatted})")
3594 }
3595 Expr::TryCast(TryCast { expr, field }) => {
3596 let formatted =
3597 format_type_and_metadata(field.data_type(), Some(field.metadata()));
3598 write!(f, "TRY_CAST({expr} AS {formatted})")
3599 }
3600 Expr::Not(expr) => write!(f, "NOT {expr}"),
3601 Expr::Negative(expr) => write!(f, "(- {expr})"),
3602 Expr::IsNull(expr) => write!(f, "{expr} IS NULL"),
3603 Expr::IsNotNull(expr) => write!(f, "{expr} IS NOT NULL"),
3604 Expr::IsTrue(expr) => write!(f, "{expr} IS TRUE"),
3605 Expr::IsFalse(expr) => write!(f, "{expr} IS FALSE"),
3606 Expr::IsUnknown(expr) => write!(f, "{expr} IS UNKNOWN"),
3607 Expr::IsNotTrue(expr) => write!(f, "{expr} IS NOT TRUE"),
3608 Expr::IsNotFalse(expr) => write!(f, "{expr} IS NOT FALSE"),
3609 Expr::IsNotUnknown(expr) => write!(f, "{expr} IS NOT UNKNOWN"),
3610 Expr::Exists(Exists {
3611 subquery,
3612 negated: true,
3613 }) => write!(f, "NOT EXISTS ({subquery:?})"),
3614 Expr::Exists(Exists {
3615 subquery,
3616 negated: false,
3617 }) => write!(f, "EXISTS ({subquery:?})"),
3618 Expr::InSubquery(InSubquery {
3619 expr,
3620 subquery,
3621 negated: true,
3622 }) => write!(f, "{expr} NOT IN ({subquery:?})"),
3623 Expr::InSubquery(InSubquery {
3624 expr,
3625 subquery,
3626 negated: false,
3627 }) => write!(f, "{expr} IN ({subquery:?})"),
3628 Expr::SetComparison(SetComparison {
3629 expr,
3630 subquery,
3631 op,
3632 quantifier,
3633 }) => write!(f, "{expr} {op} {quantifier} ({subquery:?})"),
3634 Expr::ScalarSubquery(subquery) => write!(f, "({subquery:?})"),
3635 Expr::BinaryExpr(expr) => write!(f, "{expr}"),
3636 Expr::ScalarFunction(fun) => {
3637 fmt_function(f, fun.name(), false, &fun.args, true)
3638 }
3639 Expr::WindowFunction(window_fun) => {
3640 let WindowFunction { fun, params } = window_fun.as_ref();
3641 match fun {
3642 WindowFunctionDefinition::AggregateUDF(fun) => {
3643 match fun.window_function_display_name(params) {
3644 Ok(name) => {
3645 write!(f, "{name}")
3646 }
3647 Err(e) => {
3648 write!(
3649 f,
3650 "got error from window_function_display_name {e}"
3651 )
3652 }
3653 }
3654 }
3655 WindowFunctionDefinition::WindowUDF(fun) => {
3656 let WindowFunctionParams {
3657 args,
3658 partition_by,
3659 order_by,
3660 window_frame,
3661 filter,
3662 null_treatment,
3663 distinct,
3664 } = params;
3665
3666 fmt_function(f, &fun.to_string(), *distinct, args, true)?;
3667
3668 if let Some(nt) = null_treatment {
3669 write!(f, "{nt}")?;
3670 }
3671
3672 if let Some(fe) = filter {
3673 write!(f, " FILTER (WHERE {fe})")?;
3674 }
3675
3676 if !partition_by.is_empty() {
3677 write!(f, " PARTITION BY [{}]", expr_vec_fmt!(partition_by))?;
3678 }
3679 if !order_by.is_empty() {
3680 write!(f, " ORDER BY [{}]", expr_vec_fmt!(order_by))?;
3681 }
3682 write!(
3683 f,
3684 " {} BETWEEN {} AND {}",
3685 window_frame.units,
3686 window_frame.start_bound,
3687 window_frame.end_bound
3688 )
3689 }
3690 }
3691 }
3692 Expr::AggregateFunction(AggregateFunction { func, params }) => {
3693 match func.display_name(params) {
3694 Ok(name) => {
3695 write!(f, "{name}")
3696 }
3697 Err(e) => {
3698 write!(f, "got error from display_name {e}")
3699 }
3700 }
3701 }
3702 Expr::Between(Between {
3703 expr,
3704 negated,
3705 low,
3706 high,
3707 }) => {
3708 if *negated {
3709 write!(f, "{expr} NOT BETWEEN {low} AND {high}")
3710 } else {
3711 write!(f, "{expr} BETWEEN {low} AND {high}")
3712 }
3713 }
3714 Expr::Like(Like {
3715 negated,
3716 expr,
3717 pattern,
3718 escape_char,
3719 case_insensitive,
3720 }) => {
3721 write!(f, "{expr}")?;
3722 let op_name = if *case_insensitive { "ILIKE" } else { "LIKE" };
3723 if *negated {
3724 write!(f, " NOT")?;
3725 }
3726 if let Some(char) = escape_char {
3727 write!(f, " {op_name} {pattern} ESCAPE '{char}'")
3728 } else {
3729 write!(f, " {op_name} {pattern}")
3730 }
3731 }
3732 Expr::SimilarTo(Like {
3733 negated,
3734 expr,
3735 pattern,
3736 escape_char,
3737 case_insensitive: _,
3738 }) => {
3739 write!(f, "{expr}")?;
3740 if *negated {
3741 write!(f, " NOT")?;
3742 }
3743 if let Some(char) = escape_char {
3744 write!(f, " SIMILAR TO {pattern} ESCAPE '{char}'")
3745 } else {
3746 write!(f, " SIMILAR TO {pattern}")
3747 }
3748 }
3749 Expr::InList(InList {
3750 expr,
3751 list,
3752 negated,
3753 }) => {
3754 if *negated {
3755 write!(f, "{expr} NOT IN ([{}])", expr_vec_fmt!(list))
3756 } else {
3757 write!(f, "{expr} IN ([{}])", expr_vec_fmt!(list))
3758 }
3759 }
3760 #[expect(deprecated)]
3761 Expr::Wildcard { qualifier, options } => match qualifier {
3762 Some(qualifier) => write!(f, "{qualifier}.*{options}"),
3763 None => write!(f, "*{options}"),
3764 },
3765 Expr::GroupingSet(grouping_sets) => match grouping_sets {
3766 GroupingSet::Rollup(exprs) => {
3767 write!(f, "ROLLUP ({})", expr_vec_fmt!(exprs))
3769 }
3770 GroupingSet::Cube(exprs) => {
3771 write!(f, "CUBE ({})", expr_vec_fmt!(exprs))
3773 }
3774 GroupingSet::GroupingSets(lists_of_exprs) => {
3775 write!(
3777 f,
3778 "GROUPING SETS ({})",
3779 lists_of_exprs
3780 .iter()
3781 .map(|exprs| format!("({})", expr_vec_fmt!(exprs)))
3782 .collect::<Vec<String>>()
3783 .join(", ")
3784 )
3785 }
3786 },
3787 Expr::Placeholder(Placeholder { id, .. }) => write!(f, "{id}"),
3788 Expr::Unnest(Unnest { expr, .. }) => {
3789 write!(f, "{UNNEST_COLUMN_PREFIX}({expr})")
3790 }
3791 Expr::HigherOrderFunction(fun) => {
3792 fmt_function(f, fun.name(), false, &fun.args, true)
3793 }
3794 Expr::Lambda(Lambda { params, body }) => {
3795 write!(f, "({}) -> {body}", params.join(", "))
3796 }
3797 Expr::LambdaVariable(c) => f.write_str(&c.name),
3798 }
3799 }
3800}
3801
3802fn fmt_function(
3803 f: &mut Formatter,
3804 fun: &str,
3805 distinct: bool,
3806 args: &[Expr],
3807 display: bool,
3808) -> fmt::Result {
3809 let args: Vec<String> = match display {
3810 true => args.iter().map(|arg| format!("{arg}")).collect(),
3811 false => args.iter().map(|arg| format!("{arg:?}")).collect(),
3812 };
3813
3814 let distinct_str = match distinct {
3815 true => "DISTINCT ",
3816 false => "",
3817 };
3818 write!(f, "{}({}{})", fun, distinct_str, args.join(", "))
3819}
3820
3821pub fn physical_name(expr: &Expr) -> Result<String> {
3824 match expr {
3825 Expr::Column(col) => Ok(col.name.clone()),
3826 Expr::Alias(alias) => Ok(alias.name.clone()),
3827 _ => Ok(expr.schema_name().to_string()),
3828 }
3829}
3830
3831#[cfg(test)]
3832mod test {
3833 use crate::expr_fn::col;
3834 use crate::{
3835 ColumnarValue, ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Volatility, case,
3836 lit, placeholder, qualified_wildcard, wildcard, wildcard_with_options,
3837 };
3838 use arrow::datatypes::{Field, Schema};
3839 use sqlparser::ast;
3840 use sqlparser::ast::{Ident, IdentWithAlias};
3841
3842 #[test]
3843 fn infer_placeholder_in_clause() {
3844 let column = col("department_id");
3846 let param_placeholders = vec![
3847 Expr::Placeholder(Placeholder {
3848 id: "$1".to_string(),
3849 field: None,
3850 }),
3851 Expr::Placeholder(Placeholder {
3852 id: "$2".to_string(),
3853 field: None,
3854 }),
3855 Expr::Placeholder(Placeholder {
3856 id: "$3".to_string(),
3857 field: None,
3858 }),
3859 ];
3860 let in_list = Expr::InList(InList {
3861 expr: Box::new(column),
3862 list: param_placeholders,
3863 negated: false,
3864 });
3865
3866 let schema = Arc::new(Schema::new(vec![
3867 Field::new("name", DataType::Utf8, true),
3868 Field::new("department_id", DataType::Int32, true),
3869 ]));
3870 let df_schema = DFSchema::try_from(schema).unwrap();
3871
3872 let (inferred_expr, contains_placeholder) =
3873 in_list.infer_placeholder_types(&df_schema).unwrap();
3874
3875 assert!(contains_placeholder);
3876
3877 match inferred_expr {
3878 Expr::InList(in_list) => {
3879 for expr in in_list.list {
3880 match expr {
3881 Expr::Placeholder(placeholder) => {
3882 assert_eq!(
3883 placeholder.field.unwrap().data_type(),
3884 &DataType::Int32,
3885 "Placeholder {} should infer Int32",
3886 placeholder.id
3887 );
3888 }
3889 _ => panic!("Expected Placeholder expression"),
3890 }
3891 }
3892 }
3893 _ => panic!("Expected InList expression"),
3894 }
3895 }
3896
3897 #[test]
3898 fn infer_placeholder_in_subquery() {
3899 let subquery_field = Field::new("a", DataType::Int32, false);
3901 let subquery_schema = Arc::new(
3902 DFSchema::from_unqualified_fields(
3903 vec![subquery_field].into(),
3904 Default::default(),
3905 )
3906 .unwrap(),
3907 );
3908 let subquery = Subquery {
3909 subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
3910 produce_one_row: false,
3911 schema: subquery_schema,
3912 })),
3913 outer_ref_columns: vec![],
3914 spans: Spans::new(),
3915 };
3916
3917 let in_subquery = Expr::InSubquery(InSubquery {
3918 expr: Box::new(Expr::Placeholder(Placeholder {
3919 id: "$1".to_string(),
3920 field: None,
3921 })),
3922 subquery,
3923 negated: false,
3924 });
3925
3926 let outer_schema = DFSchema::empty();
3927 let (inferred_expr, contains_placeholder) =
3928 in_subquery.infer_placeholder_types(&outer_schema).unwrap();
3929
3930 assert!(contains_placeholder);
3931
3932 match inferred_expr {
3933 Expr::InSubquery(in_subquery) => match *in_subquery.expr {
3934 Expr::Placeholder(placeholder) => {
3935 let inferred = placeholder.field.expect("placeholder field");
3936 assert_eq!(inferred.data_type(), &DataType::Int32);
3937 assert!(inferred.is_nullable());
3938 }
3939 _ => panic!("Expected Placeholder expression in InSubquery"),
3940 },
3941 _ => panic!("Expected InSubquery expression"),
3942 }
3943 }
3944
3945 #[test]
3946 fn infer_placeholder_not_in_subquery() {
3947 let subquery_field = Field::new("a", DataType::Int32, false);
3949 let subquery_schema = Arc::new(
3950 DFSchema::from_unqualified_fields(
3951 vec![subquery_field].into(),
3952 Default::default(),
3953 )
3954 .unwrap(),
3955 );
3956 let subquery = Subquery {
3957 subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
3958 produce_one_row: false,
3959 schema: subquery_schema,
3960 })),
3961 outer_ref_columns: vec![],
3962 spans: Spans::new(),
3963 };
3964
3965 let not_in_subquery = Expr::InSubquery(InSubquery {
3966 expr: Box::new(Expr::Placeholder(Placeholder {
3967 id: "$1".to_string(),
3968 field: None,
3969 })),
3970 subquery,
3971 negated: true,
3972 });
3973
3974 let outer_schema = DFSchema::empty();
3975 let (inferred_expr, contains_placeholder) = not_in_subquery
3976 .infer_placeholder_types(&outer_schema)
3977 .unwrap();
3978
3979 assert!(contains_placeholder);
3980
3981 match inferred_expr {
3982 Expr::InSubquery(in_subquery) => {
3983 assert!(in_subquery.negated, "negated flag must be preserved");
3984 match *in_subquery.expr {
3985 Expr::Placeholder(placeholder) => {
3986 let inferred = placeholder.field.expect("placeholder field");
3987 assert_eq!(inferred.data_type(), &DataType::Int32);
3988 assert!(inferred.is_nullable());
3989 }
3990 _ => {
3991 panic!("Expected Placeholder expression in InSubquery")
3992 }
3993 }
3994 }
3995 _ => panic!("Expected InSubquery expression"),
3996 }
3997 }
3998
3999 #[test]
4000 fn infer_placeholder_set_comparison_any() {
4001 let subquery_field = Field::new("a", DataType::Int32, false);
4003 let subquery_schema = Arc::new(
4004 DFSchema::from_unqualified_fields(
4005 vec![subquery_field].into(),
4006 Default::default(),
4007 )
4008 .unwrap(),
4009 );
4010 let subquery = Subquery {
4011 subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
4012 produce_one_row: false,
4013 schema: subquery_schema,
4014 })),
4015 outer_ref_columns: vec![],
4016 spans: Spans::new(),
4017 };
4018
4019 let set_cmp = Expr::SetComparison(SetComparison {
4020 expr: Box::new(Expr::Placeholder(Placeholder {
4021 id: "$1".to_string(),
4022 field: None,
4023 })),
4024 subquery,
4025 op: Operator::Eq,
4026 quantifier: SetQuantifier::Any,
4027 });
4028
4029 let outer_schema = DFSchema::empty();
4030 let (inferred_expr, contains_placeholder) =
4031 set_cmp.infer_placeholder_types(&outer_schema).unwrap();
4032
4033 assert!(contains_placeholder);
4034
4035 match inferred_expr {
4036 Expr::SetComparison(sc) => {
4037 assert_eq!(sc.quantifier, SetQuantifier::Any);
4038 match *sc.expr {
4039 Expr::Placeholder(p) => {
4040 let inferred =
4041 p.field.expect("placeholder field should be Int32");
4042 assert_eq!(inferred.data_type(), &DataType::Int32);
4043 assert!(inferred.is_nullable());
4044 }
4045 _ => panic!("Expected Placeholder expression in SetComparison"),
4046 }
4047 }
4048 _ => panic!("Expected SetComparison expression"),
4049 }
4050 }
4051
4052 #[test]
4053 fn infer_placeholder_set_comparison_all() {
4054 let subquery_field = Field::new("a", DataType::Int32, false);
4056 let subquery_schema = Arc::new(
4057 DFSchema::from_unqualified_fields(
4058 vec![subquery_field].into(),
4059 Default::default(),
4060 )
4061 .unwrap(),
4062 );
4063 let subquery = Subquery {
4064 subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
4065 produce_one_row: false,
4066 schema: subquery_schema,
4067 })),
4068 outer_ref_columns: vec![],
4069 spans: Spans::new(),
4070 };
4071
4072 let set_cmp = Expr::SetComparison(SetComparison {
4073 expr: Box::new(Expr::Placeholder(Placeholder {
4074 id: "$1".to_string(),
4075 field: None,
4076 })),
4077 subquery,
4078 op: Operator::NotEq,
4079 quantifier: SetQuantifier::All,
4080 });
4081
4082 let outer_schema = DFSchema::empty();
4083 let (inferred_expr, contains_placeholder) =
4084 set_cmp.infer_placeholder_types(&outer_schema).unwrap();
4085
4086 assert!(contains_placeholder);
4087
4088 match inferred_expr {
4089 Expr::SetComparison(sc) => {
4090 assert_eq!(sc.quantifier, SetQuantifier::All);
4091 match *sc.expr {
4092 Expr::Placeholder(p) => {
4093 let inferred =
4094 p.field.expect("placeholder field should be Int32");
4095 assert_eq!(inferred.data_type(), &DataType::Int32);
4096 assert!(inferred.is_nullable());
4097 }
4098 _ => panic!("Expected Placeholder expression in SetComparison"),
4099 }
4100 }
4101 _ => panic!("Expected SetComparison expression"),
4102 }
4103 }
4104
4105 #[test]
4106 fn infer_placeholder_like_and_similar_to() {
4107 let schema =
4109 Arc::new(Schema::new(vec![Field::new("name", DataType::Utf8, true)]));
4110 let df_schema = DFSchema::try_from(schema).unwrap();
4111
4112 let like = Like {
4113 expr: Box::new(col("name")),
4114 pattern: Box::new(Expr::Placeholder(Placeholder {
4115 id: "$1".to_string(),
4116 field: None,
4117 })),
4118 negated: false,
4119 case_insensitive: false,
4120 escape_char: None,
4121 };
4122
4123 let expr = Expr::Like(like.clone());
4124
4125 let (inferred_expr, _) = expr.infer_placeholder_types(&df_schema).unwrap();
4126 match inferred_expr {
4127 Expr::Like(like) => match *like.pattern {
4128 Expr::Placeholder(placeholder) => {
4129 assert_eq!(placeholder.field.unwrap().data_type(), &DataType::Utf8);
4130 }
4131 _ => panic!("Expected Placeholder"),
4132 },
4133 _ => panic!("Expected Like"),
4134 }
4135
4136 let expr = Expr::SimilarTo(like);
4138
4139 let (inferred_expr, _) = expr.infer_placeholder_types(&df_schema).unwrap();
4140 match inferred_expr {
4141 Expr::SimilarTo(like) => match *like.pattern {
4142 Expr::Placeholder(placeholder) => {
4143 assert_eq!(
4144 placeholder.field.unwrap().data_type(),
4145 &DataType::Utf8,
4146 "Placeholder {} should infer Utf8",
4147 placeholder.id
4148 );
4149 }
4150 _ => panic!("Expected Placeholder expression"),
4151 },
4152 _ => panic!("Expected SimilarTo expression"),
4153 }
4154 }
4155
4156 #[test]
4157 fn infer_placeholder_with_metadata() {
4158 let schema = Arc::new(Schema::new(vec![
4160 Field::new("name", DataType::Utf8, false).with_metadata(
4161 [("some_key".to_string(), "some_value".to_string())].into(),
4162 ),
4163 ]));
4164 let df_schema = DFSchema::try_from(schema).unwrap();
4165
4166 let expr = binary_expr(col("name"), Operator::Eq, placeholder("$1"));
4167
4168 let (inferred_expr, _) = expr.infer_placeholder_types(&df_schema).unwrap();
4169 match inferred_expr {
4170 Expr::BinaryExpr(BinaryExpr { right, .. }) => match *right {
4171 Expr::Placeholder(placeholder) => {
4172 assert_eq!(
4173 placeholder.field.as_ref().unwrap().data_type(),
4174 &DataType::Utf8
4175 );
4176 assert_eq!(
4177 placeholder.field.as_ref().unwrap().metadata(),
4178 df_schema.field(0).metadata()
4179 );
4180 assert!(placeholder.field.as_ref().unwrap().is_nullable());
4182 }
4183 _ => panic!("Expected Placeholder"),
4184 },
4185 _ => panic!("Expected BinaryExpr"),
4186 }
4187 }
4188
4189 #[test]
4190 fn format_case_when() -> Result<()> {
4191 let expr = case(col("a"))
4192 .when(lit(1), lit(true))
4193 .when(lit(0), lit(false))
4194 .otherwise(lit(ScalarValue::Null))?;
4195 let expected = "CASE a WHEN Int32(1) THEN Boolean(true) WHEN Int32(0) THEN Boolean(false) ELSE NULL END";
4196 assert_eq!(expected, format!("{expr}"));
4197 Ok(())
4198 }
4199
4200 #[test]
4201 fn format_cast() -> Result<()> {
4202 let expr = Expr::Cast(Cast {
4203 expr: Box::new(Expr::Literal(ScalarValue::Float32(Some(1.23)), None)),
4204 field: DataType::Utf8.into_nullable_field_ref(),
4205 });
4206 let expected_canonical = "CAST(Float32(1.23) AS Utf8)";
4207 assert_eq!(expected_canonical, format!("{expr}"));
4208 assert_eq!("Float32(1.23)", expr.schema_name().to_string());
4211 Ok(())
4212 }
4213
4214 #[test]
4215 fn format_decimal_literal() {
4216 let expr = lit(ScalarValue::Decimal128(Some(1), 1, 1));
4217 assert_eq!("Decimal128(0.1,1,1)", format!("{expr}"));
4218 assert_eq!("Decimal128(0.1,1,1)", expr.schema_name().to_string());
4219 assert_eq!("0.1", expr.human_display().to_string());
4220
4221 let expr = lit(ScalarValue::Decimal128(Some(120), 3, 2));
4222 assert_eq!("Decimal128(1.20,3,2)", format!("{expr}"));
4223 assert_eq!("Decimal128(1.20,3,2)", expr.schema_name().to_string());
4224 assert_eq!("1.20", expr.human_display().to_string());
4225
4226 let null_expr = lit(ScalarValue::Decimal128(None, 10, 2));
4227 assert_eq!("Decimal128(NULL,10,2)", format!("{null_expr}"));
4228 assert_eq!("Decimal128(NULL,10,2)", null_expr.schema_name().to_string());
4229 assert_eq!("NULL", null_expr.human_display().to_string());
4230 }
4231
4232 #[test]
4233 fn test_partial_ord() {
4234 let exp1 = col("a") + lit(1);
4237 let exp2 = col("a") + lit(2);
4238 let exp3 = !(col("a") + lit(2));
4239
4240 assert!(exp1 < exp2);
4241 assert!(exp3 > exp2);
4242 assert!(exp1 < exp3)
4243 }
4244
4245 #[test]
4246 fn test_collect_expr() -> Result<()> {
4247 {
4249 let expr = &Expr::Cast(Cast::new(Box::new(col("a")), DataType::Float64));
4250 let columns = expr.column_refs();
4251 assert_eq!(1, columns.len());
4252 assert!(columns.contains(&Column::from_name("a")));
4253 }
4254
4255 {
4257 let expr = col("a") + col("b") + lit(1);
4258 let columns = expr.column_refs();
4259 assert_eq!(2, columns.len());
4260 assert!(columns.contains(&Column::from_name("a")));
4261 assert!(columns.contains(&Column::from_name("b")));
4262 }
4263
4264 Ok(())
4265 }
4266
4267 #[test]
4268 fn test_logical_ops() {
4269 assert_eq!(
4270 format!("{}", lit(1u32).eq(lit(2u32))),
4271 "UInt32(1) = UInt32(2)"
4272 );
4273 assert_eq!(
4274 format!("{}", lit(1u32).not_eq(lit(2u32))),
4275 "UInt32(1) != UInt32(2)"
4276 );
4277 assert_eq!(
4278 format!("{}", lit(1u32).gt(lit(2u32))),
4279 "UInt32(1) > UInt32(2)"
4280 );
4281 assert_eq!(
4282 format!("{}", lit(1u32).gt_eq(lit(2u32))),
4283 "UInt32(1) >= UInt32(2)"
4284 );
4285 assert_eq!(
4286 format!("{}", lit(1u32).lt(lit(2u32))),
4287 "UInt32(1) < UInt32(2)"
4288 );
4289 assert_eq!(
4290 format!("{}", lit(1u32).lt_eq(lit(2u32))),
4291 "UInt32(1) <= UInt32(2)"
4292 );
4293 assert_eq!(
4294 format!("{}", lit(1u32).and(lit(2u32))),
4295 "UInt32(1) AND UInt32(2)"
4296 );
4297 assert_eq!(
4298 format!("{}", lit(1u32).or(lit(2u32))),
4299 "UInt32(1) OR UInt32(2)"
4300 );
4301 }
4302
4303 #[test]
4304 fn test_is_volatile_scalar_func() {
4305 #[derive(Debug, PartialEq, Eq, Hash)]
4307 struct TestScalarUDF {
4308 signature: Signature,
4309 }
4310 impl ScalarUDFImpl for TestScalarUDF {
4311 fn name(&self) -> &str {
4312 "TestScalarUDF"
4313 }
4314
4315 fn signature(&self) -> &Signature {
4316 &self.signature
4317 }
4318
4319 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
4320 Ok(DataType::Utf8)
4321 }
4322
4323 fn invoke_with_args(
4324 &self,
4325 _args: ScalarFunctionArgs,
4326 ) -> Result<ColumnarValue> {
4327 Ok(ColumnarValue::Scalar(ScalarValue::from("a")))
4328 }
4329 }
4330 let udf = Arc::new(ScalarUDF::from(TestScalarUDF {
4331 signature: Signature::uniform(1, vec![DataType::Float32], Volatility::Stable),
4332 }));
4333 assert_ne!(udf.signature().volatility, Volatility::Volatile);
4334
4335 let udf = Arc::new(ScalarUDF::from(TestScalarUDF {
4336 signature: Signature::uniform(
4337 1,
4338 vec![DataType::Float32],
4339 Volatility::Volatile,
4340 ),
4341 }));
4342 assert_eq!(udf.signature().volatility, Volatility::Volatile);
4343 }
4344
4345 use super::*;
4346 use crate::logical_plan::{EmptyRelation, LogicalPlan};
4347
4348 #[test]
4349 fn test_display_wildcard() {
4350 assert_eq!(format!("{}", wildcard()), "*");
4351 assert_eq!(format!("{}", qualified_wildcard("t1")), "t1.*");
4352 assert_eq!(
4353 format!(
4354 "{}",
4355 wildcard_with_options(wildcard_options(
4356 Some(IlikeSelectItem {
4357 pattern: "c1".to_string()
4358 }),
4359 None,
4360 None,
4361 None,
4362 None
4363 ))
4364 ),
4365 "* ILIKE 'c1'"
4366 );
4367 assert_eq!(
4368 format!(
4369 "{}",
4370 wildcard_with_options(wildcard_options(
4371 None,
4372 Some(ExcludeSelectItem::Multiple(vec![
4373 Ident::from("c1").into(),
4374 Ident::from("c2").into()
4375 ])),
4376 None,
4377 None,
4378 None
4379 ))
4380 ),
4381 "* EXCLUDE (c1, c2)"
4382 );
4383 assert_eq!(
4384 format!(
4385 "{}",
4386 wildcard_with_options(wildcard_options(
4387 None,
4388 None,
4389 Some(ExceptSelectItem {
4390 first_element: Ident::from("c1"),
4391 additional_elements: vec![Ident::from("c2")]
4392 }),
4393 None,
4394 None
4395 ))
4396 ),
4397 "* EXCEPT (c1, c2)"
4398 );
4399 assert_eq!(
4400 format!(
4401 "{}",
4402 wildcard_with_options(wildcard_options(
4403 None,
4404 None,
4405 None,
4406 Some(PlannedReplaceSelectItem {
4407 items: vec![ReplaceSelectElement {
4408 expr: ast::Expr::Identifier(Ident::from("c1")),
4409 column_name: Ident::from("a1"),
4410 as_keyword: false
4411 }],
4412 planned_expressions: vec![]
4413 }),
4414 None
4415 ))
4416 ),
4417 "* REPLACE (c1 a1)"
4418 );
4419 assert_eq!(
4420 format!(
4421 "{}",
4422 wildcard_with_options(wildcard_options(
4423 None,
4424 None,
4425 None,
4426 None,
4427 Some(RenameSelectItem::Multiple(vec![IdentWithAlias {
4428 ident: Ident::from("c1"),
4429 alias: Ident::from("a1")
4430 }]))
4431 ))
4432 ),
4433 "* RENAME (c1 AS a1)"
4434 )
4435 }
4436
4437 #[test]
4438 fn test_display_set_comparison() {
4439 let subquery = Subquery {
4440 subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
4441 produce_one_row: false,
4442 schema: Arc::new(DFSchema::empty()),
4443 })),
4444 outer_ref_columns: vec![],
4445 spans: Spans::new(),
4446 };
4447
4448 let expr = Expr::SetComparison(SetComparison::new(
4449 Box::new(Expr::Column(Column::from_name("a"))),
4450 subquery,
4451 Operator::Gt,
4452 SetQuantifier::Any,
4453 ));
4454
4455 assert_eq!(format!("{expr}"), "a > ANY (<subquery>)");
4456 assert_eq!(format!("{}", expr.human_display()), "a > ANY (<subquery>)");
4457 }
4458
4459 #[test]
4460 fn test_schema_display_alias_with_relation() {
4461 assert_eq!(
4462 format!(
4463 "{}",
4464 SchemaDisplay(
4465 &lit(1).alias_qualified("table_name".into(), "column_name")
4466 )
4467 ),
4468 "table_name.column_name"
4469 );
4470 }
4471
4472 #[test]
4473 fn test_schema_display_alias_without_relation() {
4474 assert_eq!(
4475 format!(
4476 "{}",
4477 SchemaDisplay(&lit(1).alias_qualified(None::<&str>, "column_name"))
4478 ),
4479 "column_name"
4480 );
4481 }
4482
4483 #[test]
4484 fn test_unalias_nested_respects_user_metadata() {
4485 use std::collections::HashMap;
4486
4487 let base_expr = col("id");
4488
4489 let no_metadata = base_expr.clone().alias("alias");
4490 assert_eq!(no_metadata.unalias_nested().data, base_expr);
4491
4492 let Expr::Alias(empty_metadata_alias) = base_expr.clone().alias("alias") else {
4493 unreachable!();
4494 };
4495 let empty_metadata_alias = Expr::Alias(
4496 empty_metadata_alias.with_metadata(Some(FieldMetadata::default())),
4497 );
4498 assert_eq!(empty_metadata_alias.unalias_nested().data, base_expr);
4499
4500 let user_metadata = FieldMetadata::from(HashMap::from([(
4501 "some_key".to_string(),
4502 "some_value".to_string(),
4503 )]));
4504
4505 let Expr::Alias(user_alias) = base_expr.clone().alias("alias") else {
4506 unreachable!();
4507 };
4508 let user_alias =
4509 Expr::Alias(user_alias.with_metadata(Some(user_metadata.clone())));
4510 assert_eq!(user_alias.clone().unalias_nested().data, user_alias);
4511 }
4512
4513 fn wildcard_options(
4514 opt_ilike: Option<IlikeSelectItem>,
4515 opt_exclude: Option<ExcludeSelectItem>,
4516 opt_except: Option<ExceptSelectItem>,
4517 opt_replace: Option<PlannedReplaceSelectItem>,
4518 opt_rename: Option<RenameSelectItem>,
4519 ) -> WildcardOptions {
4520 WildcardOptions {
4521 ilike: opt_ilike,
4522 exclude: opt_exclude,
4523 except: opt_except,
4524 replace: opt_replace,
4525 rename: opt_rename,
4526 }
4527 }
4528
4529 #[test]
4530 fn test_size_of_expr() {
4531 assert_eq!(size_of::<Expr>(), 112);
4538 assert_eq!(size_of::<ScalarValue>(), 64);
4539 assert_eq!(size_of::<DataType>(), 24); assert_eq!(size_of::<Vec<Expr>>(), 24);
4541 assert_eq!(size_of::<Arc<Expr>>(), 8);
4542 }
4543
4544 #[test]
4545 fn test_accept_exprs() {
4546 fn accept_exprs<E: AsRef<Expr>>(_: &[E]) {}
4547
4548 let expr = || -> Expr { lit(1) };
4549
4550 let owned_exprs = vec![expr(), expr()];
4552 accept_exprs(&owned_exprs);
4553
4554 let udf = Expr::ScalarFunction(ScalarFunction {
4556 func: Arc::new(ScalarUDF::new_from_impl(TestUDF {})),
4557 args: vec![expr(), expr()],
4558 });
4559 let Expr::ScalarFunction(scalar) = &udf else {
4560 unreachable!()
4561 };
4562 accept_exprs(&scalar.args);
4563
4564 let mut collected_refs: Vec<&Expr> = scalar.args.iter().collect();
4566 collected_refs.extend(&owned_exprs);
4567 accept_exprs(&collected_refs);
4568
4569 #[derive(Debug, PartialEq, Eq, Hash)]
4571 struct TestUDF {}
4572 impl ScalarUDFImpl for TestUDF {
4573 fn name(&self) -> &str {
4574 unimplemented!()
4575 }
4576
4577 fn signature(&self) -> &Signature {
4578 unimplemented!()
4579 }
4580
4581 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
4582 unimplemented!()
4583 }
4584
4585 fn invoke_with_args(
4586 &self,
4587 _args: ScalarFunctionArgs,
4588 ) -> Result<ColumnarValue> {
4589 unimplemented!()
4590 }
4591 }
4592 }
4593
4594 mod intersect_metadata_tests {
4595 use super::super::intersect_metadata_for_union;
4596 use std::collections::HashMap;
4597
4598 #[test]
4599 fn all_branches_same_metadata() {
4600 let m1 = HashMap::from([("key".into(), "val".into())]);
4601 let m2 = HashMap::from([("key".into(), "val".into())]);
4602 let result = intersect_metadata_for_union([&m1, &m2]);
4603 assert_eq!(result, HashMap::from([("key".into(), "val".into())]));
4604 }
4605
4606 #[test]
4607 fn conflicting_metadata_dropped() {
4608 let m1 = HashMap::from([("key".into(), "a".into())]);
4609 let m2 = HashMap::from([("key".into(), "b".into())]);
4610 let result = intersect_metadata_for_union([&m1, &m2]);
4611 assert!(result.is_empty());
4612 }
4613
4614 #[test]
4615 fn empty_metadata_branch_skipped() {
4616 let m1 = HashMap::from([("key".into(), "val".into())]);
4617 let m2 = HashMap::new(); let result = intersect_metadata_for_union([&m1, &m2]);
4619 assert_eq!(result, HashMap::from([("key".into(), "val".into())]));
4620 }
4621
4622 #[test]
4623 fn empty_metadata_first_branch_skipped() {
4624 let m1 = HashMap::new();
4625 let m2 = HashMap::from([("key".into(), "val".into())]);
4626 let result = intersect_metadata_for_union([&m1, &m2]);
4627 assert_eq!(result, HashMap::from([("key".into(), "val".into())]));
4628 }
4629
4630 #[test]
4631 fn all_branches_empty_metadata() {
4632 let m1: HashMap<String, String> = HashMap::new();
4633 let m2: HashMap<String, String> = HashMap::new();
4634 let result = intersect_metadata_for_union([&m1, &m2]);
4635 assert!(result.is_empty());
4636 }
4637
4638 #[test]
4639 fn mixed_empty_and_conflicting() {
4640 let m1 = HashMap::from([("key".into(), "a".into())]);
4641 let m2 = HashMap::new();
4642 let m3 = HashMap::from([("key".into(), "b".into())]);
4643 let result = intersect_metadata_for_union([&m1, &m2, &m3]);
4644 assert!(result.is_empty());
4646 }
4647
4648 #[test]
4649 fn no_inputs() {
4650 let result = intersect_metadata_for_union(std::iter::empty::<
4651 &HashMap<String, String>,
4652 >());
4653 assert!(result.is_empty());
4654 }
4655 }
4656}