diff --git a/datafusion/expr/src/expr.rs b/datafusion/expr/src/expr.rs index 0de4a87b941b..5fbc80fc38d2 100644 --- a/datafusion/expr/src/expr.rs +++ b/datafusion/expr/src/expr.rs @@ -307,7 +307,7 @@ pub enum Expr { /// /// This expr has to be resolved to a list of columns before translating logical /// plan into physical plan. - Wildcard { qualifier: Option }, + Wildcard { qualifier: Option }, /// List of grouping set expressions. Only valid in the context of an aggregate /// GROUP BY expression list GroupingSet(GroupingSet), diff --git a/datafusion/expr/src/utils.rs b/datafusion/expr/src/utils.rs index 6baabfcc7130..1c0c8fe47880 100644 --- a/datafusion/expr/src/utils.rs +++ b/datafusion/expr/src/utils.rs @@ -318,7 +318,7 @@ fn get_excluded_columns( opt_exclude: Option<&ExcludeSelectItem>, opt_except: Option<&ExceptSelectItem>, schema: &DFSchema, - qualifier: &Option, + qualifier: Option<&TableReference>, ) -> Result> { let mut idents = vec![]; if let Some(excepts) = opt_except { @@ -343,8 +343,7 @@ fn get_excluded_columns( let mut result = vec![]; for ident in unique_idents.into_iter() { let col_name = ident.value.as_str(); - let (qualifier, field) = - schema.qualified_field_with_name(qualifier.as_ref(), col_name)?; + let (qualifier, field) = schema.qualified_field_with_name(qualifier, col_name)?; result.push(Column::from((qualifier, field))); } Ok(result) @@ -406,7 +405,7 @@ pub fn expand_wildcard( .. }) = wildcard_options { - get_excluded_columns(opt_exclude.as_ref(), opt_except.as_ref(), schema, &None)? + get_excluded_columns(opt_exclude.as_ref(), opt_except.as_ref(), schema, None)? } else { vec![] }; @@ -417,12 +416,11 @@ pub fn expand_wildcard( /// Resolves an `Expr::Wildcard` to a collection of qualified `Expr::Column`'s. pub fn expand_qualified_wildcard( - qualifier: &str, + qualifier: &TableReference, schema: &DFSchema, wildcard_options: Option<&WildcardAdditionalOptions>, ) -> Result> { - let qualifier = TableReference::from(qualifier); - let qualified_indices = schema.fields_indices_with_qualified(&qualifier); + let qualified_indices = schema.fields_indices_with_qualified(qualifier); let projected_func_dependencies = schema .functional_dependencies() .project_functional_dependencies(&qualified_indices, qualified_indices.len()); @@ -445,7 +443,7 @@ pub fn expand_qualified_wildcard( opt_exclude.as_ref(), opt_except.as_ref(), schema, - &Some(qualifier), + Some(qualifier), )? } else { vec![] diff --git a/datafusion/proto/proto/datafusion.proto b/datafusion/proto/proto/datafusion.proto index 50356d5b6052..0cf043e40a50 100644 --- a/datafusion/proto/proto/datafusion.proto +++ b/datafusion/proto/proto/datafusion.proto @@ -369,7 +369,7 @@ message LogicalExprNode { } message Wildcard { - string qualifier = 1; + TableReference qualifier = 1; } message PlaceholderNode { diff --git a/datafusion/proto/src/generated/pbjson.rs b/datafusion/proto/src/generated/pbjson.rs index 8cca0fe4a876..2d8ec861199e 100644 --- a/datafusion/proto/src/generated/pbjson.rs +++ b/datafusion/proto/src/generated/pbjson.rs @@ -19967,12 +19967,12 @@ impl serde::Serialize for Wildcard { { use serde::ser::SerializeStruct; let mut len = 0; - if !self.qualifier.is_empty() { + if self.qualifier.is_some() { len += 1; } let mut struct_ser = serializer.serialize_struct("datafusion.Wildcard", len)?; - if !self.qualifier.is_empty() { - struct_ser.serialize_field("qualifier", &self.qualifier)?; + if let Some(v) = self.qualifier.as_ref() { + struct_ser.serialize_field("qualifier", v)?; } struct_ser.end() } @@ -20038,12 +20038,12 @@ impl<'de> serde::Deserialize<'de> for Wildcard { if qualifier__.is_some() { return Err(serde::de::Error::duplicate_field("qualifier")); } - qualifier__ = Some(map_.next_value()?); + qualifier__ = map_.next_value()?; } } } Ok(Wildcard { - qualifier: qualifier__.unwrap_or_default(), + qualifier: qualifier__, }) } } diff --git a/datafusion/proto/src/generated/prost.rs b/datafusion/proto/src/generated/prost.rs index 56f14982923d..5f368fa62d44 100644 --- a/datafusion/proto/src/generated/prost.rs +++ b/datafusion/proto/src/generated/prost.rs @@ -592,8 +592,8 @@ pub mod logical_expr_node { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Wildcard { - #[prost(string, tag = "1")] - pub qualifier: ::prost::alloc::string::String, + #[prost(message, optional, tag = "1")] + pub qualifier: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/datafusion/proto/src/logical_plan/from_proto.rs b/datafusion/proto/src/logical_plan/from_proto.rs index ba0e708218cf..fcfde8f6d4c9 100644 --- a/datafusion/proto/src/logical_plan/from_proto.rs +++ b/datafusion/proto/src/logical_plan/from_proto.rs @@ -593,13 +593,10 @@ pub fn parse_expr( parse_exprs(&in_list.list, registry, codec)?, in_list.negated, ))), - ExprType::Wildcard(protobuf::Wildcard { qualifier }) => Ok(Expr::Wildcard { - qualifier: if qualifier.is_empty() { - None - } else { - Some(qualifier.clone()) - }, - }), + ExprType::Wildcard(protobuf::Wildcard { qualifier }) => { + let qualifier = qualifier.to_owned().map(|x| x.try_into()).transpose()?; + Ok(Expr::Wildcard { qualifier }) + } ExprType::ScalarUdfExpr(protobuf::ScalarUdfExprNode { fun_name, args, diff --git a/datafusion/proto/src/logical_plan/to_proto.rs b/datafusion/proto/src/logical_plan/to_proto.rs index 08999effa4b1..7c5a13f246fe 100644 --- a/datafusion/proto/src/logical_plan/to_proto.rs +++ b/datafusion/proto/src/logical_plan/to_proto.rs @@ -618,7 +618,7 @@ pub fn serialize_expr( } Expr::Wildcard { qualifier } => protobuf::LogicalExprNode { expr_type: Some(ExprType::Wildcard(protobuf::Wildcard { - qualifier: qualifier.clone().unwrap_or("".to_string()), + qualifier: qualifier.to_owned().map(|x| x.into()), })), }, Expr::ScalarSubquery(_) diff --git a/datafusion/sql/src/select.rs b/datafusion/sql/src/select.rs index 0fa266e4e01d..102b47216e7e 100644 --- a/datafusion/sql/src/select.rs +++ b/datafusion/sql/src/select.rs @@ -18,7 +18,9 @@ use std::collections::HashSet; use std::sync::Arc; -use crate::planner::{ContextProvider, PlannerContext, SqlToRel}; +use crate::planner::{ + idents_to_table_reference, ContextProvider, PlannerContext, SqlToRel, +}; use crate::utils::{ check_columns_satisfy_exprs, extract_aliases, rebase_expr, recursive_transform_unnest, resolve_aliases_to_exprs, resolve_columns, @@ -475,9 +477,9 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { Ok(expanded_exprs) } } - SelectItem::QualifiedWildcard(ref object_name, options) => { + SelectItem::QualifiedWildcard(object_name, options) => { Self::check_wildcard_options(&options)?; - let qualifier = format!("{object_name}"); + let qualifier = idents_to_table_reference(object_name.0, false)?; // do not expand from outer schema let expanded_exprs = expand_qualified_wildcard( &qualifier,