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 2017/10/25 01:17:58 UTC

[1/5] incubator-impala git commit: IMPALA-6070: Parallel compute_table_stats.py

Repository: incubator-impala
Updated Branches:
  refs/heads/master 2bd010781 -> ca55b5926


IMPALA-6070: Parallel compute_table_stats.py

Uses a thread pool to issue many compute stats commands in parallel to
Impala, rather than doing it serially. Where it was obvious, I combined
multiple stats commands into fewer, to reduce the number
of "show databses" and serialized "show tables" commands.

This speeds up the compute stats step in data loading significantly. My
measurements for testdata/bin/compute-table-stats.sh running before and
after this change, with the Impala daemons restarted (cold) or not
restarted (warm) on an 8-core, 32GB RAM machine were:

old, cold: 7m44s
new, cold: 1m42s

old, warm: 1m23s
new, warm:   48s

The data load in the full test build behaves in a cold fashion. It's
typical for https://jenkins.impala.io/job/ubuntu-16.04-from-scratch/ to
run this compute stats step for 9 or 10 minutes. With this change, this
will come down to about 2 minutes.

Change-Id: Ifb080f2552b9dbe304ecadd6e52429214094237d
Reviewed-on: http://gerrit.cloudera.org:8080/8354
Reviewed-by: David Knupp <dk...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/77e010ae
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/77e010ae
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/77e010ae

Branch: refs/heads/master
Commit: 77e010ae4ee07c02a7a945fcb5898db50166c767
Parents: 2bd0107
Author: Philip Zeyliger <ph...@cloudera.com>
Authored: Sat Oct 21 21:27:00 2017 -0700
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Tue Oct 24 23:54:15 2017 +0000

----------------------------------------------------------------------
 testdata/bin/compute-table-stats.sh |  6 +--
 tests/util/compute_table_stats.py   | 81 ++++++++++++++++++++++----------
 2 files changed, 58 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/77e010ae/testdata/bin/compute-table-stats.sh
----------------------------------------------------------------------
diff --git a/testdata/bin/compute-table-stats.sh b/testdata/bin/compute-table-stats.sh
index f27972c..98434ee 100755
--- a/testdata/bin/compute-table-stats.sh
+++ b/testdata/bin/compute-table-stats.sh
@@ -41,10 +41,8 @@ if [ "${TARGET_FILESYSTEM}" = "hdfs" ]; then
 fi
 ${COMPUTE_STATS_SCRIPT} --db_names=tpch,tpch_parquet \
     --table_names=customer,lineitem,nation,orders,part,partsupp,region,supplier
-${COMPUTE_STATS_SCRIPT} --db_names=tpch_nested_parquet
-${COMPUTE_STATS_SCRIPT} --db_names=tpcds,tpcds_parquet
+${COMPUTE_STATS_SCRIPT} --db_names=tpch_nested_parquet,tpcds,tpcds_parquet
 
 if "$KUDU_IS_SUPPORTED"; then
-  ${COMPUTE_STATS_SCRIPT} --db_names=functional_kudu
-  ${COMPUTE_STATS_SCRIPT} --db_names=tpch_kudu
+  ${COMPUTE_STATS_SCRIPT} --db_names=functional_kudu,tpch_kudu
 fi

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/77e010ae/tests/util/compute_table_stats.py
----------------------------------------------------------------------
diff --git a/tests/util/compute_table_stats.py b/tests/util/compute_table_stats.py
index 924d33d..f982802 100755
--- a/tests/util/compute_table_stats.py
+++ b/tests/util/compute_table_stats.py
@@ -19,36 +19,63 @@
 #
 # Utility for computing table statistics of tables in the Hive Metastore
 
+from contextlib import contextmanager
 from optparse import OptionParser
+import logging
+import multiprocessing
+import multiprocessing.pool
 
 from tests.beeswax.impala_beeswax import ImpalaBeeswaxClient
 
-def compute_stats(impala_client, db_names=None, table_names=None,
-    continue_on_error=False):
+def compute_stats_table(client_factory, db, table, continue_on_error):
+  """
+  Runs 'compute stats' on a given table. If continue_on_error is
+  True, exceptions computing statistics are swallowed.
+  """
+  with client_factory() as impala_client:
+    db_table = "%s.%s" % (db, table)
+    statement = "compute stats %s" % (db_table,)
+    logging.info('Executing: %s', statement)
+    try:
+      result = impala_client.execute(statement)
+      logging.info(" %s -> %s", db_table, ' '.join(result.data).strip())
+    except:
+      logging.exception(' Failed on table %s', db_table)
+      if not continue_on_error:
+        raise
+
+def compute_stats(client_factory, db_names=None, table_names=None,
+    continue_on_error=False, parallelism=multiprocessing.cpu_count()):
   """
   Runs COMPUTE STATS over the selected tables. The target tables can be filtered by
   specifying a list of databases and/or table names. If no filters are specified this will
   run COMPUTE STATS on all tables in all databases.
+
+  parallelism controls the size of the thread pool to which compute_stats
+  is sent.
   """
-  print "Enumerating databases and tables for compute stats."
+  logging.info("Enumerating databases and tables for compute stats.")
 
-  all_dbs = set(name.split('\t')[0].lower() for name in impala_client.execute("show databases").data)
-  selected_dbs = all_dbs if db_names is None else set(db_names)
-  for db in all_dbs.intersection(selected_dbs):
-    all_tables =\
-        set([t.lower() for t in impala_client.execute("show tables in %s" % db).data])
-    selected_tables = all_tables if table_names is None else set(table_names)
-    for table in all_tables.intersection(selected_tables):
-      statement = "compute stats %s.%s" % (db, table)
-      print 'Executing: %s' % statement
-      try:
-        result = impala_client.execute(statement)
-        print "  -> %s\n" % '\n'.join(result.data)
-      except Exception, e:
-        print "  -> Error: %s\n" % str(e)
-        if not continue_on_error: raise e
+  pool = multiprocessing.pool.ThreadPool(processes=parallelism)
+  futures = []
+  with client_factory() as impala_client:
+    all_dbs = set(name.split('\t')[0].lower() for name
+        in impala_client.execute("show databases").data)
+    selected_dbs = all_dbs if db_names is None else set(db_names)
+    for db in all_dbs.intersection(selected_dbs):
+      all_tables =\
+          set([t.lower() for t in impala_client.execute("show tables in %s" % db).data])
+      selected_tables = all_tables if table_names is None else set(table_names)
+      for table in all_tables.intersection(selected_tables):
+        # Submit command to threadpool
+        futures.append(pool.apply_async(compute_stats_table,
+            (client_factory, db, table, continue_on_error,)))
+    # Wait for all stats commands to finish
+    for f in futures:
+      f.get()
 
 if __name__ == "__main__":
+  logging.basicConfig(level=logging.INFO, format='%(asctime)s %(threadName)s: %(message)s')
   parser = OptionParser()
   parser.add_option("--continue_on_error", dest="continue_on_error",
                     action="store_true", default=True, help="If True, continue "\
@@ -62,6 +89,8 @@ if __name__ == "__main__":
                     help="Compute stats on a kerberized cluster.")
   parser.add_option("--use_ssl", action="store_true", default=False,
                     help="Compute stats on a cluster with SSL enabled.")
+  parser.add_option("--parallelism", type=int, default=multiprocessing.cpu_count(),
+                    help="Number of parallel compute stats commands.")
   parser.add_option("--db_names", dest="db_names", default=None,
                     help="Comma-separated list of database names for which to compute "\
                     "stats. Can be used in conjunction with the --table_names flag. "\
@@ -80,11 +109,13 @@ if __name__ == "__main__":
   if options.db_names is not None:
     db_names = [name.lower().strip() for name in options.db_names.split(',')]
 
-  impala_client = ImpalaBeeswaxClient(options.impalad, use_kerberos=options.use_kerberos,
-      use_ssl=options.use_ssl)
-  impala_client.connect()
-  try:
-    compute_stats(impala_client, db_names=db_names,
-        table_names=table_names, continue_on_error=options.continue_on_error)
-  finally:
+  @contextmanager
+  def client_factory():
+    impala_client = ImpalaBeeswaxClient(options.impalad,
+        use_kerberos=options.use_kerberos, use_ssl=options.use_ssl)
+    impala_client.connect()
+    yield impala_client
     impala_client.close_connection()
+
+  compute_stats(client_factory, db_names=db_names, table_names=table_names,
+      continue_on_error=options.continue_on_error, parallelism=options.parallelism)


[4/5] incubator-impala git commit: IMPALA-5957: print memory address, not memory

Posted by ta...@apache.org.
IMPALA-5957: print memory address, not memory

The bug is that the pointer was a uint8_t*, which C++ iostreams
print as a C-style string. The intent was to instead print the
memory address, which happens for void*. To avoid the subtlety,
instead convert to uintptr_t and print as hex.

Change-Id: I89250646bf683dd2d636dcb37a66ceb0428af8b2
Reviewed-on: http://gerrit.cloudera.org:8080/8371
Reviewed-by: anujphadke <ap...@cloudera.com>
Reviewed-by: Dan Hecht <dh...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/98f8b19c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/98f8b19c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/98f8b19c

Branch: refs/heads/master
Commit: 98f8b19c3bd0debfe25055aaecaf86e38b23c748
Parents: 5ebea0e
Author: Tim Armstrong <ta...@cloudera.com>
Authored: Tue Oct 24 11:04:55 2017 -0700
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Wed Oct 25 00:48:44 2017 +0000

----------------------------------------------------------------------
 be/src/runtime/bufferpool/system-allocator.cc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/98f8b19c/be/src/runtime/bufferpool/system-allocator.cc
----------------------------------------------------------------------
diff --git a/be/src/runtime/bufferpool/system-allocator.cc b/be/src/runtime/bufferpool/system-allocator.cc
index b3ba2b8..8dc4625 100644
--- a/be/src/runtime/bufferpool/system-allocator.cc
+++ b/be/src/runtime/bufferpool/system-allocator.cc
@@ -96,7 +96,8 @@ Status SystemAllocator::AllocateViaMMap(int64_t len, uint8_t** buffer_mem) {
       map_len -= fixup;
     }
     munmap(mem + len, map_len - len);
-    DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) % HUGE_PAGE_SIZE, 0) << mem;
+    DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) % HUGE_PAGE_SIZE, 0)
+        << std::hex << reinterpret_cast<uintptr_t>(mem);
     // Mark the buffer as a candidate for promotion to huge pages. The Linux Transparent
     // Huge Pages implementation will try to back the memory with a huge page if it is
     // enabled. MADV_HUGEPAGE was introduced in 2.6.38, so we similarly need to skip this


[5/5] incubator-impala git commit: IMPALA-4236: Codegen CopyRows() for select nodes

Posted by ta...@apache.org.
IMPALA-4236: Codegen CopyRows() for select nodes

Testing:
Added test case to verify that CopyRows in select node is successfully
codegened.
Improved test coverage for select node with limit.

Performance:
Queries used (num_nodes set to 1):
500 Predicates: select * from (select * from tpch_parquet.lineitem
limit 6001215) t1 where l_partkey > 10 and l_extendedprice > 10000 and
l_linenumber > 1 and l_comment >'foo0' .... and l_comment >'foo500'
order by l_orderkey limit 10;

1 Predicate: select * from (select * from tpch_parquet.lineitem
limit 6001215) t1 where l_partkey > 10 order by l_orderkey limit 10;

+--------------+-----------------------------------------------------+
|              |      500 Predicates      |       1 Predicate        |
|              +------------+-------------+------------+-------------+
|              |   After    |   Before    |   After    |   Before    |
+--------------+------------+-------------+------------+-------------+
| Select Node  | 12s385ms   | 1m1s        | 234ms      | 797ms       |
| Codegen time | 2s619ms    | 1s962ms     | 200ms      | 181ms       |
+--------------+------------+-------------+------------+-------------+

Change-Id: Ie0d496d004418468e16b6f564f90f45ebbf87c1e
Reviewed-on: http://gerrit.cloudera.org:8080/8196
Reviewed-by: Bikramjeet Vig <bi...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/ca55b592
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/ca55b592
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/ca55b592

Branch: refs/heads/master
Commit: ca55b5926ecfaf764f3f46add4391588e18b90f0
Parents: 98f8b19
Author: Bikramjeet Vig <bi...@cloudera.com>
Authored: Wed Sep 6 14:33:40 2017 -0700
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Wed Oct 25 01:17:28 2017 +0000

----------------------------------------------------------------------
 be/src/codegen/gen_ir_descriptions.py           |   3 +-
 be/src/codegen/impala-ir.cc                     |   1 +
 be/src/exec/CMakeLists.txt                      |   1 +
 be/src/exec/select-node-ir.cc                   |  41 ++++++++
 be/src/exec/select-node.cc                      | 102 +++++++++----------
 be/src/exec/select-node.h                       |  22 ++--
 .../queries/QueryTest/inline-view-limit.test    |  12 +++
 tests/query_test/test_codegen.py                |  11 ++
 8 files changed, 131 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/be/src/codegen/gen_ir_descriptions.py
----------------------------------------------------------------------
diff --git a/be/src/codegen/gen_ir_descriptions.py b/be/src/codegen/gen_ir_descriptions.py
index 5e1ce43..5236f7b 100755
--- a/be/src/codegen/gen_ir_descriptions.py
+++ b/be/src/codegen/gen_ir_descriptions.py
@@ -206,7 +206,8 @@ ir_functions = [
   ["UNION_MATERIALIZE_BATCH",
   "_ZN6impala9UnionNode16MaterializeBatchEPNS_8RowBatchEPPh"],
   ["BLOOM_FILTER_INSERT_NO_AVX2", "_ZN6impala11BloomFilter12InsertNoAvx2Ej"],
-  ["BLOOM_FILTER_INSERT_AVX2", "_ZN6impala11BloomFilter10InsertAvx2Ej"]
+  ["BLOOM_FILTER_INSERT_AVX2", "_ZN6impala11BloomFilter10InsertAvx2Ej"],
+  ["SELECT_NODE_COPY_ROWS", "_ZN6impala10SelectNode8CopyRowsEPNS_8RowBatchE"]
 ]
 
 enums_preamble = '\

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/be/src/codegen/impala-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/codegen/impala-ir.cc b/be/src/codegen/impala-ir.cc
index 24e0ce7..bc3cfcb 100644
--- a/be/src/codegen/impala-ir.cc
+++ b/be/src/codegen/impala-ir.cc
@@ -33,6 +33,7 @@
 #include "exec/partitioned-aggregation-node-ir.cc"
 #include "exec/partitioned-hash-join-builder-ir.cc"
 #include "exec/partitioned-hash-join-node-ir.cc"
