You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2019/04/28 17:26:34 UTC

[impala] branch master updated: IMPALA-4865: Reject Expr Rewrite When Appropriate

This is an automated email from the ASF dual-hosted git repository.

tarmstrong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git


The following commit(s) were added to refs/heads/master by this push:
     new 931a8f0  IMPALA-4865: Reject Expr Rewrite When Appropriate
931a8f0 is described below

commit 931a8f0ba7f45d5b1608e62aff397b517b943e95
Author: Fang-Yu Rao <ja...@gmail.com>
AuthorDate: Mon Mar 18 16:52:38 2019 -0700

    IMPALA-4865: Reject Expr Rewrite When Appropriate
    
    Avoided rewrite if the resulting string literal exceeds a defined limit.
    
    Testing:
    Added three statements in testFoldConstantsRule() to verify that the
    expression rewrite is accepted only when the size of the rewritten
    expression is below a specified threshold.
    
    Change-Id: I8b078113ccc1aa49b0cea0c86dff2e02e1dd0e23
    Reviewed-on: http://gerrit.cloudera.org:8080/12814
    Reviewed-by: Tim Armstrong <ta...@cloudera.com>
    Tested-by: Tim Armstrong <ta...@cloudera.com>
---
 .gitignore                                         |  2 ++
 be/src/service/fe-support.cc                       | 23 +++++++++++---
 common/thrift/generate_error_codes.py              |  3 ++
 .../java/org/apache/impala/analysis/ColumnDef.java |  8 +++--
 .../org/apache/impala/analysis/LiteralExpr.java    | 18 +++++++++--
 .../apache/impala/analysis/PartitionKeyValue.java  |  4 ++-
 .../org/apache/impala/analysis/RangePartition.java | 14 +++++----
 .../org/apache/impala/analysis/StringLiteral.java  |  1 +
 .../org/apache/impala/planner/HBaseScanNode.java   |  9 +++---
 .../apache/impala/rewrite/FoldConstantsRule.java   |  7 +++--
 .../impala/rewrite/RemoveRedundantStringCast.java  |  5 ++--
 .../java/org/apache/impala/service/FeSupport.java  | 35 ++++++++++++++++++----
 .../main/java/org/apache/impala/util/KuduUtil.java |  2 +-
 .../impala/analysis/ExprRewriteRulesTest.java      | 18 +++++++++++
 14 files changed, 117 insertions(+), 32 deletions(-)

diff --git a/.gitignore b/.gitignore
index 32e3528..fdae036 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,6 +92,8 @@ gdb.txt
 .project
 .classpath
 .settings
+eclipse-classes/
+.pydevproject
 
 # Debugging
 ad-hoc.test
