@@ -21,14 +21,14 @@ use datafusion_expr::planner::{
2121 PlannerResult , RawBinaryExpr , RawDictionaryExpr , RawFieldAccessExpr ,
2222} ;
2323use sqlparser:: ast:: {
24- BinaryOperator , CastFormat , CastKind , DataType as SQLDataType , DictionaryField ,
25- Expr as SQLExpr , ExprWithAlias as SQLExprWithAlias , MapEntry , StructField , Subscript ,
26- TrimWhereField , Value ,
24+ AccessExpr , BinaryOperator , CastFormat , CastKind , DataType as SQLDataType ,
25+ DictionaryField , Expr as SQLExpr , ExprWithAlias as SQLExprWithAlias , MapEntry ,
26+ StructField , Subscript , TrimWhereField , Value ,
2727} ;
2828
2929use datafusion_common:: {
30- internal_datafusion_err, internal_err, not_impl_err, plan_err, DFSchema , Result ,
31- ScalarValue ,
30+ internal_datafusion_err, internal_err, not_impl_err, plan_err, Column , DFSchema ,
31+ Result , ScalarValue ,
3232} ;
3333use datafusion_expr:: expr:: ScalarFunction ;
3434use datafusion_expr:: expr:: { InList , WildcardOptions } ;
@@ -236,14 +236,14 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
236236 self . sql_identifier_to_expr ( id, schema, planner_context)
237237 }
238238
239- SQLExpr :: MapAccess { .. } => {
240- not_impl_err ! ( "Map Access" )
241- }
242-
243239 // <expr>["foo"], <expr>[4] or <expr>[4:5]
244- SQLExpr :: Subscript { expr, subscript } => {
245- self . sql_subscript_to_expr ( * expr, subscript, schema, planner_context)
246- }
240+ SQLExpr :: CompoundFieldAccess { root, access_chain } => self
241+ . sql_compound_field_access_to_expr (
242+ * root,
243+ access_chain,
244+ schema,
245+ planner_context,
246+ ) ,
247247
248248 SQLExpr :: CompoundIdentifier ( ids) => {
249249 self . sql_compound_identifier_to_expr ( ids, schema, planner_context)
@@ -984,84 +984,141 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
984984 Ok ( Expr :: Cast ( Cast :: new ( Box :: new ( expr) , dt) ) )
985985 }
986986
987- fn sql_subscript_to_expr (
987+ fn sql_compound_field_access_to_expr (
988988 & self ,
989- expr : SQLExpr ,
990- subscript : Box < Subscript > ,
989+ root : SQLExpr ,
990+ access_chain : Vec < AccessExpr > ,
991991 schema : & DFSchema ,
992992 planner_context : & mut PlannerContext ,
993993 ) -> Result < Expr > {
994- let expr = self . sql_expr_to_logical_expr ( expr, schema, planner_context) ?;
995-
996- let field_access = match * subscript {
997- Subscript :: Index { index } => {
998- // index can be a name, in which case it is a named field access
999- match index {
1000- SQLExpr :: Value (
1001- Value :: SingleQuotedString ( s) | Value :: DoubleQuotedString ( s) ,
1002- ) => GetFieldAccess :: NamedStructField {
1003- name : ScalarValue :: from ( s) ,
1004- } ,
1005- SQLExpr :: JsonAccess { .. } => {
1006- return not_impl_err ! ( "JsonAccess" ) ;
994+ let mut root = self . sql_expr_to_logical_expr ( root, schema, planner_context) ?;
995+ let fields = access_chain
996+ . into_iter ( )
997+ . map ( |field| match field {
998+ AccessExpr :: Subscript ( subscript) => {
999+ match subscript {
1000+ Subscript :: Index { index } => {
1001+ // index can be a name, in which case it is a named field access
1002+ match index {
1003+ SQLExpr :: Value (
1004+ Value :: SingleQuotedString ( s)
1005+ | Value :: DoubleQuotedString ( s) ,
1006+ ) => Ok ( Some ( GetFieldAccess :: NamedStructField {
1007+ name : ScalarValue :: from ( s) ,
1008+ } ) ) ,
1009+ SQLExpr :: JsonAccess { .. } => {
1010+ not_impl_err ! ( "JsonAccess" )
1011+ }
1012+ // otherwise treat like a list index
1013+ _ => Ok ( Some ( GetFieldAccess :: ListIndex {
1014+ key : Box :: new ( self . sql_expr_to_logical_expr (
1015+ index,
1016+ schema,
1017+ planner_context,
1018+ ) ?) ,
1019+ } ) ) ,
1020+ }
1021+ }
1022+ Subscript :: Slice {
1023+ lower_bound,
1024+ upper_bound,
1025+ stride,
1026+ } => {
1027+ // Means access like [:2]
1028+ let lower_bound = if let Some ( lower_bound) = lower_bound {
1029+ self . sql_expr_to_logical_expr (
1030+ lower_bound,
1031+ schema,
1032+ planner_context,
1033+ )
1034+ } else {
1035+ not_impl_err ! ( "Slice subscript requires a lower bound" )
1036+ } ?;
1037+
1038+ // means access like [2:]
1039+ let upper_bound = if let Some ( upper_bound) = upper_bound {
1040+ self . sql_expr_to_logical_expr (
1041+ upper_bound,
1042+ schema,
1043+ planner_context,
1044+ )
1045+ } else {
1046+ not_impl_err ! ( "Slice subscript requires an upper bound" )
1047+ } ?;
1048+
1049+ // stride, default to 1
1050+ let stride = if let Some ( stride) = stride {
1051+ self . sql_expr_to_logical_expr (
1052+ stride,
1053+ schema,
1054+ planner_context,
1055+ ) ?
1056+ } else {
1057+ lit ( 1i64 )
1058+ } ;
1059+
1060+ Ok ( Some ( GetFieldAccess :: ListRange {
1061+ start : Box :: new ( lower_bound) ,
1062+ stop : Box :: new ( upper_bound) ,
1063+ stride : Box :: new ( stride) ,
1064+ } ) )
1065+ }
10071066 }
1008- // otherwise treat like a list index
1009- _ => GetFieldAccess :: ListIndex {
1010- key : Box :: new ( self . sql_expr_to_logical_expr (
1011- index,
1012- schema,
1013- planner_context,
1014- ) ?) ,
1015- } ,
10161067 }
1017- }
1018- Subscript :: Slice {
1019- lower_bound,
1020- upper_bound,
1021- stride,
1022- } => {
1023- // Means access like [:2]
1024- let lower_bound = if let Some ( lower_bound) = lower_bound {
1025- self . sql_expr_to_logical_expr ( lower_bound, schema, planner_context)
1026- } else {
1027- not_impl_err ! ( "Slice subscript requires a lower bound" )
1028- } ?;
1029-
1030- // means access like [2:]
1031- let upper_bound = if let Some ( upper_bound) = upper_bound {
1032- self . sql_expr_to_logical_expr ( upper_bound, schema, planner_context)
1033- } else {
1034- not_impl_err ! ( "Slice subscript requires an upper bound" )
1035- } ?;
1036-
1037- // stride, default to 1
1038- let stride = if let Some ( stride) = stride {
1039- self . sql_expr_to_logical_expr ( stride, schema, planner_context) ?
1040- } else {
1041- lit ( 1i64 )
1042- } ;
1043-
1044- GetFieldAccess :: ListRange {
1045- start : Box :: new ( lower_bound) ,
1046- stop : Box :: new ( upper_bound) ,
1047- stride : Box :: new ( stride) ,
1068+ AccessExpr :: Dot ( expr) => {
1069+ let expr =
1070+ self . sql_expr_to_logical_expr ( expr, schema, planner_context) ?;
1071+ match expr {
1072+ Expr :: Column ( Column { name, relation } ) => {
1073+ if let Some ( relation) = & relation {
1074+ // If the first part of the dot access is a column reference, we should
1075+ // check if the column is from the same table as the root expression.
1076+ // If it is, we should replace the root expression with the column reference.
1077+ // Otherwise, we should treat the dot access as a named field access.
1078+ if relation. table ( ) == root. schema_name ( ) . to_string ( ) {
1079+ root = Expr :: Column ( Column {
1080+ name,
1081+ relation : Some ( relation. clone ( ) ) ,
1082+ } ) ;
1083+ Ok ( None )
1084+ } else {
1085+ plan_err ! (
1086+ "table name mismatch: {} != {}" ,
1087+ relation. table( ) ,
1088+ root. schema_name( )
1089+ )
1090+ }
1091+ } else {
1092+ Ok ( Some ( GetFieldAccess :: NamedStructField {
1093+ name : ScalarValue :: from ( name) ,
1094+ } ) )
1095+ }
1096+ }
1097+ _ => not_impl_err ! (
1098+ "Dot access not supported for non-column expr: {expr:?}"
1099+ ) ,
1100+ }
10481101 }
1049- }
1050- } ;
1102+ } )
1103+ . collect :: < Result < Vec < _ > > > ( ) ? ;
10511104
1052- let mut field_access_expr = RawFieldAccessExpr { expr, field_access } ;
1053- for planner in self . context_provider . get_expr_planners ( ) {
1054- match planner. plan_field_access ( field_access_expr, schema) ? {
1055- PlannerResult :: Planned ( expr) => return Ok ( expr) ,
1056- PlannerResult :: Original ( expr) => {
1057- field_access_expr = expr;
1105+ fields
1106+ . into_iter ( )
1107+ . flatten ( )
1108+ . try_fold ( root, |expr, field_access| {
1109+ let mut field_access_expr = RawFieldAccessExpr { expr, field_access } ;
1110+ for planner in self . context_provider . get_expr_planners ( ) {
1111+ match planner. plan_field_access ( field_access_expr, schema) ? {
1112+ PlannerResult :: Planned ( expr) => return Ok ( expr) ,
1113+ PlannerResult :: Original ( expr) => {
1114+ field_access_expr = expr;
1115+ }
1116+ }
10581117 }
1059- }
1060- }
1061-
1062- not_impl_err ! (
1063- "GetFieldAccess not supported by ExprPlanner: {field_access_expr:?}"
1064- )
1118+ not_impl_err ! (
1119+ "GetFieldAccess not supported by ExprPlanner: {field_access_expr:?}"
1120+ )
1121+ } )
10651122 }
10661123}
10671124
0 commit comments