+#include "exec/select-node-ir.cc"
 #include "exec/topn-node-ir.cc"
 #include "exec/union-node-ir.cc"
 #include "exprs/aggregate-functions-ir.cc"

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/be/src/exec/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/be/src/exec/CMakeLists.txt b/be/src/exec/CMakeLists.txt
index b5f7d3e..aab1383 100644
--- a/be/src/exec/CMakeLists.txt
+++ b/be/src/exec/CMakeLists.txt
@@ -85,6 +85,7 @@ add_library(Exec
   scan-node.cc
   scanner-context.cc
   select-node.cc
+  select-node-ir.cc
   singular-row-src-node.cc
   sort-node.cc
   subplan-node.cc

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/be/src/exec/select-node-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exec/select-node-ir.cc b/be/src/exec/select-node-ir.cc
new file mode 100644
index 0000000..35cea13
--- /dev/null
+++ b/be/src/exec/select-node-ir.cc
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "exec/select-node.h"
+#include "runtime/tuple-row.h"
+
+using namespace impala;
+
+void SelectNode::CopyRows(RowBatch* output_batch) {
+  ScalarExprEvaluator* const* conjunct_evals = conjunct_evals_.data();
+  int num_conjuncts = conjuncts_.size();
+  DCHECK_EQ(num_conjuncts, conjunct_evals_.size());
+
+  FOREACH_ROW(child_row_batch_.get(), child_row_idx_, batch_iter) {
+    // Add a new row to output_batch
+    int dst_row_idx = output_batch->AddRow();
+    TupleRow* dst_row = output_batch->GetRow(dst_row_idx);
+    TupleRow* src_row = batch_iter.Get();
+    ++child_row_idx_;
+    if (EvalConjuncts(conjunct_evals, num_conjuncts, src_row)) {
+      output_batch->CopyRow(src_row, dst_row);
+      output_batch->CommitLastRow();
+      ++num_rows_returned_;
+      if (ReachedLimit() || output_batch->AtCapacity()) return;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/be/src/exec/select-node.cc
----------------------------------------------------------------------
diff --git a/be/src/exec/select-node.cc b/be/src/exec/select-node.cc
index 86aac1d..b82b3e3 100644
--- a/be/src/exec/select-node.cc
+++ b/be/src/exec/select-node.cc
@@ -16,6 +16,7 @@
 // under the License.
 
 #include "exec/select-node.h"
+#include "codegen/llvm-codegen.h"
 #include "exprs/scalar-expr.h"
 #include "exprs/scalar-expr-evaluator.h"
 #include "runtime/row-batch.h"
@@ -26,6 +27,8 @@
 
 #include "common/names.h"
 
+using llvm::Function;
+
 namespace impala {
 
 SelectNode::SelectNode(
@@ -33,7 +36,8 @@ SelectNode::SelectNode(
     : ExecNode(pool, tnode, descs),
       child_row_batch_(NULL),
       child_row_idx_(0),
-      child_eos_(false) {
+      child_eos_(false),
+      codegend_copy_rows_fn_(nullptr) {
 }
 
 Status SelectNode::Prepare(RuntimeState* state) {
@@ -42,6 +46,35 @@ Status SelectNode::Prepare(RuntimeState* state) {
   return Status::OK();
 }
 
+void SelectNode::Codegen(RuntimeState* state) {
+  DCHECK(state->ShouldCodegen());
+  ExecNode::Codegen(state);
+  if (IsNodeCodegenDisabled()) return;
+  SCOPED_TIMER(state->codegen()->codegen_timer());
+  Status codegen_status = CodegenCopyRows(state);
+  runtime_profile()->AddCodegenMsg(codegen_status.ok(), codegen_status);
+}
+
+Status SelectNode::CodegenCopyRows(RuntimeState* state) {
+  LlvmCodeGen* codegen = state->codegen();
+  DCHECK(codegen != nullptr);
+  Function* copy_rows_fn = codegen->GetFunction(IRFunction::SELECT_NODE_COPY_ROWS, true);
+  DCHECK(copy_rows_fn != nullptr);
+
+  Function* eval_conjuncts_fn;
+  RETURN_IF_ERROR(
+      ExecNode::CodegenEvalConjuncts(codegen, conjuncts_, &eval_conjuncts_fn));
+
+  int replaced = codegen->ReplaceCallSites(copy_rows_fn, eval_conjuncts_fn,
+      "EvalConjuncts");
+  DCHECK_EQ(replaced, 1);
+  copy_rows_fn = codegen->FinalizeFunction(copy_rows_fn);
+  if (copy_rows_fn == nullptr) return Status("Failed to finalize CopyRows().");
+  codegen->AddFunctionToJit(copy_rows_fn,
+      reinterpret_cast<void**>(&codegend_copy_rows_fn_));
+  return Status::OK();
+}
+
 Status SelectNode::Open(RuntimeState* state) {
   SCOPED_TIMER(runtime_profile_->total_time_counter());
   RETURN_IF_ERROR(ExecNode::Open(state));
@@ -54,69 +87,32 @@ Status SelectNode::Open(RuntimeState* state) {
 Status SelectNode::GetNext(RuntimeState* state, RowBatch* row_batch, bool* eos) {
   SCOPED_TIMER(runtime_profile_->total_time_counter());
   RETURN_IF_ERROR(ExecDebugAction(TExecNodePhase::GETNEXT, state));
-
-  if (ReachedLimit() || (child_row_idx_ == child_row_batch_->num_rows() && child_eos_)) {
-    // we're already done or we exhausted the last child batch and there won't be any
-    // new ones
-    *eos = true;
-    child_row_batch_->TransferResourceOwnership(row_batch);
-    return Status::OK();
-  }
-  *eos = false;
-
   // start (or continue) consuming row batches from child
-  while (true) {
+  do {
     RETURN_IF_CANCELLED(state);
     RETURN_IF_ERROR(QueryMaintenance(state));
-    if (child_row_idx_ == child_row_batch_->num_rows()) {
-      child_row_idx_ = 0;
-      // fetch next batch
-      child_row_batch_->TransferResourceOwnership(row_batch);
-      child_row_batch_->Reset();
-      if (row_batch->AtCapacity()) return Status::OK();
+    if (child_row_batch_->num_rows() == 0) {
+      // Fetch rows from child if either child row batch has been
+      // consumed completely or it is empty.
       RETURN_IF_ERROR(child(0)->GetNext(state, child_row_batch_.get(), &child_eos_));
     }
-
-    if (CopyRows(row_batch)) {
-      *eos = ReachedLimit()
-          || (child_row_idx_ == child_row_batch_->num_rows() && child_eos_);
-      if (*eos) child_row_batch_->TransferResourceOwnership(row_batch);
-      return Status::OK();
+    if (codegend_copy_rows_fn_ != nullptr) {
+      codegend_copy_rows_fn_(this, row_batch);
+    } else {
+      CopyRows(row_batch);
     }
-    if (child_eos_) {
-      // finished w/ last child row batch, and child eos is true
+    COUNTER_SET(rows_returned_counter_, num_rows_returned_);
+    *eos = ReachedLimit()
+        || (child_row_idx_ == child_row_batch_->num_rows() && child_eos_);
+    if (*eos || child_row_idx_ == child_row_batch_->num_rows()) {
+      child_row_idx_ = 0;
       child_row_batch_->TransferResourceOwnership(row_batch);
-      *eos = true;
-      return Status::OK();
+      child_row_batch_->Reset();
     }
-  }
+  } while (!*eos && !row_batch->AtCapacity());
   return Status::OK();
 }
 
-bool SelectNode::CopyRows(RowBatch* output_batch) {
-  ScalarExprEvaluator* const* conjunct_evals = conjunct_evals_.data();
-  int num_conjuncts = conjuncts_.size();
-  DCHECK_EQ(num_conjuncts, conjunct_evals_.size());
-
-  while (child_row_idx_ < child_row_batch_->num_rows()) {
-    // Add a new row to output_batch
-    int dst_row_idx = output_batch->AddRow();
-    TupleRow* dst_row = output_batch->GetRow(dst_row_idx);
-    TupleRow* src_row = child_row_batch_->GetRow(child_row_idx_);
-    // Make sure to increment row idx before returning.
-    ++child_row_idx_;
-
-    if (EvalConjuncts(conjunct_evals, num_conjuncts, src_row)) {
-      output_batch->CopyRow(src_row, dst_row);
-      output_batch->CommitLastRow();
-      ++num_rows_returned_;
-      COUNTER_SET(rows_returned_counter_, num_rows_returned_);
-      if (ReachedLimit() || output_batch->AtCapacity()) return true;
-    }
-  }
-  return output_batch->AtCapacity();
-}
-
 Status SelectNode::Reset(RuntimeState* state) {
   child_row_batch_->Reset();
   child_row_idx_ = 0;

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/be/src/exec/select-node.h
----------------------------------------------------------------------
diff --git a/be/src/exec/select-node.h b/be/src/exec/select-node.h
index 3f8749a..ce85cfb 100644
--- a/be/src/exec/select-node.h
+++ b/be/src/exec/select-node.h
@@ -36,11 +36,12 @@ class SelectNode : public ExecNode {
  public:
   SelectNode(ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs);
 
-  virtual Status Prepare(RuntimeState* state);
-  virtual Status Open(RuntimeState* state);
-  virtual Status GetNext(RuntimeState* state, RowBatch* row_batch, bool* eos);
-  virtual Status Reset(RuntimeState* state);
-  virtual void Close(RuntimeState* state);
+  virtual Status Prepare(RuntimeState* state) override;
+  virtual void Codegen(RuntimeState* state) override;
+  virtual Status Open(RuntimeState* state) override;
+  virtual Status GetNext(RuntimeState* state, RowBatch* row_batch, bool* eos) override;
+  virtual Status Reset(RuntimeState* state) override;
+  virtual void Close(RuntimeState* state) override;
 
  private:
   /////////////////////////////////////////
@@ -58,10 +59,15 @@ class SelectNode : public ExecNode {
   /// END: Members that must be Reset()
   /////////////////////////////////////////
 
+  typedef void (*CopyRowsFn)(SelectNode*, RowBatch*);
+  CopyRowsFn codegend_copy_rows_fn_;
+
   /// Copy rows from child_row_batch_ for which conjuncts_ evaluate to true to
-  /// output_batch, up to limit_.
-  /// Return true if limit was hit or output_batch should be returned, otherwise false.
-  bool CopyRows(RowBatch* output_batch);
+  /// output_batch, up to limit_ or till the output row batch reaches capacity.
+  void CopyRows(RowBatch* output_batch);
+
+  /// Codegen CopyRows(). Used for mostly codegen'ing the conjuncts evaluation logic.
+  Status CodegenCopyRows(RuntimeState* state);
 };
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/testdata/workloads/functional-query/queries/QueryTest/inline-view-limit.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-query/queries/QueryTest/inline-view-limit.test b/testdata/workloads/functional-query/queries/QueryTest/inline-view-limit.test
index 38e81b0..93a7a58 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/inline-view-limit.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/inline-view-limit.test
@@ -91,3 +91,15 @@ select count(*) from (
 ---- TYPES
 bigint
 ====
+---- QUERY
+# Test that limit is enforced by select node.
+select * from (select * from alltypes order by id limit 20) t1 where int_col <100 limit 5
+---- RESULTS
+0,true,0,0,0,0,0,0,'01/01/09','0',2009-01-01 00:00:00,2009,1
+1,false,1,1,1,10,1.100000023841858,10.1,'01/01/09','1',2009-01-01 00:01:00,2009,1
+2,true,2,2,2,20,2.200000047683716,20.2,'01/01/09','2',2009-01-01 00:02:00.100000000,2009,1
+3,false,3,3,3,30,3.299999952316284,30.3,'01/01/09','3',2009-01-01 00:03:00.300000000,2009,1
+4,true,4,4,4,40,4.400000095367432,40.4,'01/01/09','4',2009-01-01 00:04:00.600000000,2009,1
+---- TYPES
+INT, BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, FLOAT, DOUBLE, STRING, STRING, TIMESTAMP, INT, INT
+====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/ca55b592/tests/query_test/test_codegen.py
----------------------------------------------------------------------
diff --git a/tests/query_test/test_codegen.py b/tests/query_test/test_codegen.py
index 8a4390a..ccd85e1 100644
--- a/tests/query_test/test_codegen.py
+++ b/tests/query_test/test_codegen.py
@@ -19,6 +19,8 @@
 
 from tests.common.impala_test_suite import ImpalaTestSuite
 from tests.common.test_dimensions import create_exec_option_dimension_from_dict
+from tests.common.test_result_verifier import get_node_exec_options,\
+    assert_codegen_enabled
 
 class TestCodegen(ImpalaTestSuite):
   @classmethod
@@ -39,3 +41,12 @@ class TestCodegen(ImpalaTestSuite):
   def test_disable_codegen(self, vector):
     """Test that codegen is enabled/disabled by the planner as expected."""
     self.run_test_case('QueryTest/disable-codegen', vector)
+
+  def test_select_node_codegen(self, vector):
+    """Test that select node is codegened"""
+    result = self.execute_query('select * from (select * from functional.alltypes '
+        'limit 1000000) t1 where int_col > 10 limit 10')
+    exec_options = get_node_exec_options(result.runtime_profile, 1)
+    # Make sure test fails if there are no exec options in the profile for the node
+    assert len(exec_options) > 0
+    assert_codegen_enabled(result.runtime_profile, [1])
\ No newline at end of file


[2/5] incubator-impala git commit: IMPALA-6070: Parallel data load.

Posted by ta...@apache.org.
IMPALA-6070: Parallel data load.

This commit loads functional-query, TPC-H data, and TPC-DS data in
parallel. In parallel, these take about 37 minutes, dominated by
functional-query. Serially, these take about 30 minutes more, namely the
13 minutes of tpcds and 16 minutes of tpcds. This works out nicely
because CPU usage during data load is very low in aggregate. (We don't
sustain more than 1 CPU of load, whereas build machines are likely to
have many CPUs.)

To do this, I added support to run-step.sh to have a notion of a
backgroundable task, and support waiting for all tasks.

I also increased the heapsize of our HiveServer2 server. When datasets
were being loaded in parallel, we ran out of memory at 256MB of heap.

The resulting log output is currently like so (but without the
timestamps):

15:58:04  Started Loading functional-query data in background; pid 8105.
15:58:04  Started Loading TPC-H data in background; pid 8106.
15:58:04  Loading functional-query data (logging to /home/impdev/Impala/logs/data_loading/load-functional-query.log)...
15:58:04  Started Loading TPC-DS data in background; pid 8107.
15:58:04  Loading TPC-H data (logging to /home/impdev/Impala/logs/data_loading/load-tpch.log)...
15:58:04  Loading TPC-DS data (logging to /home/impdev/Impala/logs/data_loading/load-tpcds.log)...
16:11:31    Loading workload 'tpch' using exploration strategy 'core' OK (Took: 13 min 27 sec)
16:14:33    Loading workload 'tpcds' using exploration strategy 'core' OK (Took: 16 min 29 sec)
16:35:08    Loading workload 'functional-query' using exploration strategy 'exhaustive' OK (Took: 37 min 4 sec)

I tested dataloading with the following command on an 8-core, 32GB
machine. I saw 19GB of available memory during my run:
  ./buildall.sh -testdata -build_shared_libs -start_minicluster -start_impala_cluster -format

Change-Id: I836c4e1586f229621c102c4f4ba22ce7224ab9ac
Reviewed-on: http://gerrit.cloudera.org:8080/8320
Reviewed-by: Jim Apple <jb...@apache.org>
Reviewed-by: Michael Brown <mi...@cloudera.com>
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/e020c371
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/e020c371
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/e020c371

Branch: refs/heads/master
Commit: e020c37106383be5416f882cbe11fc25efad8968
Parents: 77e010a
Author: Philip Zeyliger <ph...@cloudera.com>
Authored: Tue Oct 17 17:10:49 2017 -0700
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Wed Oct 25 00:00:25 2017 +0000

----------------------------------------------------------------------
 testdata/bin/create-load-data.sh | 11 ++++++++---
 testdata/bin/run-hive-server.sh  |  2 +-
 testdata/bin/run-step.sh         | 36 ++++++++++++++++++++++++++++++++++-
 3 files changed, 44 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e020c371/testdata/bin/create-load-data.sh
----------------------------------------------------------------------
diff --git a/testdata/bin/create-load-data.sh b/testdata/bin/create-load-data.sh
index 97787c2..099fe59 100755
--- a/testdata/bin/create-load-data.sh
+++ b/testdata/bin/create-load-data.sh
@@ -477,9 +477,15 @@ fi
 
 if [ $SKIP_METADATA_LOAD -eq 0 ]; then
   run-step "Loading custom schemas" load-custom-schemas.log load-custom-schemas
-  run-step "Loading functional-query data" load-functional-query.log \
+  # Run some steps in parallel, with run-step-backgroundable / run-step-wait-all.
+  # This is effective on steps that take a long time and don't depend on each
+  # other. Functional-query takes about ~35 minutes, and TPC-H and TPC-DS can
+  # finish while functional-query is running.
+  run-step-backgroundable "Loading functional-query data" load-functional-query.log \
       load-data "functional-query" "exhaustive"
-  run-step "Loading TPC-H data" load-tpch.log load-data "tpch" "core"
+  run-step-backgroundable "Loading TPC-H data" load-tpch.log load-data "tpch" "core"
+  run-step-backgroundable "Loading TPC-DS data" load-tpcds.log load-data "tpcds" "core"
+  run-step-wait-all
   # Load tpch nested data.
   # TODO: Hacky and introduces more complexity into the system, but it is expedient.
   if [[ -n "$CM_HOST" ]]; then
@@ -487,7 +493,6 @@ if [ $SKIP_METADATA_LOAD -eq 0 ]; then
   fi
   run-step "Loading nested data" load-nested.log \
     ${IMPALA_HOME}/testdata/bin/load_nested.py ${LOAD_NESTED_ARGS:-}
-  run-step "Loading TPC-DS data" load-tpcds.log load-data "tpcds" "core"
   run-step "Loading auxiliary workloads" load-aux-workloads.log load-aux-workloads
   run-step "Loading dependent tables" copy-and-load-dependent-tables.log \
       copy-and-load-dependent-tables

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e020c371/testdata/bin/run-hive-server.sh
----------------------------------------------------------------------
diff --git a/testdata/bin/run-hive-server.sh b/testdata/bin/run-hive-server.sh
index 530b804..42d95b5 100755
--- a/testdata/bin/run-hive-server.sh
+++ b/testdata/bin/run-hive-server.sh
@@ -72,7 +72,7 @@ ${CLUSTER_BIN}/wait-for-metastore.py --transport=${METASTORE_TRANSPORT}
 if [ ${ONLY_METASTORE} -eq 0 ]; then
   # Starts a HiveServer2 instance on the port specified by the HIVE_SERVER2_THRIFT_PORT
   # environment variable.
-  hive --service hiveserver2 > ${LOGDIR}/hive-server2.out 2>&1 &
+  HADOOP_HEAPSIZE="512" hive --service hiveserver2 > ${LOGDIR}/hive-server2.out 2>&1 &
 
   # Wait for the HiveServer2 service to come up because callers of this script
   # may rely on it being available.

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/e020c371/testdata/bin/run-step.sh
----------------------------------------------------------------------
diff --git a/testdata/bin/run-step.sh b/testdata/bin/run-step.sh
index 45c5774..9943013 100755
--- a/testdata/bin/run-step.sh
+++ b/testdata/bin/run-step.sh
@@ -48,5 +48,39 @@ function run-step {
     return 1
   fi
   ELAPSED_TIME=$(($SECONDS - $START_TIME))
-  echo "    OK (Took: $(($ELAPSED_TIME/60)) min $(($ELAPSED_TIME%60)) sec)"
+  echo "  ${MSG} OK (Took: $(($ELAPSED_TIME/60)) min $(($ELAPSED_TIME%60)) sec)"
+}
+
+# Array to manage background tasks.
+declare -a RUN_STEP_PIDS
+declare -a RUN_STEP_MSGS
+
+# Runs the given step in the background. Many tasks may be started in the
+# background, and all of them must be joined together with run-step-wait-all.
+# No dependency management or maximums on number of tasks are provided.
+function run-step-backgroundable {
+  MSG="$1"
+  run-step "$@" &
+  local pid=$!
+  echo "Started ${MSG} in background; pid $pid."
+  RUN_STEP_PIDS+=($pid)
+  RUN_STEP_MSGS+=("${MSG}")
+}
+
+# Wait for all tasks that were run with run-step-backgroundable.
+# Fails if any of the background tasks has failed. Clears $RUN_STEP_PIDS.
+function run-step-wait-all {
+  local ret=0
+  for idx in "${!RUN_STEP_PIDS[@]}"; do
+    pid="${RUN_STEP_PIDS[$idx]}"
+    msg="${RUN_STEP_MSGS[$idx]}"
+
+    if ! wait $pid; then
+      ret=1
+      echo "Background task $msg (pid $pid) failed."
+    fi
+  done
+  RUN_STEP_PIDS=()
+  RUN_STEP_MSGS=()
+  return $ret
 }


[3/5] incubator-impala git commit: IMPALA-5018: Error on decimal modulo or divide by zero

Posted by ta...@apache.org.
IMPALA-5018: Error on decimal modulo or divide by zero

Before this patch, decimal operations would never produce an error.
Division by and modulo zero would result in a NULL.

In this patch, we change this behavior so that we raise an error
instead of returning a NULL. We also modify the format of the decimal
expr tests format to also include an error field.

Testing:
- Added several expr and end to end tests.

Change-Id: If7a7131e657fcdd293ade78d62f851dac0f1e3eb
Reviewed-on: http://gerrit.cloudera.org:8080/8344
Reviewed-by: Dan Hecht <dh...@cloudera.com>
Tested-by: Impala Public Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/5ebea0ec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/5ebea0ec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/5ebea0ec

Branch: refs/heads/master
Commit: 5ebea0ec4db9a0b954988975b4b7c02971a780a0
Parents: e020c37
Author: Taras Bobrovytsky <tb...@cloudera.com>
Authored: Thu Oct 19 13:43:14 2017 -0700
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Wed Oct 25 00:44:34 2017 +0000

----------------------------------------------------------------------
 be/src/exprs/decimal-operators-ir.cc            |   23 +-
 be/src/exprs/expr-test.cc                       | 1156 +++++++++---------
 .../queries/QueryTest/decimal-exprs.test        |   68 +-
 3 files changed, 682 insertions(+), 565 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/5ebea0ec/be/src/exprs/decimal-operators-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/decimal-operators-ir.cc b/be/src/exprs/decimal-operators-ir.cc
index 17ba972..4af2366 100644
--- a/be/src/exprs/decimal-operators-ir.cc
+++ b/be/src/exprs/decimal-operators-ir.cc
@@ -716,34 +716,43 @@ BooleanVal DecimalOperators::CastToBooleanVal(
         ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \
     int return_scale = \
         ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \
-    bool round = \
+    const bool decimal_v2 = \
         ctx->impl()->GetConstFnAttr(FunctionContextImpl::DECIMAL_V2); \
     switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE)) { \
       case 4: { \
         Decimal4Value x_val = GetDecimal4Value(x, x_size, &overflow); \
         Decimal4Value y_val = GetDecimal4Value(y, y_size, &overflow); \
         Decimal4Value result = x_val.OP_FN<int32_t>(x_scale, y_val, y_scale, \
-            return_precision, return_scale, round, &is_nan, &overflow); \
+            return_precision, return_scale, decimal_v2, &is_nan, &overflow); \
         DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \
-        if (is_nan) return DecimalVal::null(); \
+        if (is_nan) { \
+          if (decimal_v2) ctx->SetError("Cannot divide decimal by zero"); \
+          return DecimalVal::null(); \
+        } \
         return DecimalVal(result.value()); \
       } \
       case 8: { \
         Decimal8Value x_val = GetDecimal8Value(x, x_size, &overflow); \
         Decimal8Value y_val = GetDecimal8Value(y, y_size, &overflow); \
         Decimal8Value result = x_val.OP_FN<int64_t>(x_scale, y_val, y_scale, \
-            return_precision, return_scale, round, &is_nan, &overflow); \
+            return_precision, return_scale, decimal_v2, &is_nan, &overflow); \
         DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \
-        if (is_nan) return DecimalVal::null(); \
+        if (is_nan) { \
+          if (decimal_v2) ctx->SetError("Cannot divide decimal by zero"); \
+          return DecimalVal::null(); \
+        } \
         return DecimalVal(result.value()); \
       } \
       case 16: { \
         Decimal16Value x_val = GetDecimal16Value(x, x_size, &overflow); \
         Decimal16Value y_val = GetDecimal16Value(y, y_size, &overflow); \
         Decimal16Value result = x_val.OP_FN<int128_t>(x_scale, y_val, y_scale, \
-            return_precision, return_scale, round, &is_nan, &overflow); \
+            return_precision, return_scale, decimal_v2, &is_nan, &overflow); \
         RETURN_IF_OVERFLOW(ctx, overflow, DecimalVal); \
-        if (is_nan) return DecimalVal::null(); \
+        if (is_nan) { \
+          if (decimal_v2) ctx->SetError("Cannot divide decimal by zero"); \
+          return DecimalVal::null(); \
+        } \
         return DecimalVal(result.value()); \
       } \
       default: \

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/5ebea0ec/be/src/exprs/expr-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc
index ed78535..b509da6 100644
--- a/be/src/exprs/expr-test.cc
+++ b/be/src/exprs/expr-test.cc
@@ -1476,6 +1476,7 @@ TEST_F(ExprTest, ArithmeticExprs) {
 // Use a table-driven approach to test DECIMAL expressions to make it easier to test
 // both the old (decimal_v2=false) and new (decimal_v2=true) DECIMAL semantics.
 struct DecimalExpectedResult {
+  bool error;
   bool null;
   int128_t scaled_val;
   int precision;
@@ -1558,921 +1559,960 @@ int128_t StringToInt128(string s) {
 
 // Format is:
 // { Test Expression (as a string),
-//  { expected null, scaled_val, precision, scale for V1
-//    expected null, scaled_val, precision, scale for V2 }}
+//  { expected error, expected null, scaled_val, precision, scale for V1
+//    expected error, expected null, scaled_val, precision, scale for V2 }}
 DecimalTestCase decimal_cases[] = {
   // Test add/subtract operators
-  { "1.23 + cast(1 as decimal(4,3))", {{ false, 2230, 5, 3 }}},
-  { "1.23 - cast(0.23 as decimal(10,3))", {{ false, 1000, 11, 3 }}},
-  { "cast(1.23 as decimal(8,2)) + cast(1 as decimal(20,3))", {{ false, 2230, 21, 3 }}},
-  { "cast(1.23 as decimal(30,2)) - cast(1 as decimal(4,3))", {{ false, 230, 32, 3 }}},
-  { "cast(1 as decimal(38,0)) + cast(.2 as decimal(38,1))", {{ false, 12, 38, 1 }}},
+  { "1.23 + cast(1 as decimal(4,3))", {{ false, false, 2230, 5, 3 }}},
+  { "1.23 - cast(0.23 as decimal(10,3))", {{ false, false, 1000, 11, 3 }}},
+  { "cast(1.23 as decimal(8,2)) + cast(1 as decimal(20,3))",
+    {{ false, false, 2230, 21, 3 }}},
+  { "cast(1.23 as decimal(30,2)) - cast(1 as decimal(4,3))",
+    {{ false, false, 230, 32, 3 }}},
+  { "cast(1 as decimal(38,0)) + cast(.2 as decimal(38,1))",
+    {{ false, false, 12, 38, 1 }}},
   // Test multiply operator
   { "cast(1.23 as decimal(30,2)) * cast(1 as decimal(10,3))",
-    {{ false, 123000, 38, 5 }}},
+    {{ false, false, 123000, 38, 5 }}},
   { "cast(1.23 as decimal(3,2)) * cast(1 as decimal(20,3))",
-    {{ false, 123000, 23, 5 },
-     { false, 123000, 24, 5 }}},
+    {{ false, false, 123000, 23, 5 },
+     { false, false, 123000, 24, 5 }}},
   { "cast(0.1 as decimal(20,20)) * cast(1 as decimal(20,19))",
-    {{ false, StringToInt128("10000000000000000000000000000000000000"), 38, 38 },
-     { false, StringToInt128("100000000000000000000000000000000000"), 38, 36 }}},
+    {{ false, false, StringToInt128("10000000000000000000000000000000000000"), 38, 38 },
+     { false, false, StringToInt128("100000000000000000000000000000000000"), 38, 36 }}},
   { "cast(111.22 as decimal(5,2)) * cast(3333.444 as decimal(7,3))",
-    {{ false, 37074564168, 12, 5 },
-     { false, 37074564168, 13, 5 }}},
+    {{ false, false, 37074564168, 12, 5 },
+     { false, false, 37074564168, 13, 5 }}},
   { "cast(0.01 as decimal(38,38)) * cast(25 as decimal(38,0))",
-    {{ false, StringToInt128("25000000000000000000000000000000000000"), 38, 38 },
-     { false, 250000, 38, 6 }}},
+    {{ false, false, StringToInt128("25000000000000000000000000000000000000"), 38, 38 },
+     { false, false, 250000, 38, 6 }}},
   { "cast(-0.01 as decimal(38,38)) * cast(25 as decimal(38,0))",
-    {{ false, StringToInt128("-25000000000000000000000000000000000000"), 38, 38 },
-     { false, -250000, 38, 6 }}},
+    {{ false, false, StringToInt128("-25000000000000000000000000000000000000"), 38, 38 },
+     { false, false, -250000, 38, 6 }}},
   { "cast(-0.01 as decimal(38,38)) * cast(-25 as decimal(38,0))",
-    {{ false, StringToInt128("25000000000000000000000000000000000000"), 38, 38 },
-     { false, 250000, 38, 6 }}},
+    {{ false, false, StringToInt128("25000000000000000000000000000000000000"), 38, 38 },
+     { false, false, 250000, 38, 6 }}},
   { "cast(0.1 as decimal(38,38)) * cast(25 as decimal(38,0))",
-    {{ true, 0, 38, 38 },
-     { false, 2500000, 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, 2500000, 38, 6 }}},
   { "cast(-0.1 as decimal(38,38)) * cast(25 as decimal(38,0))",
-    {{ true, 0, 38, 38 },
-     { false, -2500000, 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, -2500000, 38, 6 }}},
   { "cast(-0.1 as decimal(38,38)) * cast(-25 as decimal(38,0))",
-    {{ true, 0, 38, 38 },
-     { false, 2500000, 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, 2500000, 38, 6 }}},
   { "cast(9999999999999999.9999 as decimal(20,4)) * "
       "cast(9999999999999999.994 as decimal(19,3))",
-    {{ true, 0, 38, 7 },
-     { false, StringToInt128("99999999999999999939000000000000000001"), 38, 6 }}},
+    {{ false, true, 0, 38, 7 },
+     { false, false, StringToInt128("99999999999999999939000000000000000001"), 38, 6 }}},
   { "cast(9.99999 as decimal(6,5)) * "
       "cast(9999999999999999999999999999999.94 as decimal(33,2))",
-    {{ true, 0, 38, 7 },
-     { false, StringToInt128("99999899999999999999999999999999400001"), 38, 6 }}},
+    {{ false, true, 0, 38, 7 },
+     { false, false, StringToInt128("99999899999999999999999999999999400001"), 38, 6 }}},
   { "cast(0 as decimal(38,38)) * cast(1 as decimal(5,2))",
-    {{ false, 0, 38, 38 },
-     { false, 0, 38, 34 }}},
+    {{ false, false, 0, 38, 38 },
+     { false, false, 0, 38, 34 }}},
   { "cast(12345.67 as decimal(7,2)) * cast(12345.67 as decimal(7,2))",
-    {{ false, 1524155677489, 14, 4 },
-     { false, 1524155677489, 15, 4 }}},
+    {{ false, false, 1524155677489, 14, 4 },
+     { false, false, 1524155677489, 15, 4 }}},
   { "cast(2643918831543678.5772617359442611897419 as decimal(38,22)) * "
       "cast(3972211379387512.6946776728996748717839 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("10502204468834736291038133384309593605"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("10502204468834736291038133384309593605"), 38, 6 }}},
   { "cast(-2643918831543678.5772617359442611897419 as decimal(38,22)) * "
       "cast(3972211379387512.6946776728996748717839 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("-10502204468834736291038133384309593605"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("-10502204468834736291038133384309593605"), 38, 6 }}},
   { "cast(-2643918831543678.5772617359442611897419 as decimal(38,22)) * "
       "cast(-3972211379387512.6946776728996748717839 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("10502204468834736291038133384309593605"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("10502204468834736291038133384309593605"), 38, 6 }}},
   { "cast(2545664579818579.6268123468146829994472 as decimal(38,22)) * "
       "cast(8862165565622381.6689679519457799681439 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("22560100980892785285767018366785939200"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("22560100980892785285767018366785939200"), 38, 6 }}},
   { "cast(2575543652687181.7412422395638291836214 as decimal(38,22)) * "
       "cast(9142529549684737.3986798331295277312253 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("23546983951195523383767823614338114083"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("23546983951195523383767823614338114083"), 38, 6 }}},
   { "cast(6188696551164477.9944646378584981371524 as decimal(38,22)) * "
       "cast(9234914917975734.1781526147879384775182 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("57152086103173814294786121078946977968"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("57152086103173814294786121078946977968"), 38, 6 }}},
   { "cast(-6188696551164477.9944646378584981371524 as decimal(38,22)) * "
       "cast(9234914917975734.1781526147879384775182 as decimal(38,22))",
-    {{ true, 0, 38, 38 },
-     { false, StringToInt128("-57152086103173814294786121078946977968"), 38, 6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, false, StringToInt128("-57152086103173814294786121078946977968"), 38, 6 }}},
   { "cast(1.006 as decimal(4,2)) * cast(1.1 as decimal(4,2))",
-    {{ false, 11000, 8, 4 },
-     { false, 11110, 9, 4 }}},
+    {{ false, false, 11000, 8, 4 },
+     { false, false, 11110, 9, 4 }}},
   { "cast(0.9994 as decimal(38,4)) * cast(0.999 as decimal(38,3))",
-    {{ false, 9984006, 38, 7 },
-     { false, 998401, 38, 6 }}},
+    {{ false, false, 9984006, 38, 7 },
+     { false, false, 998401, 38, 6 }}},
   { "cast(0.000000000000000000000000000000000001 as decimal(38,38)) * "
       "cast(0.000000000000000000000000000000000001 as decimal(38,38))",
-    {{ false, 0, 38, 38 },
-     { false, 0, 38, 37 }}},
+    {{ false, false, 0, 38, 38 },
+     { false, false, 0, 38, 37 }}},
   { "cast(0.00000000000000000000000000000000001 as decimal(38,37)) * "
       "cast(0.00000000000000000000000000000000001 as decimal(38,37))",
-    {{ false, 0, 38, 38 },
-     { false, 0, 38, 35 }}},
+    {{ false, false, 0, 38, 38 },
+     { false, false, 0, 38, 35 }}},
   { "cast(0.00000000000000001 as decimal(38,37)) * "
       "cast(0.000000000000000001 as decimal(38,37))",
-    {{ false, 1000, 38, 38 },
-     { false, 1, 38, 35 }}},
+    {{ false, false, 1000, 38, 38 },
+     { false, false, 1, 38, 35 }}},
   { "cast(9e-18 as decimal(38,38)) * cast(1e-21 as decimal(38,38))",
-    {{ false, 0, 38, 38 },
-     { false, 0, 38, 37 }}},
+    {{ false, false, 0, 38, 38 },
+     { false, false, 0, 38, 37 }}},
   { "cast(1e-37 as decimal(38,38)) * cast(0.1 as decimal(38,38))",
-    {{ false, 1, 38, 38 },
-     { false, 0, 38, 37 }}},
+    {{ false, false, 1, 38, 38 },
+     { false, false, 0, 38, 37 }}},
   { "cast(1e-37 as decimal(38,38)) * cast(-0.1 as decimal(38,38))",
-    {{ false, -1, 38, 38 },
-     { false, 0, 38, 37 }}},
+    {{ false, false, -1, 38, 38 },
+     { false, false, 0, 38, 37 }}},
   { "cast(9e-36 as decimal(38,38)) * cast(0.1 as decimal(38,38))",
-    {{ false, 90, 38, 38 },
-     { false, 9, 38, 37 }}},
+    {{ false, false, 90, 38, 38 },
+     { false, false, 9, 38, 37 }}},
   { "cast(9e-37 as decimal(38,38)) * cast(0.1 as decimal(38,38))",
-    {{ false, 9, 38, 38 },
-     { false, 1, 38, 37 }}},
+    {{ false, false, 9, 38, 38 },
+     { false, false, 1, 38, 37 }}},
   // We are multiplying (2^64 - 1) * (2^63 - 1), which produces the largest intermediate
   // result that does not require int256. It overflows because the result is larger than
   // MAX_UNSCALED_DECIMAL16.
-  { "cast(18446744073709551615 as decimal(38,0)) * cast(9223372036854775807 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
-  { "cast(-18446744073709551615 as decimal(38,0)) * cast(9223372036854775807 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
+  { "cast(18446744073709551615 as decimal(38,0)) * "
+    "cast(9223372036854775807 as decimal(38,0))",
+    {{ false, true, 0, 38, 0 }}},
+  { "cast(-18446744073709551615 as decimal(38,0)) * "
+    "cast(9223372036854775807 as decimal(38,0))",
+    {{ false, true, 0, 38, 0 }}},
   // int256 is required. We are multiplying (2^64 - 1) * (2^63) here.
-  { "cast(18446744073709551615 as decimal(38,0)) * cast(9223372036854775808 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
-  { "cast(-18446744073709551615 as decimal(38,0)) * cast(9223372036854775808 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
+  { "cast(18446744073709551615 as decimal(38,0)) * "
+    "cast(9223372036854775808 as decimal(38,0))",
+    {{ false, true, 0, 38, 0 }}},
+  { "cast(-18446744073709551615 as decimal(38,0)) * "
+    "cast(9223372036854775808 as decimal(38,0))",
+    {{ false, true, 0, 38, 0 }}},
   // Largest intermediate result that does not require int256.
-  { "cast(1844674407370.9551615 as decimal(38,7)) * cast(9223372036854775807 as decimal(38,0))",
-    {{ true, 0, 38, 7 },
-     { false, StringToInt128("17014118346046923170401718760531977831"), 38, 6 }}},
-  { "cast(-1844674407370.9551615 as decimal(38,7)) * cast(9223372036854775807 as decimal(38,0))",
-    {{ true, 0, 38, 7 },
-     { false, StringToInt128("-17014118346046923170401718760531977831"), 38, 6 }}},
+  { "cast(1844674407370.9551615 as decimal(38,7)) * "
+    "cast(9223372036854775807 as decimal(38,0))",
+    {{ false, true, 0, 38, 7 },
+     { false, false, StringToInt128("17014118346046923170401718760531977831"), 38, 6 }}},
+  { "cast(-1844674407370.9551615 as decimal(38,7)) * "
+    "cast(9223372036854775807 as decimal(38,0))",
+    {{ false, true, 0, 38, 7 },
+     { false, false, StringToInt128("-17014118346046923170401718760531977831"), 38, 6 }}},
   // int256 is required.
-  { "cast(1844674407370.9551615 as decimal(38,7)) * cast(9223372036854775808 as decimal(38,0))",
-    {{ true, 0, 38, 7 },
-     { false, StringToInt128("17014118346046923172246393167902932992"), 38, 6 }}},
-  { "cast(-1844674407370.9551615 as decimal(38,7)) * cast(9223372036854775808 as decimal(38,0))",
-    {{ true, 0, 38, 7 },
-     { false, StringToInt128("-17014118346046923172246393167902932992"), 38, 6 }}},
+  { "cast(1844674407370.9551615 as decimal(38,7)) * "
+    "cast(9223372036854775808 as decimal(38,0))",
+    {{ false, true, 0, 38, 7 },
+     { false, false, StringToInt128("17014118346046923172246393167902932992"), 38, 6 }}},
+  { "cast(-1844674407370.9551615 as decimal(38,7)) * "
+    "cast(9223372036854775808 as decimal(38,0))",
+    {{ false, true, 0, 38, 7 },
+     { false, false, StringToInt128("-17014118346046923172246393167902932992"), 38, 6 }}},
   // Smallest intermediate value that requires double checking if int256 is required.
-  { "cast(9223372036854775808 as decimal(38,0)) * cast(9223372036854775808 as decimal(38,0))",
-    {{ false, StringToInt128("85070591730234615865843651857942052864"), 38, 0 }}},
-  { "cast(-9223372036854775808 as decimal(38,0)) * cast(9223372036854775808 as decimal(38,0))",
-    {{ false, StringToInt128("-85070591730234615865843651857942052864"), 38, 0 }}},
+  { "cast(9223372036854775808 as decimal(38,0)) * "
+    "cast(9223372036854775808 as decimal(38,0))",
+    {{ false, false, StringToInt128("85070591730234615865843651857942052864"), 38, 0 }}},
+  { "cast(-9223372036854775808 as decimal(38,0)) * "
+    "cast(9223372036854775808 as decimal(38,0))",
+    {{ false, false, StringToInt128("-85070591730234615865843651857942052864"), 38, 0 }}},
   // Scale down the intermediate value by 10^39.
   { "cast(0.33333333333333333333333333333333333333 as decimal(38,38)) * "
       "cast(0.00000000000000000000000000000000000003 as decimal(38,38))",
-    {{ false, 0, 38, 38 },
-     { false, 0, 38, 37 }}},
+    {{ false, false, 0, 38, 38 },
+     { false, false, 0, 38, 37 }}},
   { "cast(0.33333333333333333333333333333333333333 as decimal(38,38)) * "
       "cast(0.3 as decimal(38,38))",
-    {{ false, StringToInt128("9999999999999999999999999999999999999"), 38, 38 },
-     { false, StringToInt128("1000000000000000000000000000000000000"), 38, 37 }}},
+    {{ false, false, StringToInt128("9999999999999999999999999999999999999"), 38, 38 },
+     { false, false, StringToInt128("1000000000000000000000000000000000000"), 38, 37 }}},
   { "cast(10000000000000000000 as decimal(21,0)) * "
       "cast(10000000000000000000 as decimal(21,0))",
-    {{ true, 0, 38, 0 }}},
+    {{ false, true, 0, 38, 0 }}},
   { "cast(1000000000000000.0000 as decimal(38,4)) * "
       "cast(1000000000000000.0000 as decimal(38,4))",
-    {{ true, 0, 38, 8 },
-     { false, StringToInt128("1000000000000000000000000000000000000"), 38, 6 }}},
+    {{ false, true, 0, 38, 8 },
+     { false, false, StringToInt128("1000000000000000000000000000000000000"), 38, 6 }}},
   { "cast(-1000000000000000.0000 as decimal(38,4)) * "
       "cast(1000000000000000.0000 as decimal(38,4))",
-    {{ true, 0, 38, 8 },
-     { false, StringToInt128("-1000000000000000000000000000000000000"), 38, 6 }}},
+    {{ false, true, 0, 38, 8 },
+     { false, false, StringToInt128("-1000000000000000000000000000000000000"), 38, 6 }}},
   // Smallest 256 bit intermediate result that can't be scaled down to 128 bits.
   { "cast(10000000000000000.0000 as decimal(38,4)) * "
       "cast(10000000000000000.0000 as decimal(38,4))",
-    {{ true, 0, 38, 8 },
-     { true, 0, 38, 6 }}},
+    {{ false, true, 0, 38, 8 },
+     { false, true, 0, 38, 6 }}},
   { "cast(-10000000000000000.0000 as decimal(38,4)) * "
       "cast(10000000000000000.0000 as decimal(38,4))",
-    {{ true, 0, 38, 8 },
-     { true, 0, 38, 6 }}},
+    {{ false, true, 0, 38, 8 },
+     { false, true, 0, 38, 6 }}},
   // The reason why the result of (38,38) * (38,38) is (38,37).
   { "cast(0.99999999999999999999999999999999999999 as decimal(38,38)) * "
       "cast(0.99999999999999999999999999999999999999 as decimal(38,38))",
-    {{ false, StringToInt128("99999999999999999999999999999999999998"), 38, 38 },
-     { false, StringToInt128("10000000000000000000000000000000000000"), 38, 37 }}},
+    {{ false, false, StringToInt128("99999999999999999999999999999999999998"), 38, 38 },
+     { false, false, StringToInt128("10000000000000000000000000000000000000"), 38, 37 }}},
   { "cast(-0.99999999999999999999999999999999999999 as decimal(38,38)) * "
       "cast(0.99999999999999999999999999999999999999 as decimal(38,38))",
-    {{ false, StringToInt128("-99999999999999999999999999999999999998"), 38, 38 },
-     { false, StringToInt128("-10000000000000000000000000000000000000"), 38, 37 }}},
+    {{ false, false, StringToInt128("-99999999999999999999999999999999999998"), 38, 38 },
+     { false, false, StringToInt128("-10000000000000000000000000000000000000"), 38, 37 }}},
   { "cast(99999999999999999999999999999999999999 as decimal(38,0)) * "
       "cast(1 as decimal(38,0))",
-    {{ false, StringToInt128("99999999999999999999999999999999999999"), 38, 0 }}},
+    {{ false, false, StringToInt128("99999999999999999999999999999999999999"), 38, 0 }}},
   { "cast(99999999999999999999999999999999999999 as decimal(38,0)) * "
       "cast(-1 as decimal(38,0))",
-    {{ false, StringToInt128("-99999999999999999999999999999999999999"), 38, 0 }}},
+    {{ false, false, StringToInt128("-99999999999999999999999999999999999999"), 38, 0 }}},
   // Rounding.
   { "cast(0.000005 as decimal(38,6)) * cast(0.1 as decimal(38,1))",
-    {{ false, 5, 38, 7 },
-     { false, 1, 38, 6 }}},
+    {{ false, false, 5, 38, 7 },
+     { false, false, 1, 38, 6 }}},
   { "cast(-0.000005 as decimal(38,6)) * cast(0.1 as decimal(38,1))",
-    {{ false, -5, 38, 7 },
-     { false, -1, 38, 6 }}},
+    {{ false, false, -5, 38, 7 },
+     { false, false, -1, 38, 6 }}},
   { "cast(0.000004 as decimal(38,6)) * cast(0.1 as decimal(38,1))",
-    {{ false, 4, 38, 7 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 4, 38, 7 },
+     { false, false, 0, 38, 6 }}},
   { "cast(-0.000004 as decimal(38,6)) * cast(0.1 as decimal(38,1))",
-    {{ false, -4, 38, 7 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, -4, 38, 7 },
+     { false, false, 0, 38, 6 }}},
   // Test divide operator