diff --git a/be/src/service/fe-support.cc b/be/src/service/fe-support.cc
index f629702..894e1a2 100644
--- a/be/src/service/fe-support.cc
+++ b/be/src/service/fe-support.cc
@@ -167,11 +167,13 @@ static void SetTColumnValue(
 // a predicate evaluation. It requires JniUtil::Init() to have been
 // called. Throws a Java exception if an error or warning is encountered during
 // the expr evaluation.
+// We also reject the expression rewrite if the size of the returned rewritten result
+// is too large.
 extern "C"
 JNIEXPORT jbyteArray JNICALL
 Java_org_apache_impala_service_FeSupport_NativeEvalExprsWithoutRow(
-    JNIEnv* env, jclass fe_support_class, jbyteArray thrift_expr_batch,
-    jbyteArray thrift_query_ctx_bytes) {
+    JNIEnv* env, jclass caller_class, jbyteArray thrift_expr_batch,
+    jbyteArray thrift_query_ctx_bytes, jlong max_result_size) {
   Status status;
   jbyteArray result_bytes = NULL;
   TQueryCtx query_ctx;
@@ -244,9 +246,22 @@ Java_org_apache_impala_service_FeSupport_NativeEvalExprsWithoutRow(
     void* result = eval->GetValue(nullptr);
     status = eval->GetError();
     if (!status.ok()) goto error;
+
+    const ColumnType& type = eval->root().type();
+    // reject the expression rewrite if the returned string greater than
+    if (type.IsVarLenStringType()) {
+      const StringValue* string_val = reinterpret_cast<const StringValue*>(result);
+      if (string_val != nullptr) {
+        if (string_val->len > max_result_size) {
+          status = Status(TErrorCode::EXPR_REWRITE_RESULT_LIMIT_EXCEEDED,
+              string_val->len, max_result_size);
+          goto error;
+        }
+      }
+    }
+
     // 'output_scale' should only be set for MathFunctions::RoundUpTo()
     // with return type double.
-    const ColumnType& type = eval->root().type();
     DCHECK(eval->output_scale() == -1 || type.type == TYPE_DOUBLE);
     TColumnValue val;
     SetTColumnValue(result, type, &val);
@@ -699,7 +714,7 @@ static JNINativeMethod native_methods[] = {
       (void*)::Java_org_apache_impala_service_FeSupport_NativeFeTestInit
   },
   {
-      const_cast<char*>("NativeEvalExprsWithoutRow"), const_cast<char*>("([B[B)[B"),
+      const_cast<char*>("NativeEvalExprsWithoutRow"), const_cast<char*>("([B[BJ)[B"),
       (void*)::Java_org_apache_impala_service_FeSupport_NativeEvalExprsWithoutRow
   },
   {
diff --git a/common/thrift/generate_error_codes.py b/common/thrift/generate_error_codes.py
index 10f7d4d..519a7a8 100755
--- a/common/thrift/generate_error_codes.py
+++ b/common/thrift/generate_error_codes.py
@@ -397,6 +397,9 @@ error_codes = (
   ("ROWS_PRODUCED_LIMIT_EXCEEDED", 131,
    "Query $0 terminated due to rows produced limit of $1. "
    "Unset or increase NUM_ROWS_PRODUCED_LIMIT query option to produce more rows."),
+
+  ("EXPR_REWRITE_RESULT_LIMIT_EXCEEDED", 132,
+   "Expression rewrite rejected due to result size ($0) exceeding the limit ($1).")
 )
 
 import sys
diff --git a/fe/src/main/java/org/apache/impala/analysis/ColumnDef.java b/fe/src/main/java/org/apache/impala/analysis/ColumnDef.java
index c966f8bb..5935166 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ColumnDef.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ColumnDef.java
@@ -30,6 +30,7 @@ import org.apache.hadoop.hive.metastore.api.FieldSchema;
 import org.apache.impala.catalog.Type;
 import org.apache.impala.common.AnalysisException;
 import org.apache.impala.compat.MetastoreShim;
+import org.apache.impala.service.FeSupport;
 import org.apache.impala.thrift.TColumn;
 import org.apache.impala.util.KuduUtil;
 import org.apache.impala.util.MetaStoreUtil;
@@ -251,8 +252,8 @@ public class ColumnDef {
         throw new AnalysisException(String.format("Only constant values are allowed " +
             "for default values: %s", defaultValue_.toSql()));
       }
-      LiteralExpr defaultValLiteral = LiteralExpr.create(defaultValue_,
-          analyzer.getQueryCtx());
+      LiteralExpr defaultValLiteral = LiteralExpr.createBounded(defaultValue_,
+          analyzer.getQueryCtx(), StringLiteral.MAX_STRING_LEN);
       if (defaultValLiteral == null) {
         throw new AnalysisException(String.format("Only constant values are allowed " +
             "for default values: %s", defaultValue_.toSql()));
@@ -285,7 +286,8 @@ public class ColumnDef {
       if (!defaultValLiteral.getType().equals(type_)) {
         Expr castLiteral = defaultValLiteral.uncheckedCastTo(type_);
         Preconditions.checkNotNull(castLiteral);
-        defaultValLiteral = LiteralExpr.create(castLiteral, analyzer.getQueryCtx());
+        defaultValLiteral = LiteralExpr.createBounded(castLiteral,
+            analyzer.getQueryCtx(), StringLiteral.MAX_STRING_LEN);
       }
       Preconditions.checkNotNull(defaultValLiteral);
       outputDefaultValue_ = defaultValLiteral;
diff --git a/fe/src/main/java/org/apache/impala/analysis/LiteralExpr.java b/fe/src/main/java/org/apache/impala/analysis/LiteralExpr.java
index 0c71ef9..a258c3e 100644
--- a/fe/src/main/java/org/apache/impala/analysis/LiteralExpr.java
+++ b/fe/src/main/java/org/apache/impala/analysis/LiteralExpr.java
@@ -43,6 +43,7 @@ import com.google.common.base.Preconditions;
  */
 public abstract class LiteralExpr extends Expr implements Comparable<LiteralExpr> {
   private final static Logger LOG = LoggerFactory.getLogger(LiteralExpr.class);
+  public static final int MAX_STRING_LITERAL_SIZE = 64 * 1024;
 
   public LiteralExpr() {
     // Literals start analyzed: there is nothing more to check.
@@ -177,6 +178,17 @@ public abstract class LiteralExpr extends Expr implements Comparable<LiteralExpr
   }
 
   /**
+   * If it is known that the size of the rewritten expression is fixed, e.g.,
+   * the size of an integer, then this method will be called to perform the rewrite.
+   * Otherwise, the method createBounded that takes an additional argument specifying
+   * the upper bound on the size of rewritten expression should be invoked.
+   */
+  public static LiteralExpr create(Expr constExpr, TQueryCtx queryCtx)
+    throws AnalysisException {
+    return createBounded(constExpr, queryCtx, 0);
+  }
+
+  /**
    * Evaluates the given constant expr and returns its result as a LiteralExpr.
    * Assumes expr has been analyzed. Returns constExpr if is it already a LiteralExpr.
    * Returns null for types that do not have a LiteralExpr subclass, e.g. TIMESTAMP, or
@@ -185,15 +197,15 @@ public abstract class LiteralExpr extends Expr implements Comparable<LiteralExpr
    * or warnings in the BE.
    * TODO: Support non-scalar types.
    */
-  public static LiteralExpr create(Expr constExpr, TQueryCtx queryCtx)
-      throws AnalysisException {
+  public static LiteralExpr createBounded(Expr constExpr, TQueryCtx queryCtx,
+    int maxResultSize) throws AnalysisException {
     Preconditions.checkState(constExpr.isConstant());
     Preconditions.checkState(constExpr.getType().isValid());
     if (constExpr instanceof LiteralExpr) return (LiteralExpr) constExpr;
 
     TColumnValue val = null;
     try {
-      val = FeSupport.EvalExprWithoutRow(constExpr, queryCtx);
+      val = FeSupport.EvalExprWithoutRowBounded(constExpr, queryCtx, maxResultSize);
     } catch (InternalException e) {
       LOG.error(String.format("Failed to evaluate expr '%s': %s",
           constExpr.toSql(), e.getMessage()));
diff --git a/fe/src/main/java/org/apache/impala/analysis/PartitionKeyValue.java b/fe/src/main/java/org/apache/impala/analysis/PartitionKeyValue.java
index 1aebcbe..c7c51c9 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PartitionKeyValue.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PartitionKeyValue.java
@@ -22,6 +22,7 @@ import java.util.Comparator;
 import java.util.List;
 
 import org.apache.impala.common.AnalysisException;
+import org.apache.impala.service.FeSupport;
 
 import com.google.common.base.Preconditions;
 
@@ -50,7 +51,8 @@ public class PartitionKeyValue {
               "as static partition-key values in '%s'.", toString()));
     }
     value_.analyze(analyzer);
-    literalValue_ = LiteralExpr.create(value_, analyzer.getQueryCtx());
+    literalValue_ = LiteralExpr.createBounded(value_, analyzer.getQueryCtx(),
+        StringLiteral.MAX_STRING_LEN);
   }
 
   public String getColName() { return colName_; }
diff --git a/fe/src/main/java/org/apache/impala/analysis/RangePartition.java b/fe/src/main/java/org/apache/impala/analysis/RangePartition.java
index c3abf50..ac1972a 100644
--- a/fe/src/main/java/org/apache/impala/analysis/RangePartition.java
+++ b/fe/src/main/java/org/apache/impala/analysis/RangePartition.java
@@ -17,6 +17,8 @@
 
 package org.apache.impala.analysis;
 
+import static org.apache.impala.analysis.ToSqlOptions.DEFAULT;
+
 import java.math.BigInteger;
 import java.util.List;
 
@@ -24,14 +26,13 @@ import org.apache.impala.catalog.Type;
 import org.apache.impala.common.AnalysisException;
 import org.apache.impala.common.InternalException;
 import org.apache.impala.common.Pair;
+import org.apache.impala.service.FeSupport;
 import org.apache.impala.thrift.TRangePartition;
 import org.apache.impala.util.KuduUtil;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
-import static org.apache.impala.analysis.ToSqlOptions.DEFAULT;
-
 /**
  * Represents a range partition of a Kudu table.
  *
@@ -164,7 +165,8 @@ public class RangePartition extends StmtNode {
       throw new AnalysisException(String.format("Only constant values are allowed " +
           "for range-partition bounds: %s", value.toSql()));
     }
-    LiteralExpr literal = LiteralExpr.create(value, analyzer.getQueryCtx());
+    LiteralExpr literal = LiteralExpr.createBounded(value, analyzer.getQueryCtx(),
+        StringLiteral.MAX_STRING_LEN);
     if (literal == null) {
       throw new AnalysisException(String.format("Only constant values are allowed " +
           "for range-partition bounds: %s", value.toSql()));
@@ -181,7 +183,8 @@ public class RangePartition extends StmtNode {
       // Add an explicit cast to TIMESTAMP
       Expr e = new CastExpr(new TypeDef(Type.TIMESTAMP), literal);
       e.analyze(analyzer);
-      literal = LiteralExpr.create(e, analyzer.getQueryCtx());
+      literal = LiteralExpr.createBounded(e, analyzer.getQueryCtx(),
+        StringLiteral.MAX_STRING_LEN);
       Preconditions.checkNotNull(literal);
       if (Expr.IS_NULL_VALUE.apply(literal)) {
         throw new AnalysisException(String.format("Range partition value %s cannot be " +
@@ -199,7 +202,8 @@ public class RangePartition extends StmtNode {
     if (!literalType.equals(colType)) {
       Expr castLiteral = literal.uncheckedCastTo(colType);
       Preconditions.checkNotNull(castLiteral);
-      literal = LiteralExpr.create(castLiteral, analyzer.getQueryCtx());
+      literal = LiteralExpr.createBounded(castLiteral, analyzer.getQueryCtx(),
+        StringLiteral.MAX_STRING_LEN);
     }
     Preconditions.checkNotNull(literal);
 
diff --git a/fe/src/main/java/org/apache/impala/analysis/StringLiteral.java b/fe/src/main/java/org/apache/impala/analysis/StringLiteral.java
index 0024cee..797ad5e 100644
--- a/fe/src/main/java/org/apache/impala/analysis/StringLiteral.java
+++ b/fe/src/main/java/org/apache/impala/analysis/StringLiteral.java
@@ -36,6 +36,7 @@ import java_cup.runtime.Symbol;
 
 public class StringLiteral extends LiteralExpr {
   private final String value_;
+  public static int MAX_STRING_LEN = Integer.MAX_VALUE;
 
   // Indicates whether this value needs to be unescaped in toThrift().
   private final boolean needsUnescaping_;
diff --git a/fe/src/main/java/org/apache/impala/planner/HBaseScanNode.java b/fe/src/main/java/org/apache/impala/planner/HBaseScanNode.java
index 23adfa3..25ccae1 100644
--- a/fe/src/main/java/org/apache/impala/planner/HBaseScanNode.java
+++ b/fe/src/main/java/org/apache/impala/planner/HBaseScanNode.java
@@ -44,6 +44,7 @@ import org.apache.impala.catalog.PrimitiveType;
 import org.apache.impala.catalog.Type;
 import org.apache.impala.common.ImpalaException;
 import org.apache.impala.common.Pair;
+import org.apache.impala.service.FeSupport;
 import org.apache.impala.thrift.TExplainLevel;
 import org.apache.impala.thrift.THBaseFilter;
 import org.apache.impala.thrift.THBaseKeyRange;
@@ -236,8 +237,8 @@ public class HBaseScanNode extends ScanNode {
         Preconditions.checkState(rowRange.getLowerBound().isConstant());
         Preconditions.checkState(
             rowRange.getLowerBound().getType().equals(Type.STRING));
-        LiteralExpr val = LiteralExpr.create(rowRange.getLowerBound(),
-            analyzer.getQueryCtx());
+        LiteralExpr val = LiteralExpr.createBounded(rowRange.getLowerBound(),
+            analyzer.getQueryCtx(), StringLiteral.MAX_STRING_LEN);
         // TODO: Make this a Preconditions.checkState(). If we get here,
         // and the value is not a string literal, then we've got a predicate
         // that we removed from the conjunct list, but which we won't evaluate
@@ -256,8 +257,8 @@ public class HBaseScanNode extends ScanNode {
         Preconditions.checkState(rowRange.getUpperBound().isConstant());
         Preconditions.checkState(
             rowRange.getUpperBound().getType().equals(Type.STRING));
-        LiteralExpr val = LiteralExpr.create(rowRange.getUpperBound(),
-            analyzer.getQueryCtx());
+        LiteralExpr val = LiteralExpr.createBounded(rowRange.getUpperBound(),
+            analyzer.getQueryCtx(), StringLiteral.MAX_STRING_LEN);
         if (val instanceof StringLiteral) {
           StringLiteral litVal = (StringLiteral) val;
           stopKey_ = convertToBytes(litVal.getUnescapedValue(),
diff --git a/fe/src/main/java/org/apache/impala/rewrite/FoldConstantsRule.java b/fe/src/main/java/org/apache/impala/rewrite/FoldConstantsRule.java
index 9a0e714..a88d213 100644
--- a/fe/src/main/java/org/apache/impala/rewrite/FoldConstantsRule.java
+++ b/fe/src/main/java/org/apache/impala/rewrite/FoldConstantsRule.java
@@ -18,10 +18,9 @@
 package org.apache.impala.rewrite;
 
 import org.apache.impala.analysis.Analyzer;
+import org.apache.impala.analysis.CastExpr;
 import org.apache.impala.analysis.Expr;
 import org.apache.impala.analysis.LiteralExpr;
-import org.apache.impala.analysis.CastExpr;
-
 import org.apache.impala.common.AnalysisException;
 
 /**
@@ -64,7 +63,9 @@ public class FoldConstantsRule implements ExprRewriteRule {
       expr.analyze(analyzer);
       if (!expr.isConstant()) return expr;
     }
-    Expr result = LiteralExpr.create(expr, analyzer.getQueryCtx());
+    Expr result = LiteralExpr.createBounded(expr, analyzer.getQueryCtx(),
+      LiteralExpr.MAX_STRING_LITERAL_SIZE);
+
     // Preserve original type so parent Exprs do not need to be re-analyzed.
     if (result != null) return result.castTo(expr.getType());
     return expr;
diff --git a/fe/src/main/java/org/apache/impala/rewrite/RemoveRedundantStringCast.java b/fe/src/main/java/org/apache/impala/rewrite/RemoveRedundantStringCast.java
index 24f34ba..015f0a1 100644
--- a/fe/src/main/java/org/apache/impala/rewrite/RemoveRedundantStringCast.java
+++ b/fe/src/main/java/org/apache/impala/rewrite/RemoveRedundantStringCast.java
@@ -22,6 +22,7 @@ import org.apache.impala.analysis.BinaryPredicate;
 import org.apache.impala.analysis.CastExpr;
 import org.apache.impala.analysis.Expr;
 import org.apache.impala.analysis.LiteralExpr;
+import org.apache.impala.analysis.StringLiteral;
 import org.apache.impala.analysis.TypeDef;
 import org.apache.impala.common.AnalysisException;
 
@@ -77,8 +78,8 @@ public class RemoveRedundantStringCast implements ExprRewriteRule {
     Expr castForRedundancyCheck = new CastExpr(new TypeDef(castExpr.getType()),
         new CastExpr(new TypeDef(castExprChild.getType()), literalExpr));
     castForRedundancyCheck.analyze(analyzer);
-    LiteralExpr resultOfReverseCast = LiteralExpr.create(castForRedundancyCheck,
-        analyzer.getQueryCtx());
+    LiteralExpr resultOfReverseCast = LiteralExpr.createBounded(castForRedundancyCheck,
+        analyzer.getQueryCtx(), StringLiteral.MAX_STRING_LEN);
     // Need to trim() while comparing char(n) types as conversion might add trailing
     // spaces to the 'resultOfReverseCast'.
     if (resultOfReverseCast != null &&
diff --git a/fe/src/main/java/org/apache/impala/service/FeSupport.java b/fe/src/main/java/org/apache/impala/service/FeSupport.java
index 3c3295e..6339d1d 100644
--- a/fe/src/main/java/org/apache/impala/service/FeSupport.java
+++ b/fe/src/main/java/org/apache/impala/service/FeSupport.java
@@ -76,7 +76,7 @@ public class FeSupport {
 
   // Returns a serialized TResultRow
   public native static byte[] NativeEvalExprsWithoutRow(
-      byte[] thriftExprBatch, byte[] thriftQueryGlobals);
+      byte[] thriftExprBatch, byte[] thriftQueryGlobals, long maxResultSize);
 
   // Returns a serialized TSymbolLookupResult
   public native static byte[] NativeLookupSymbol(byte[] thriftSymbolLookup);
@@ -172,16 +172,27 @@ public class FeSupport {
     return NativeCacheJar(thriftParams);
   }
 
+  /**
+   * If it is known that the size of the evaluated expression is fixed, e.g.,
+   * the size of an integer, then this method will be called to perform the evaluation.
+   * Otherwise, the method EvalExprWithoutRowBounded that takes an additional argument
+   * specifying the upper bound on the size of evaluated expression should be invoked.
+   */
   public static TColumnValue EvalExprWithoutRow(Expr expr, TQueryCtx queryCtx)
-      throws InternalException {
+    throws InternalException {
+    return EvalExprWithoutRowBounded(expr, queryCtx, 0);
+  }
+
+  public static TColumnValue EvalExprWithoutRowBounded(Expr expr, TQueryCtx queryCtx,
+    int maxResultSize) throws InternalException {
     Preconditions.checkState(!expr.contains(SlotRef.class));
     TExprBatch exprBatch = new TExprBatch();
     exprBatch.addToExprs(expr.treeToThrift());
     TSerializer serializer = new TSerializer(new TBinaryProtocol.Factory());
     byte[] result;
     try {
-      result = EvalExprsWithoutRow(
-          serializer.serialize(exprBatch), serializer.serialize(queryCtx));
+      result = EvalExprsWithoutRowBounded(
+          serializer.serialize(exprBatch), serializer.serialize(queryCtx), maxResultSize);
       Preconditions.checkNotNull(result);
       TDeserializer deserializer = new TDeserializer(new TBinaryProtocol.Factory());
       TResultRow val = new TResultRow();
@@ -222,14 +233,26 @@ public class FeSupport {
     }
   }
 
+  /**
+   * If it is known that the size of the evaluated expression is fixed, e.g.,
+   * the size of an integer, then this method will be called to perform the evaluation.
+   * Otherwise, the method EvalExprsWithoutRowBounded that takes an additional argument
+   * specifying the upper bound on the size of rewritten expression should be invoked.
+   */
   private static byte[] EvalExprsWithoutRow(
       byte[] thriftExprBatch, byte[] thriftQueryContext) {
+    return EvalExprsWithoutRowBounded(thriftExprBatch, thriftQueryContext, 0);
+  }
+
+  private static byte[] EvalExprsWithoutRowBounded(
+      byte[] thriftExprBatch, byte[] thriftQueryContext, int maxResultSize) {
     try {
-      return NativeEvalExprsWithoutRow(thriftExprBatch, thriftQueryContext);
+      return NativeEvalExprsWithoutRow(thriftExprBatch, thriftQueryContext,
+        maxResultSize);
     } catch (UnsatisfiedLinkError e) {
       loadLibrary();
     }
-    return NativeEvalExprsWithoutRow(thriftExprBatch, thriftQueryContext);
+    return NativeEvalExprsWithoutRow(thriftExprBatch, thriftQueryContext, maxResultSize);
   }
 
   public static boolean EvalPredicate(Expr pred, TQueryCtx queryCtx)
diff --git a/fe/src/main/java/org/apache/impala/util/KuduUtil.java b/fe/src/main/java/org/apache/impala/util/KuduUtil.java
index d9bbdd3..00e0f7c 100644
--- a/fe/src/main/java/org/apache/impala/util/KuduUtil.java
+++ b/fe/src/main/java/org/apache/impala/util/KuduUtil.java
@@ -21,9 +21,9 @@ import static java.lang.String.format;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.impala.analysis.Analyzer;
 import org.apache.impala.analysis.DescriptorTable;
diff --git a/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java b/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
index c473d5a..5a6ef20 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
@@ -205,6 +205,17 @@ public class ExprRewriteRulesTest extends FrontendTestBase {
     return qf.verifyWhereRewrite(rules, expectedExprStr);
   }
 
+  public String repeat(String givenStr, long numberOfRepetitions) {
+    StringBuilder resultStr = new StringBuilder();
+    resultStr.append("'");
+    for (long i = 0; i < numberOfRepetitions; i = i + 1) {
+      resultStr.append(givenStr);
+    }
+    resultStr.append("'");
+    System.out.println("resultStr.length(): " + resultStr.length());
+    return resultStr.toString();
+  }
+
   @Test
   public void testBetweenToCompoundRule() throws ImpalaException {
     ExprRewriteRule rule = BetweenToCompoundRule.INSTANCE;
@@ -370,6 +381,13 @@ public class ExprRewriteRulesTest extends FrontendTestBase {
     RewritesOk("null + 1", rule, "NULL");
     RewritesOk("(1 + 1) is null", rule, "FALSE");
     RewritesOk("(null + 1) is null", rule, "TRUE");
+
+    // Test if the rewrite would be rejected if the result size is larger than
+    // the predefined threshold, i.e., 65_536
+    RewritesOk("repeat('AZ', 2)", rule, "'AZAZ'");
+    RewritesOk("repeat('A', 65536)", rule, repeat("A", 65_536));
+    RewritesOk("repeat('A', 4294967296)", rule, null);
+
   }
 
   @Test