5050import org .apache .doris .nereids .trees .expressions .Cast ;
5151import org .apache .doris .nereids .trees .expressions .ComparisonPredicate ;
5252import org .apache .doris .nereids .trees .expressions .CompoundPredicate ;
53+ import org .apache .doris .nereids .trees .expressions .DereferenceExpression ;
5354import org .apache .doris .nereids .trees .expressions .Divide ;
5455import org .apache .doris .nereids .trees .expressions .EqualTo ;
5556import org .apache .doris .nereids .trees .expressions .ExprId ;
7576import org .apache .doris .nereids .trees .expressions .functions .agg .AggregateFunction ;
7677import org .apache .doris .nereids .trees .expressions .functions .agg .NullableAggregateFunction ;
7778import org .apache .doris .nereids .trees .expressions .functions .agg .SupportMultiDistinct ;
79+ import org .apache .doris .nereids .trees .expressions .functions .scalar .Cardinality ;
80+ import org .apache .doris .nereids .trees .expressions .functions .scalar .ElementAt ;
7881import org .apache .doris .nereids .trees .expressions .functions .scalar .Lambda ;
82+ import org .apache .doris .nereids .trees .expressions .functions .scalar .MapKeys ;
83+ import org .apache .doris .nereids .trees .expressions .functions .scalar .MapSize ;
84+ import org .apache .doris .nereids .trees .expressions .functions .scalar .MapValues ;
85+ import org .apache .doris .nereids .trees .expressions .functions .scalar .StructElement ;
7986import org .apache .doris .nereids .trees .expressions .functions .udf .AliasUdfBuilder ;
8087import org .apache .doris .nereids .trees .expressions .functions .udf .JavaUdaf ;
8188import org .apache .doris .nereids .trees .expressions .functions .udf .JavaUdf ;
94101import org .apache .doris .nereids .types .BooleanType ;
95102import org .apache .doris .nereids .types .DataType ;
96103import org .apache .doris .nereids .types .StringType ;
104+ import org .apache .doris .nereids .types .StructField ;
105+ import org .apache .doris .nereids .types .StructType ;
97106import org .apache .doris .nereids .types .TinyIntType ;
98107import org .apache .doris .nereids .util .ExpressionUtils ;
99108import org .apache .doris .nereids .util .TypeCoercionUtils ;
@@ -256,6 +265,35 @@ public Expression visitUnboundAlias(UnboundAlias unboundAlias, ExpressionRewrite
256265 }
257266 }
258267
268+ @ Override
269+ public Expression visitDereferenceExpression (DereferenceExpression dereferenceExpression ,
270+ ExpressionRewriteContext context ) {
271+ Expression expression = dereferenceExpression .child (0 ).accept (this , context );
272+ DataType dataType = expression .getDataType ();
273+ if (dataType .isStructType ()) {
274+ StructType structType = (StructType ) dataType ;
275+ StructField field = structType .getField (dereferenceExpression .fieldName );
276+ if (field != null ) {
277+ return new StructElement (expression , dereferenceExpression .child (1 ));
278+ }
279+ } else if (dataType .isArrayType ()) {
280+ if (dereferenceExpression .fieldName .equalsIgnoreCase ("size" )) {
281+ return new Cardinality (expression );
282+ }
283+ } else if (dataType .isMapType ()) {
284+ if (dereferenceExpression .fieldName .equalsIgnoreCase ("size" )) {
285+ return new MapSize (expression );
286+ } else if (dereferenceExpression .fieldName .equalsIgnoreCase ("keys" )) {
287+ return new MapKeys (expression );
288+ } else if (dereferenceExpression .fieldName .equalsIgnoreCase ("values" )) {
289+ return new MapValues (expression );
290+ } else {
291+ return new ElementAt (expression , dereferenceExpression .child (1 ));
292+ }
293+ }
294+ throw new AnalysisException ("Can not dereference field: " + dereferenceExpression .fieldName );
295+ }
296+
259297 @ Override
260298 public Expression visitUnboundSlot (UnboundSlot unboundSlot , ExpressionRewriteContext context ) {
261299 Optional <Scope > outerScope = getScope ().getOuterScope ();
@@ -937,13 +975,13 @@ protected List<? extends Expression> bindSlotByThisScope(UnboundSlot unboundSlot
937975 return bindSlotByScope (unboundSlot , getScope ());
938976 }
939977
940- protected List <Slot > bindExactSlotsByThisScope (UnboundSlot unboundSlot , Scope scope ) {
941- List <Slot > candidates = bindSlotByScope (unboundSlot , scope );
978+ protected List <Expression > bindExactSlotsByThisScope (UnboundSlot unboundSlot , Scope scope ) {
979+ List <Expression > candidates = bindSlotByScope (unboundSlot , scope );
942980 if (candidates .size () == 1 ) {
943981 return candidates ;
944982 }
945- List <Slot > extractSlots = Utils .filterImmutableList (candidates , bound ->
946- unboundSlot .getNameParts ().size () == bound .getQualifier ().size () + 1
983+ List <Expression > extractSlots = Utils .filterImmutableList (candidates , bound ->
984+ bound instanceof Slot && unboundSlot .getNameParts ().size () == (( Slot ) bound ) .getQualifier ().size () + 1
947985 );
948986 // we should return origin candidates slots if extract slots is empty,
949987 // and then throw an ambiguous exception
@@ -962,33 +1000,150 @@ private List<Slot> addSqlIndexInfo(List<Slot> slots, Optional<Pair<Integer, Inte
9621000 }
9631001
9641002 /** bindSlotByScope */
965- public List <Slot > bindSlotByScope (UnboundSlot unboundSlot , Scope scope ) {
1003+ public List <Expression > bindSlotByScope (UnboundSlot unboundSlot , Scope scope ) {
9661004 List <String > nameParts = unboundSlot .getNameParts ();
9671005 Optional <Pair <Integer , Integer >> idxInSql = unboundSlot .getIndexInSqlString ();
9681006 int namePartSize = nameParts .size ();
9691007 switch (namePartSize ) {
9701008 // column
9711009 case 1 : {
972- return addSqlIndexInfo ( bindSingleSlotByName ( nameParts . get ( 0 ), scope ) , idxInSql );
1010+ return ( List < Expression >) bindExpressionByColumn ( unboundSlot , nameParts , idxInSql , scope );
9731011 }
9741012 // table.column
9751013 case 2 : {
976- return addSqlIndexInfo ( bindSingleSlotByTable ( nameParts . get ( 0 ), nameParts . get ( 1 ), scope ) , idxInSql );
1014+ return ( List < Expression >) bindExpressionByTableColumn ( unboundSlot , nameParts , idxInSql , scope );
9771015 }
9781016 // db.table.column
9791017 case 3 : {
980- return addSqlIndexInfo (bindSingleSlotByDb (nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), scope ),
981- idxInSql );
1018+ return (List <Expression >) bindExpressionByDbTableColumn (unboundSlot , nameParts , idxInSql , scope );
9821019 }
9831020 // catalog.db.table.column
984- case 4 : {
985- return addSqlIndexInfo (bindSingleSlotByCatalog (
986- nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), nameParts .get (3 ), scope ), idxInSql );
987- }
9881021 default : {
989- throw new AnalysisException ("Not supported name: " + StringUtils .join (nameParts , "." ));
1022+ return (List <Expression >) bindExpressionByCatalogDbTableColumn (unboundSlot , nameParts , idxInSql , scope );
1023+ }
1024+ }
1025+ }
1026+
1027+ private List <? extends Expression > bindExpressionByCatalogDbTableColumn (
1028+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1029+ List <Slot > slots = addSqlIndexInfo (bindSingleSlotByCatalog (
1030+ nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), nameParts .get (3 ), scope ), idxInSql );
1031+ if (slots .isEmpty ()) {
1032+ return bindExpressionByDbTableColumn (unboundSlot , nameParts , idxInSql , scope );
1033+ } else if (slots .size () > 1 ) {
1034+ return slots ;
1035+ }
1036+ if (nameParts .size () == 4 ) {
1037+ return slots ;
1038+ }
1039+
1040+ Optional <Expression > expression = bindNestedFields (
1041+ unboundSlot , slots .get (0 ), nameParts .subList (4 , nameParts .size ())
1042+ );
1043+ if (!expression .isPresent ()) {
1044+ return slots ;
1045+ }
1046+ return ImmutableList .of (expression .get ());
1047+ }
1048+
1049+ private List <? extends Expression > bindExpressionByDbTableColumn (
1050+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1051+ List <Slot > slots = addSqlIndexInfo (
1052+ bindSingleSlotByDb (nameParts .get (0 ), nameParts .get (1 ), nameParts .get (2 ), scope ), idxInSql );
1053+ if (slots .isEmpty ()) {
1054+ return bindExpressionByTableColumn (unboundSlot , nameParts , idxInSql , scope );
1055+ } else if (slots .size () > 1 ) {
1056+ return slots ;
1057+ }
1058+ if (nameParts .size () == 3 ) {
1059+ return slots ;
1060+ }
1061+
1062+ Optional <Expression > expression = bindNestedFields (
1063+ unboundSlot , slots .get (0 ), nameParts .subList (3 , nameParts .size ())
1064+ );
1065+ if (!expression .isPresent ()) {
1066+ return slots ;
1067+ }
1068+ return ImmutableList .of (expression .get ());
1069+ }
1070+
1071+ private List <? extends Expression > bindExpressionByTableColumn (
1072+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1073+ List <Slot > slots = addSqlIndexInfo (bindSingleSlotByTable (nameParts .get (0 ), nameParts .get (1 ), scope ), idxInSql );
1074+ if (slots .isEmpty ()) {
1075+ return bindExpressionByColumn (unboundSlot , nameParts , idxInSql , scope );
1076+ } else if (slots .size () > 1 ) {
1077+ return slots ;
1078+ }
1079+ if (nameParts .size () == 2 ) {
1080+ return slots ;
1081+ }
1082+
1083+ Optional <Expression > expression = bindNestedFields (
1084+ unboundSlot , slots .get (0 ), nameParts .subList (2 , nameParts .size ())
1085+ );
1086+ if (!expression .isPresent ()) {
1087+ return slots ;
1088+ }
1089+ return ImmutableList .of (expression .get ());
1090+ }
1091+
1092+ private List <? extends Expression > bindExpressionByColumn (
1093+ UnboundSlot unboundSlot , List <String > nameParts , Optional <Pair <Integer , Integer >> idxInSql , Scope scope ) {
1094+ List <Slot > slots = addSqlIndexInfo (bindSingleSlotByName (nameParts .get (0 ), scope ), idxInSql );
1095+ if (slots .size () != 1 ) {
1096+ return slots ;
1097+ }
1098+ if (nameParts .size () == 1 ) {
1099+ return slots ;
1100+ }
1101+ Optional <Expression > expression = bindNestedFields (
1102+ unboundSlot , slots .get (0 ), nameParts .subList (1 , nameParts .size ())
1103+ );
1104+ if (!expression .isPresent ()) {
1105+ return slots ;
1106+ }
1107+ return ImmutableList .of (expression .get ());
1108+ }
1109+
1110+ private Optional <Expression > bindNestedFields (UnboundSlot unboundSlot , Slot slot , List <String > fieldNames ) {
1111+ Expression expression = slot ;
1112+ String lastFieldName = slot .getName ();
1113+ for (String fieldName : fieldNames ) {
1114+ DataType dataType = expression .getDataType ();
1115+ if (dataType .isStructType ()) {
1116+ StructType structType = (StructType ) dataType ;
1117+ StructField field = structType .getField (fieldName );
1118+ if (field == null ) {
1119+ throw new AnalysisException ("No such struct field " + fieldName + " in " + lastFieldName );
1120+ }
1121+ lastFieldName = fieldName ;
1122+ expression = new StructElement (expression , new StringLiteral (fieldName ));
1123+ continue ;
1124+ } else if (dataType .isMapType ()) {
1125+ if (fieldName .equalsIgnoreCase ("keys" )) {
1126+ expression = new MapKeys (expression );
1127+ continue ;
1128+ } else if (fieldName .equalsIgnoreCase ("values" )) {
1129+ expression = new MapValues (expression );
1130+ continue ;
1131+ } else if (fieldName .equalsIgnoreCase ("size" )) {
1132+ expression = new MapSize (expression );
1133+ continue ;
1134+ } else {
1135+ expression = new ElementAt (expression , new StringLiteral (fieldName ));
1136+ continue ;
1137+ }
1138+ } else if (dataType .isArrayType ()) {
1139+ if (fieldName .equalsIgnoreCase ("size" )) {
1140+ expression = new Cardinality (expression );
1141+ continue ;
1142+ }
9901143 }
1144+ throw new AnalysisException ("No such field " + fieldName + " in " + lastFieldName );
9911145 }
1146+ return Optional .of (new Alias (expression ));
9921147 }
9931148
9941149 public static boolean sameTableName (String boundSlot , String unboundSlot ) {
0 commit comments