-  { "cast(1.23 as decimal(8,2)) / cast(1 as decimal(4,3))", {{ false, 12300000, 16, 7}}},
+  { "cast(1.23 as decimal(8,2)) / cast(1 as decimal(4,3))",
+    {{ false, false, 12300000, 16, 7}}},
   { "cast(1.23 as decimal(30,2)) / cast(1 as decimal(20,3))",
-    {{ false,     1230, 38, 3 },
-     { false, 12300000, 38, 7 }}},
+    {{ false, false,     1230, 38, 3 },
+     { false, false, 12300000, 38, 7 }}},
   { "cast(1 as decimal(38,0)) / cast(.2 as decimal(38,1))",
-    {{ false,      50, 38, 1 },
-     { false, 5000000, 38, 6 }}},
+    {{ false, false,      50, 38, 1 },
+     { false, false, 5000000, 38, 6 }}},
   { "cast(1 as decimal(38,0)) / cast(3 as decimal(38,0))",
-    {{ false,      0, 38, 0 },
-     { false, 333333, 38, 6 }}},
+    {{ false, false,      0, 38, 0 },
+     { false, false, 333333, 38, 6 }}},
   { "cast(99999999999999999999999999999999999999 as decimal(38,0)) / "
     "cast(99999999999999999999999999999999999999 as decimal(38,0))",
-    {{ false,       1, 38, 0 },
-     { false, 1000000, 38, 6 }}},
+    {{ false, false,       1, 38, 0 },
+     { false, false, 1000000, 38, 6 }}},
   { "cast(99999999999999999999999999999999999999 as decimal(38,0)) / "
     "cast(0.00000000000000000000000000000000000001 as decimal(38,38))",
-    {{ true, 0, 38, 38 },
-     { true, 0, 38,  6 }}},
+    {{ false, true, 0, 38, 38 },
+     { false, true, 0, 38,  6 }}},
   { "cast(0.00000000000000000000000000000000000001 as decimal(38,38)) / "
     "cast(99999999999999999999999999999999999999 as decimal(38,0))",
-    {{ false, 0, 38, 38 }}},
+    {{ false, false, 0, 38, 38 }}},
   { "cast(0.00000000000000000000000000000000000001 as decimal(38,38)) / "
     "cast(0.00000000000000000000000000000000000001 as decimal(38,38))",
-    {{ true,        0, 38, 38 },
-     { false, 1000000, 38,  6 }}},
+    {{ false, true,        0, 38, 38 },
+     { false, false, 1000000, 38,  6 }}},
   { "cast(9999999999999999999.9999999999999999999 as decimal(38,19)) / "
     "cast(99999999999999999999999999999.999999999 as decimal(38,9))",
-    {{ false, 1000000000, 38, 19 },
-     { false,          1, 38, 10 }}},
+    {{ false, false, 1000000000, 38, 19 },
+     { false, false,          1, 38, 10 }}},
   { "cast(999999999999999999999999999999999999.99 as decimal(38,2)) / "
     "cast(99999999999.999999999999999999999999999 as decimal(38,27))",
-    {{ true,  0, 38, 27 },
-     { false, static_cast<int128_t>(10) * 10000000000ll *
+    {{ false, true,  0, 38, 27 },
+     { false, false, static_cast<int128_t>(10) * 10000000000ll *
        10000000000ll * 10000000000ll, 38, 6 }}},
   { "cast(-2.12 as decimal(17,2)) / cast(12515.95 as decimal(17,2))",
-    {{ false, -16938386618674571, 37, 20 }}},
+    {{ false, false, -16938386618674571, 37, 20 }}},
   { "cast(-2.12 as decimal(18,2)) / cast(12515.95 as decimal(18,2))",
-    {{ false,                  0, 38,  2 },
-     { false, -16938386618674571, 38, 20 }}},
+    {{ false, false,                  0, 38,  2 },
+     { false, false, -16938386618674571, 38, 20 }}},
   { "cast(737373 as decimal(6,0)) / cast(.52525252 as decimal(38,38))",
-    {{ true,              0, 38, 38 },
-     { false, 1403844764038, 38,  6 }}},
+    {{ false, true,              0, 38, 38 },
+     { false, false, 1403844764038, 38,  6 }}},
   { "cast(0.000001 as decimal(6,6)) / "
     "cast(0.0000000000000000000000000000000000001 as decimal(38,38))",
-    {{ true, 0, 38, 38 },
-     { false, static_cast<int128_t>(10000000ll) *
+    {{ false, true, 0, 38, 38 },
+     { false, false, static_cast<int128_t>(10000000ll) *
        10000000000ll * 10000000000ll * 10000000000ll, 38, 6 }}},
   { "cast(98765432109876543210 as decimal(20,0)) / "
     "cast(98765432109876543211 as decimal(20,0))",
-    {{ false,                   0, 38,  0 },
-     { false, 1000000000000000000, 38, 18 }}},
+    {{ false, false,                   0, 38,  0 },
+     { false, false, 1000000000000000000, 38, 18 }}},
   { "cast(111111.1111 as decimal(20, 10)) / cast(.7777 as decimal(38, 38))",
-    {{ true,             0, 38, 38 },
-     { false, 142871429986, 38,  6 }}},
+    {{ false, true,             0, 38, 38 },
+     { false, false, 142871429986, 38,  6 }}},
   { "2.0 / 3.0",
-    {{ false,   6666, 6, 4},
-     { false, 666667, 8, 6}}},
+    {{ false, false,   6666, 6, 4},
+     { false, false, 666667, 8, 6}}},
   { "-2.0 / 3.0",
-    {{ false,   -6666, 6, 4},
-     { false, -666667, 8, 6}}},
+    {{ false, false,   -6666, 6, 4},
+     { false, false, -666667, 8, 6}}},
   { "2.0 / -3.0",
-    {{ false,   -6666, 6, 4},
-     { false, -666667, 8, 6}}},
+    {{ false, false,   -6666, 6, 4},
+     { false, false, -666667, 8, 6}}},
   { "-2.0 / -3.0",
-    {{ false,   6666, 6, 4},
-     { false, 666667, 8, 6}}},
+    {{ false, false,   6666, 6, 4},
+     { false, false, 666667, 8, 6}}},
   // Test divide rounding
   { "10.10 / 3.0",
-    {{ false, 336666, 8, 5 },
-     { false, 3366667, 9, 6 }}},
+    {{ false, false, 336666, 8, 5 },
+     { false, false, 3366667, 9, 6 }}},
   { "cast(-10.10 as decimal(4,2)) / 3.0", // XXX JIRA: IMPALA-4877
-    {{ false, -336666, 8, 5 },
-     { false, -3366667, 9, 6 }}},
+    {{ false, false, -336666, 8, 5 },
+     { false, false, -3366667, 9, 6 }}},
   { "10.10 / 20.3",
-    {{ false, 497536, 9, 6 },
-     { false, 497537, 9, 6 }}},
+    {{ false, false, 497536, 9, 6 },
+     { false, false, 497537, 9, 6 }}},
   { "10.10 / -20.3",
-    {{ false, -497536, 9, 6 },
-     { false, -497537, 9, 6 }}},
+    {{ false, false, -497536, 9, 6 },
+     { false, false, -497537, 9, 6 }}},
   // N.B. - Google and python both insist that 999999.998 / 999 is 1001.000999
   // However, multiplying the result back, 999 * 1001.000998999 gives the
   // original value exactly, while their answer does not, 999 * 10001.000999 =
   // 999999.998001. The same issue comes up many times during the following
   // computations.  Division is hard, let's go shopping.
   { "cast(999999.998 as decimal(9,3)) / 999",
-    {{ false, 1001000998998, 15, 9 },
-     { false, 1001000998999, 15, 9 }}},
+    {{ false, false, 1001000998998, 15, 9 },
+     { false, false, 1001000998999, 15, 9 }}},
   { "cast(999.999998 as decimal(9,3)) / 999",
-    {{ false, 1001000000, 15, 9 },
-     { false, 1001001001, 15, 9 }}},
+    {{ false, false, 1001000000, 15, 9 },
+     { false, false, 1001001001, 15, 9 }}},
   { "cast(999.999998 as decimal(9,6)) / 999",
-    {{ false, 1001000998998, 15, 12 },
-     { false, 1001000998999, 15, 12 }}},
+    {{ false, false, 1001000998998, 15, 12 },
+     { false, false, 1001000998999, 15, 12 }}},
   { "cast(0.999999998 as decimal(9,6)) / 999",
-    {{ false, 1001000000, 15, 12 },
-     { false, 1001001001, 15, 12 }}},
+    {{ false, false, 1001000000, 15, 12 },
+     { false, false, 1001001001, 15, 12 }}},
   { "cast(0.999999998 as decimal(9,9)) / 999",
-    {{ false, 1001000998998, 15, 15 },
-     { false, 1001000998999, 15, 15 }}},
+    {{ false, false, 1001000998998, 15, 15 },
+     { false, false, 1001000998999, 15, 15 }}},
   { "cast(-999999.998 as decimal(9,3)) / 999",
-    {{ false, -1001000998998, 15, 9 },
-     { false, -1001000998999, 15, 9 }}},
+    {{ false, false, -1001000998998, 15, 9 },
+     { false, false, -1001000998999, 15, 9 }}},
   { "cast(-999.999998 as decimal(9,3)) / 999",
-    {{ false, -1001000000, 15, 9 },
-     { false, -1001001001, 15, 9 }}},
+    {{ false, false, -1001000000, 15, 9 },
+     { false, false, -1001001001, 15, 9 }}},
   { "cast(-999.999998 as decimal(9,6)) / 999",
-    {{ false, -1001000998998, 15, 12 },
-     { false, -1001000998999, 15, 12 }}},
+    {{ false, false, -1001000998998, 15, 12 },
+     { false, false, -1001000998999, 15, 12 }}},
   { "cast(-0.999999998 as decimal(9,6)) / 999",
-    {{ false, -1001000000, 15, 12 },
-     { false, -1001001001, 15, 12 }}},
+    {{ false, false, -1001000000, 15, 12 },
+     { false, false, -1001001001, 15, 12 }}},
   { "cast(-0.999999998 as decimal(9,9)) / 999",
-    {{ false, -1001000998998, 15, 15 },
-     { false, -1001000998999, 15, 15 }}},
+    {{ false, false, -1001000998998, 15, 15 },
+     { false, false, -1001000998999, 15, 15 }}},
   { "cast(-999999.998 as decimal(9,3)) / -999",
-    {{ false, 1001000998998, 15, 9 },
-     { false, 1001000998999, 15, 9 }}},
+    {{ false, false, 1001000998998, 15, 9 },
+     { false, false, 1001000998999, 15, 9 }}},
   { "cast(-999.999998 as decimal(9,3)) / -999",
-    {{ false, 1001000000, 15, 9 },
-     { false, 1001001001, 15, 9 }}},
+    {{ false, false, 1001000000, 15, 9 },
+     { false, false, 1001001001, 15, 9 }}},
   { "cast(-999.999998 as decimal(9,6)) / -999",
-    {{ false, 1001000998998, 15, 12 },
-     { false, 1001000998999, 15, 12 }}},
+    {{ false, false, 1001000998998, 15, 12 },
+     { false, false, 1001000998999, 15, 12 }}},
   { "cast(-0.999999998 as decimal(9,6)) / -999",
-    {{ false, 1001000000, 15, 12 },
-     { false, 1001001001, 15, 12 }}},
+    {{ false, false, 1001000000, 15, 12 },
+     { false, false, 1001001001, 15, 12 }}},
   { "cast(-0.999999998 as decimal(9,9)) / -999",
-    {{ false, 1001000998998, 15, 15 },
-     { false, 1001000998999, 15, 15 }}},
+    {{ false, false, 1001000998998, 15, 15 },
+     { false, false, 1001000998999, 15, 15 }}},
   { "cast(999999.998 as decimal(9,3)) / -999",
-    {{ false, -1001000998998, 15, 9 },
-     { false, -1001000998999, 15, 9 }}},
+    {{ false, false, -1001000998998, 15, 9 },
+     { false, false, -1001000998999, 15, 9 }}},
   { "cast(999.999998 as decimal(9,3)) / -999",
-    {{ false, -1001000000, 15, 9 },
-     { false, -1001001001, 15, 9 }}},
+    {{ false, false, -1001000000, 15, 9 },
+     { false, false, -1001001001, 15, 9 }}},
   { "cast(999.999998 as decimal(9,6)) / -999",
-    {{ false, -1001000998998, 15, 12 },
-     { false, -1001000998999, 15, 12 }}},
+    {{ false, false, -1001000998998, 15, 12 },
+     { false, false, -1001000998999, 15, 12 }}},
   { "cast(0.999999998 as decimal(9,6)) / -999",
-    {{ false, -1001000000, 15, 12 },
-     { false, -1001001001, 15, 12 }}},
+    {{ false, false, -1001000000, 15, 12 },
+     { false, false, -1001001001, 15, 12 }}},
   { "cast(0.999999998 as decimal(9,9)) / -999",
-    {{ false, -1001000998998, 15, 15 },
-     { false, -1001000998999, 15, 15 }}},
+    {{ false, false, -1001000998998, 15, 15 },
+     { false, false, -1001000998999, 15, 15 }}},
   { "cast(999.999998 as decimal(9,3)) / 999999999",
-    {{ false, 99999900, 20, 14 },
-     { false, 100000000, 20, 14 }}},
+    {{ false, false, 99999900, 20, 14 },
+     { false, false, 100000000, 20, 14 }}},
   { "cast(999.999998 as decimal(9,6)) / 999999999",
-    {{ false, 99999999899, 20, 17 },
-     { false, 99999999900, 20, 17 }}},
+    {{ false, false, 99999999899, 20, 17 },
+     { false, false, 99999999900, 20, 17 }}},
   { "cast(0.999999998 as decimal(9,6)) / 999999999",
-    {{ false, 99999900, 20, 17 },
-     { false, 100000000, 20, 17 }}},
+    {{ false, false, 99999900, 20, 17 },
+     { false, false, 100000000, 20, 17 }}},
   { "cast(0.999999998 as decimal(9,9)) / 999999999",
-    {{ false, 99999999899, 20, 20 },
-     { false, 99999999900, 20, 20 }}},
+    {{ false, false, 99999999899, 20, 20 },
+     { false, false, 99999999900, 20, 20 }}},
   { "cast(-999999.998 as decimal(9,3)) / 999999999",
-    {{ false, -99999999899, 20, 14 },
-     { false, -99999999900, 20, 14 }}},
+    {{ false, false, -99999999899, 20, 14 },
+     { false, false, -99999999900, 20, 14 }}},
   { "cast(-999.999998 as decimal(9,3)) / 999999999",
-    {{ false, -99999900, 20, 14 },
-     { false, -100000000, 20, 14 }}},
+    {{ false, false, -99999900, 20, 14 },
+     { false, false, -100000000, 20, 14 }}},
   { "cast(-999.999998 as decimal(9,6)) / 999999999",
-    {{ false, -99999999899, 20, 17 },
-     { false, -99999999900, 20, 17 }}},
+    {{ false, false, -99999999899, 20, 17 },
+     { false, false, -99999999900, 20, 17 }}},
   { "cast(-0.999999998 as decimal(9,6)) / 999999999",
-    {{ false, -99999900, 20, 17 },
-     { false, -100000000, 20, 17 }}},
+    {{ false, false, -99999900, 20, 17 },
+     { false, false, -100000000, 20, 17 }}},
   { "cast(-0.999999998 as decimal(9,9)) / 999999999",
-    {{ false, -99999999899, 20, 20 },
-     { false, -99999999900, 20, 20 }}},
+    {{ false, false, -99999999899, 20, 20 },
+     { false, false, -99999999900, 20, 20 }}},
   { "cast(-999999.998 as decimal(9,3)) / 999999999",
-    {{ false, -99999999899, 20, 14 },
-     { false, -99999999900, 20, 14 }}},
+    {{ false, false, -99999999899, 20, 14 },
+     { false, false, -99999999900, 20, 14 }}},
   { "cast(-999.999998 as decimal(9,3)) / 999999999",
-    {{ false, -99999900, 20, 14 },
-     { false, -100000000, 20, 14 }}},
+    {{ false, false, -99999900, 20, 14 },
+     { false, false, -100000000, 20, 14 }}},
   { "cast(-999.999998 as decimal(9,6)) / 999999999",
-    {{ false, -99999999899, 20, 17 },
-     { false, -99999999900, 20, 17 }}},
+    {{ false, false, -99999999899, 20, 17 },
+     { false, false, -99999999900, 20, 17 }}},
   { "cast(-0.999999998 as decimal(9,6)) / 999999999",
-    {{ false, -99999900, 20, 17 },
-     { false, -100000000, 20, 17 }}},
+    {{ false, false, -99999900, 20, 17 },
+     { false, false, -100000000, 20, 17 }}},
   { "cast(-0.999999998 as decimal(9,9)) / 999999999",
-    {{ false, -99999999899, 20, 20 },
-     { false, -99999999900, 20, 20 }}},
+    {{ false, false, -99999999899, 20, 20 },
+     { false, false, -99999999900, 20, 20 }}},
   { "cast(999999.998 as decimal(9,3)) / -999999999",
-    {{ false, -99999999899, 20, 14 },
-     { false, -99999999900, 20, 14 }}},
+    {{ false, false, -99999999899, 20, 14 },
+     { false, false, -99999999900, 20, 14 }}},
   { "cast(999.999998 as decimal(9,3)) / -999999999",
-    {{ false, -99999900, 20, 14 },
-     { false, -100000000, 20, 14 }}},
+    {{ false, false, -99999900, 20, 14 },
+     { false, false, -100000000, 20, 14 }}},
   { "cast(999.999998 as decimal(9,6)) / -999999999",
-    {{ false, -99999999899, 20, 17 },
-     { false, -99999999900, 20, 17 }}},
+    {{ false, false, -99999999899, 20, 17 },
+     { false, false, -99999999900, 20, 17 }}},
   { "cast(0.999999998 as decimal(9,6)) / -999999999",
-    {{ false, -99999900, 20, 17 },
-     { false, -100000000, 20, 17 }}},
+    {{ false, false, -99999900, 20, 17 },
+     { false, false, -100000000, 20, 17 }}},
   { "cast(0.999999998 as decimal(9,9)) / -999999999",
-    {{ false, -99999999899, 20, 20 },
-     { false, -99999999900, 20, 20 }}},
+    {{ false, false, -99999999899, 20, 20 },
+     { false, false, -99999999900, 20, 20 }}},
   { "17014118346046923173168730371588.410/17014118346046923173168730371588.410",
-    {{ false, 1000, 38, 3 },
-     { false, 1000000, 38, 6 }}},
+    {{ false, false, 1000, 38, 3 },
+     { false, false, 1000000, 38, 6 }}},
   { "17014118346046923173168730371588.410/17014118346046923173168730371588.409",
-    {{ false, 1000, 38, 3 },
-     { false, 1000000, 38, 6 }}},
+    {{ false, false, 1000, 38, 3 },
+     { false, false, 1000000, 38, 6 }}},
   { "17014118346046923173168730371588.410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, 1, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 1, 38, 6 }}},
   { "17014118346046923173168730371588.410/34028236692093846346337460743176820001",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "17014118346046923173168730371588.410/51042355038140769519506191114765230000",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "17014118346046923173168730371588.410/10208471007628153903901238222953046343",
-    {{ false, 0, 38, 3 },
-     { false, 2, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 2, 38, 6 }}},
   { "170141183460469231731687303715884.10/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, 5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 5, 38, 6 }}},
   { "170141183460469231731687303715884.10/34028236692093846346337460743176820001",
-    {{ false, 0, 38, 2 },
-     { false, 5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 5, 38, 6 }}},
   { "170141183460469231731687303715884.10/51042355038140769519506191114765230000",
-    {{ false, 0, 38, 2 },
-     { false, 3, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 3, 38, 6 }}},
   { "170141183460469231731687303715884.10/10208471007628153903901238222953046343",
-    {{ false, 0, 38, 2 },
-     { false, 17, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 17, 38, 6 }}},
   { "1701411834604692317316873037158841.0/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, 50, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 50, 38, 6 }}},
   { "1701411834604692317316873037158841.0/34028236692093846346337460743176820001",
-    {{ false, 0, 38, 1 },
-     { false, 50, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 50, 38, 6 }}},
   { "1701411834604692317316873037158841.0/51042355038140769519506191114765229999",
-    {{ false, 0, 38, 1 },
-     { false, 33, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 33, 38, 6 }}},
   { "1701411834604692317316873037158841.0/10208471007628153903901238222953046343",
-    {{ false, 0, 38, 1 },
-     { false, 167, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 167, 38, 6 }}},
   { "17014118346046923173168730371588410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, 500, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 500, 38, 6 }}},
   { "17014118346046923173168730371588410/34028236692093846346337460743176820001",
-    {{ false, 0, 38, 0 },
-     { false, 500, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 500, 38, 6 }}},
   { "17014118346046923173168730371588410/51042355038140769519506191114765229999",
-    {{ false, 0, 38, 0 },
-     { false, 333, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 333, 38, 6 }}},
   { "17014118346046923173168730371588410/10208471007628153903901238222953046343",
-    {{ false, 0, 38, 0 },
-     { false, 1667, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 1667, 38, 6 }}},
   { "17014118346046923173168730371588410/3402823669209384634633746074317682000.0",
-    {{ false, 0, 38, 1 },
-     { false, 5000, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 5000, 38, 6 }}},
   { "17014118346046923173168730371588410/3402823669209384634633746074317682000.1",
-    {{ false, 0, 38, 1 },
-     { false, 5000, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 5000, 38, 6 }}},
   { "17014118346046923173168730371588410/5104235503814076951950619111476522999.9",
-    {{ false, 0, 38, 1 },
-     { false, 3333, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 3333, 38, 6 }}},
   { "17014118346046923173168730371588410/1020847100762815390390123822295304634.3",
-    {{ false, 0, 38, 1 },
-     { false, 16667, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 16667, 38, 6 }}},
   { "15014118346046923173168730371588.410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "150141183460469231731687303715884.10/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, 4, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 4, 38, 6 }}},
   { "1501411834604692317316873037158841.0/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, 44, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 44, 38, 6 }}},
   { "15014118346046923173168730371588410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, 441, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 441, 38, 6 }}},
   { "16014118346046923173168730371588.410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "160141183460469231731687303715884.10/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, 5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 5, 38, 6 }}},
   { "1601411834604692317316873037158841.0/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, 47, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 47, 38, 6 }}},
   { "16014118346046923173168730371588410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, 471, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 471, 38, 6 }}},
   { "16014118346046923173168730371588410/3402823669209384634633746074317682000",
-    {{ false, 0, 38, 0 },
-     { false, 4706, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 4706, 38, 6 }}},
   { "18014118346046923173168730371588.410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, 1, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 1, 38, 6 }}},
   { "180141183460469231731687303715884.10/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, 5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, 5, 38, 6 }}},
   { "1801411834604692317316873037158841.0/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, 53, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, 53, 38, 6 }}},
   { "18014118346046923173168730371588410/34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, 529, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 529, 38, 6 }}},
   { "18014118346046923173168730371588410/3402823669209384634633746074317682000",
-    {{ false, 0, 38, 0 },
-     { false, 5294, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 5294, 38, 6 }}},
   { "18014118346046923173168730371588410/340282366920938463463374607431768200",
-    {{ false, 0, 38, 0 },
-     { false, 52939, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, 52939, 38, 6 }}},
   { "17014118346046923173168730371588.410/-17014118346046923173168730371588.410",
-    {{ false, -1000, 38, 3 },
-     { false, -1000000, 38, 6 }}},
+    {{ false, false, -1000, 38, 3 },
+     { false, false, -1000000, 38, 6 }}},
   { "17014118346046923173168730371588.410/-17014118346046923173168730371588.409",
-    {{ false, -1000, 38, 3 },
-     { false, -1000000, 38, 6 }}},
+    {{ false, false, -1000, 38, 3 },
+     { false, false, -1000000, 38, 6 }}},
   { "17014118346046923173168730371588.410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, -1, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, -1, 38, 6 }}},
   { "17014118346046923173168730371588.410/-34028236692093846346337460743176820001",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "17014118346046923173168730371588.410/-51042355038140769519506191114765230000",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "17014118346046923173168730371588.410/-10208471007628153903901238222953046343",
-    {{ false, 0, 38, 3 },
-     { false, -2, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, -2, 38, 6 }}},
   { "170141183460469231731687303715884.10/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, -5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -5, 38, 6 }}},
   { "170141183460469231731687303715884.10/-34028236692093846346337460743176820001",
-    {{ false, 0, 38, 2 },
-     { false, -5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -5, 38, 6 }}},
   { "170141183460469231731687303715884.10/-51042355038140769519506191114765230000",
-    {{ false, 0, 38, 2 },
-     { false, -3, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -3, 38, 6 }}},
   { "170141183460469231731687303715884.10/-10208471007628153903901238222953046343",
-    {{ false, 0, 38, 2 },
-     { false, -17, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -17, 38, 6 }}},
   { "1701411834604692317316873037158841.0/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, -50, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -50, 38, 6 }}},
   { "1701411834604692317316873037158841.0/-34028236692093846346337460743176820001",
-    {{ false, 0, 38, 1 },
-     { false, -50, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -50, 38, 6 }}},
   { "1701411834604692317316873037158841.0/-51042355038140769519506191114765229999",
-    {{ false, 0, 38, 1 },
-     { false, -33, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -33, 38, 6 }}},
   { "1701411834604692317316873037158841.0/-10208471007628153903901238222953046343",
-    {{ false, 0, 38, 1 },
-     { false, -167, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -167, 38, 6 }}},
   { "17014118346046923173168730371588410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, -500, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -500, 38, 6 }}},
   { "17014118346046923173168730371588410/-34028236692093846346337460743176820001",
-    {{ false, 0, 38, 0 },
-     { false, -500, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -500, 38, 6 }}},
   { "17014118346046923173168730371588410/-51042355038140769519506191114765229999",
-    {{ false, 0, 38, 0 },
-     { false, -333, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -333, 38, 6 }}},
   { "17014118346046923173168730371588410/-10208471007628153903901238222953046343",
-    {{ false, 0, 38, 0 },
-     { false, -1667, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -1667, 38, 6 }}},
   { "17014118346046923173168730371588410/-3402823669209384634633746074317682000.0",
-    {{ false, 0, 38, 1 },
-     { false, -5000, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -5000, 38, 6 }}},
   { "17014118346046923173168730371588410/-3402823669209384634633746074317682000.1",
-    {{ false, 0, 38, 1 },
-     { false, -5000, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -5000, 38, 6 }}},
   { "17014118346046923173168730371588410/-5104235503814076951950619111476522999.9",
-    {{ false, 0, 38, 1 },
-     { false, -3333, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -3333, 38, 6 }}},
   { "17014118346046923173168730371588410/-1020847100762815390390123822295304634.3",
-    {{ false, 0, 38, 1 },
-     { false, -16667, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -16667, 38, 6 }}},
   { "15014118346046923173168730371588.410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "150141183460469231731687303715884.10/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, -4, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -4, 38, 6 }}},
   { "1501411834604692317316873037158841.0/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, -44, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -44, 38, 6 }}},
   { "15014118346046923173168730371588410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, -441, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -441, 38, 6 }}},
   { "16014118346046923173168730371588.410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, 0, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, 0, 38, 6 }}},
   { "160141183460469231731687303715884.10/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, -5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -5, 38, 6 }}},
   { "1601411834604692317316873037158841.0/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, -47, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -47, 38, 6 }}},
   { "16014118346046923173168730371588410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, -471, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -471, 38, 6 }}},
   { "16014118346046923173168730371588410/-3402823669209384634633746074317682000",
-    {{ false, 0, 38, 0 },
-     { false, -4706, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -4706, 38, 6 }}},
   { "18014118346046923173168730371588.410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 3 },
-     { false, -1, 38, 6 }}},
+    {{ false, false, 0, 38, 3 },
+     { false, false, -1, 38, 6 }}},
   { "180141183460469231731687303715884.10/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 2 },
-     { false, -5, 38, 6 }}},
+    {{ false, false, 0, 38, 2 },
+     { false, false, -5, 38, 6 }}},
   { "1801411834604692317316873037158841.0/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 1 },
-     { false, -53, 38, 6 }}},
+    {{ false, false, 0, 38, 1 },
+     { false, false, -53, 38, 6 }}},
   { "18014118346046923173168730371588410/-34028236692093846346337460743176820000",
-    {{ false, 0, 38, 0 },
-     { false, -529, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -529, 38, 6 }}},
   { "18014118346046923173168730371588410/-3402823669209384634633746074317682000",
-    {{ false, 0, 38, 0 },
-     { false, -5294, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -5294, 38, 6 }}},
   { "18014118346046923173168730371588410/-340282366920938463463374607431768200",
-    {{ false, 0, 38, 0 },
-     { false, -52939, 38, 6 }}},
+    {{ false, false, 0, 38, 0 },
+     { false, false, -52939, 38, 6 }}},
   // Test modulo operator
-  { "cast(1.23 as decimal(8,2)) % cast(1 as decimal(10,3))", {{ false, 230, 9, 3 }}},
-  { "cast(1 as decimal(38,0)) % cast(.2 as decimal(38,1))", {{ false, 0, 38, 1 }}},
-  { "cast(1 as decimal(38,0)) % cast(3 as decimal(38,0))", {{ false, 1, 38, 0 }}},
+  { "cast(1.23 as decimal(8,2)) % cast(1 as decimal(10,3))",
+    {{ false, false, 230, 9, 3 }}},
+  { "cast(1 as decimal(38,0)) % cast(.2 as decimal(38,1))",
+    {{ false, false, 0, 38, 1 }}},
+  { "cast(1 as decimal(38,0)) % cast(3 as decimal(38,0))",
+    {{ false, false, 1, 38, 0 }}},
   { "cast(-2.12 as decimal(17,2)) % cast(12515.95 as decimal(17,2))",
-    {{ false, -212, 17, 2 }}},
+    {{ false, false, -212, 17, 2 }}},
   { "cast(-2.12 as decimal(18,2)) % cast(12515.95 as decimal(18,2))",
-    {{ false, -212, 18, 2 }}},
+    {{ false, false, -212, 18, 2 }}},
   { "cast(99999999999999999999999999999999999999 as decimal(38,0)) % "
     "cast(99999999999999999999999999999999999999 as decimal(38,0))",
-    {{ false, 0, 38, 0 }}},
+    {{ false, false, 0, 38, 0 }}},
   { "cast(998 as decimal(38,0)) % cast(0.999 as decimal(38,38))",
-    {{ true, 0, 38, 38 },   // IMPALA-4964 - this should not overflow
-     { true, 0, 38, 38 }}},
+    {{ false, true, 0, 38, 38 },   // IMPALA-4964 - this should not overflow
+     { false, true, 0, 38, 38 }}},
   { "cast(0.998 as decimal(38,38)) % cast(999 as decimal(38,0))",
-    {{ true, 0, 38, 38 },   // IMPALA-4964 - this should not overflow
-     { true, 0, 38, 38 }}},
+    {{ false, true, 0, 38, 38 },   // IMPALA-4964 - this should not overflow
+     { false, true, 0, 38, 38 }}},
   { "cast(0.00000000000000000000000000000000000001 as decimal(38,38)) % "
     "cast(0.0000000000000000000000000000000000001 as decimal(38,38))",
-    {{ false, 1, 38, 38 }}},
+    {{ false, false, 1, 38, 38 }}},
   // Test MOD builtin
-  { "mod(cast('1' as decimal(2,0)), cast('10' as decimal(2,0)))", {{ false, 1, 2, 0 }}},
-  { "mod(cast('1.1' as decimal(2,1)), cast('1.0' as decimal(2,1)))", {{ false, 1, 2, 1 }}},
+  { "mod(cast('1' as decimal(2,0)), cast('10' as decimal(2,0)))",
+    {{ false, false, 1, 2, 0 }}},
+  { "mod(cast('1.1' as decimal(2,1)), cast('1.0' as decimal(2,1)))",
+    {{ false, false, 1, 2, 1 }}},
   { "mod(cast('-1.23' as decimal(5,2)), cast('1.0' as decimal(5,2)))",
-    {{ false, -23, 5, 2 }}},
-  { "mod(cast('1' as decimal(12,0)), cast('10' as decimal(12,0)))", {{ false, 1, 12, 0 }}},
+    {{ false, false, -23, 5, 2 }}},
+  { "mod(cast('1' as decimal(12,0)), cast('10' as decimal(12,0)))",
+    {{ false, false, 1, 12, 0 }}},
   { "mod(cast('1.1' as decimal(12,1)), cast('1.0' as decimal(12,1)))",
-    {{ false, 1, 12, 1 }}},
+    {{ false, false, 1, 12, 1 }}},
   { "mod(cast('-1.23' as decimal(12,2)), cast('1.0' as decimal(12,2)))",
-    {{ false, -23, 12, 2 }}},
+    {{ false, false, -23, 12, 2 }}},
   { "mod(cast('1' as decimal(32,0)), cast('10' as decimal(32,0)))",
-    {{ false, 1, 32, 0 }}},
+    {{ false, false, 1, 32, 0 }}},
   { "mod(cast('1.1' as decimal(32,1)), cast('1.0' as decimal(32,1)))",
-    {{ false, 1, 32, 1 }}},
+    {{ false, false, 1, 32, 1 }}},
   { "mod(cast('-1.23' as decimal(32,2)), cast('1.0' as decimal(32,2)))",
-    {{ false, -23, 32, 2 }}},
-  { "mod(cast(NULL as decimal(2,0)), cast('10' as decimal(2,0)))", {{ true, 0, 2, 0 }}},
-  { "mod(cast('10' as decimal(2,0)), cast(NULL as decimal(2,0)))", {{ true, 0, 2, 0 }}},
-  { "mod(cast('10' as decimal(2,0)), cast('0' as decimal(2,0)))", {{ true, 0, 2, 0 }}},
-  { "mod(cast('10' as decimal(2,0)), cast('0' as decimal(2,0)))", {{ true, 0, 2, 0 }}},
-  { "mod(cast(NULL as decimal(2,0)), NULL)", {{ true, 0, 2, 0 }}},
+    {{ false, false, -23, 32, 2 }}},
+  { "mod(cast(NULL as decimal(2,0)), cast('10' as decimal(2,0)))",
+    {{ false, true, 0, 2, 0 }}},
+  { "mod(cast('10' as decimal(2,0)), cast(NULL as decimal(2,0)))",
+    {{ false, true, 0, 2, 0 }}},
+  { "mod(cast('10' as decimal(2,0)), cast('0' as decimal(2,0)))",
+    {{ false, true, 0, 2, 0 },
+     { true, false, 0, 2, 0 }}},
+  { "mod(cast('10' as decimal(2,0)), cast('0' as decimal(2,0)))",
+    {{ false, true, 0, 2, 0 },
+     { true, false, 0, 2, 0 }}},
+  { "cast('10' as decimal(2,0)) % cast('0' as decimal(2,0))",
+    {{ false, true, 0, 2, 0 },
+     { true, false, 0, 2, 0 }}},
+  { "cast('10' as decimal(2,0)) % cast('0' as decimal(38,19))",
+    {{ false, true, 0, 21, 19 },
+     { true, false, 0, 21, 19 }}},
+  { "cast('10' as decimal(2,0)) / cast('0' as decimal(2,0))",
+    {{ false, true, 0, 6, 4 },
+     { true, false, 0, 6, 4 }}},
+  { "cast('10' as decimal(2,0)) / cast('0' as decimal(38,19))",
+    {{ false, true, 0, 38, 19 },
+     { true, false, 0, 38, 19 }}},
+  { "mod(cast(NULL as decimal(2,0)), NULL)", {{ false, true, 0, 2, 0 }}},
   // Test CAST DECIMAL -> DECIMAL
   { "cast(cast(0.12344 as decimal(6,5)) as decimal(6,4))",
-    {{ false, 1234, 6, 4 }}},
+    {{ false, false, 1234, 6, 4 }}},
   { "cast(cast(0.12345 as decimal(6,5)) as decimal(6,4))",
-    {{ false, 1234, 6, 4 },
-     { false, 1235, 6, 4 }}},
+    {{ false, false, 1234, 6, 4 },
+     { false, false, 1235, 6, 4 }}},
   { "cast(cast('0.999' as decimal(4,3)) as decimal(1,0))",
-    {{ false, 0, 1, 0 },
-     { false, 1, 1, 0 }}},
+    {{ false, false, 0, 1, 0 },
+     { false, false, 1, 1, 0 }}},
   { "cast(cast(999999999.99 as DECIMAL(11,2)) as DECIMAL(9,0))",
-    {{ false, 999999999, 9, 0 },
-     { true, 0, 9, 0 }}},
+    {{ false, false, 999999999, 9, 0 },
+     { false, true, 0, 9, 0 }}},
   { "cast(cast(-999999999.99 as DECIMAL(11,2)) as DECIMAL(9,0))",
-    {{ false, -999999999, 9, 0 },
-     { true, 0, 9, 0 }}},
+    {{ false, false, -999999999, 9, 0 },
+     { false, true, 0, 9, 0 }}},
   // IMPALA-2233: Test that implicit casts do not lose precision.
   // The overload greatest(decimal(*,*)) is available and should be used.
   { "greatest(0, cast('99999.1111' as decimal(30,10)))",
-    {{ false, 999991111000000, 30, 10 },
-     { false, 999991111000000, 30, 10 }}},
+    {{ false, false, 999991111000000, 30, 10 },
+     { false, false, 999991111000000, 30, 10 }}},
   // Test AVG() with DECIMAL
   { "avg(d) from (values((cast(100000000000000000000000000000000.00000 as DECIMAL(38,5)) "
     "as d))) as t",
-    {{ false, static_cast<int128_t>(10000000ll) *
+    {{ false, false, static_cast<int128_t>(10000000ll) *
        10000000000ll * 10000000000ll * 10000000000ll, 38, 5 },
-     { true, 0, 38, 6}}},
+     { false, true, 0, 38, 6}}},
   { "avg(d) from (values((cast(1234567890 as DECIMAL(10,0)) as d))) as t",
-    {{false, 1234567890, 10, 0},
-     {false, 1234567890000000, 16, 6}}},
+    {{ false, false, 1234567890, 10, 0},
+     { false, false, 1234567890000000, 16, 6}}},
   { "avg(d) from (values((cast(1234567.89 as DECIMAL(10,2)) as d))) as t",
-    {{false, 123456789, 10, 2},
-     {false, 1234567890000, 14, 6}}},
+    {{ false, false, 123456789, 10, 2},
+     { false, false, 1234567890000, 14, 6}}},
   { "avg(d) from (values((cast(10000000000000000000000000000000 as DECIMAL(32,0)) "
     "as d))) as t",
-    {{false, static_cast<int128_t>(10) *
+    {{ false, false, static_cast<int128_t>(10) *
       10000000000ll * 10000000000ll * 10000000000ll, 32, 0},
-     {false, static_cast<int128_t>(10000000) *
+     { false, false, static_cast<int128_t>(10000000) *
       10000000000ll * 10000000000ll * 10000000000ll, 38, 6}}},
   { "avg(d) from (values((cast(100000000000000000000000000000000 as DECIMAL(33,0)) "
     "as d))) as t",
-    {{false, static_cast<int128_t>(100) *
+    {{ false, false, static_cast<int128_t>(100) *
       10000000000ll * 10000000000ll * 10000000000ll, 33, 0},
-     {true, 0, 38, 6}}},
+     { false, true, 0, 38, 6}}},
   { "avg(d) from (values((cast(100000000000000000000000000000000.0 as DECIMAL(34,1)) "
     "as d))) as t",
-    {{false, static_cast<int128_t>(1000) *
+    {{ false, false, static_cast<int128_t>(1000) *
       10000000000ll * 10000000000ll * 10000000000ll, 34, 1},
-     {true, 0, 38, 6}}},
+     { false, true, 0, 38, 6}}},
   { "avg(d) from (values((cast(100000000000000000000000000000000.00000 as DECIMAL(38,5)) "
     "as d))) as t",
-    {{false, static_cast<int128_t>(10000000) *
+    {{ false, false, static_cast<int128_t>(10000000) *
       10000000000ll * 10000000000ll * 10000000000ll, 38, 5},
-     {true, 0, 38, 6}}},
+     { false, true, 0, 38, 6}}},
   { "avg(d) from (values((cast(10000000000000000000000000000000.000000 as DECIMAL(38,6)) "
     "as d))) as t",
-    {{false, static_cast<int128_t>(10000000) *
+    {{ false, false, static_cast<int128_t>(10000000) *
       10000000000ll * 10000000000ll * 10000000000ll, 38, 6}}},
-  { "avg(d) from (values((cast(0.10000000000000000000000000000000000000 as DECIMAL(38,38)) "
-    "as d))) as t",
-    {{false, static_cast<int128_t>(10000000) *
+  { "avg(d) from (values((cast("
+    "0.10000000000000000000000000000000000000 as DECIMAL(38,38)) as d))) as t",
+    {{ false, false, static_cast<int128_t>(10000000) *
       10000000000ll * 10000000000ll * 10000000000ll, 38, 38}}},
   // Test CAST DECIMAL -> INT
   { "cast(cast(0.5999999 AS tinyint) AS decimal(10,6))",
-    {{ false, 0, 10, 6 },
-     { false, 1000000, 10, 6 }}},
+    {{ false, false, 0, 10, 6 },
+     { false, false, 1000000, 10, 6 }}},
   { "cast(cast(99999999.4999999 AS int) AS decimal(10,2))",
-    {{ false, 9999999900, 10, 2 }}},
+    {{ false, false, 9999999900, 10, 2 }}},
   { "cast(cast(99999999.5999999 AS int) AS decimal(10,2))",
-    {{ false, 9999999900, 10, 2 },
-     { true, 0, 10, 2 }}},
+    {{ false, false, 9999999900, 10, 2 },
+     { false, true, 0, 10, 2 }}},
   { "cast(cast(10000.5999999 as int) as decimal(30,6))",
-    {{ false, 10000000000, 30, 6 },
-     { false, 10001000000, 30, 6 }}},
+    {{ false, false, 10000000000, 30, 6 },
+     { false, false, 10001000000, 30, 6 }}},
   { "cast(cast(10000.5 AS int) AS decimal(6,1))",
-    {{ false, 100000, 6, 1 },
-     { false, 100010, 6, 1 }}},
+    {{ false, false, 100000, 6, 1 },
+     { false, false, 100010, 6, 1 }}},
   { "cast(cast(-10000.5 AS int) AS decimal(6,1))",
-    {{ false, -100000, 6, 1 },
-     { false, -100010, 6, 1 }}},
+    {{ false, false, -100000, 6, 1 },
+     { false, false, -100010, 6, 1 }}},
   { "cast(cast(9999.5 AS int) AS decimal(4,0))",
-    {{ false, 9999, 4, 0 },
-     { true, 0, 4, 0 }}},
+    {{ false, false, 9999, 4, 0 },
+     { false, true, 0, 4, 0 }}},
   { "cast(cast(-9999.5 AS int) AS decimal(4,0))",
-    {{ false, -9999, 4, 0 },
-     { true, 0, 4, 0 }}},
+    {{ false, false, -9999, 4, 0 },
+     { false, true, 0, 4, 0 }}},
   { "cast(cast(127.4999 AS tinyint) AS decimal(30,0))",
-    {{ false, 127, 30, 0 }}},
+    {{ false, false, 127, 30, 0 }}},
   { "cast(cast(127.5 AS tinyint) AS decimal(30,0))",
-    {{ false, 127, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, 127, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(128.0 AS tinyint) AS decimal(30,0))",
-    {{ false, -128, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, -128, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-128.4999 AS tinyint) AS decimal(30,0))",
-    {{ false, -128, 30, 0 }}},
+    {{ false, false, -128, 30, 0 }}},
   { "cast(cast(-128.5 AS tinyint) AS decimal(30,0))",
-    {{ false, -128, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, -128, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-129.0 AS tinyint) AS decimal(30,0))",
-    {{ false, 127, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, 127, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(32767.4999 AS smallint) AS decimal(30,0))",
-    {{ false, 32767, 30, 0 }}},
+    {{ false, false, 32767, 30, 0 }}},
   { "cast(cast(32767.5 AS smallint) AS decimal(30,0))",
-    {{ false, 32767, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, 32767, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(32768.0 AS smallint) AS decimal(30,0))",
-    {{ false, -32768, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, -32768, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-32768.4999 AS smallint) AS decimal(30,0))",
-    {{ false, -32768, 30, 0 }}},
+    {{ false, false, -32768, 30, 0 }}},
   { "cast(cast(-32768.5 AS smallint) AS decimal(30,0))",
-    {{ false, -32768, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, -32768, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-32769.0 AS smallint) AS decimal(30,0))",
-    {{ false, 32767, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, 32767, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(2147483647.4999 AS int) AS decimal(30,0))",
-    {{ false, 2147483647, 30, 0 }}},
+    {{ false, false, 2147483647, 30, 0 }}},
   { "cast(cast(2147483647.5 AS int) AS decimal(30,0))",
-    {{ false, 2147483647, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, 2147483647, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(2147483648.0 AS int) AS decimal(30,0))",
-    {{ false, -2147483648, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, -2147483648, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-2147483648.4999 AS int) AS decimal(30,0))",
-    {{ false, -2147483648, 30, 0 }}},
+    {{ false, false, -2147483648, 30, 0 }}},
   { "cast(cast(-2147483648.5 AS int) AS decimal(30,0))",
-    {{ false, -2147483648, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, -2147483648, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-2147483649.0 AS int) AS decimal(30,0))",
-    {{ false, 2147483647, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, 2147483647, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(9223372036854775807.4999 AS bigint) AS decimal(30,0))",
-    {{ false, 9223372036854775807, 30, 0 }}},
+    {{ false, false, 9223372036854775807, 30, 0 }}},
   { "cast(cast(9223372036854775807.5 AS bigint) AS decimal(30,0))",
-    {{ false, 9223372036854775807, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, 9223372036854775807, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(9223372036854775808.0 AS bigint) AS decimal(30,0))",
-    {{ false, -9223372036854775807 - 1, 30, 0 }, // BUG; also GCC workaround with -1
+    // BUG; also GCC workaround with -1
+    {{ false, false, -9223372036854775807 - 1, 30, 0 },
      // error: integer constant is so large that it is unsigned
-     { true, 0, 30, 0 }}},
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-9223372036854775808.4999 AS bigint) AS decimal(30,0))",
-    {{ false, -9223372036854775807 - 1, 30, 0 }}},
+    {{ false, false, -9223372036854775807 - 1, 30, 0 }}},
   { "cast(cast(-9223372036854775808.5 AS bigint) AS decimal(30,0))",
-    {{ false, -9223372036854775807 - 1, 30, 0 },
-     { true, 0, 30, 0 }}},
+    {{ false, false, -9223372036854775807 - 1, 30, 0 },
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(-9223372036854775809.0 AS bigint) AS decimal(30,0))",
-    {{ false, 9223372036854775807, 30, 0 }, // BUG: JIRA: IMPALA-865
-     { true, 0, 30, 0 }}},
+    {{ false, false, 9223372036854775807, 30, 0 }, // BUG: JIRA: IMPALA-865
+     { false, true, 0, 30, 0 }}},
   { "cast(cast(cast(pow(1, -38) as decimal(38,38)) as bigint) as decimal(18,10))",
-    {{ false, 0, 18, 10 },
-     { false, 10000000000, 18, 10 }}},
+    {{ false, false, 0, 18, 10 },
+     { false, false, 10000000000, 18, 10 }}},
   { "cast(cast(cast(-pow(1, -38) as decimal(38,38)) as bigint) as decimal(18,10))",
-    {{ false, 0, 18, 10 },
-     { false, -10000000000, 18, 10 }}},
+    {{ false, false, 0, 18, 10 },
+     { false, false, -10000000000, 18, 10 }}},
   // Test CAST FLOAT -> DECIMAL
   { "cast(cast(power(10, 3) - power(10, -1) as float) as decimal(4,1))",
-    {{ false, 9999, 4, 1 }}},
+    {{ false, false, 9999, 4, 1 }}},
   { "cast(cast(power(10, 3) - power(10, -2) as float) as decimal(5,1))",
-    {{ false, 9999, 5, 1 },
-     { false, 10000, 5, 1 }}},
+    {{ false, false, 9999, 5, 1 },
+     { false, false, 10000, 5, 1 }}},
   { "cast(cast(power(10, 3) - power(10, -2) as float) as decimal(4,1))",
-    {{ false, 9999, 4, 1 },
-     { true, 0, 4, 1 }}},
+    {{ false, false, 9999, 4, 1 },
+     { false, true, 0, 4, 1 }}},
   { "cast(cast(-power(10, 3) + power(10, -1) as float) as decimal(4,1))",
-    {{ false, -9999, 4, 1 }}},
+    {{ false, false, -9999, 4, 1 }}},
   { "cast(cast(-power(10, 3) + power(10, -2) as float) as decimal(5,1))",
-    {{ false, -9999, 5, 1 },
-     { false, -10000, 5, 1 }}},
+    {{ false, false, -9999, 5, 1 },
+     { false, false, -10000, 5, 1 }}},
   { "cast(cast(-power(10, 3) + power(10, -2) as float) as decimal(4,1))",
-    {{ false, -9999, 4, 1 },
-     { true, 0, 4, 1 }}},
+    {{ false, false, -9999, 4, 1 },
+     { false, true, 0, 4, 1 }}},
   { "cast(cast(power(10, 3) - 0.45 as double) as decimal(4,1))",
-    {{ false, 9995, 4, 1 },
-     { false, 9996, 4, 1 }}},
+    {{ false, false, 9995, 4, 1 },
+     { false, false, 9996, 4, 1 }}},
   { "cast(cast(power(10, 3) - 0.45 as double) as decimal(5,2))",
-    {{ false, 99955, 5, 2 }}},
+    {{ false, false, 99955, 5, 2 }}},
   { "cast(cast(power(10, 3) - 0.45 as double) as decimal(5,0))",
-    {{ false, 999, 5, 0 },
-     { false, 1000, 5, 0 }}},
+    {{ false, false, 999, 5, 0 },
+     { false, false, 1000, 5, 0 }}},
   { "cast(cast(power(10, 3) - 0.45 as double) as decimal(3,0))",
-    {{ false, 999, 3, 0 },
-     { true, 0, 3, 0 }}},
+    {{ false, false, 999, 3, 0 },
+     { false, true, 0, 3, 0 }}},
   { "cast(cast(-power(10, 3) + 0.45 as double) as decimal(4,1))",
-    {{ false, -9995, 4, 1 },
-     { false, -9996, 4, 1 }}},
+    {{ false, false, -9995, 4, 1 },
+     { false, false, -9996, 4, 1 }}},
   { "cast(cast(-power(10, 3) + 0.45 as double) as decimal(5,2))",
-    {{ false, -99955, 5, 2 }}},
+    {{ false, false, -99955, 5, 2 }}},
   { "cast(cast(-power(10, 3) + 0.45 as double) as decimal(5,0))",
-    {{ false, -999, 5, 0 },
-     { false, -1000, 5, 0 }}},
+    {{ false, false, -999, 5, 0 },
+     { false, false, -1000, 5, 0 }}},
   { "cast(cast(-power(10, 3) + 0.45 as double) as decimal(3,0))",
-    {{ false, -999, 3, 0 },
-     { true, 0, 3, 0 }}},
+    {{ false, false, -999, 3, 0 },
+     { false, true, 0, 3, 0 }}},
   { "cast(cast(power(10, 3) - 0.5 as double) as decimal(4,1))",
-    {{ false, 9995, 4, 1 }}},
+    {{ false, false, 9995, 4, 1 }}},
   { "cast(cast(power(10, 3) - 0.5 as double) as decimal(5,2))",
-    {{ false, 99950, 5, 2 }}},
+    {{ false, false, 99950, 5, 2 }}},
   { "cast(cast(power(10, 3) - 0.5 as double) as decimal(5,0))",
-    {{ false, 999, 5, 0 },
-     { false, 1000, 5, 0 }}},
+    {{ false, false, 999, 5, 0 },
+     { false, false, 1000, 5, 0 }}},
   { "cast(cast(power(10, 3) - 0.5 as double) as decimal(3,0))",
-    {{ false, 999, 3, 0 },
-     { true, 0, 3, 0 }}},
+    {{ false, false, 999, 3, 0 },
+     { false, true, 0, 3, 0 }}},
   { "cast(cast(-power(10, 3) + 0.5 as double) as decimal(4,1))",
-    {{ false, -9995, 4, 1 }}},
+    {{ false, false, -9995, 4, 1 }}},
   { "cast(cast(-power(10, 3) + 0.5 as double) as decimal(5,2))",
-    {{ false, -99950, 5, 2 }}},
+    {{ false, false, -99950, 5, 2 }}},
   { "cast(cast(-power(10, 3) + 0.5 as double) as decimal(5,0))",
-    {{ false, -999, 5, 0 },
-     { false, -1000, 5, 0 }}},
+    {{ false, false, -999, 5, 0 },
+     { false, false, -1000, 5, 0 }}},
   { "cast(cast(-power(10, 3) + 0.5 as double) as decimal(3,0))",
-    {{ false, -999, 3, 0 },
-     { true, 0, 3, 0 }}},
+    {{ false, false, -999, 3, 0 },
+     { false, true, 0, 3, 0 }}},
   { "cast(cast(power(10, 3) - 0.55 as double) as decimal(4,1))",
-    {{ false, 9994, 4, 1 },
-     { false, 9995, 4, 1 }}},
+    {{ false, false, 9994, 4, 1 },
+     { false, false, 9995, 4, 1 }}},
   { "cast(cast(power(10, 3) - 0.55 as double) as decimal(5,2))",
-    {{ false, 99945, 5, 2 }}},
+    {{ false, false, 99945, 5, 2 }}},
   { "cast(cast(power(10, 3) - 0.55 as double) as decimal(5,0))",
-    {{ false, 999, 5, 0 }}},
+    {{ false, false, 999, 5, 0 }}},
   { "cast(cast(power(10, 3) - 0.55 as double) as decimal(3,0))",
-    {{ false, 999, 3, 0 }}},
+    {{ false, false, 999, 3, 0 }}},
   { "cast(cast(-power(10, 3) + 0.55 as double) as decimal(4,1))",
-    {{ false, -9994, 4, 1 },
-     { false, -9995, 4, 1 }}},
+    {{ false, false, -9994, 4, 1 },
+     { false, false, -9995, 4, 1 }}},
   { "cast(cast(-power(10, 3) + 0.55 as double) as decimal(5,2))",
-    {{ false, -99945, 5, 2 }}},
+    {{ false, false, -99945, 5, 2 }}},
   { "cast(cast(-power(10, 3) + 0.55 as double) as decimal(5,0))",
-    {{ false, -999, 5, 0 }}},
+    {{ false, false, -999, 5, 0 }}},
   { "cast(cast(-power(10, 3) + 0.55 as double) as decimal(3,0))",
-    {{ false, -999, 3, 0 }}},
+    {{ false, false, -999, 3, 0 }}},
   { "cast(power(2, 1023) * 100 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
+    {{ false, true, 0, 38, 0 }}},
   { "cast(power(2, 1023) * 100 as decimal(18,0))",
-    {{ true, 0, 18, 0 }}},
+    {{ false, true, 0, 18, 0 }}},
   { "cast(power(2, 1023) * 100 as decimal(9,0))",
-    {{ true, 0, 9, 0 }}},
+    {{ false, true, 0, 9, 0 }}},
   { "cast(0/0 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
+    {{ false, true, 0, 38, 0 }}},
   { "cast(0/0 as decimal(18,0))",
-    {{ true, 0, 18, 0 }}},
+    {{ false, true, 0, 18, 0 }}},
   { "cast(0/0 as decimal(9,0))",
-    {{ true, 0, 9, 0 }}},
+    {{ false, true, 0, 9, 0 }}},
   // 39 5's - legal double but will overflow in decimal
   { "cast(555555555555555555555555555555555555555 as decimal(38,0))",
-    {{ true, 0, 38, 0 }}},
+    {{ false, true, 0, 38, 0 }}},
 };
 
 TEST_F(ExprTest, DecimalArithmeticExprs) {
@@ -2483,7 +2523,9 @@ TEST_F(ExprTest, DecimalArithmeticExprs) {
     for (const DecimalTestCase& c : decimal_cases) {
       const DecimalExpectedResult& r = c.Expected(v2);
       const ColumnType& type = ColumnType::CreateDecimalType(r.precision, r.scale);
-      if (r.null) {
+      if (r.error) {
+        TestError(c.expr);
+      } else if (r.null) {
         TestDecimalResultType(c.expr, type);
         TestIsNull(c.expr, type);
       } else {

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/5ebea0ec/testdata/workloads/functional-query/queries/QueryTest/decimal-exprs.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-query/queries/QueryTest/decimal-exprs.test b/testdata/workloads/functional-query/queries/QueryTest/decimal-exprs.test
index b1c62ec..ef707f2 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/decimal-exprs.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/decimal-exprs.test
@@ -28,6 +28,72 @@ select d1 / d2, d2 / d1, d3 / d4, d5 / d3, d3 / d5 from decimal_tbl;
 DECIMAL, DECIMAL, DECIMAL, DECIMAL, DECIMAL
 ====
 ---- QUERY
+# Test DECIMAL V1 division by zero.
+set decimal_v2=false;
+select d1 / cast(0 as decimal(7, 2)), d1 / 0, 10.0 / 0 from decimal_tbl;
+---- RESULTS
+NULL,NULL,Infinity
+NULL,NULL,Infinity
+NULL,NULL,Infinity
+NULL,NULL,Infinity
+NULL,NULL,Infinity
+---- TYPES
+DECIMAL,DECIMAL,DOUBLE
+====
+---- QUERY
+# Test DECIMAL V2 division by zero. Verify that Impala throws an error.
+set decimal_v2=true;
+select d1 / cast(0 as decimal(7, 2)) from decimal_tbl;
+---- CATCH
+UDF ERROR: Cannot divide decimal by zero
+====
+---- QUERY
+set decimal_v2=true;
+select d1 / 0 from decimal_tbl;
+---- CATCH
+UDF ERROR: Cannot divide decimal by zero
+====
+---- QUERY
+set decimal_v2=true;
+select 10.0 / 0;
+---- CATCH
+UDF ERROR: Cannot divide decimal by zero
+====
+---- QUERY
+# Test DECIMAL V1 modulo zero.
+set decimal_v2=false;
+select d1 % cast(0 as decimal(7, 2)), d1 % 0, 10.0 % 0 from decimal_tbl;
+---- RESULTS
+NULL,NULL,NULL
+NULL,NULL,NULL
+NULL,NULL,NULL
+NULL,NULL,NULL
+NULL,NULL,NULL
+---- TYPES
+DECIMAL,DECIMAL,DOUBLE
+====
+---- QUERY
+# Test DECIMAL V2 modulo zero. Verify that Impala throws an error.
+set decimal_v2=true;
+select d1 % cast(0 as decimal(7, 2)) from decimal_tbl;
+---- CATCH
+UDF ERROR: Cannot divide decimal by zero
+====
+---- QUERY
+# Test DECIMAL V2 modulo zero. Verify that Impala throws an error.
+set decimal_v2=true;
+select d1 % 0 from decimal_tbl;
+---- CATCH
+UDF ERROR: Cannot divide decimal by zero
+====
+---- QUERY
+# Test DECIMAL V2 modulo zero. Verify that Impala throws an error.
+set decimal_v2=true;
+select 10.0 % 0 from decimal_tbl;
+---- CATCH
+UDF ERROR: Cannot divide decimal by zero
+====
+---- QUERY
 # Test casting behavior without decimal_v2 query option set.
 set decimal_v2=false;
 select cast(d3 as decimal(20, 3)) from decimal_tbl;
@@ -205,4 +271,4 @@ from decimal_tiny where c2 < 112
 4.3329,647.66658,2.2,0.722150,107.944430,0.550000
 ---- TYPES
 DECIMAL,DECIMAL,DECIMAL,DECIMAL,DECIMAL,DECIMAL
-====
\ No newline at end of file
+====