diff --git a/itests/src/test/resources/testconfiguration.properties b/itests/src/test/resources/testconfiguration.properties index 2df49a7220..08e5e604a7 100644 --- a/itests/src/test/resources/testconfiguration.properties +++ b/itests/src/test/resources/testconfiguration.properties @@ -30,7 +30,6 @@ disabled.query.files=ql_rewrite_gbtoidx.q,\ cbo_rp_subq_not_in.q,\ cbo_rp_subq_exists.q,\ orc_llap.q,\ - min_structvalue.q,\ ql_rewrite_gbtoidx_cbo_2.q,\ rcfile_merge1.q,\ smb_mapjoin_8.q,\ diff --git a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/ASTConverter.java b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/ASTConverter.java index 165f8c4317..30fb1b1980 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/ASTConverter.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/ASTConverter.java @@ -19,9 +19,12 @@ import java.math.BigDecimal; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; + import org.apache.calcite.adapter.druid.DruidQuery; import org.apache.calcite.rel.RelFieldCollation; @@ -40,6 +43,7 @@ import org.apache.calcite.rel.core.TableScan; import org.apache.calcite.rel.core.Union; import org.apache.calcite.rel.type.RelDataTypeField; +import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexFieldAccess; import org.apache.calcite.rex.RexFieldCollation; @@ -205,12 +209,8 @@ else if (aggregateType == Group.CUBE) { int i = 0; for (RexNode r : select.getChildExps()) { - if (RexUtil.isNull(r) && r.getType().getSqlTypeName() != SqlTypeName.NULL) { - // It is NULL value with different type, we need to introduce a CAST - // to keep it - r = select.getCluster().getRexBuilder().makeAbstractCast(r.getType(), r); - } - ASTNode expr = r.accept(new RexVisitor(schema, r instanceof RexLiteral)); + ASTNode expr = r.accept(new RexVisitor(schema, r instanceof RexLiteral, + select.getCluster().getRexBuilder())); String alias = select.getRowType().getFieldNames().get(i++); ASTNode selectExpr = ASTBuilder.selectExpr(expr, alias); b.add(selectExpr); @@ -223,12 +223,8 @@ else if (aggregateType == Group.CUBE) { List children = new ArrayList<>(); RexCall call = (RexCall) udtf.getCall(); for (RexNode r : call.getOperands()) { - if (RexUtil.isNull(r) && r.getType().getSqlTypeName() != SqlTypeName.NULL) { - // It is NULL value with different type, we need to introduce a CAST - // to keep it - r = select.getCluster().getRexBuilder().makeAbstractCast(r.getType(), r); - } - ASTNode expr = r.accept(new RexVisitor(schema, r instanceof RexLiteral)); + ASTNode expr = r.accept(new RexVisitor(schema, r instanceof RexLiteral, + select.getCluster().getRexBuilder())); children.add(expr); } ASTBuilder sel = ASTBuilder.construct(HiveParser.TOK_SELEXPR, "TOK_SELEXPR"); @@ -464,15 +460,23 @@ public void visit(RelNode node, int ordinal, RelNode parent) { private final Schema schema; private final boolean useTypeQualInLiteral; + private final RexBuilder rexBuilder; + private Set nullLiteralSet; + protected RexVisitor(Schema schema, boolean useTypeQualInLiteral) { + this(schema, useTypeQualInLiteral, null); + + } protected RexVisitor(Schema schema) { this(schema, false); } - protected RexVisitor(Schema schema, boolean useTypeQualInLiteral) { + protected RexVisitor(Schema schema, boolean useTypeQualInLiteral, RexBuilder rexBuilder) { super(true); this.schema = schema; this.useTypeQualInLiteral = useTypeQualInLiteral; + this.rexBuilder = rexBuilder; + this.nullLiteralSet = new HashSet<>(); } @Override @@ -497,6 +501,19 @@ public ASTNode visitInputRef(RexInputRef inputRef) { @Override public ASTNode visitLiteral(RexLiteral literal) { + + if (RexUtil.isNull(literal) && literal.getType().getSqlTypeName() != SqlTypeName.NULL + && rexBuilder != null) { + // It is NULL value with different type, we need to introduce a CAST + // to keep it + if(nullLiteralSet.contains(literal)) { + return ASTBuilder.literal(literal, useTypeQualInLiteral); + } + nullLiteralSet.add(literal); + RexNode r = rexBuilder.makeAbstractCast(literal.getType(), literal); + + return r.accept(this); + } return ASTBuilder.literal(literal, useTypeQualInLiteral); } diff --git a/ql/src/test/results/clientpositive/min_structvalue.q.out b/ql/src/test/results/clientpositive/min_structvalue.q.out new file mode 100644 index 0000000000..35828373da --- /dev/null +++ b/ql/src/test/results/clientpositive/min_structvalue.q.out @@ -0,0 +1,45 @@ +PREHOOK: query: select max(a), min(a) FROM (select named_struct("field",1) as a union all select named_struct("field",2) as a union all select named_struct("field",cast(null as int)) as a) tmp +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select max(a), min(a) FROM (select named_struct("field",1) as a union all select named_struct("field",2) as a union all select named_struct("field",cast(null as int)) as a) tmp +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +{"field":2} {"field":1} +PREHOOK: query: select min(a) FROM (select named_struct("field",1) as a union all select named_struct("field",-2) as a union all select named_struct("field",cast(null as int)) as a) tmp +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select min(a) FROM (select named_struct("field",1) as a union all select named_struct("field",-2) as a union all select named_struct("field",cast(null as int)) as a) tmp +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +{"field":-2} +PREHOOK: query: select min(a) FROM (select named_struct("field",1) as a union all select named_struct("field",2) as a union all select named_struct("field",cast(5 as int)) as a) tmp +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select min(a) FROM (select named_struct("field",1) as a union all select named_struct("field",2) as a union all select named_struct("field",cast(5 as int)) as a) tmp +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +{"field":1} +PREHOOK: query: select min(a) FROM (select named_struct("field",1, "secf", cast(null as int) ) as a union all select named_struct("field",2, "secf", 3) as a union all select named_struct("field",cast(5 as int), "secf", 4) as a) tmp +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select min(a) FROM (select named_struct("field",1, "secf", cast(null as int) ) as a union all select named_struct("field",2, "secf", 3) as a union all select named_struct("field",cast(5 as int), "secf", 4) as a) tmp +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +{"field":1,"secf":null} +PREHOOK: query: select min(a) FROM (select named_struct("field",1, "secf", 2) as a union all select named_struct("field",-2, "secf", 3) as a union all select named_struct("field",cast(null as int), "secf", 1) as a) tmp +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select min(a) FROM (select named_struct("field",1, "secf", 2) as a union all select named_struct("field",-2, "secf", 3) as a union all select named_struct("field",cast(null as int), "secf", 1) as a) tmp +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +{"field":-2,"secf":3}