4949import org .apache .doris .nereids .trees .expressions .CaseWhen ;
5050import org .apache .doris .nereids .trees .expressions .Cast ;
5151import org .apache .doris .nereids .trees .expressions .ComparisonPredicate ;
52+ import org .apache .doris .nereids .trees .expressions .DereferenceExpression ;
5253import org .apache .doris .nereids .trees .expressions .Divide ;
5354import org .apache .doris .nereids .trees .expressions .EqualTo ;
5455import org .apache .doris .nereids .trees .expressions .ExprId ;
7475import org .apache .doris .nereids .trees .expressions .functions .agg .AggregateFunction ;
7576import org .apache .doris .nereids .trees .expressions .functions .agg .NullableAggregateFunction ;
7677import org .apache .doris .nereids .trees .expressions .functions .agg .SupportMultiDistinct ;
78+ import org .apache .doris .nereids .trees .expressions .functions .scalar .ElementAt ;
7779import org .apache .doris .nereids .trees .expressions .functions .scalar .Lambda ;
80+ import org .apache .doris .nereids .trees .expressions .functions .scalar .StructElement ;
7881import org .apache .doris .nereids .trees .expressions .functions .udf .AliasUdfBuilder ;
7982import org .apache .doris .nereids .trees .expressions .functions .udf .JavaUdaf ;
8083import org .apache .doris .nereids .trees .expressions .functions .udf .JavaUdf ;
9396import org .apache .doris .nereids .types .BooleanType ;
9497import org .apache .doris .nereids .types .DataType ;
9598import org .apache .doris .nereids .types .StringType ;
99+ import org .apache .doris .nereids .types .StructField ;
100+ import org .apache .doris .nereids .types .StructType ;
96101import org .apache .doris .nereids .types .TinyIntType ;
97102import org .apache .doris .nereids .util .ExpressionUtils ;
98103import org .apache .doris .nereids .util .TypeCoercionUtils ;
@@ -240,6 +245,25 @@ public Expression visitUnboundAlias(UnboundAlias unboundAlias, ExpressionRewrite
240245 }
241246 }
242247
248+ @ Override
249+ public Expression visitDereferenceExpression (DereferenceExpression dereferenceExpression ,
250+ ExpressionRewriteContext context ) {
251+ Expression expression = dereferenceExpression .child (0 ).accept (this , context );
252+ DataType dataType = expression .getDataType ();
253+ if (dataType .isStructType ()) {
254+ StructType structType = (StructType ) dataType ;
255+ StructField field = structType .getField (dereferenceExpression .fieldName );
256+ if (field != null ) {
257+ return new StructElement (expression , dereferenceExpression .child (1 ));
258+ }
259+ } else if (dataType .isMapType ()) {
260+ return new ElementAt (expression , dereferenceExpression .child (1 ));
261+ } else if (dataType .isVariantType ()) {
262+ return new ElementAt (expression , dereferenceExpression .child (1 ));
263+ }
264+ throw new AnalysisException ("Can not dereference field: " + dereferenceExpression .fieldName );
265+ }
266+
243267 @ Override
244268 public Expression visitUnboundSlot (UnboundSlot unboundSlot , ExpressionRewriteContext context ) {
245269 Optional <Scope > outerScope = getScope ().getOuterScope ();
@@ -913,13 +937,13 @@ protected List<? extends Expression> bindSlotByThisScope(UnboundSlot unboundSlot
913937 return bindSlotByScope (unboundSlot , getScope ());
914938 }
915939
916- protected List <Slot > bindExactSlotsByThisScope (UnboundSlot unboundSlot , Scope scope ) {
917- List <Slot > candidates = bindSlotByScope (unboundSlot , scope );
940+ protected List <Expression > bindExactSlotsByThisScope (UnboundSlot unboundSlot , Scope scope ) {
941+ List <Expression > candidates = bindSlotByScope (unboundSlot , scope );
918942 if (candidates .size () == 1 ) {
919943 return candidates ;
920944 }
921- List <Slot > extractSlots = Utils .filterImmutableList (candidates , bound ->
922- unboundSlot .getNameParts ().size () == bound .getQualifier ().size () + 1
945+ List <Expression > extractSlots = Utils .filterImmutableList (candidates , bound ->
946+ bound instanceof Slot && unboundSlot .getNameParts ().size () == (( Slot ) bound ) .getQualifier ().size () + 1
923947 );
924948 // we should return origin candidates slots if extract slots is empty,
925949 // and then throw an ambiguous exception
@@ -938,33 +962,137 @@ private List<Slot> addSqlIndexInfo(List<Slot> slots, Optional<Pair<Integer, Inte
938962 }
939963
940964 /** bindSlotByScope */
941- public List <Slot > bindSlotByScope (UnboundSlot unboundSlot , Scope scope ) {
965+ public List <Expression > bindSlotByScope (UnboundSlot unboundSlot , Scope scope ) {
942966 List <String > nameParts = unboundSlot .getNameParts ();
943967 Optional <Pair <Integer , Integer >> idxInSql = unboundSlot .getIndexInSqlString ();
944968 int namePartSize = nameParts .size ();
945969 switch (namePartSize ) {
946970 // column
947971 case 1 : {
948- return addSqlIndexInfo ( bindSingleSlotByName ( nameParts . get ( 0 ), scope ) , idxInSql );
972+ return ( List < Expression >) bindExpressionByColumn ( unboundSlot , nameParts , idxInSql , scope );
949973 }
950974 // table.column
951975 case 2 : {
952- return addSqlIndexInfo ( bindSingleSlotByTable ( nameParts . get ( 0 ), nameParts . get ( 1 ), scope ) , idxInSql );
976+ return ( List < Expression >) bindExpressionByTableColumn ( unboundSlot , nameParts , idxInSql , scope );
953977 }
954978 // db.table.column
955979 case 3 : {
956- return addSqlIndexInfo (bindSingleSlotByDb (nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), scope ),
957- idxInSql );
980+ return (List <Expression >) bindExpressionByDbTableColumn (unboundSlot , nameParts , idxInSql , scope );
958981 }
959982 // catalog.db.table.column
960- case 4 : {
961- return addSqlIndexInfo (bindSingleSlotByCatalog (
962- nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), nameParts .get (3 ), scope ), idxInSql );
963- }
964983 default : {
965- throw new AnalysisException ("Not supported name: " + StringUtils .join (nameParts , "." ));
984+ return (List <Expression >) bindExpressionByCatalogDbTableColumn (unboundSlot , nameParts , idxInSql , scope );
985+ }
986+ }
987+ }
988+
989+ private List <? extends Expression > bindExpressionByCatalogDbTableColumn (
990+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
991+ List <Slot > slots = addSqlIndexInfo (bindSingleSlotByCatalog (
992+ nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), nameParts .get (3 ), scope ), idxInSql );
993+ if (slots .isEmpty ()) {
994+ return bindExpressionByDbTableColumn (unboundSlot , nameParts , idxInSql , scope );
995+ } else if (slots .size () > 1 ) {
996+ return slots ;
997+ }
998+ if (nameParts .size () == 4 ) {
999+ return slots ;
1000+ }
1001+
1002+ Optional <Expression > expression = bindNestedFields (
1003+ unboundSlot , slots .get (0 ), nameParts .subList (4 , nameParts .size ())
1004+ );
1005+ if (!expression .isPresent ()) {
1006+ return slots ;
1007+ }
1008+ return ImmutableList .of (expression .get ());
1009+ }
1010+
1011+ private List <? extends Expression > bindExpressionByDbTableColumn (
1012+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1013+ List <Slot > slots = addSqlIndexInfo (
1014+ bindSingleSlotByDb (nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), scope ), idxInSql );
1015+ if (slots .isEmpty ()) {
1016+ return bindExpressionByTableColumn (unboundSlot , nameParts , idxInSql , scope );
1017+ } else if (slots .size () > 1 ) {
1018+ return slots ;
1019+ }
1020+ if (nameParts .size () == 3 ) {
1021+ return slots ;
1022+ }
1023+
1024+ Optional <Expression > expression = bindNestedFields (
1025+ unboundSlot , slots .get (0 ), nameParts .subList (3 , nameParts .size ())
1026+ );
1027+ if (!expression .isPresent ()) {
1028+ return slots ;
1029+ }
1030+ return ImmutableList .of (expression .get ());
1031+ }
1032+
1033+ private List <? extends Expression > bindExpressionByTableColumn (
1034+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1035+ List <Slot > slots = addSqlIndexInfo (bindSingleSlotByTable (nameParts .get (0 ), nameParts .get (1 ), scope ), idxInSql );
1036+ if (slots .isEmpty ()) {
1037+ return bindExpressionByColumn (unboundSlot , nameParts , idxInSql , scope );
1038+ } else if (slots .size () > 1 ) {
1039+ return slots ;
1040+ }
1041+ if (nameParts .size () == 2 ) {
1042+ return slots ;
1043+ }
1044+
1045+ Optional <Expression > expression = bindNestedFields (
1046+ unboundSlot , slots .get (0 ), nameParts .subList (2 , nameParts .size ())
1047+ );
1048+ if (!expression .isPresent ()) {
1049+ return slots ;
1050+ }
1051+ return ImmutableList .of (expression .get ());
1052+ }
1053+
1054+ private List <? extends Expression > bindExpressionByColumn (
1055+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1056+ List <Slot > slots = addSqlIndexInfo (bindSingleSlotByName (nameParts .get (0 ), scope ), idxInSql );
1057+ if (slots .size () != 1 ) {
1058+ return slots ;
1059+ }
1060+ if (nameParts .size () == 1 ) {
1061+ return slots ;
1062+ }
1063+ Optional <Expression > expression = bindNestedFields (
1064+ unboundSlot , slots .get (0 ), nameParts .subList (1 , nameParts .size ())
1065+ );
1066+ if (!expression .isPresent ()) {
1067+ return slots ;
1068+ }
1069+ return ImmutableList .of (expression .get ());
1070+ }
1071+
1072+ private Optional <Expression > bindNestedFields (UnboundSlot unboundSlot , Slot slot , List <String > fieldNames ) {
1073+ Expression expression = slot ;
1074+ String lastFieldName = slot .getName ();
1075+ for (String fieldName : fieldNames ) {
1076+ DataType dataType = expression .getDataType ();
1077+ if (dataType .isStructType ()) {
1078+ StructType structType = (StructType ) dataType ;
1079+ StructField field = structType .getField (fieldName );
1080+ if (field == null ) {
1081+ throw new AnalysisException ("No such struct field '" + fieldName + "' in '" + lastFieldName + "'" );
1082+ }
1083+ lastFieldName = fieldName ;
1084+ expression = new StructElement (expression , new StringLiteral (fieldName ));
1085+ continue ;
1086+ } else if (dataType .isMapType ()) {
1087+ expression = new ElementAt (expression , new StringLiteral (fieldName ));
1088+ continue ;
1089+ } else if (dataType .isVariantType ()) {
1090+ expression = new ElementAt (expression , new StringLiteral (fieldName ));
1091+ continue ;
9661092 }
1093+ throw new AnalysisException ("No such field '" + fieldName + "' in '" + lastFieldName + "'" );
9671094 }
1095+ return Optional .of (new Alias (expression ));
9681096 }
9691097
9701098 public static boolean sameTableName (String boundSlot , String unboundSlot ) {
0 commit comments