You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by kw...@apache.org on 2017/02/13 19:23:24 UTC
[1/4] incubator-impala git commit: IMPALA-4884: Add JVM heap and
non-heap usage in metrics and UI
Repository: incubator-impala
Updated Branches:
refs/heads/master 6242478d0 -> f982c3f76
IMPALA-4884: Add JVM heap and non-heap usage in metrics and UI
This commit adds heap and non-heap memory usage of the embedded
JVM in the memory metrics and exposes these metrics in /memz web page of
the impalad and catalog web UI.
Change-Id: I543d4d428d7240e0f710d67973867162f2fcabc8
Reviewed-on: http://gerrit.cloudera.org:8080/5909
Reviewed-by: Dimitris Tsirogiannis <dt...@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/af469984
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/af469984
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/af469984
Branch: refs/heads/master
Commit: af4699847090ff7d03a588aa1b2e48170c64f03f
Parents: 6242478
Author: Dimitris Tsirogiannis <dt...@cloudera.com>
Authored: Sat Feb 4 21:14:05 2017 -0800
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Sat Feb 11 01:34:13 2017 +0000
----------------------------------------------------------------------
be/src/util/default-path-handlers.cc | 12 +++-
.../java/org/apache/impala/common/JniUtil.java | 36 ++++++++++
www/memz.tmpl | 70 ++++++++++++++++++--
3 files changed, 110 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/af469984/be/src/util/default-path-handlers.cc
----------------------------------------------------------------------
diff --git a/be/src/util/default-path-handlers.cc b/be/src/util/default-path-handlers.cc
index 91c51d3..732d3b3 100644
--- a/be/src/util/default-path-handlers.cc
+++ b/be/src/util/default-path-handlers.cc
@@ -148,17 +148,23 @@ void MemUsageHandler(MemTracker* mem_tracker, MetricGroup* metric_group,
if (jvm_group != NULL) {
Value jvm(kObjectType);
jvm_group->ToJson(false, document, &jvm);
+ Value heap(kArrayType);
+ Value non_heap(kArrayType);
Value total(kArrayType);
for (SizeType i = 0; i < jvm["metrics"].Size(); ++i) {
if (strstr(jvm["metrics"][i]["name"].GetString(), "total") != nullptr) {
total.PushBack(jvm["metrics"][i], document->GetAllocator());
+ } else if (strstr(jvm["metrics"][i]["name"].GetString(), "non-heap") != nullptr) {
+ non_heap.PushBack(jvm["metrics"][i], document->GetAllocator());
+ } else if (strstr(jvm["metrics"][i]["name"].GetString(), "heap") != nullptr) {
+ heap.PushBack(jvm["metrics"][i], document->GetAllocator());
}
}
- document->AddMember("jvm", total, document->GetAllocator());
-
+ document->AddMember("jvm_total", total, document->GetAllocator());
+ document->AddMember("jvm_heap", heap, document->GetAllocator());
+ document->AddMember("jvm_non_heap", non_heap, document->GetAllocator());
}
}
-
}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/af469984/fe/src/main/java/org/apache/impala/common/JniUtil.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/org/apache/impala/common/JniUtil.java b/fe/src/main/java/org/apache/impala/common/JniUtil.java
index 4446a55..223c8bb 100644
--- a/fe/src/main/java/org/apache/impala/common/JniUtil.java
+++ b/fe/src/main/java/org/apache/impala/common/JniUtil.java
@@ -22,6 +22,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
@@ -142,6 +143,41 @@ public class JniUtil {
}
}
}
+
+ if (request.get_all || request.getMemory_pool().equals("heap")) {
+ // Populate heap usage
+ MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
+ TJvmMemoryPool heap = new TJvmMemoryPool();
+ MemoryUsage heapUsage = mBean.getHeapMemoryUsage();
+ heap.setCommitted(heapUsage.getCommitted());
+ heap.setInit(heapUsage.getInit());
+ heap.setMax(heapUsage.getMax());
+ heap.setUsed(heapUsage.getUsed());
+ heap.setName("heap");
+ heap.setPeak_committed(0);
+ heap.setPeak_init(0);
+ heap.setPeak_max(0);
+ heap.setPeak_used(0);
+ jvmMetrics.getMemory_pools().add(heap);
+ }
+
+ if (request.get_all || request.getMemory_pool().equals("non-heap")) {
+ // Populate non-heap usage
+ MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
+ TJvmMemoryPool nonHeap = new TJvmMemoryPool();
+ MemoryUsage nonHeapUsage = mBean.getNonHeapMemoryUsage();
+ nonHeap.setCommitted(nonHeapUsage.getCommitted());
+ nonHeap.setInit(nonHeapUsage.getInit());
+ nonHeap.setMax(nonHeapUsage.getMax());
+ nonHeap.setUsed(nonHeapUsage.getUsed());
+ nonHeap.setName("non-heap");
+ nonHeap.setPeak_committed(0);
+ nonHeap.setPeak_init(0);
+ nonHeap.setPeak_max(0);
+ nonHeap.setPeak_used(0);
+ jvmMetrics.getMemory_pools().add(nonHeap);
+ }
+
TSerializer serializer = new TSerializer(protocolFactory_);
try {
return serializer.serialize(jvmMetrics);
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/af469984/www/memz.tmpl
----------------------------------------------------------------------
diff --git a/www/memz.tmpl b/www/memz.tmpl
index f54cdaa..48bd651 100644
--- a/www/memz.tmpl
+++ b/www/memz.tmpl
@@ -28,15 +28,15 @@ Memory consumption / limit: <strong>{{consumption}}</strong> / <strong>{{mem_lim
<h3>Breakdown</h3>
<pre>{{detailed}}</pre>
-{{?jvm}}
-<h3>JVM memory total usage</h3>
+{{?jvm_heap}}
+<h3>JVM heap usage</h3>
<table class='table table-bordered table-hover'>
<tr>
<th>Name</th>
<th>Value</th>
<th>Description</th>
</tr>
- {{#jvm}}
+ {{#jvm_heap}}
<tr>
<td><tt>{{name}}</tt></td>
{{! Is this a stats metric? }}
@@ -54,8 +54,68 @@ Memory consumption / limit: <strong>{{consumption}}</strong> / <strong>{{mem_lim
{{description}}
</td>
</tr>
- {{/jvm}}
+ {{/jvm_heap}}
</table>
-{{/jvm}}
+{{/jvm_heap}}
+
+{{?jvm_non_heap}}
+<h3>JVM non-heap usage</h3>
+<table class='table table-bordered table-hover'>
+ <tr>
+ <th>Name</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ {{#jvm_non_heap}}
+ <tr>
+ <td><tt>{{name}}</tt></td>
+ {{! Is this a stats metric? }}
+ {{?mean}}
+ <td>
+ Last (of {{count}}): <strong>{{last}}</strong>.
+ Min: {{min}}, max: {{max}}, avg: {{mean}}</td>
+ {{/mean}}
+ {{^mean}}
+ <td>
+ {{human_readable}}
+ </td>
+ {{/mean}}
+ <td>
+ {{description}}
+ </td>
+ </tr>
+ {{/jvm_non_heap}}
+</table>
+{{/jvm_non_heap}}
+
+{{?jvm_total}}
+<h3>JVM total memory usage</h3>
+<table class='table table-bordered table-hover'>
+ <tr>
+ <th>Name</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ {{#jvm_total}}
+ <tr>
+ <td><tt>{{name}}</tt></td>
+ {{! Is this a stats metric? }}
+ {{?mean}}
+ <td>
+ Last (of {{count}}): <strong>{{last}}</strong>.
+ Min: {{min}}, max: {{max}}, avg: {{mean}}</td>
+ {{/mean}}
+ {{^mean}}
+ <td>
+ {{human_readable}}
+ </td>
+ {{/mean}}
+ <td>
+ {{description}}
+ </td>
+ </tr>
+ {{/jvm_total}}
+</table>
+{{/jvm_total}}
{{> www/common-footer.tmpl }}
[4/4] incubator-impala git commit: IMPALA-2020,
IMPALA-4809: Codegen support for DECIMAL_V2
Posted by kw...@apache.org.
IMPALA-2020, IMPALA-4809: Codegen support for DECIMAL_V2
Currently, codegen supports converting type attributes (e.g.
decimal type's precision and scale, type's size) obtained via
calls to FunctionContextImpl::GetFnAttr() (previously
Expr::GetConstantInt()) in cross-compiled code to runtime constants.
This change extends this support for the query option DECIMAL_V2.
To test this change, this change also handles a subset of IMPALA-2020:
casting between decimal values is updated to support rounding (instead
of truncation) when decimal_v2 is true.
This change also cleans up the existing code by moving the codegen
logic Expr::InlineConstant() to the codegen module and the type
related logic in Expr::GetConstantInt() to FunctionContextImpl.
Change-Id: I2434d240f65b81389b8a8ba027f980a0e1d1f981
Reviewed-on: http://gerrit.cloudera.org:8080/5950
Reviewed-by: Michael Ho <kw...@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/f982c3f7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/f982c3f7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/f982c3f7
Branch: refs/heads/master
Commit: f982c3f76e762f646b52a01659796b4edcfbc1ad
Parents: a78726d
Author: Michael Ho <kw...@cloudera.com>
Authored: Fri Feb 3 20:55:18 2017 -0800
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Sat Feb 11 07:07:45 2017 +0000
----------------------------------------------------------------------
be/src/benchmarks/hash-benchmark.cc | 18 +-
be/src/codegen/llvm-codegen-test.cc | 60 +++--
be/src/codegen/llvm-codegen.cc | 98 +++++++--
be/src/codegen/llvm-codegen.h | 48 ++--
be/src/exec/partitioned-aggregation-node.cc | 8 +-
be/src/exec/partitioned-aggregation-node.h | 2 +-
be/src/exprs/agg-fn-evaluator.cc | 2 +-
be/src/exprs/aggregate-functions-ir.cc | 12 +-
be/src/exprs/conditional-functions-ir.cc | 27 ++-
be/src/exprs/decimal-functions-ir.cc | 78 +++----
be/src/exprs/decimal-operators-ir.cc | 219 ++++++++++---------
be/src/exprs/decimal-operators.h | 2 +-
be/src/exprs/expr-codegen-test.cc | 152 ++++++++-----
be/src/exprs/expr-test.cc | 12 +-
be/src/exprs/expr.cc | 86 --------
be/src/exprs/expr.h | 59 -----
be/src/exprs/math-functions-ir.cc | 4 +-
be/src/exprs/scalar-fn-call.cc | 4 +-
be/src/runtime/decimal-value.inline.h | 3 +-
be/src/runtime/lib-cache.cc | 9 +-
be/src/runtime/runtime-state.cc | 2 +-
be/src/runtime/runtime-state.h | 1 +
be/src/service/frontend.cc | 2 +-
be/src/udf/udf-internal.h | 47 +++-
be/src/udf/udf-test-harness.cc | 5 +-
be/src/udf/udf-test-harness.h | 4 +-
be/src/udf/udf.cc | 60 ++++-
.../queries/QueryTest/decimal.test | 44 ++++
tests/query_test/test_decimal_casting.py | 70 +++---
29 files changed, 646 insertions(+), 492 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/benchmarks/hash-benchmark.cc
----------------------------------------------------------------------
diff --git a/be/src/benchmarks/hash-benchmark.cc b/be/src/benchmarks/hash-benchmark.cc
index 125310b..fb37bed 100644
--- a/be/src/benchmarks/hash-benchmark.cc
+++ b/be/src/benchmarks/hash-benchmark.cc
@@ -26,6 +26,7 @@
#include "experiments/data-provider.h"
#include "runtime/mem-tracker.h"
#include "runtime/string-value.h"
+#include "runtime/test-env.h"
#include "util/benchmark.h"
#include "util/cpu-info.h"
#include "util/hash-util.h"
@@ -419,17 +420,24 @@ int main(int argc, char **argv) {
const int NUM_ROWS = 1024;
- ObjectPool obj_pool;
+ Status status;
+ RuntimeState* state;
+ TestEnv test_env;
+ status = test_env.CreateQueryState(0, 0, 0, nullptr, &state);
+ if (!status.ok()) {
+ cout << "Could not create RuntimeState";
+ return -1;
+ }
+
MemTracker tracker;
MemPool mem_pool(&tracker);
- RuntimeProfile int_profile(&obj_pool, "IntGen");
- RuntimeProfile mixed_profile(&obj_pool, "MixedGen");
+ RuntimeProfile int_profile(state->obj_pool(), "IntGen");
+ RuntimeProfile mixed_profile(state->obj_pool(), "MixedGen");
DataProvider int_provider(&mem_pool, &int_profile);
DataProvider mixed_provider(&mem_pool, &mixed_profile);
- Status status;
scoped_ptr<LlvmCodeGen> codegen;
- status = LlvmCodeGen::CreateImpalaCodegen(&obj_pool, NULL, "test", &codegen);
+ status = LlvmCodeGen::CreateImpalaCodegen(state, NULL, "test", &codegen);
if (!status.ok()) {
cout << "Could not start codegen.";
return -1;
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/codegen/llvm-codegen-test.cc
----------------------------------------------------------------------
diff --git a/be/src/codegen/llvm-codegen-test.cc b/be/src/codegen/llvm-codegen-test.cc
index 412426f..59c66f4 100644
--- a/be/src/codegen/llvm-codegen-test.cc
+++ b/be/src/codegen/llvm-codegen-test.cc
@@ -24,6 +24,8 @@
#include "common/init.h"
#include "common/object-pool.h"
#include "runtime/string-value.h"
+#include "runtime/test-env.h"
+#include "service/fe-support.h"
#include "util/cpu-info.h"
#include "util/hash-util.h"
#include "util/path-builder.h"
@@ -38,13 +40,27 @@ namespace impala {
class LlvmCodeGenTest : public testing:: Test {
protected:
+ scoped_ptr<TestEnv> test_env_;
+ RuntimeState* runtime_state_;
+
+ virtual void SetUp() {
+ test_env_.reset(new TestEnv());
+ EXPECT_OK(test_env_->CreateQueryState(0, 1, 8 * 1024 * 1024, nullptr,
+ &runtime_state_));
+ }
+
+ virtual void TearDown() {
+ runtime_state_ = NULL;
+ test_env_.reset();
+ }
+
static void LifetimeTest() {
ObjectPool pool;
Status status;
for (int i = 0; i < 10; ++i) {
- LlvmCodeGen object1(&pool, NULL, "Test");
- LlvmCodeGen object2(&pool, NULL, "Test");
- LlvmCodeGen object3(&pool, NULL, "Test");
+ LlvmCodeGen object1(NULL, &pool, NULL, "Test");
+ LlvmCodeGen object2(NULL, &pool, NULL, "Test");
+ LlvmCodeGen object3(NULL, &pool, NULL, "Test");
ASSERT_OK(object1.Init(unique_ptr<Module>(new Module("Test", object1.context()))));
ASSERT_OK(object2.Init(unique_ptr<Module>(new Module("Test", object2.context()))));
@@ -53,22 +69,12 @@ class LlvmCodeGenTest : public testing:: Test {
}
// Wrapper to call private test-only methods on LlvmCodeGen object
- static Status CreateFromFile(
- ObjectPool* pool, const string& filename, scoped_ptr<LlvmCodeGen>* codegen) {
- RETURN_IF_ERROR(LlvmCodeGen::CreateFromFile(pool, NULL, filename, "test", codegen));
+ Status CreateFromFile(const string& filename, scoped_ptr<LlvmCodeGen>* codegen) {
+ RETURN_IF_ERROR(LlvmCodeGen::CreateFromFile(runtime_state_,
+ runtime_state_->obj_pool(), NULL, filename, "test", codegen));
return (*codegen)->MaterializeModule();
}
- static LlvmCodeGen* CreateCodegen(ObjectPool* pool) {
- LlvmCodeGen* codegen = pool->Add(new LlvmCodeGen(pool, NULL, "Test"));
- if (codegen != NULL) {
- Status status =
- codegen->Init(unique_ptr<Module>(new Module("Test", codegen->context())));
- if (!status.ok()) return NULL;
- }
- return codegen;
- }
-
static void ClearHashFns(LlvmCodeGen* codegen) {
codegen->ClearHashFns();
}
@@ -104,11 +110,9 @@ TEST_F(LlvmCodeGenTest, MultithreadedLifetime) {
// Test loading a non-existent file
TEST_F(LlvmCodeGenTest, BadIRFile) {
- ObjectPool pool;
string module_file = "NonExistentFile.ir";
scoped_ptr<LlvmCodeGen> codegen;
- EXPECT_FALSE(
- LlvmCodeGenTest::CreateFromFile(&pool, module_file.c_str(), &codegen).ok());
+ EXPECT_FALSE(CreateFromFile(module_file.c_str(), &codegen).ok());
}
// IR for the generated linner loop
@@ -159,7 +163,6 @@ Function* CodegenInnerLoop(LlvmCodeGen* codegen, int64_t* jitted_counter, int de
// 5. Updated the jitted loop in place with another jitted inner loop function
// 6. Run the loop and make sure the updated is called.
TEST_F(LlvmCodeGenTest, ReplaceFnCall) {
- ObjectPool pool;
const string loop_call_name("_Z21DefaultImplementationv");
const string loop_name("_Z8TestLoopi");
typedef void (*TestLoopFn)(int);
@@ -169,7 +172,7 @@ TEST_F(LlvmCodeGenTest, ReplaceFnCall) {
// Part 1: Load the module and make sure everything is loaded correctly.
scoped_ptr<LlvmCodeGen> codegen;
- ASSERT_OK(LlvmCodeGenTest::CreateFromFile(&pool, module_file.c_str(), &codegen));
+ ASSERT_OK(CreateFromFile(module_file.c_str(), &codegen));
EXPECT_TRUE(codegen.get() != NULL);
Function* loop_call = codegen->GetFunction(loop_call_name, false);
@@ -285,10 +288,8 @@ Function* CodegenStringTest(LlvmCodeGen* codegen) {
// struct. Just create a simple StringValue struct and make sure the IR can read it
// and modify it.
TEST_F(LlvmCodeGenTest, StringValue) {
- ObjectPool pool;
-
scoped_ptr<LlvmCodeGen> codegen;
- ASSERT_OK(LlvmCodeGen::CreateImpalaCodegen(&pool, NULL, "test", &codegen));
+ ASSERT_OK(LlvmCodeGen::CreateImpalaCodegen(runtime_state_, NULL, "test", &codegen));
EXPECT_TRUE(codegen.get() != NULL);
string str("Test");
@@ -328,10 +329,8 @@ TEST_F(LlvmCodeGenTest, StringValue) {
// Test calling memcpy intrinsic
TEST_F(LlvmCodeGenTest, MemcpyTest) {
- ObjectPool pool;
-
scoped_ptr<LlvmCodeGen> codegen;
- ASSERT_OK(LlvmCodeGen::CreateImpalaCodegen(&pool, NULL, "test", &codegen));
+ ASSERT_OK(LlvmCodeGen::CreateImpalaCodegen(runtime_state_, NULL, "test", &codegen));
ASSERT_TRUE(codegen.get() != NULL);
LlvmCodeGen::FnPrototype prototype(codegen.get(), "MemcpyTest", codegen->void_type());
@@ -367,8 +366,6 @@ TEST_F(LlvmCodeGenTest, MemcpyTest) {
// Test codegen for hash
TEST_F(LlvmCodeGenTest, HashTest) {
- ObjectPool pool;
-
// Values to compute hash on
const char* data1 = "test string";
const char* data2 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -378,7 +375,7 @@ TEST_F(LlvmCodeGenTest, HashTest) {
// Loop to test both the sse4 on/off paths
for (int i = 0; i < 2; ++i) {
scoped_ptr<LlvmCodeGen> codegen;
- ASSERT_OK(LlvmCodeGen::CreateImpalaCodegen(&pool, NULL, "test", &codegen));
+ ASSERT_OK(LlvmCodeGen::CreateImpalaCodegen(runtime_state_, NULL, "test", &codegen));
ASSERT_TRUE(codegen.get() != NULL);
Value* llvm_data1 =
@@ -452,7 +449,8 @@ TEST_F(LlvmCodeGenTest, HashTest) {
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
- impala::InitCommonRuntime(argc, argv, false, impala::TestInfo::BE_TEST);
+ impala::InitCommonRuntime(argc, argv, true, impala::TestInfo::BE_TEST);
+ impala::InitFeSupport(false);
impala::LlvmCodeGen::InitializeLlvm();
return RUN_ALL_TESTS();
}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/codegen/llvm-codegen.cc
----------------------------------------------------------------------
diff --git a/be/src/codegen/llvm-codegen.cc b/be/src/codegen/llvm-codegen.cc
index 6cf43f6..a548654 100644
--- a/be/src/codegen/llvm-codegen.cc
+++ b/be/src/codegen/llvm-codegen.cc
@@ -58,12 +58,14 @@
#include "codegen/instruction-counter.h"
#include "codegen/mcjit-mem-mgr.h"
#include "common/logging.h"
+#include "exprs/anyval-util.h"
#include "impala-ir/impala-ir-names.h"
#include "runtime/descriptors.h"
#include "runtime/hdfs-fs-cache.h"
#include "runtime/lib-cache.h"
#include "runtime/mem-pool.h"
#include "runtime/mem-tracker.h"
+#include "runtime/runtime-state.h"
#include "runtime/string-value.h"
#include "runtime/timestamp-value.h"
#include "util/cpu-info.h"
@@ -170,7 +172,8 @@ Status LlvmCodeGen::InitializeLlvm(bool load_backend) {
ObjectPool init_pool;
scoped_ptr<LlvmCodeGen> init_codegen;
- RETURN_IF_ERROR(LlvmCodeGen::CreateFromMemory(&init_pool, NULL, "init", &init_codegen));
+ RETURN_IF_ERROR(LlvmCodeGen::CreateFromMemory(
+ nullptr, &init_pool, nullptr, "init", &init_codegen));
// LLVM will construct "use" lists only when the entire module is materialized.
RETURN_IF_ERROR(init_codegen->MaterializeModule());
@@ -209,9 +212,10 @@ Status LlvmCodeGen::InitializeLlvm(bool load_backend) {
return Status::OK();
}
-LlvmCodeGen::LlvmCodeGen(
- ObjectPool* pool, MemTracker* parent_mem_tracker, const string& id)
- : id_(id),
+LlvmCodeGen::LlvmCodeGen(RuntimeState* state, ObjectPool* pool,
+ MemTracker* parent_mem_tracker, const string& id)
+ : state_(state),
+ id_(id),
profile_(pool, "CodeGen"),
mem_tracker_(new MemTracker(&profile_, -1, "CodeGen", parent_mem_tracker)),
optimizations_enabled_(false),
@@ -233,9 +237,10 @@ LlvmCodeGen::LlvmCodeGen(
num_instructions_ = ADD_COUNTER(&profile_, "NumInstructions", TUnit::UNIT);
}
-Status LlvmCodeGen::CreateFromFile(ObjectPool* pool, MemTracker* parent_mem_tracker,
- const string& file, const string& id, scoped_ptr<LlvmCodeGen>* codegen) {
- codegen->reset(new LlvmCodeGen(pool, parent_mem_tracker, id));
+Status LlvmCodeGen::CreateFromFile(RuntimeState* state, ObjectPool* pool,
+ MemTracker* parent_mem_tracker, const string& file, const string& id,
+ scoped_ptr<LlvmCodeGen>* codegen) {
+ codegen->reset(new LlvmCodeGen(state, pool, parent_mem_tracker, id));
SCOPED_TIMER((*codegen)->profile_.total_time_counter());
unique_ptr<Module> loaded_module;
@@ -244,9 +249,9 @@ Status LlvmCodeGen::CreateFromFile(ObjectPool* pool, MemTracker* parent_mem_trac
return (*codegen)->Init(std::move(loaded_module));
}
-Status LlvmCodeGen::CreateFromMemory(ObjectPool* pool, MemTracker* parent_mem_tracker,
- const string& id, scoped_ptr<LlvmCodeGen>* codegen) {
- codegen->reset(new LlvmCodeGen(pool, parent_mem_tracker, id));
+Status LlvmCodeGen::CreateFromMemory(RuntimeState* state, ObjectPool* pool,
+ MemTracker* parent_mem_tracker, const string& id, scoped_ptr<LlvmCodeGen>* codegen) {
+ codegen->reset(new LlvmCodeGen(state, pool, parent_mem_tracker, id));
SCOPED_TIMER((*codegen)->profile_.total_time_counter());
// Select the appropriate IR version. We cannot use LLVM IR with SSE4.2 instructions on
@@ -355,9 +360,12 @@ void LlvmCodeGen::StripGlobalCtorsDtors(llvm::Module* module) {
if (destructors != NULL) destructors->eraseFromParent();
}
-Status LlvmCodeGen::CreateImpalaCodegen(ObjectPool* pool, MemTracker* parent_mem_tracker,
- const string& id, scoped_ptr<LlvmCodeGen>* codegen_ret) {
- RETURN_IF_ERROR(CreateFromMemory(pool, parent_mem_tracker, id, codegen_ret));
+Status LlvmCodeGen::CreateImpalaCodegen(RuntimeState* state,
+ MemTracker* parent_mem_tracker, const string& id,
+ scoped_ptr<LlvmCodeGen>* codegen_ret) {
+ DCHECK(state != nullptr);
+ RETURN_IF_ERROR(CreateFromMemory(
+ state, state->obj_pool(), parent_mem_tracker, id, codegen_ret));
LlvmCodeGen* codegen = codegen_ret->get();
// Parse module for cross compiled functions and types
@@ -681,17 +689,19 @@ Function* LlvmCodeGen::GetFunction(IRFunction::Type ir_type, bool clone) {
bool LlvmCodeGen::VerifyFunction(Function* fn) {
if (is_corrupt_) return false;
- // Check that there are no calls to Expr::GetConstant(). These should all have been
- // inlined via Expr::InlineConstants().
+ // Check that there are no calls to FunctionContextImpl::GetConstFnAttr(). These should all
+ // have been inlined via InlineConstFnAttrs().
for (inst_iterator iter = inst_begin(fn); iter != inst_end(fn); ++iter) {
Instruction* instr = &*iter;
if (!isa<CallInst>(instr)) continue;
CallInst* call_instr = reinterpret_cast<CallInst*>(instr);
Function* called_fn = call_instr->getCalledFunction();
- // look for call to Expr::GetConstant()
- if (called_fn != NULL &&
- called_fn->getName().find(Expr::GET_CONSTANT_INT_SYMBOL_PREFIX) != string::npos) {
- LOG(ERROR) << "Found call to Expr::GetConstant*(): " << Print(call_instr);
+
+ // Look for call to FunctionContextImpl::GetConstFnAttr().
+ if (called_fn != nullptr &&
+ called_fn->getName() == FunctionContextImpl::GET_CONST_FN_ATTR_SYMBOL) {
+ LOG(ERROR) << "Found call to FunctionContextImpl::GetConstFnAttr(): "
+ << Print(call_instr);
is_corrupt_ = true;
break;
}
@@ -916,6 +926,47 @@ int LlvmCodeGen::ReplaceCallSitesWithBoolConst(llvm::Function* caller, bool cons
return ReplaceCallSitesWithValue(caller, replacement, target_name);
}
+int LlvmCodeGen::InlineConstFnAttrs(const FunctionContext::TypeDesc& ret_type,
+ const vector<FunctionContext::TypeDesc>& arg_types, Function* fn) {
+ int replaced = 0;
+ for (inst_iterator iter = inst_begin(fn), end = inst_end(fn); iter != end; ) {
+ // Increment iter now so we don't mess it up modifying the instruction below
+ Instruction* instr = &*(iter++);
+
+ // Look for call instructions
+ if (!isa<CallInst>(instr)) continue;
+ CallInst* call_instr = cast<CallInst>(instr);
+ Function* called_fn = call_instr->getCalledFunction();
+
+ // Look for call to FunctionContextImpl::GetConstFnAttr().
+ if (called_fn == nullptr ||
+ called_fn->getName() != FunctionContextImpl::GET_CONST_FN_ATTR_SYMBOL) {
+ continue;
+ }
+
+ // 't' and 'i' arguments must be constant
+ ConstantInt* t_arg = dyn_cast<ConstantInt>(call_instr->getArgOperand(1));
+ ConstantInt* i_arg = dyn_cast<ConstantInt>(call_instr->getArgOperand(2));
+ // This optimization is only applied to built-ins which should have constant args.
+ DCHECK(t_arg != nullptr)
+ << "Non-constant 't' argument to FunctionContextImpl::GetConstFnAttr()";
+ DCHECK(i_arg != nullptr)
+ << "Non-constant 'i' argument to FunctionContextImpl::GetConstFnAttr";
+
+ // Replace the called function with the appropriate constant
+ FunctionContextImpl::ConstFnAttr t_val =
+ static_cast<FunctionContextImpl::ConstFnAttr>(t_arg->getSExtValue());
+ int i_val = static_cast<int>(i_arg->getSExtValue());
+ DCHECK(state_ != nullptr);
+ // All supported constants are currently integers.
+ call_instr->replaceAllUsesWith(ConstantInt::get(GetType(TYPE_INT),
+ FunctionContextImpl::GetConstFnAttr(state_, ret_type, arg_types, t_val, i_val)));
+ call_instr->eraseFromParent();
+ ++replaced;
+ }
+ return replaced;
+}
+
void LlvmCodeGen::FindCallSites(Function* caller, const string& target_name,
vector<CallInst*>* results) {
for (inst_iterator iter = inst_begin(caller); iter != inst_end(caller); ++iter) {
@@ -1216,10 +1267,15 @@ void LlvmCodeGen::CodegenDebugTrace(LlvmBuilder* builder, const char* str,
builder->CreateCall(printf, calling_args);
}
-void LlvmCodeGen::GetSymbols(unordered_set<string>* symbols) {
- for (const Function& fn: module_->functions()) {
+Status LlvmCodeGen::GetSymbols(const string& file, const string& module_id,
+ unordered_set<string>* symbols) {
+ ObjectPool pool;
+ scoped_ptr<LlvmCodeGen> codegen;
+ RETURN_IF_ERROR(CreateFromFile(nullptr, &pool, nullptr, file, module_id, &codegen));
+ for (const Function& fn: codegen->module_->functions()) {
if (fn.isMaterializable()) symbols->insert(fn.getName());
}
+ return Status::OK();
}
// TODO: cache this function (e.g. all min(int, int) are identical).
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/codegen/llvm-codegen.h
----------------------------------------------------------------------
diff --git a/be/src/codegen/llvm-codegen.h b/be/src/codegen/llvm-codegen.h
index d51faab..058403d 100644
--- a/be/src/codegen/llvm-codegen.h
+++ b/be/src/codegen/llvm-codegen.h
@@ -153,17 +153,9 @@ class LlvmCodeGen {
/// 'codegen' will contain the created object on success.
/// 'parent_mem_tracker' - if non-NULL, the CodeGen MemTracker is created under this.
/// 'id' is used for outputting the IR module for debugging.
- static Status CreateImpalaCodegen(ObjectPool*, MemTracker* parent_mem_tracker,
+ static Status CreateImpalaCodegen(RuntimeState* state, MemTracker* parent_mem_tracker,
const std::string& id, boost::scoped_ptr<LlvmCodeGen>* codegen);
- /// Creates a LlvmCodeGen instance initialized with the module bitcode from 'file'.
- /// 'codegen' will contain the created object on success. The functions in the module
- /// are materialized lazily. Getting a reference to a function via GetFunction() will
- /// materialize the function and its callees recursively.
- static Status CreateFromFile(ObjectPool*, MemTracker* parent_mem_tracker,
- const std::string& file, const std::string& id,
- boost::scoped_ptr<LlvmCodeGen>* codegen);
-
/// Removes all jit compiled dynamically linked functions from the process.
~LlvmCodeGen();
@@ -204,6 +196,7 @@ class LlvmCodeGen {
void AddArgument(const NamedVariable& var) {
args_.push_back(var);
}
+
void AddArgument(const std::string& name, llvm::Type* type) {
args_.push_back(NamedVariable(name, type));
}
@@ -333,6 +326,17 @@ class LlvmCodeGen {
int ReplaceCallSitesWithValue(llvm::Function* caller, llvm::Value* replacement,
const std::string& target_name);
+ /// This function replaces calls to FunctionContextImpl::GetConstFnAttr() with constants
+ /// derived from 'return_type', 'arg_types' and the runtime state 'state_'. Please note
+ /// that this function only replaces call instructions inside 'fn' so to replace the
+ /// call to FunctionContextImpl::GetConstFnAttr() inside the callee functions, please
+ /// inline the callee functions (by annotating them with IR_ALWAYS_INLINE).
+ ///
+ /// TODO: implement a loop unroller (or use LLVM's) so we can use
+ /// FunctionContextImpl::GetConstFnAttr() in loops
+ int InlineConstFnAttrs(const FunctionContext::TypeDesc& return_type,
+ const std::vector<FunctionContext::TypeDesc>& arg_types, llvm::Function* fn);
+
/// Returns a copy of fn. The copy is added to the module.
llvm::Function* CloneFunction(llvm::Function* fn);
@@ -471,8 +475,9 @@ class LlvmCodeGen {
llvm::Type* void_type() { return void_type_; }
llvm::Type* i128_type() { return llvm::Type::getIntNTy(context(), 128); }
- /// Fils in 'symbols' with all the symbols in the module.
- void GetSymbols(boost::unordered_set<std::string>* symbols);
+ /// Load the module temporarily and populate 'symbols' with the symbols in the module.
+ static Status GetSymbols(const string& file, const string& module_id,
+ boost::unordered_set<std::string>* symbols);
/// Generates function to return min/max(v1, v2)
llvm::Function* CodegenMinMax(const ColumnType& type, bool min);
@@ -524,19 +529,28 @@ class LlvmCodeGen {
static void FindGlobalUsers(llvm::User* val, std::vector<llvm::GlobalObject*>* users);
/// Top level codegen object. 'module_id' is used for debugging when outputting the IR.
- LlvmCodeGen(
- ObjectPool* pool, MemTracker* parent_mem_tracker, const std::string& module_id);
+ LlvmCodeGen(RuntimeState* state, ObjectPool* pool, MemTracker* parent_mem_tracker,
+ const std::string& module_id);
/// Initializes the jitter and execution engine with the given module.
Status Init(std::unique_ptr<llvm::Module> module);
- /// Creates a LlvmCodeGen instance initialized with the module bitcode in memory.
+ /// Creates a LlvmCodeGen instance initialized with the module bitcode from 'file'.
/// 'codegen' will contain the created object on success. The functions in the module
/// are materialized lazily. Getting a reference to a function via GetFunction() will
/// materialize the function and its callees recursively.
- static Status CreateFromMemory(ObjectPool* pool, MemTracker* parent_mem_tracker,
+ static Status CreateFromFile(RuntimeState* state, ObjectPool* pool,
+ MemTracker* parent_mem_tracker, const std::string& file,
const std::string& id, boost::scoped_ptr<LlvmCodeGen>* codegen);
+ /// Creates a LlvmCodeGen instance initialized with the module bitcode in memory.
+ /// 'codegen' will contain the created object on success. The functions in the module
+ /// are materialized lazily. Getting a reference to a function via GetFunction() will
+ /// materialize the function and its callees recursively.
+ static Status CreateFromMemory(RuntimeState* state, ObjectPool* pool,
+ MemTracker* parent_mem_tracker, const std::string& id,
+ boost::scoped_ptr<LlvmCodeGen>* codegen);
+
/// Loads an LLVM module from 'file' which is the local path to the LLVM bitcode file.
/// The functions in the module are materialized lazily. Getting a reference to the
/// function via GetFunction() will materialize the function and its callees
@@ -639,6 +653,10 @@ class LlvmCodeGen {
/// when a module is loaded to ensure that LLVM can resolve references to them.
static boost::unordered_set<std::string> fns_to_always_materialize_;
+ /// Pointer to the RuntimeState which owns this codegen object. Needed in
+ /// InlineConstFnAttr() to access the query options.
+ const RuntimeState* state_;
+
/// ID used for debugging (can be e.g. the fragment instance ID)
std::string id_;
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exec/partitioned-aggregation-node.cc
----------------------------------------------------------------------
diff --git a/be/src/exec/partitioned-aggregation-node.cc b/be/src/exec/partitioned-aggregation-node.cc
index 7c75d01..83232d2 100644
--- a/be/src/exec/partitioned-aggregation-node.cc
+++ b/be/src/exec/partitioned-aggregation-node.cc
@@ -1681,8 +1681,8 @@ Status PartitionedAggregationNode::CodegenUpdateSlot(LlvmCodeGen* codegen,
// Call the UDA to update/merge 'src' into 'dst', with the result stored in
// 'updated_dst_val'.
CodegenAnyVal updated_dst_val;
- RETURN_IF_ERROR(CodegenCallUda(
- codegen, &builder, evaluator, agg_fn_ctx_arg, input_vals, dst, &updated_dst_val));
+ RETURN_IF_ERROR(CodegenCallUda(codegen, &builder, evaluator, agg_fn_ctx_arg,
+ input_vals, dst, &updated_dst_val));
result = updated_dst_val.ToNativeValue();
if (slot_desc->is_nullable() && !special_null_handling) {
@@ -1717,7 +1717,7 @@ Status PartitionedAggregationNode::CodegenUpdateSlot(LlvmCodeGen* codegen,
}
Status PartitionedAggregationNode::CodegenCallUda(LlvmCodeGen* codegen,
- LlvmBuilder* builder, AggFnEvaluator* evaluator, Value* agg_fn_ctx,
+ LlvmBuilder* builder, AggFnEvaluator* evaluator, Value* agg_fn_ctx_arg,
const vector<CodegenAnyVal>& input_vals, const CodegenAnyVal& dst,
CodegenAnyVal* updated_dst_val) {
DCHECK_EQ(evaluator->input_expr_ctxs().size(), input_vals.size());
@@ -1727,7 +1727,7 @@ Status PartitionedAggregationNode::CodegenCallUda(LlvmCodeGen* codegen,
// Set up arguments for call to UDA, which are the FunctionContext*, followed by
// pointers to all input values, followed by a pointer to the destination value.
vector<Value*> uda_fn_args;
- uda_fn_args.push_back(agg_fn_ctx);
+ uda_fn_args.push_back(agg_fn_ctx_arg);
// Create pointers to input args to pass to uda_fn. We must use the unlowered type,
// e.g. IntVal, because the UDA interface expects the values to be passed as const
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exec/partitioned-aggregation-node.h
----------------------------------------------------------------------
diff --git a/be/src/exec/partitioned-aggregation-node.h b/be/src/exec/partitioned-aggregation-node.h
index 54840c7..f26a252 100644
--- a/be/src/exec/partitioned-aggregation-node.h
+++ b/be/src/exec/partitioned-aggregation-node.h
@@ -651,7 +651,7 @@ class PartitionedAggregationNode : public ExecNode {
/// operation is applied. The instruction sequence for the UDA call is inserted at
/// the insert position of 'builder'.
Status CodegenCallUda(LlvmCodeGen* codegen, LlvmBuilder* builder,
- AggFnEvaluator* evaluator, llvm::Value* agg_fn_ctx,
+ AggFnEvaluator* evaluator, llvm::Value* agg_fn_ctx_arg,
const std::vector<CodegenAnyVal>& input_vals, const CodegenAnyVal& dst_val,
CodegenAnyVal* updated_dst_val);
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/agg-fn-evaluator.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/agg-fn-evaluator.cc b/be/src/exprs/agg-fn-evaluator.cc
index b623130..81c0277 100644
--- a/be/src/exprs/agg-fn-evaluator.cc
+++ b/be/src/exprs/agg-fn-evaluator.cc
@@ -528,7 +528,7 @@ Status AggFnEvaluator::GetUpdateOrMergeFunction(LlvmCodeGen* codegen, Function**
if (!(*uda_fn)->isDeclaration()) {
// TODO: IMPALA-4785: we should also replace references to GetIntermediateType()
// with constants.
- Expr::InlineConstants(GetOutputTypeDesc(), arg_type_descs_, codegen, *uda_fn);
+ codegen->InlineConstFnAttrs(GetOutputTypeDesc(), arg_type_descs_, *uda_fn);
*uda_fn = codegen->FinalizeFunction(*uda_fn);
if (*uda_fn == NULL) {
return Status(TErrorCode::UDF_VERIFY_FAILED, symbol, fn_.hdfs_location);
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/aggregate-functions-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/aggregate-functions-ir.cc b/be/src/exprs/aggregate-functions-ir.cc
index 8505d43..531598c 100644
--- a/be/src/exprs/aggregate-functions-ir.cc
+++ b/be/src/exprs/aggregate-functions-ir.cc
@@ -401,7 +401,7 @@ IR_ALWAYS_INLINE void AggregateFunctions::DecimalAvgAddOrRemove(FunctionContext*
// Since the src and dst are guaranteed to be the same scale, we can just
// do a simple add.
int m = remove ? -1 : 1;
- switch (Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_SIZE, 0)) {
+ switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0)) {
case 4:
avg->sum.val16 += m * src.val4;
break;
@@ -511,7 +511,7 @@ IR_ALWAYS_INLINE void AggregateFunctions::SumDecimalAddOrSubtract(FunctionContex
const DecimalVal& src, DecimalVal* dst, bool subtract) {
if (src.is_null) return;
if (dst->is_null) InitZero<DecimalVal>(ctx, dst);
- int precision = Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_PRECISION, 0);
+ int precision = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
// Since the src and dst are guaranteed to be the same scale, we can just
// do a simple add.
int m = subtract ? -1 : 1;
@@ -573,7 +573,7 @@ template<>
void AggregateFunctions::Min(FunctionContext* ctx,
const DecimalVal& src, DecimalVal* dst) {
if (src.is_null) return;
- int precision = Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_PRECISION, 0);
+ int precision = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
if (precision <= 9) {
if (dst->is_null || src.val4 < dst->val4) *dst = src;
} else if (precision <= 19) {
@@ -587,7 +587,7 @@ template<>
void AggregateFunctions::Max(FunctionContext* ctx,
const DecimalVal& src, DecimalVal* dst) {
if (src.is_null) return;
- int precision = Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_PRECISION, 0);
+ int precision = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
if (precision <= 9) {
if (dst->is_null || src.val4 > dst->val4) *dst = src;
} else if (precision <= 19) {
@@ -1200,8 +1200,8 @@ void AggregateFunctions::HllUpdate(
if (src.is_null) return;
DCHECK(!dst->is_null);
DCHECK_EQ(dst->len, HLL_LEN);
- uint64_t hash_value = AnyValUtil::HashDecimal64(
- src, Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_SIZE, 0), HashUtil::FNV64_SEED);
+ int byte_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0);
+ uint64_t hash_value = AnyValUtil::HashDecimal64(src, byte_size, HashUtil::FNV64_SEED);
if (hash_value != 0) {
// Use the lower bits to index into the number of streams and then
// find the first 1 bit after the index bits.
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/conditional-functions-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/conditional-functions-ir.cc b/be/src/exprs/conditional-functions-ir.cc
index ed98a87..662f167 100644
--- a/be/src/exprs/conditional-functions-ir.cc
+++ b/be/src/exprs/conditional-functions-ir.cc
@@ -23,11 +23,11 @@ using namespace impala;
using namespace impala_udf;
#define IS_NULL_COMPUTE_FUNCTION(type) \
- type IsNullExpr::Get##type(ExprContext* context, const TupleRow* row) { \
+ type IsNullExpr::Get##type(ExprContext* ctx, const TupleRow* row) { \
DCHECK_EQ(children_.size(), 2); \
- type val = children_[0]->Get##type(context, row); \
+ type val = children_[0]->Get##type(ctx, row); \
if (!val.is_null) return val; /* short-circuit */ \
- return children_[1]->Get##type(context, row); \
+ return children_[1]->Get##type(ctx, row); \
}
IS_NULL_COMPUTE_FUNCTION(BooleanVal);
@@ -68,15 +68,14 @@ NULL_IF_COMPUTE_FUNCTION(TimestampVal);
NULL_IF_COMPUTE_FUNCTION(DecimalVal);
#define NULL_IF_ZERO_COMPUTE_FUNCTION(type) \
- type ConditionalFunctions::NullIfZero(FunctionContext* context, const type& val) { \
+ type ConditionalFunctions::NullIfZero(FunctionContext* ctx, const type& val) { \
if (val.is_null || val.val == 0) return type::null(); \
return val; \
}
-DecimalVal ConditionalFunctions::NullIfZero(
- FunctionContext* context, const DecimalVal& val) {
+DecimalVal ConditionalFunctions::NullIfZero(FunctionContext* ctx, const DecimalVal& val) {
if (val.is_null) return DecimalVal::null();
- int type_byte_size = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SIZE);
+ int type_byte_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE);
switch (type_byte_size) {
case 4:
if (val.val4 == 0) return DecimalVal::null();
@@ -101,7 +100,7 @@ NULL_IF_ZERO_COMPUTE_FUNCTION(FloatVal);
NULL_IF_ZERO_COMPUTE_FUNCTION(DoubleVal);
#define ZERO_IF_NULL_COMPUTE_FUNCTION(type) \
- type ConditionalFunctions::ZeroIfNull(FunctionContext* context, const type& val) { \
+ type ConditionalFunctions::ZeroIfNull(FunctionContext* ctx, const type& val) { \
if (val.is_null) return type(0); \
return val; \
}
@@ -115,13 +114,13 @@ ZERO_IF_NULL_COMPUTE_FUNCTION(DoubleVal);
ZERO_IF_NULL_COMPUTE_FUNCTION(DecimalVal);
#define IF_COMPUTE_FUNCTION(type) \
- type IfExpr::Get##type(ExprContext* context, const TupleRow* row) { \
+ type IfExpr::Get##type(ExprContext* ctx, const TupleRow* row) { \
DCHECK_EQ(children_.size(), 3); \
- BooleanVal cond = children_[0]->GetBooleanVal(context, row); \
+ BooleanVal cond = children_[0]->GetBooleanVal(ctx, row); \
if (cond.is_null || !cond.val) { \
- return children_[2]->Get##type(context, row); \
+ return children_[2]->Get##type(ctx, row); \
} \
- return children_[1]->Get##type(context, row); \
+ return children_[1]->Get##type(ctx, row); \
}
IF_COMPUTE_FUNCTION(BooleanVal);
@@ -136,10 +135,10 @@ IF_COMPUTE_FUNCTION(TimestampVal);
IF_COMPUTE_FUNCTION(DecimalVal);
#define COALESCE_COMPUTE_FUNCTION(type) \
- type CoalesceExpr::Get##type(ExprContext* context, const TupleRow* row) { \
+ type CoalesceExpr::Get##type(ExprContext* ctx, const TupleRow* row) { \
DCHECK_GE(children_.size(), 1); \
for (int i = 0; i < children_.size(); ++i) { \
- type val = children_[i]->Get##type(context, row); \
+ type val = children_[i]->Get##type(ctx, row); \
if (!val.is_null) return val; \
} \
return type::null(); \
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/decimal-functions-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/decimal-functions-ir.cc b/be/src/exprs/decimal-functions-ir.cc
index cdbd799..3262e27 100644
--- a/be/src/exprs/decimal-functions-ir.cc
+++ b/be/src/exprs/decimal-functions-ir.cc
@@ -28,17 +28,17 @@
namespace impala {
-IntVal DecimalFunctions::Precision(FunctionContext* context, const DecimalVal& val) {
- return IntVal(Expr::GetConstantInt(*context, Expr::ARG_TYPE_PRECISION, 0));
+IntVal DecimalFunctions::Precision(FunctionContext* ctx, const DecimalVal& val) {
+ return IntVal(ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0));
}
-IntVal DecimalFunctions::Scale(FunctionContext* context, const DecimalVal& val) {
- return IntVal(Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0));
+IntVal DecimalFunctions::Scale(FunctionContext* ctx, const DecimalVal& val) {
+ return IntVal(ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0));
}
-DecimalVal DecimalFunctions::Abs(FunctionContext* context, const DecimalVal& val) {
+DecimalVal DecimalFunctions::Abs(FunctionContext* ctx, const DecimalVal& val) {
if (val.is_null) return DecimalVal::null();
- int type_byte_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0);
+ int type_byte_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0);
switch (type_byte_size) {
case 4:
return DecimalVal(abs(val.val4));
@@ -52,79 +52,83 @@ DecimalVal DecimalFunctions::Abs(FunctionContext* context, const DecimalVal& val
}
}
-DecimalVal DecimalFunctions::Ceil(FunctionContext* context, const DecimalVal& val) {
- return DecimalOperators::RoundDecimal(context, val, DecimalOperators::CEIL);
+DecimalVal DecimalFunctions::Ceil(FunctionContext* ctx, const DecimalVal& val) {
+ return DecimalOperators::RoundDecimal(ctx, val, DecimalOperators::CEIL);
}
-DecimalVal DecimalFunctions::Floor(FunctionContext* context, const DecimalVal& val) {
- return DecimalOperators::RoundDecimal(context, val, DecimalOperators::FLOOR);
+DecimalVal DecimalFunctions::Floor(FunctionContext* ctx, const DecimalVal& val) {
+ return DecimalOperators::RoundDecimal(ctx, val, DecimalOperators::FLOOR);
}
-DecimalVal DecimalFunctions::Round(FunctionContext* context, const DecimalVal& val) {
- return DecimalOperators::RoundDecimal(context, val, DecimalOperators::ROUND);
+DecimalVal DecimalFunctions::Round(FunctionContext* ctx, const DecimalVal& val) {
+ return DecimalOperators::RoundDecimal(ctx, val, DecimalOperators::ROUND);
}
/// Always inline in IR module so that constants can be replaced.
IR_ALWAYS_INLINE DecimalVal DecimalFunctions::RoundTo(
- FunctionContext* context, const DecimalVal& val, int scale,
+ FunctionContext* ctx, const DecimalVal& val, int scale,
DecimalOperators::DecimalRoundOp op) {
- int val_precision = Expr::GetConstantInt(*context, Expr::ARG_TYPE_PRECISION, 0);
- int val_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0);
- int return_precision = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION);
- int return_scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE);
+ int val_precision =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
+ int val_scale =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0);
+ int return_precision =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION);
+ int return_scale =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE);
if (scale < 0) {
- return DecimalOperators::RoundDecimalNegativeScale(context,
+ return DecimalOperators::RoundDecimalNegativeScale(ctx,
val, val_precision, val_scale, return_precision, return_scale, op, -scale);
} else {
- return DecimalOperators::RoundDecimal(context,
+ return DecimalOperators::RoundDecimal(ctx,
val, val_precision, val_scale, return_precision, return_scale, op);
}
}
DecimalVal DecimalFunctions::RoundTo(
- FunctionContext* context, const DecimalVal& val, const TinyIntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const TinyIntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::ROUND);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::ROUND);
}
DecimalVal DecimalFunctions::RoundTo(
- FunctionContext* context, const DecimalVal& val, const SmallIntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const SmallIntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::ROUND);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::ROUND);
}
DecimalVal DecimalFunctions::RoundTo(
- FunctionContext* context, const DecimalVal& val, const IntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const IntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::ROUND);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::ROUND);
}
DecimalVal DecimalFunctions::RoundTo(
- FunctionContext* context, const DecimalVal& val, const BigIntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const BigIntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::ROUND);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::ROUND);
}
-DecimalVal DecimalFunctions::Truncate(FunctionContext* context, const DecimalVal& val) {
- return DecimalOperators::RoundDecimal(context, val, DecimalOperators::TRUNCATE);
+DecimalVal DecimalFunctions::Truncate(FunctionContext* ctx, const DecimalVal& val) {
+ return DecimalOperators::RoundDecimal(ctx, val, DecimalOperators::TRUNCATE);
}
DecimalVal DecimalFunctions::TruncateTo(
- FunctionContext* context, const DecimalVal& val, const TinyIntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const TinyIntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::TRUNCATE);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::TRUNCATE);
}
DecimalVal DecimalFunctions::TruncateTo(
- FunctionContext* context, const DecimalVal& val, const SmallIntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const SmallIntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::TRUNCATE);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::TRUNCATE);
}
DecimalVal DecimalFunctions::TruncateTo(
- FunctionContext* context, const DecimalVal& val, const IntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const IntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::TRUNCATE);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::TRUNCATE);
}
DecimalVal DecimalFunctions::TruncateTo(
- FunctionContext* context, const DecimalVal& val, const BigIntVal& scale) {
+ FunctionContext* ctx, const DecimalVal& val, const BigIntVal& scale) {
DCHECK(!scale.is_null);
- return RoundTo(context, val, scale.val, DecimalOperators::TRUNCATE);
+ return RoundTo(ctx, val, scale.val, DecimalOperators::TRUNCATE);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/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 516acbc..4dfc8dc 100644
--- a/be/src/exprs/decimal-operators-ir.cc
+++ b/be/src/exprs/decimal-operators-ir.cc
@@ -34,32 +34,32 @@
namespace impala {
-#define RETURN_IF_OVERFLOW(context, overflow) \
+#define RETURN_IF_OVERFLOW(ctx, overflow) \
do {\
if (UNLIKELY(overflow)) {\
- context->AddWarning("Expression overflowed, returning NULL");\
+ ctx->AddWarning("Expression overflowed, returning NULL");\
return DecimalVal::null();\
}\
} while (false)
// Inline in IR module so branches can be optimised out.
IR_ALWAYS_INLINE DecimalVal DecimalOperators::IntToDecimalVal(
- FunctionContext* context, int precision, int scale, int64_t val) {
+ FunctionContext* ctx, int precision, int scale, int64_t val) {
bool overflow = false;
switch (ColumnType::GetDecimalByteSize(precision)) {
case 4: {
Decimal4Value dv = Decimal4Value::FromInt(precision, scale, val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(dv.value());
}
case 8: {
Decimal8Value dv = Decimal8Value::FromInt(precision, scale, val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(dv.value());
}
case 16: {
Decimal16Value dv = Decimal16Value::FromInt(precision, scale, val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(dv.value());
}
default:
@@ -70,25 +70,25 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::IntToDecimalVal(
// Inline in IR module so branches can be optimised out.
IR_ALWAYS_INLINE DecimalVal DecimalOperators::FloatToDecimalVal(
- FunctionContext* context, int precision, int scale, double val) {
+ FunctionContext* ctx, int precision, int scale, double val) {
bool overflow = false;
switch (ColumnType::GetDecimalByteSize(precision)) {
case 4: {
Decimal4Value dv =
Decimal4Value::FromDouble(precision, scale, val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(dv.value());
}
case 8: {
Decimal8Value dv =
Decimal8Value::FromDouble(precision, scale, val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(dv.value());
}
case 16: {
Decimal16Value dv =
Decimal16Value::FromDouble(precision, scale, val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(dv.value());
}
default:
@@ -105,28 +105,28 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::FloatToDecimalVal(
// When going from a smaller type to a larger type, we convert and then scale.
// Inline these functions in IR module so branches can be optimised out.
-IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext* context,
+IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext* ctx,
const Decimal4Value& val, int val_scale, int output_precision, int output_scale) {
bool overflow = false;
switch (ColumnType::GetDecimalByteSize(output_precision)) {
case 4: {
Decimal4Value scaled_val = val.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(scaled_val.value());
}
case 8: {
Decimal8Value val8 = ToDecimal8(val, &overflow);
Decimal8Value scaled_val = val8.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(scaled_val.value());
}
case 16: {
Decimal16Value val16 = ToDecimal16(val, &overflow);
Decimal16Value scaled_val = val16.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(scaled_val.value());
}
default:
@@ -135,7 +135,7 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext*
}
}
-IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext* context,
+IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext* ctx,
const Decimal8Value& val, int val_scale, int output_precision, int output_scale) {
bool overflow = false;
switch (ColumnType::GetDecimalByteSize(output_precision)) {
@@ -143,20 +143,20 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext*
Decimal8Value scaled_val = val.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
Decimal4Value val4 = ToDecimal4(scaled_val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(val4.value());
}
case 8: {
Decimal8Value scaled_val = val.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(scaled_val.value());
}
case 16: {
Decimal16Value val16 = ToDecimal16(val, &overflow);
Decimal16Value scaled_val = val16.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(scaled_val.value());
}
default:
@@ -165,7 +165,7 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext*
}
}
-IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext* context,
+IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext* ctx,
const Decimal16Value& val, int val_scale, int output_precision, int output_scale) {
bool overflow = false;
switch (ColumnType::GetDecimalByteSize(output_precision)) {
@@ -173,20 +173,20 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::ScaleDecimalValue(FunctionContext*
Decimal16Value scaled_val = val.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
Decimal4Value val4 = ToDecimal4(scaled_val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(val4.value());
}
case 8: {
Decimal16Value scaled_val = val.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
Decimal8Value val8 = ToDecimal8(scaled_val, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(val8.value());
}
case 16: {
Decimal16Value scaled_val = val.ScaleTo(
val_scale, output_scale, output_precision, &overflow);
- RETURN_IF_OVERFLOW(context, overflow);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return DecimalVal(scaled_val.value());
}
default:
@@ -268,29 +268,31 @@ static inline Decimal16Value GetDecimal16Value(
}
#define CAST_INT_TO_DECIMAL(from_type) \
- DecimalVal DecimalOperators::CastToDecimalVal( \
- FunctionContext* context, const from_type& val) { \
+ IR_ALWAYS_INLINE DecimalVal DecimalOperators::CastToDecimalVal( \
+ FunctionContext* ctx, const from_type& val) { \
if (val.is_null) return DecimalVal::null(); \
- int precision = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION); \
- int scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE); \
- return IntToDecimalVal(context, precision, scale, val.val); \
+ int precision = \
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \
+ return IntToDecimalVal(ctx, precision, scale, val.val); \
}
#define CAST_FLOAT_TO_DECIMAL(from_type) \
- DecimalVal DecimalOperators::CastToDecimalVal( \
- FunctionContext* context, const from_type& val) { \
+ IR_ALWAYS_INLINE DecimalVal DecimalOperators::CastToDecimalVal( \
+ FunctionContext* ctx, const from_type& val) { \
if (val.is_null) return DecimalVal::null(); \
- int precision = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION); \
- int scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE); \
- return FloatToDecimalVal(context, precision, scale, val.val); \
+ int precision = \
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \
+ return FloatToDecimalVal(ctx, precision, scale, val.val); \
}
#define CAST_DECIMAL_TO_INT(to_type) \
- to_type DecimalOperators::CastTo##to_type( \
- FunctionContext* context, const DecimalVal& val) { \
+ IR_ALWAYS_INLINE to_type DecimalOperators::CastTo##to_type( \
+ FunctionContext* ctx, const DecimalVal& val) { \
if (val.is_null) return to_type::null(); \
- int scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0); \
- switch (Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0)) { \
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0); \
+ switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0)) { \
case 4: { \
Decimal4Value dv(val.val4); \
return to_type(dv.whole_part(scale)); \
@@ -310,11 +312,11 @@ static inline Decimal16Value GetDecimal16Value(
}
#define CAST_DECIMAL_TO_FLOAT(to_type) \
- to_type DecimalOperators::CastTo##to_type( \
- FunctionContext* context, const DecimalVal& val) { \
+ IR_ALWAYS_INLINE to_type DecimalOperators::CastTo##to_type( \
+ FunctionContext* ctx, const DecimalVal& val) { \
if (val.is_null) return to_type::null(); \
- int scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0); \
- switch (Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0)) { \
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0); \
+ switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0)) { \
case 4: { \
Decimal4Value dv(val.val4); \
return to_type(dv.ToDouble(scale)); \
@@ -349,7 +351,7 @@ CAST_DECIMAL_TO_FLOAT(DoubleVal)
// Inline in IR module so branches can be optimised out.
IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimalNegativeScale(
- FunctionContext* context, const DecimalVal& val, int val_precision, int val_scale,
+ FunctionContext* ctx, const DecimalVal& val, int val_precision, int val_scale,
int output_precision, int output_scale, const DecimalRoundOp& op,
int64_t rounding_scale) {
DCHECK_GT(rounding_scale, 0);
@@ -360,19 +362,19 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimalNegativeScale(
switch (ColumnType::GetDecimalByteSize(val_precision)) {
case 4: {
Decimal4Value val4(val.val4);
- result = ScaleDecimalValue(context, val4, val_scale, output_precision,
+ result = ScaleDecimalValue(ctx, val4, val_scale, output_precision,
output_scale);
break;
}
case 8: {
Decimal8Value val8(val.val8);
- result = ScaleDecimalValue(context, val8, val_scale, output_precision,
+ result = ScaleDecimalValue(ctx, val8, val_scale, output_precision,
output_scale);
break;
}
case 16: {
Decimal16Value val16(val.val16);
- result = ScaleDecimalValue(context, val16, val_scale, output_precision,
+ result = ScaleDecimalValue(ctx, val16, val_scale, output_precision,
output_scale);
break;
}
@@ -410,7 +412,7 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimalNegativeScale(
// Need to check for overflow. This can't happen in the other cases since the
// FE should have picked a high enough precision.
if (DecimalUtil::MAX_UNSCALED_DECIMAL16 - abs(delta) < abs(val16.value())) {
- context->AddWarning("Expression overflowed, returning NULL");
+ ctx->AddWarning("Expression overflowed, returning NULL");
return DecimalVal::null();
}
result.val16 += delta;
@@ -424,7 +426,7 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimalNegativeScale(
}
// Inline in IR module so branches can be optimised out.
-IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimal(FunctionContext* context,
+IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimal(FunctionContext* ctx,
const DecimalVal& val, int val_precision, int val_scale, int output_precision,
int output_scale, const DecimalRoundOp& op) {
if (val.is_null) return DecimalVal::null();
@@ -434,23 +436,22 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimal(FunctionContext* cont
switch (ColumnType::GetDecimalByteSize(val_precision)) {
case 4: {
Decimal4Value val4(val.val4);
- result = ScaleDecimalValue(context, val4, val_scale, output_precision,
+ result = ScaleDecimalValue(ctx, val4, val_scale, output_precision,
output_scale);
delta = RoundDelta(val4, val_scale, output_scale, op);
break;
}
case 8: {
Decimal8Value val8(val.val8);
- result = ScaleDecimalValue(context, val8, val_scale, output_precision,
+ result = ScaleDecimalValue(ctx, val8, val_scale, output_precision,
output_scale);
delta = RoundDelta(val8, val_scale, output_scale, op);
break;
}
case 16: {
Decimal16Value val16(val.val16);
- result = ScaleDecimalValue(context, val16, val_scale, output_precision,
+ result = ScaleDecimalValue(ctx, val16, val_scale, output_precision,
output_scale);
-
delta = RoundDelta(val16, val_scale, output_scale, op);
break;
}
@@ -466,41 +467,49 @@ IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimal(FunctionContext* cont
// done the cast.
if (delta == 0) return result;
-
- // The value in 'result' is before the rounding has occurred.
- // This can't overflow. Rounding to a non-negative scale means at least one digit is
- // dropped if rounding occurred and the round can add at most one digit before the
- // decimal.
+ // The value in 'result' is before any rounding has occurred. If there is any rounding,
+ // the ouput's scale must be less than the input's scale.
+ DCHECK_GT(val_scale, output_scale);
result.val16 += delta;
+
+ // Rounding to a non-negative scale means at least one digit is dropped if rounding
+ // occurred and the round can add at most one digit before the decimal. This cannot
+ // overflow if output_precision >= val_precision. Otherwise, result can overflow.
+ bool overflow = output_precision < val_precision &&
+ abs(result.val16) >= DecimalUtil::GetScaleMultiplier<int128_t>(output_precision);
+ RETURN_IF_OVERFLOW(ctx, overflow);
return result;
}
// Inline in IR module so branches can be optimised out.
IR_ALWAYS_INLINE DecimalVal DecimalOperators::RoundDecimal(
- FunctionContext* context, const DecimalVal& val, const DecimalRoundOp& op) {
- int val_precision = Expr::GetConstantInt(*context, Expr::ARG_TYPE_PRECISION, 0);
- int val_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0);
- int return_precision = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION);
- int return_scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE);
- return RoundDecimal(context, val, val_precision, val_scale, return_precision,
+ FunctionContext* ctx, const DecimalVal& val, const DecimalRoundOp& op) {
+ int val_precision =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
+ int val_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0);
+ int return_precision =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION);
+ int return_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE);
+ return RoundDecimal(ctx, val, val_precision, val_scale, return_precision,
return_scale, op);
}
-// Cast is just RoundDecimal(TRUNCATE).
-// TODO: how we handle cast to a smaller scale is an implementation detail in the spec.
-// We could also choose to cast by doing ROUND.
-DecimalVal DecimalOperators::CastToDecimalVal(
- FunctionContext* context, const DecimalVal& val) {
- return RoundDecimal(context, val, TRUNCATE);
+// If query option decimal_v2 is true, cast is RoundDecimal(ROUND).
+// Otherwise, it's RoundDecimal(TRUNCATE).
+IR_ALWAYS_INLINE DecimalVal DecimalOperators::CastToDecimalVal(
+ FunctionContext* ctx, const DecimalVal& val) {
+ int is_decimal_v2 = ctx->impl()->GetConstFnAttr(FunctionContextImpl::DECIMAL_V2);
+ DCHECK(is_decimal_v2 == 0 || is_decimal_v2 == 1);
+ return RoundDecimal(ctx, val, is_decimal_v2 != 0 ? ROUND : TRUNCATE);
}
-DecimalVal DecimalOperators::CastToDecimalVal(
- FunctionContext* context, const StringVal& val) {
+IR_ALWAYS_INLINE DecimalVal DecimalOperators::CastToDecimalVal(
+ FunctionContext* ctx, const StringVal& val) {
if (val.is_null) return DecimalVal::null();
StringParser::ParseResult result;
DecimalVal dv;
- int precision = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION);
- int scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE);
+ int precision = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION);
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE);
switch (ColumnType::GetDecimalByteSize(precision)) {
case 4: {
Decimal4Value dv4 = StringParser::StringToDecimal<int32_t>(
@@ -534,10 +543,10 @@ DecimalVal DecimalOperators::CastToDecimalVal(
}
StringVal DecimalOperators::CastToStringVal(
- FunctionContext* context, const DecimalVal& val) {
+ FunctionContext* ctx, const DecimalVal& val) {
if (val.is_null) return StringVal::null();
- int precision = Expr::GetConstantInt(*context, Expr::ARG_TYPE_PRECISION, 0);
- int scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0);
+ int precision = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0);
string s;
switch (ColumnType::GetDecimalByteSize(precision)) {
case 4:
@@ -553,7 +562,7 @@ StringVal DecimalOperators::CastToStringVal(
DCHECK(false);
return StringVal::null();
}
- StringVal result(context, s.size());
+ StringVal result(ctx, s.size());
memcpy(result.ptr, s.c_str(), s.size());
return result;
}
@@ -574,10 +583,10 @@ IR_ALWAYS_INLINE T DecimalOperators::ConvertToNanoseconds(T val, int scale) {
}
TimestampVal DecimalOperators::CastToTimestampVal(
- FunctionContext* context, const DecimalVal& val) {
+ FunctionContext* ctx, const DecimalVal& val) {
if (val.is_null) return TimestampVal::null();
- int precision = Expr::GetConstantInt(*context, Expr::ARG_TYPE_PRECISION, 0);
- int scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0);
+ int precision = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_PRECISION, 0);
+ int scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0);
TimestampVal result;
switch (ColumnType::GetDecimalByteSize(precision)) {
case 4: {
@@ -620,9 +629,9 @@ TimestampVal DecimalOperators::CastToTimestampVal(
}
BooleanVal DecimalOperators::CastToBooleanVal(
- FunctionContext* context, const DecimalVal& val) {
+ FunctionContext* ctx, const DecimalVal& val) {
if (val.is_null) return BooleanVal::null();
- switch (Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0)) {
+ switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0)) {
case 4:
return BooleanVal(val.val4 != 0);
case 8:
@@ -637,17 +646,18 @@ BooleanVal DecimalOperators::CastToBooleanVal(
#define DECIMAL_ARITHMETIC_OP(FN_NAME, OP_FN) \
DecimalVal DecimalOperators::FN_NAME( \
- FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
+ FunctionContext* ctx, const DecimalVal& x, const DecimalVal& y) { \
if (x.is_null || y.is_null) return DecimalVal::null(); \
bool overflow = false; \
- int x_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0); \
- int x_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0); \
- int y_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 1); \
- int y_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 1); \
+ int x_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0); \
+ int x_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0); \
+ int y_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 1); \
+ int y_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 1); \
int return_precision = \
- Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION); \
- int return_scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE); \
- switch (Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SIZE)) { \
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \
+ int return_scale = \
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \
+ 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); \
@@ -669,7 +679,7 @@ BooleanVal DecimalOperators::CastToBooleanVal(
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, &overflow); \
- RETURN_IF_OVERFLOW(context, overflow); \
+ RETURN_IF_OVERFLOW(ctx, overflow); \
return DecimalVal(result.value()); \
} \
default: \
@@ -680,18 +690,19 @@ BooleanVal DecimalOperators::CastToBooleanVal(
#define DECIMAL_ARITHMETIC_OP_CHECK_NAN(FN_NAME, OP_FN) \
DecimalVal DecimalOperators::FN_NAME( \
- FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
+ FunctionContext* ctx, const DecimalVal& x, const DecimalVal& y) { \
if (x.is_null || y.is_null) return DecimalVal::null(); \
bool overflow = false; \
bool is_nan = false; \
- int x_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0); \
- int x_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0); \
- int y_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 1); \
- int y_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 1); \
+ int x_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0); \
+ int x_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0); \
+ int y_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 1); \
+ int y_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 1); \
int return_precision = \
- Expr::GetConstantInt(*context, Expr::RETURN_TYPE_PRECISION); \
- int return_scale = Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SCALE); \
- switch (Expr::GetConstantInt(*context, Expr::RETURN_TYPE_SIZE)) { \
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \
+ int return_scale = \
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \
+ 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); \
@@ -715,7 +726,7 @@ BooleanVal DecimalOperators::CastToBooleanVal(
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, &is_nan, &overflow); \
- RETURN_IF_OVERFLOW(context, overflow); \
+ RETURN_IF_OVERFLOW(ctx, overflow); \
if (is_nan) return DecimalVal::null(); \
return DecimalVal(result.value()); \
} \
@@ -727,10 +738,10 @@ BooleanVal DecimalOperators::CastToBooleanVal(
#define DECIMAL_BINARY_OP_NONNULL(OP_FN, X, Y) \
bool dummy = false; \
- int x_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 0); \
- int x_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 0); \
- int y_size = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SIZE, 1); \
- int y_scale = Expr::GetConstantInt(*context, Expr::ARG_TYPE_SCALE, 1); \
+ int x_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0); \
+ int x_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0); \
+ int y_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 1); \
+ int y_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 1); \
int byte_size = ::max(x_size, y_size); \
switch (byte_size) { \
case 4: { \
@@ -759,14 +770,14 @@ BooleanVal DecimalOperators::CastToBooleanVal(
#define DECIMAL_BINARY_OP(FN_NAME, OP_FN) \
BooleanVal DecimalOperators::FN_NAME( \
- FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
+ FunctionContext* ctx, const DecimalVal& x, const DecimalVal& y) { \
if (x.is_null || y.is_null) return BooleanVal::null(); \
DECIMAL_BINARY_OP_NONNULL(OP_FN, x, y) \
}
#define NULLSAFE_DECIMAL_BINARY_OP(FN_NAME, OP_FN, IS_EQUAL) \
BooleanVal DecimalOperators::FN_NAME( \
- FunctionContext* context, const DecimalVal& x, const DecimalVal& y) { \
+ FunctionContext* ctx, const DecimalVal& x, const DecimalVal& y) { \
if (x.is_null) return BooleanVal(IS_EQUAL ? y.is_null : !y.is_null); \
if (y.is_null) return BooleanVal(!IS_EQUAL); \
DECIMAL_BINARY_OP_NONNULL(OP_FN, x, y) \
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/decimal-operators.h
----------------------------------------------------------------------
diff --git a/be/src/exprs/decimal-operators.h b/be/src/exprs/decimal-operators.h
index 9f425b0..196ffdb 100644
--- a/be/src/exprs/decimal-operators.h
+++ b/be/src/exprs/decimal-operators.h
@@ -104,7 +104,7 @@ class DecimalOperators {
};
/// Evaluates a round from 'val' and returns the result, using the rounding rule of
- /// 'type'.
+ /// 'op. Returns DecimalVal::null() on overflow.
static DecimalVal RoundDecimal(FunctionContext* context,
const DecimalVal& val, int val_precision, int val_scale, int output_precision,
int output_scale, const DecimalRoundOp& op);
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/expr-codegen-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-codegen-test.cc b/be/src/exprs/expr-codegen-test.cc
index 0c484f4..c73c89e 100644
--- a/be/src/exprs/expr-codegen-test.cc
+++ b/be/src/exprs/expr-codegen-test.cc
@@ -16,30 +16,39 @@
// under the License.
// The following is cross-compiled to native code and IR, and used in the test below
-
+#include "exprs/decimal-operators.h"
#include "exprs/expr.h"
#include "udf/udf.h"
using namespace impala;
using namespace impala_udf;
-// TestGetConstant() fills in the following constants
-struct Constants {
+// TestGetTypeAttrs() fills in the following constants
+struct FnAttr {
int return_type_size;
int arg0_type_size;
int arg1_type_size;
int arg2_type_size;
};
-IntVal TestGetConstant(
+#ifdef IR_COMPILE
+#include "exprs/decimal-operators-ir.cc"
+#endif
+
+DecimalVal TestGetFnAttrs(
FunctionContext* ctx, const DecimalVal& arg0, StringVal arg1, StringVal arg2) {
- Constants* state = reinterpret_cast<Constants*>(
+ FnAttr* state = reinterpret_cast<FnAttr*>(
ctx->GetFunctionState(FunctionContext::THREAD_LOCAL));
- state->return_type_size = Expr::GetConstantInt(*ctx, Expr::RETURN_TYPE_SIZE);
- state->arg0_type_size = Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_SIZE, 0);
- state->arg1_type_size = Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_SIZE, 1);
- state->arg2_type_size = Expr::GetConstantInt(*ctx, Expr::ARG_TYPE_SIZE, 2);
- return IntVal(10);
+ state->return_type_size =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE);
+ state->arg0_type_size =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 0);
+ state->arg1_type_size =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 1);
+ state->arg2_type_size =
+ ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SIZE, 2);
+ // This function and its callees call FunctionContextImpl::GetConstFnAttr();
+ return DecimalOperators::CastToDecimalVal(ctx, arg0);
}
// Don't compile the actual test to IR
@@ -48,10 +57,12 @@ IntVal TestGetConstant(
#include "testutil/gtest-util.h"
#include "codegen/llvm-codegen.h"
#include "common/init.h"
+#include "exprs/anyval-util.h"
#include "exprs/expr-context.h"
#include "runtime/exec-env.h"
#include "runtime/mem-tracker.h"
#include "runtime/runtime-state.h"
+#include "runtime/test-env.h"
#include "service/fe-support.h"
#include "udf/udf-internal.h"
#include "udf/udf-test-harness.h"
@@ -64,28 +75,48 @@ using namespace llvm;
namespace impala {
-const char* TEST_GET_CONSTANT_SYMBOL =
- "_Z15TestGetConstantPN10impala_udf15FunctionContextERKNS_10DecimalValENS_9StringValES5_";
+const char* TEST_GET_FN_ATTR_SYMBOL =
+ "_Z14TestGetFnAttrsPN10impala_udf15FunctionContextERKNS_10DecimalValENS_9StringValES5_";
const int ARG0_PRECISION = 10;
const int ARG0_SCALE = 2;
const int ARG1_LEN = 1;
+const int RET_PRECISION = 10;
+const int RET_SCALE = 1;
class ExprCodegenTest : public ::testing::Test {
protected:
- int InlineConstants(Expr* expr, LlvmCodeGen* codegen, llvm::Function* fn) {
- return expr->InlineConstants(codegen, fn);
+ scoped_ptr<TestEnv> test_env_;
+ RuntimeState* runtime_state_;
+ FunctionContext* fn_ctx_;
+ FnAttr fn_type_attr_;
+
+ int InlineConstFnAttrs(Expr* expr, LlvmCodeGen* codegen, llvm::Function* fn) {
+ FunctionContext::TypeDesc ret_type = AnyValUtil::ColumnTypeToTypeDesc(expr->type());
+ vector<FunctionContext::TypeDesc> arg_types;
+ for (const Expr* child : expr->children()) {
+ arg_types.push_back(AnyValUtil::ColumnTypeToTypeDesc(child->type()));
+ }
+ return codegen->InlineConstFnAttrs(ret_type, arg_types, fn);
}
- static Status CreateFromFile(
- ObjectPool* pool, const string& filename, scoped_ptr<LlvmCodeGen>* codegen) {
- RETURN_IF_ERROR(LlvmCodeGen::CreateFromFile(pool, NULL, filename, "test", codegen));
+ Status CreateFromFile(const string& filename, scoped_ptr<LlvmCodeGen>* codegen) {
+ RETURN_IF_ERROR(LlvmCodeGen::CreateFromFile(runtime_state_,
+ runtime_state_->obj_pool(), NULL, filename, "test", codegen));
return (*codegen)->MaterializeModule();
}
virtual void SetUp() {
+ TQueryOptions query_options;
+ query_options.__set_decimal_v2(true);
+ test_env_.reset(new TestEnv());
+ EXPECT_OK(test_env_->CreateQueryState(0, 1, 8 * 1024 * 1024, &query_options,
+ &runtime_state_));
+
FunctionContext::TypeDesc return_type;
- return_type.type = FunctionContext::TYPE_INT;
+ return_type.type = FunctionContext::TYPE_DECIMAL;
+ return_type.precision = RET_PRECISION;
+ return_type.scale = RET_SCALE;
FunctionContext::TypeDesc arg0_type;
arg0_type.type = FunctionContext::TYPE_DECIMAL;
@@ -104,23 +135,25 @@ class ExprCodegenTest : public ::testing::Test {
arg_types.push_back(arg1_type);
arg_types.push_back(arg2_type);
- fn_ctx_ = UdfTestHarness::CreateTestContext(return_type, arg_types);
+ fn_ctx_ = UdfTestHarness::CreateTestContext(return_type, arg_types, runtime_state_);
// Initialize fn_ctx_ with constants
- memset(&constants_, -1, sizeof(Constants));
- fn_ctx_->SetFunctionState(FunctionContext::THREAD_LOCAL, &constants_);
+ memset(&fn_type_attr_, -1, sizeof(FnAttr));
+ fn_ctx_->SetFunctionState(FunctionContext::THREAD_LOCAL, &fn_type_attr_);
}
virtual void TearDown() {
fn_ctx_->impl()->Close();
delete fn_ctx_;
+ runtime_state_ = NULL;
+ test_env_.reset();
}
- void CheckConstants() {
- EXPECT_EQ(constants_.return_type_size, 4);
- EXPECT_EQ(constants_.arg0_type_size, 8);
- EXPECT_EQ(constants_.arg1_type_size, ARG1_LEN);
- EXPECT_EQ(constants_.arg2_type_size, 0); // varlen
+ void CheckFnAttr() {
+ EXPECT_EQ(fn_type_attr_.return_type_size, 8);
+ EXPECT_EQ(fn_type_attr_.arg0_type_size, 8);
+ EXPECT_EQ(fn_type_attr_.arg1_type_size, ARG1_LEN);
+ EXPECT_EQ(fn_type_attr_.arg2_type_size, 0); // varlen
}
static bool VerifyFunction(LlvmCodeGen* codegen, llvm::Function* fn) {
@@ -130,9 +163,6 @@ class ExprCodegenTest : public ::testing::Test {
static void ResetVerification(LlvmCodeGen* codegen) {
codegen->ResetVerification();
}
-
- FunctionContext* fn_ctx_;
- Constants constants_;
};
TExprNode CreateDecimalLiteral(int precision, int scale) {
@@ -183,10 +213,12 @@ TExprNode CreateStringLiteral(int len = -1) {
return expr;
}
-// Creates a function call to TestGetConstant() in test-udfs.h
-TExprNode CreateFunctionCall(vector<TExprNode> children) {
+// Creates a function call to TestGetFnAttrs() in test-udfs.h
+TExprNode CreateFunctionCall(vector<TExprNode> children, int precision, int scale) {
TScalarType scalar_type;
- scalar_type.type = TPrimitiveType::INT;
+ scalar_type.type = TPrimitiveType::DECIMAL;
+ scalar_type.__set_precision(precision);
+ scalar_type.__set_scale(scale);
TTypeNode type;
type.type = TTypeNodeType::SCALAR;
@@ -196,10 +228,10 @@ TExprNode CreateFunctionCall(vector<TExprNode> children) {
col_type.__set_types(vector<TTypeNode>(1, type));
TFunctionName fn_name;
- fn_name.function_name = "test_get_constant";
+ fn_name.function_name = "test_get_type_attr";
TScalarFunction scalar_fn;
- scalar_fn.symbol = TEST_GET_CONSTANT_SYMBOL;
+ scalar_fn.symbol = TEST_GET_FN_ATTR_SYMBOL;
TFunction fn;
fn.name = fn_name;
@@ -219,18 +251,22 @@ TExprNode CreateFunctionCall(vector<TExprNode> children) {
return expr;
}
-TEST_F(ExprCodegenTest, TestGetConstantInterpreted) {
- DecimalVal arg0_val;
+TEST_F(ExprCodegenTest, TestGetConstFnAttrsInterpreted) {
+ // Call fn and check results'. The input is of type Decimal(10,2) (i.e. 10000.25) and
+ // the output type is Decimal(10,1) (i.e. 10000.3). The precision and scale of arguments
+ // and return types are encoded above (ARG0_*, RET_*);
+ int64_t v = 1000025;
+ DecimalVal arg0_val(v);
StringVal arg1_val;
StringVal arg2_val;
- IntVal result = TestGetConstant(fn_ctx_, arg0_val, arg1_val, arg2_val);
+ DecimalVal result = TestGetFnAttrs(fn_ctx_, arg0_val, arg1_val, arg2_val);
// sanity check result
EXPECT_EQ(result.is_null, false);
- EXPECT_EQ(result.val, 10);
- CheckConstants();
+ EXPECT_EQ(result.val8, 100003);
+ CheckFnAttr();
}
-TEST_F(ExprCodegenTest, TestInlineConstants) {
+TEST_F(ExprCodegenTest, TestInlineConstFnAttrs) {
// Setup thrift descriptors
TExprNode arg0 = CreateDecimalLiteral(ARG0_PRECISION, ARG0_SCALE);
TExprNode arg1 = CreateStringLiteral(ARG1_LEN);
@@ -241,7 +277,7 @@ TEST_F(ExprCodegenTest, TestInlineConstants) {
exprs.push_back(arg1);
exprs.push_back(arg2);
- TExprNode fn_call = CreateFunctionCall(exprs);
+ TExprNode fn_call = CreateFunctionCall(exprs, RET_PRECISION, RET_SCALE);
exprs.insert(exprs.begin(), fn_call);
TExpr texpr;
@@ -253,21 +289,21 @@ TEST_F(ExprCodegenTest, TestInlineConstants) {
ExprContext* ctx;
ASSERT_OK(Expr::CreateExprTree(&pool, texpr, &ctx));
- // Get TestGetConstant() IR function
+ // Get TestGetFnAttrs() IR function
stringstream test_udf_file;
test_udf_file << getenv("IMPALA_HOME") << "/be/build/latest/exprs/expr-codegen-test.ll";
scoped_ptr<LlvmCodeGen> codegen;
- ASSERT_OK(ExprCodegenTest::CreateFromFile(&pool, test_udf_file.str(), &codegen));
- Function* fn = codegen->GetFunction(TEST_GET_CONSTANT_SYMBOL, false);
+ ASSERT_OK(CreateFromFile(test_udf_file.str(), &codegen));
+ Function* fn = codegen->GetFunction(TEST_GET_FN_ATTR_SYMBOL, false);
ASSERT_TRUE(fn != NULL);
- // Function verification should fail because we haven't inlined GetConstant() calls
+ // Function verification should fail because we haven't inlined GetTypeAttr() calls
bool verification_succeeded = VerifyFunction(codegen.get(), fn);
EXPECT_FALSE(verification_succeeded);
- // Call InlineConstants() and rerun verification
- int replaced = InlineConstants(ctx->root(), codegen.get(), fn);
- EXPECT_EQ(replaced, 4);
+ // Call InlineConstFnAttrs() and rerun verification
+ int replaced = InlineConstFnAttrs(ctx->root(), codegen.get(), fn);
+ EXPECT_EQ(replaced, 9);
ResetVerification(codegen.get());
verification_succeeded = VerifyFunction(codegen.get(), fn);
EXPECT_TRUE(verification_succeeded) << LlvmCodeGen::Print(fn);
@@ -277,17 +313,19 @@ TEST_F(ExprCodegenTest, TestInlineConstants) {
ASSERT_TRUE(fn != NULL);
void* fn_ptr;
codegen->AddFunctionToJit(fn, &fn_ptr);
- ASSERT_OK(codegen->FinalizeModule());
- LOG(ERROR) << "Optimized fn: " << LlvmCodeGen::Print(fn);
-
- // Call fn and check results
- DecimalVal arg0_val;
- typedef IntVal (*TestGetConstantType)(FunctionContext*, const DecimalVal&);
- IntVal result = reinterpret_cast<TestGetConstantType>(fn_ptr)(fn_ctx_, arg0_val);
+ EXPECT_TRUE(codegen->FinalizeModule().ok()) << LlvmCodeGen::Print(fn);
+
+ // Call fn and check results'. The input is of type Decimal(10,2) (i.e. 10000.25) and
+ // the output type is Decimal(10,1) (i.e. 10000.3). The precision and scale of arguments
+ // and return types are encoded above (ARG0_*, RET_*);
+ int64_t v = 1000025;
+ DecimalVal arg0_val(v);
+ typedef DecimalVal (*TestGetFnAttrs)(FunctionContext*, const DecimalVal&);
+ DecimalVal result = reinterpret_cast<TestGetFnAttrs>(fn_ptr)(fn_ctx_, arg0_val);
// sanity check result
EXPECT_EQ(result.is_null, false);
- EXPECT_EQ(result.val, 10);
- CheckConstants();
+ EXPECT_EQ(result.val8, 100003);
+ CheckFnAttr();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/expr-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc
index cad716e..1b2dc51 100644
--- a/be/src/exprs/expr-test.cc
+++ b/be/src/exprs/expr-test.cc
@@ -1335,6 +1335,16 @@ DecimalTestCase decimal_cases[] = {
{{ false, 1, 32, 1 }, { false, 1, 32, 1 }} },
{ "mod(cast('-1.23' as decimal(32,2)), cast('1.0' as decimal(32,2)))",
{{ false, -23, 32, 2 }, { false, -23, 32, 2 }} },
+ { "cast(cast(0.12344 as decimal(6,5)) as decimal(6,4))",
+ {{ false, 1234, 6, 4 }, { false, 1234, 6, 4 }} },
+ { "cast(cast(0.12345 as decimal(6,5)) as decimal(6,4))",
+ {{ false, 1234, 6, 4 }, { false, 1235, 6, 4 }} },
+ { "cast(cast('0.999' as decimal(4,3)) as decimal(1,0))",
+ {{ false, 0, 1, 0 }, { false, 1, 1, 0 }} },
+ { "cast(cast(999999999.99 as DECIMAL(11,2)) as DECIMAL(9,0))",
+ {{ false, 999999999, 9, 0 }, { true, 0, 9, 0 }} },
+ { "cast(cast(-999999999.99 as DECIMAL(11,2)) as DECIMAL(9,0))",
+ {{ false, -999999999, 9, 0 }, { true, 0, 9, 0 }} },
{ "mod(cast(NULL as decimal(2,0)), cast('10' as decimal(2,0)))",
{{ true, 0, 2, 0 }, { true, 0, 2, 0 }} },
{ "mod(cast('10' as decimal(2,0)), cast(NULL as decimal(2,0)))",
@@ -1357,7 +1367,7 @@ TEST_F(ExprTest, DecimalArithmeticExprs) {
string opt = "DECIMAL_V2=" + lexical_cast<string>(v2);
executor_->pushExecOption(opt);
for (const DecimalTestCase& c : decimal_cases) {
- const DecimalExpectedResult& r = c.expected[0];
+ const DecimalExpectedResult& r = c.expected[v2];
const ColumnType& type = ColumnType::CreateDecimalType(r.precision, r.scale);
if (r.null) {
TestIsNull(c.expr, type);
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/expr.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr.cc b/be/src/exprs/expr.cc
index f119a9d..32c16a0 100644
--- a/be/src/exprs/expr.cc
+++ b/be/src/exprs/expr.cc
@@ -79,8 +79,6 @@ namespace impala {
const char* Expr::LLVM_CLASS_NAME = "class.impala::Expr";
-const char* Expr::GET_CONSTANT_INT_SYMBOL_PREFIX = "_ZN6impala4Expr14GetConstantInt";
-
template<class T>
bool ParseString(const string& str, T* val) {
istringstream stream(str);
@@ -589,90 +587,6 @@ Status Expr::GetConstVal(
return GetFnContextError(context);
}
-int Expr::GetConstantInt(const FunctionContext::TypeDesc& return_type,
- const std::vector<FunctionContext::TypeDesc>& arg_types, ExprConstant c, int i) {
- switch (c) {
- case RETURN_TYPE_SIZE:
- DCHECK_EQ(i, -1);
- return AnyValUtil::TypeDescToColumnType(return_type).GetByteSize();
- case RETURN_TYPE_PRECISION:
- DCHECK_EQ(i, -1);
- DCHECK_EQ(return_type.type, FunctionContext::TYPE_DECIMAL);
- return return_type.precision;
- case RETURN_TYPE_SCALE:
- DCHECK_EQ(i, -1);
- DCHECK_EQ(return_type.type, FunctionContext::TYPE_DECIMAL);
- return return_type.scale;
- case ARG_TYPE_SIZE:
- DCHECK_GE(i, 0);
- DCHECK_LT(i, arg_types.size());
- return AnyValUtil::TypeDescToColumnType(arg_types[i]).GetByteSize();
- case ARG_TYPE_PRECISION:
- DCHECK_GE(i, 0);
- DCHECK_LT(i, arg_types.size());
- DCHECK_EQ(arg_types[i].type, FunctionContext::TYPE_DECIMAL);
- return arg_types[i].precision;
- case ARG_TYPE_SCALE:
- DCHECK_GE(i, 0);
- DCHECK_LT(i, arg_types.size());
- DCHECK_EQ(arg_types[i].type, FunctionContext::TYPE_DECIMAL);
- return arg_types[i].scale;
- default:
- CHECK(false) << "NYI";
- return -1;
- }
-}
-
-int Expr::GetConstantInt(const FunctionContext& ctx, ExprConstant c, int i) {
- return GetConstantInt(ctx.GetReturnType(), ctx.impl()->arg_types(), c, i);
-}
-
-int Expr::InlineConstants(LlvmCodeGen* codegen, Function* fn) {
- FunctionContext::TypeDesc return_type = AnyValUtil::ColumnTypeToTypeDesc(type_);
- vector<FunctionContext::TypeDesc> arg_types;
- for (int i = 0; i < children_.size(); ++i) {
- arg_types.push_back(AnyValUtil::ColumnTypeToTypeDesc(children_[i]->type_));
- }
- return InlineConstants(return_type, arg_types, codegen, fn);
-}
-
-int Expr::InlineConstants(const FunctionContext::TypeDesc& return_type,
- const std::vector<FunctionContext::TypeDesc>& arg_types, LlvmCodeGen* codegen,
- Function* fn) {
- int replaced = 0;
- for (inst_iterator iter = inst_begin(fn), end = inst_end(fn); iter != end;) {
- // Increment iter now so we don't mess it up modifying the instruction below
- Instruction* instr = &*(iter++);
-
- // Look for call instructions
- if (!isa<CallInst>(instr)) continue;
- CallInst* call_instr = cast<CallInst>(instr);
- Function* called_fn = call_instr->getCalledFunction();
-
- // Look for call to Expr::GetConstant*()
- if (called_fn == NULL ||
- called_fn->getName().find(GET_CONSTANT_INT_SYMBOL_PREFIX) == string::npos) {
- continue;
- }
-
- // 'c' and 'i' arguments must be constant
- ConstantInt* c_arg = dyn_cast<ConstantInt>(call_instr->getArgOperand(1));
- ConstantInt* i_arg = dyn_cast<ConstantInt>(call_instr->getArgOperand(2));
- DCHECK(c_arg != NULL) << "Non-constant 'c' argument to Expr::GetConstant*()";
- DCHECK(i_arg != NULL) << "Non-constant 'i' argument to Expr::GetConstant*()";
-
- // Replace the called function with the appropriate constant
- ExprConstant c_val = static_cast<ExprConstant>(c_arg->getSExtValue());
- int i_val = static_cast<int>(i_arg->getSExtValue());
- // All supported constants are currently integers.
- call_instr->replaceAllUsesWith(ConstantInt::get(codegen->GetType(TYPE_INT),
- GetConstantInt(return_type, arg_types, c_val, i_val)));
- call_instr->eraseFromParent();
- ++replaced;
- }
- return replaced;
-}
-
Status Expr::GetCodegendComputeFnWrapper(LlvmCodeGen* codegen, Function** fn) {
if (ir_compute_fn_ != NULL) {
*fn = ir_compute_fn_;
[2/4] incubator-impala git commit: IMPALA-4810: fix incorrect
expr-test decimal types
Posted by kw...@apache.org.
IMPALA-4810: fix incorrect expr-test decimal types
Many of the types for the decimal round/truncate and related tests
are incorrect. This was never caught because the type was only used
by the string parser, and larger types would work. The change for
IMPALA-4370 adds validation of the expected type, so fix these.
Change-Id: I1e750fc01ab64ff27182670d8e823c012743804b
Reviewed-on: http://gerrit.cloudera.org:8080/5959
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/a78726db
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/a78726db
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/a78726db
Branch: refs/heads/master
Commit: a78726db308f41c3a7a710cda8f049d21793bc42
Parents: af46998
Author: Dan Hecht <dh...@cloudera.com>
Authored: Thu Feb 9 14:41:37 2017 -0800
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Sat Feb 11 03:30:15 2017 +0000
----------------------------------------------------------------------
be/src/exprs/expr-test.cc | 183 ++++++++++++++++++++++-------------------
be/src/runtime/types.cc | 5 +-
2 files changed, 101 insertions(+), 87 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a78726db/be/src/exprs/expr-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc
index e6cfcdb..cad716e 100644
--- a/be/src/exprs/expr-test.cc
+++ b/be/src/exprs/expr-test.cc
@@ -400,27 +400,38 @@ class ExprTest : public testing::Test {
"1970-01-01 00:00:00");
}
+ // Verify that 'expr' has the same precision and scale as 'expected_type'.
+ void TestDecimalResultType(const string& expr, const ColumnType& expected_type) {
+ const string typeof_expr = "typeof(" + expr + ")";
+ const string typeof_result = GetValue(typeof_expr, TYPE_STRING);
+ EXPECT_EQ(expected_type.DebugString(), typeof_result) << typeof_expr;
+ }
+
// Decimals don't work with TestValue.
// TODO: figure out what operators need to be implemented to work with EXPECT_EQ
- // TODO: verify that the result type has the same precision/scale as 'expected_type'.
template<typename T>
void TestDecimalValue(const string& expr, const T& expected_result,
const ColumnType& expected_type) {
+ // Verify precision and scale of the expression match the expected type.
+ TestDecimalResultType(expr, expected_type);
+ // Verify the expression result matches the expected result, for the given the
+ // precision and scale.
const string value = GetValue(expr, expected_type);
-
StringParser::ParseResult result;
+ // These require that we've passed the correct type to StringToDecimal(), so these
+ // results are valid only when TestDecimalResultType() succeeded.
switch (expected_type.GetByteSize()) {
case 4:
EXPECT_EQ(expected_result.value(), StringParser::StringToDecimal<int32_t>(
- &value[0], value.size(), expected_type, &result).value());
+ &value[0], value.size(), expected_type, &result).value()) << expr;
break;
case 8:
EXPECT_EQ(expected_result.value(), StringParser::StringToDecimal<int64_t>(
- &value[0], value.size(), expected_type, &result).value());
+ &value[0], value.size(), expected_type, &result).value()) << expr;
break;
case 16:
EXPECT_EQ(expected_result.value(), StringParser::StringToDecimal<int128_t>(
- &value[0], value.size(), expected_type, &result).value());
+ &value[0], value.size(), expected_type, &result).value()) << expr;
break;
default:
EXPECT_TRUE(false) << expected_type << " " << expected_type.GetByteSize();
@@ -1297,7 +1308,7 @@ DecimalTestCase decimal_cases[] = {
{ "cast(1.23 as decimal(8,2)) + cast(1 as decimal(20,3))",
{{ false, 2230, 21, 3 }, { false, 2230, 21, 3 }} },
{ "cast(1.23 as decimal(30,2)) - cast(1 as decimal(4,3))",
- {{ false, 230, 34, 3 }, { false, 230, 34, 3 }} },
+ {{ false, 230, 32, 3 }, { false, 230, 32, 3 }} },
{ "cast(1.23 as decimal(30,2)) * cast(1 as decimal(10,3))",
{{ false, 123000, 38, 5 }, { false, 123000, 38, 5 }} },
{ "cast(1.23 as decimal(30,2)) / cast(1 as decimal(20,3))",
@@ -5489,75 +5500,75 @@ TEST_F(ExprTest, DecimalFunctions) {
// Ceil()
TestDecimalValue("ceil(cast('0' as decimal(6,5)))", Decimal4Value(0),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("ceil(cast('3.14159' as decimal(6,5)))", Decimal4Value(4),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("ceil(cast('-3.14159' as decimal(6,5)))", Decimal4Value(-3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("ceil(cast('3' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("ceil(cast('3.14159' as decimal(13,5)))", Decimal8Value(4),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("ceil(cast('-3.14159' as decimal(13,5)))", Decimal8Value(-3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("ceil(cast('3' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("ceil(cast('3.14159' as decimal(33,5)))", Decimal16Value(4),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("ceil(cast('-3.14159' as decimal(33,5)))", Decimal16Value(-3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("ceil(cast('3' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("ceil(cast('9.14159' as decimal(6,5)))", Decimal4Value(10),
ColumnType::CreateDecimalType(2, 0));
TestIsNull("ceil(cast(NULL as decimal(2,0)))", ColumnType::CreateDecimalType(2,0));
// Floor()
TestDecimalValue("floor(cast('3.14159' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("floor(cast('-3.14159' as decimal(6,5)))", Decimal4Value(-4),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("floor(cast('3' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("floor(cast('3.14159' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("floor(cast('-3.14159' as decimal(13,5)))", Decimal8Value(-4),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("floor(cast('3' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("floor(cast('3.14159' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("floor(cast('-3.14159' as decimal(33,5)))", Decimal16Value(-4),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("floor(cast('3' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("floor(cast('-9.14159' as decimal(6,5)))", Decimal4Value(-10),
ColumnType::CreateDecimalType(2, 0));
TestIsNull("floor(cast(NULL as decimal(2,0)))", ColumnType::CreateDecimalType(2,0));
// Dfloor() alias
TestDecimalValue("dfloor(cast('3.14159' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
// Round()
TestDecimalValue("round(cast('3.14159' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("round(cast('-3.14159' as decimal(6,5)))", Decimal4Value(-3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("round(cast('3' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("round(cast('3.14159' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("round(cast('-3.14159' as decimal(13,5)))", Decimal8Value(-3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("round(cast('3' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(9, 0));
TestDecimalValue("round(cast('3.14159' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("round(cast('-3.14159' as decimal(33,5)))", Decimal16Value(-3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("round(cast('3' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("round(cast('9.54159' as decimal(6,5)))", Decimal4Value(10),
ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("round(cast('-9.54159' as decimal(6,5)))", Decimal4Value(-10),
@@ -5566,23 +5577,23 @@ TEST_F(ExprTest, DecimalFunctions) {
// Truncate()
TestDecimalValue("truncate(cast('3.54159' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(1, 0));
TestDecimalValue("truncate(cast('-3.54159' as decimal(6,5)))", Decimal4Value(-3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(1, 0));
TestDecimalValue("truncate(cast('3' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(1, 0));
TestDecimalValue("truncate(cast('3.54159' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(8, 0));
TestDecimalValue("truncate(cast('-3.54159' as decimal(13,5)))", Decimal8Value(-3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(8, 0));
TestDecimalValue("truncate(cast('3' as decimal(13,5)))", Decimal8Value(3),
- ColumnType::CreateDecimalType(13, 0));
+ ColumnType::CreateDecimalType(8, 0));
TestDecimalValue("truncate(cast('3.54159' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(28, 0));
TestDecimalValue("truncate(cast('-3.54159' as decimal(33,5)))", Decimal16Value(-3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(28, 0));
TestDecimalValue("truncate(cast('3' as decimal(33,5)))", Decimal16Value(3),
- ColumnType::CreateDecimalType(33, 0));
+ ColumnType::CreateDecimalType(28, 0));
TestDecimalValue("truncate(cast('9.54159' as decimal(6,5)))", Decimal4Value(9),
ColumnType::CreateDecimalType(1, 0));
TestIsNull("truncate(cast(NULL as decimal(2,0)))", ColumnType::CreateDecimalType(2,0));
@@ -5591,15 +5602,15 @@ TEST_F(ExprTest, DecimalFunctions) {
TestIsNull("round(cast(NULL as decimal(2,0)), 1)", ColumnType::CreateDecimalType(2,0));
TestDecimalValue("round(cast('3.1615' as decimal(6,4)), 0)", Decimal4Value(3),
- ColumnType::CreateDecimalType(2, 0));
+ ColumnType::CreateDecimalType(3, 0));
TestDecimalValue("round(cast('-3.1615' as decimal(6,4)), 1)", Decimal4Value(-32),
- ColumnType::CreateDecimalType(3, 1));
+ ColumnType::CreateDecimalType(4, 1));
TestDecimalValue("round(cast('3.1615' as decimal(6,4)), 2)", Decimal4Value(316),
- ColumnType::CreateDecimalType(4, 2));
+ ColumnType::CreateDecimalType(5, 2));
TestDecimalValue("round(cast('3.1615' as decimal(6,4)), 3)", Decimal4Value(3162),
- ColumnType::CreateDecimalType(5, 3));
+ ColumnType::CreateDecimalType(6, 3));
TestDecimalValue("round(cast('-3.1615' as decimal(6,4)), 3)", Decimal4Value(-3162),
- ColumnType::CreateDecimalType(5, 3));
+ ColumnType::CreateDecimalType(6, 3));
TestDecimalValue("round(cast('3.1615' as decimal(6,4)), 4)", Decimal4Value(31615),
ColumnType::CreateDecimalType(6, 4));
TestDecimalValue("round(cast('-3.1615' as decimal(6,4)), 5)", Decimal4Value(-316150),
@@ -5618,21 +5629,21 @@ TEST_F(ExprTest, DecimalFunctions) {
ColumnType::CreateDecimalType(5, 1));
TestDecimalValue("round(cast('-3.1615' as decimal(16,4)), 0)", Decimal8Value(-3),
- ColumnType::CreateDecimalType(12, 0));
+ ColumnType::CreateDecimalType(13, 0));
TestDecimalValue("round(cast('3.1615' as decimal(16,4)), 1)", Decimal8Value(32),
- ColumnType::CreateDecimalType(13, 1));
+ ColumnType::CreateDecimalType(14, 1));
TestDecimalValue("round(cast('-3.1615' as decimal(16,4)), 2)", Decimal8Value(-316),
- ColumnType::CreateDecimalType(14, 2));
+ ColumnType::CreateDecimalType(15, 2));
TestDecimalValue("round(cast('3.1615' as decimal(16,4)), 3)", Decimal8Value(3162),
- ColumnType::CreateDecimalType(15, 3));
+ ColumnType::CreateDecimalType(16, 3));
TestDecimalValue("round(cast('-3.1615' as decimal(16,4)), 3)", Decimal8Value(-3162),
- ColumnType::CreateDecimalType(15, 3));
+ ColumnType::CreateDecimalType(16, 3));
TestDecimalValue("round(cast('-3.1615' as decimal(16,4)), 4)", Decimal8Value(-31615),
ColumnType::CreateDecimalType(16, 4));
TestDecimalValue("round(cast('3.1615' as decimal(16,4)), 5)", Decimal8Value(316150),
ColumnType::CreateDecimalType(17, 5));
TestDecimalValue("round(cast('-999.951' as decimal(16,3)), 1)", Decimal8Value(-10000),
- ColumnType::CreateDecimalType(17, 1));
+ ColumnType::CreateDecimalType(15, 1));
TestDecimalValue("round(cast('-175.0' as decimal(15,1)), 0)", Decimal8Value(-175),
ColumnType::CreateDecimalType(15, 0));
@@ -5646,19 +5657,19 @@ TEST_F(ExprTest, DecimalFunctions) {
ColumnType::CreateDecimalType(15, 0));
TestDecimalValue("round(cast('3.1615' as decimal(32,4)), 0)", Decimal16Value(3),
- ColumnType::CreateDecimalType(32, 0));
+ ColumnType::CreateDecimalType(29, 0));
TestDecimalValue("round(cast('-3.1615' as decimal(32,4)), 1)", Decimal16Value(-32),
- ColumnType::CreateDecimalType(33, 1));
+ ColumnType::CreateDecimalType(30, 1));
TestDecimalValue("round(cast('3.1615' as decimal(32,4)), 2)", Decimal16Value(316),
- ColumnType::CreateDecimalType(34, 2));
+ ColumnType::CreateDecimalType(31, 2));
TestDecimalValue("round(cast('3.1615' as decimal(32,4)), 3)", Decimal16Value(3162),
- ColumnType::CreateDecimalType(35, 3));
+ ColumnType::CreateDecimalType(32, 3));
TestDecimalValue("round(cast('-3.1615' as decimal(32,4)), 3)", Decimal16Value(-3162),
- ColumnType::CreateDecimalType(36, 3));
+ ColumnType::CreateDecimalType(32, 3));
TestDecimalValue("round(cast('3.1615' as decimal(32,4)), 4)", Decimal16Value(31615),
- ColumnType::CreateDecimalType(37, 4));
+ ColumnType::CreateDecimalType(32, 4));
TestDecimalValue("round(cast('-3.1615' as decimal(32,5)), 5)", Decimal16Value(-316150),
- ColumnType::CreateDecimalType(38, 5));
+ ColumnType::CreateDecimalType(32, 5));
TestDecimalValue("round(cast('-175.0' as decimal(35,1)), 0)", Decimal16Value(-175),
ColumnType::CreateDecimalType(35, 0));
TestDecimalValue("round(cast('175.0' as decimal(35,1)), -1)", Decimal16Value(180),
@@ -5670,40 +5681,40 @@ TEST_F(ExprTest, DecimalFunctions) {
TestDecimalValue("round(cast('-175.0' as decimal(35,1)), -4)", Decimal16Value(0),
ColumnType::CreateDecimalType(35, 0));
TestDecimalValue("round(cast('99999.9951' as decimal(35,4)), 2)",
- Decimal16Value(10000000), ColumnType::CreateDecimalType(36, 2));
+ Decimal16Value(10000000), ColumnType::CreateDecimalType(34, 2));
// Dround() alias
TestDecimalValue("dround(cast('3.14159' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("dround(cast('99999.9951' as decimal(35,4)), 2)",
- Decimal16Value(10000000), ColumnType::CreateDecimalType(36, 2));
+ Decimal16Value(10000000), ColumnType::CreateDecimalType(34, 2));
// TruncateTo()
TestIsNull("truncate(cast(NULL as decimal(2,0)), 1)",
ColumnType::CreateDecimalType(2,0));
TestDecimalValue("truncate(cast('-3.1615' as decimal(6,4)), 0)", Decimal4Value(-3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
TestDecimalValue("truncate(cast('3.1615' as decimal(6,4)), 1)", Decimal4Value(31),
- ColumnType::CreateDecimalType(6, 1));
+ ColumnType::CreateDecimalType(3, 1));
TestDecimalValue("truncate(cast('-3.1615' as decimal(6,4)), 2)", Decimal4Value(-316),
- ColumnType::CreateDecimalType(6, 2));
+ ColumnType::CreateDecimalType(4, 2));
TestDecimalValue("truncate(cast('3.1615' as decimal(6,4)), 3)", Decimal4Value(3161),
- ColumnType::CreateDecimalType(6, 3));
+ ColumnType::CreateDecimalType(5, 3));
TestDecimalValue("truncate(cast('-3.1615' as decimal(6,4)), 4)", Decimal4Value(-31615),
ColumnType::CreateDecimalType(6, 4));
TestDecimalValue("truncate(cast('3.1615' as decimal(6,4)), 5)", Decimal4Value(316150),
ColumnType::CreateDecimalType(7, 5));
TestDecimalValue("truncate(cast('175.0' as decimal(6,1)), 0)", Decimal4Value(175),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(5, 0));
TestDecimalValue("truncate(cast('-175.0' as decimal(6,1)), -1)", Decimal4Value(-170),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(5, 0));
TestDecimalValue("truncate(cast('175.0' as decimal(6,1)), -2)", Decimal4Value(100),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(5, 0));
TestDecimalValue("truncate(cast('-175.0' as decimal(6,1)), -3)", Decimal4Value(0),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(5, 0));
TestDecimalValue("truncate(cast('175.0' as decimal(6,1)), -4)", Decimal4Value(0),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(5, 0));
TestDecimalValue("truncate(cast('-3.1615' as decimal(16,4)), 0)", Decimal8Value(-3),
ColumnType::CreateDecimalType(12, 0));
@@ -5718,15 +5729,15 @@ TEST_F(ExprTest, DecimalFunctions) {
TestDecimalValue("truncate(cast('-3.1615' as decimal(16,4)), 5)",
Decimal8Value(-316150), ColumnType::CreateDecimalType(17, 5));
TestDecimalValue("truncate(cast('-175.0' as decimal(15,1)), 0)", Decimal8Value(-175),
- ColumnType::CreateDecimalType(15, 0));
+ ColumnType::CreateDecimalType(14, 0));
TestDecimalValue("truncate(cast('175.0' as decimal(15,1)), -1)", Decimal8Value(170),
- ColumnType::CreateDecimalType(15, 0));
+ ColumnType::CreateDecimalType(14, 0));
TestDecimalValue("truncate(cast('-175.0' as decimal(15,1)), -2)", Decimal8Value(-100),
- ColumnType::CreateDecimalType(15, 0));
+ ColumnType::CreateDecimalType(14, 0));
TestDecimalValue("truncate(cast('175.0' as decimal(15,1)), -3)", Decimal8Value(0),
- ColumnType::CreateDecimalType(15, 0));
+ ColumnType::CreateDecimalType(14, 0));
TestDecimalValue("truncate(cast('-175.0' as decimal(15,1)), -4)", Decimal8Value(0),
- ColumnType::CreateDecimalType(15, 0));
+ ColumnType::CreateDecimalType(14, 0));
TestDecimalValue("truncate(cast('-3.1615' as decimal(32,4)), 0)",
Decimal16Value(-3), ColumnType::CreateDecimalType(28, 0));
@@ -5741,21 +5752,21 @@ TEST_F(ExprTest, DecimalFunctions) {
TestDecimalValue("truncate(cast('3.1615' as decimal(32,4)), 5)",
Decimal16Value(316150), ColumnType::CreateDecimalType(33, 5));
TestDecimalValue("truncate(cast('-175.0' as decimal(35,1)), 0)",
- Decimal16Value(-175), ColumnType::CreateDecimalType(35, 0));
+ Decimal16Value(-175), ColumnType::CreateDecimalType(34, 0));
TestDecimalValue("truncate(cast('175.0' as decimal(35,1)), -1)",
- Decimal16Value(170), ColumnType::CreateDecimalType(35, 0));
+ Decimal16Value(170), ColumnType::CreateDecimalType(34, 0));
TestDecimalValue("truncate(cast('-175.0' as decimal(35,1)), -2)",
- Decimal16Value(-100), ColumnType::CreateDecimalType(35, 0));
+ Decimal16Value(-100), ColumnType::CreateDecimalType(34, 0));
TestDecimalValue("truncate(cast('175.0' as decimal(35,1)), -3)",
- Decimal16Value(0), ColumnType::CreateDecimalType(35, 0));
+ Decimal16Value(0), ColumnType::CreateDecimalType(34, 0));
TestDecimalValue("truncate(cast('-175.0' as decimal(35,1)), -4)",
- Decimal16Value(0), ColumnType::CreateDecimalType(35, 0));
+ Decimal16Value(0), ColumnType::CreateDecimalType(34, 0));
// Dtrunc() alias
TestDecimalValue("dtrunc(cast('3.54159' as decimal(6,5)))", Decimal4Value(3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(1, 0));
TestDecimalValue("dtrunc(cast('-3.1615' as decimal(6,4)), 0)", Decimal4Value(-3),
- ColumnType::CreateDecimalType(6, 0));
+ ColumnType::CreateDecimalType(2, 0));
// Overflow on Round()/etc. This can only happen when the input is has enough
// leading 9's.
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/a78726db/be/src/runtime/types.cc
----------------------------------------------------------------------
diff --git a/be/src/runtime/types.cc b/be/src/runtime/types.cc
index f580628..2cc63ef 100644
--- a/be/src/runtime/types.cc
+++ b/be/src/runtime/types.cc
@@ -303,7 +303,10 @@ string ColumnType::DebugString() const {
ss << "CHAR(" << len << ")";
return ss.str();
case TYPE_DECIMAL:
- ss << "DECIMAL(" << precision << ", " << scale << ")";
+ ss << "DECIMAL(" << precision << "," << scale << ")";
+ return ss.str();
+ case TYPE_VARCHAR:
+ ss << "VARCHAR(" << len << ")";
return ss.str();
default:
return TypeToString(type);
[3/4] incubator-impala git commit: IMPALA-2020,
IMPALA-4809: Codegen support for DECIMAL_V2
Posted by kw...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/expr.h
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr.h b/be/src/exprs/expr.h
index 13ba312..3a92c21 100644
--- a/be/src/exprs/expr.h
+++ b/be/src/exprs/expr.h
@@ -260,55 +260,8 @@ class Expr {
/// not strip these symbols.
static void InitBuiltinsDummy();
- // Any additions to this enum must be reflected in both GetConstant*() and
- // GetIrConstant().
- enum ExprConstant {
- // RETURN_TYPE_*: properties of FunctionContext::GetReturnType().
- RETURN_TYPE_SIZE, // int
- RETURN_TYPE_PRECISION, // int
- RETURN_TYPE_SCALE, // int
- // ARG_TYPE_* with parameter i: properties of FunctionContext::GetArgType(i).
- ARG_TYPE_SIZE, // int[]
- ARG_TYPE_PRECISION, // int[]
- ARG_TYPE_SCALE, // int[]
- };
-
- // Static function for obtaining a runtime constant. Expr compute functions and
- // builtins implementing the UDF interface should use this function, rather than
- // accessing runtime constants directly, so any recognized constants can be inlined via
- // InlineConstants() in the codegen path. In the interpreted path, this function will
- // work as-is.
- //
- // 'c' determines which constant is returned. The type of the constant is annotated in
- // the ExprConstant enum above. If the constant is an array, 'i' must be specified and
- // indicates which element to return. 'i' must always be an immediate integer value so
- // InlineConstants() can resolve the index, e.g., it cannot be a variable or an
- // expression like "1 + 1". For example, if 'c' = ARG_TYPE_SIZE, then 'T' = int and
- // 0 <= i < children_.size().
- //
- // InlineConstants() can be run on the function to replace recognized constants. The
- // constants are only replaced in the function itself, so any callee functions with
- // constants to be replaced must be inlined into the function that InlineConstants()
- // is run on (e.g. by annotating them with IR_ALWAYS_INLINE).
- //
- // TODO: implement a loop unroller (or use LLVM's) so we can use GetConstantInt() in
- // loops
- static int GetConstantInt(const FunctionContext& ctx, ExprConstant c, int i = -1);
-
- /// Finds all calls to Expr::GetConstantInt() in 'fn' and replaces them with the
- /// appropriate runtime constants based on the arguments. 'return_type' is the
- /// return type of the UDF or UDAF, i.e. the value of FunctionContext::GetReturnType().
- /// 'arg_types' are the argument types of the UDF or UDAF, i.e. the values of
- /// FunctionContext::GetArgType().
- static int InlineConstants(const FunctionContext::TypeDesc& return_type,
- const std::vector<FunctionContext::TypeDesc>& arg_types, LlvmCodeGen* codegen,
- llvm::Function* fn);
-
static const char* LLVM_CLASS_NAME;
- // Expr::GetConstantInt() symbol prefix.
- static const char* GET_CONSTANT_INT_SYMBOL_PREFIX;
-
protected:
friend class AggFnEvaluator;
friend class CastExpr;
@@ -409,11 +362,6 @@ class Expr {
/// functions (e.g. in ScalarFnCall() when codegen is disabled).
llvm::Function* GetStaticGetValWrapper(ColumnType type, LlvmCodeGen* codegen);
- /// Replace all calls to Expr::GetConstant() in 'fn' based on the types of the
- /// expr and its children. This is a convenience method that invokes the static
- /// InlineConstants() function with the correct arguments for the expr.
- int InlineConstants(LlvmCodeGen* codegen, llvm::Function* fn);
-
/// Simple debug string that provides no expr subclass-specific information
std::string DebugString(const std::string& expr_name) const;
@@ -457,13 +405,6 @@ class Expr {
static StringVal GetStringVal(Expr* expr, ExprContext* context, const TupleRow* row);
static TimestampVal GetTimestampVal(Expr* expr, ExprContext* context, const TupleRow* row);
static DecimalVal GetDecimalVal(Expr* expr, ExprContext* context, const TupleRow* row);
-
-
- // Helper function for GetConstantInt() and InlineConstants(): return the constant value
- // given the specific argument and return types.
- static int GetConstantInt(const FunctionContext::TypeDesc& return_type,
- const std::vector<FunctionContext::TypeDesc>& arg_types, ExprConstant c,
- int i = -1);
};
}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/math-functions-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/math-functions-ir.cc b/be/src/exprs/math-functions-ir.cc
index da8df36..6a331ba 100644
--- a/be/src/exprs/math-functions-ir.cc
+++ b/be/src/exprs/math-functions-ir.cc
@@ -433,7 +433,7 @@ template <typename T> T MathFunctions::Negative(FunctionContext* ctx, const T& v
template <>
DecimalVal MathFunctions::Negative(FunctionContext* ctx, const DecimalVal& val) {
if (val.is_null) return val;
- int type_byte_size = Expr::GetConstantInt(*ctx, Expr::RETURN_TYPE_SIZE);
+ int type_byte_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE);
switch (type_byte_size) {
case 4:
return DecimalVal(-val.val4);
@@ -519,7 +519,7 @@ template <bool ISLEAST> DecimalVal MathFunctions::LeastGreatest(
DCHECK_GT(num_args, 0);
if (args[0].is_null) return DecimalVal::null();
DecimalVal result_val = args[0];
- int type_byte_size = Expr::GetConstantInt(*ctx, Expr::RETURN_TYPE_SIZE);
+ int type_byte_size = ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE);
for (int i = 1; i < num_args; ++i) {
if (args[i].is_null) return DecimalVal::null();
switch (type_byte_size) {
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/exprs/scalar-fn-call.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/scalar-fn-call.cc b/be/src/exprs/scalar-fn-call.cc
index 06830b7..59aac6d 100644
--- a/be/src/exprs/scalar-fn-call.cc
+++ b/be/src/exprs/scalar-fn-call.cc
@@ -316,8 +316,8 @@ Status ScalarFnCall::GetCodegendComputeFn(LlvmCodeGen* codegen, Function** fn) {
NumFixedArgs(), vararg_start_idx_ != -1, &udf, &cache_entry_));
// Inline constants into the function if it has an IR body.
if (!udf->isDeclaration()) {
- InlineConstants(AnyValUtil::ColumnTypeToTypeDesc(type_),
- AnyValUtil::ColumnTypesToTypeDescs(arg_types), codegen, udf);
+ codegen->InlineConstFnAttrs(AnyValUtil::ColumnTypeToTypeDesc(type_),
+ AnyValUtil::ColumnTypesToTypeDescs(arg_types), udf);
udf = codegen->FinalizeFunction(udf);
if (udf == NULL) {
return Status(
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/runtime/decimal-value.inline.h
----------------------------------------------------------------------
diff --git a/be/src/runtime/decimal-value.inline.h b/be/src/runtime/decimal-value.inline.h
index f886787..3a65a16 100644
--- a/be/src/runtime/decimal-value.inline.h
+++ b/be/src/runtime/decimal-value.inline.h
@@ -79,7 +79,8 @@ inline const T DecimalValue<T>::fractional_part(int scale) const {
template<typename T>
inline DecimalValue<T> DecimalValue<T>::ScaleTo(int src_scale, int dst_scale,
- int dst_precision, bool* overflow) const { int delta_scale = src_scale - dst_scale;
+ int dst_precision, bool* overflow) const {
+ int delta_scale = src_scale - dst_scale;
T result = value();
T max_value = DecimalUtil::GetScaleMultiplier<T>(dst_precision);
if (delta_scale >= 0) {
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/runtime/lib-cache.cc
----------------------------------------------------------------------
diff --git a/be/src/runtime/lib-cache.cc b/be/src/runtime/lib-cache.cc
index 00c1159..9a8d873 100644
--- a/be/src/runtime/lib-cache.cc
+++ b/be/src/runtime/lib-cache.cc
@@ -400,12 +400,9 @@ Status LibCache::GetCacheEntryInternal(const string& hdfs_lib_file, LibType type
DynamicOpen((*entry)->local_path.c_str(), &(*entry)->shared_object_handle));
} else if (type == TYPE_IR) {
// Load the module temporarily and populate all symbols.
- ObjectPool pool;
- scoped_ptr<LlvmCodeGen> codegen;
- string module_id = filesystem::path((*entry)->local_path).stem().string();
- RETURN_IF_ERROR(LlvmCodeGen::CreateFromFile(
- &pool, NULL, (*entry)->local_path, module_id, &codegen));
- codegen->GetSymbols(&(*entry)->symbols);
+ const string file = (*entry)->local_path;
+ const string module_id = filesystem::path(file).stem().string();
+ RETURN_IF_ERROR(LlvmCodeGen::GetSymbols(file, module_id, &(*entry)->symbols));
} else {
DCHECK_EQ(type, TYPE_JAR);
// Nothing to do.
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/runtime/runtime-state.cc
----------------------------------------------------------------------
diff --git a/be/src/runtime/runtime-state.cc b/be/src/runtime/runtime-state.cc
index de0fc97..0d7f262 100644
--- a/be/src/runtime/runtime-state.cc
+++ b/be/src/runtime/runtime-state.cc
@@ -156,7 +156,7 @@ Status RuntimeState::CreateBlockMgr() {
Status RuntimeState::CreateCodegen() {
if (codegen_.get() != NULL) return Status::OK();
// TODO: add the fragment ID to the codegen ID as well
- RETURN_IF_ERROR(LlvmCodeGen::CreateImpalaCodegen(obj_pool_.get(),
+ RETURN_IF_ERROR(LlvmCodeGen::CreateImpalaCodegen(this,
instance_mem_tracker_.get(), PrintId(fragment_instance_id()), &codegen_));
codegen_->EnableOptimizations(true);
profile_.AddChild(codegen_->runtime_profile());
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/runtime/runtime-state.h
----------------------------------------------------------------------
diff --git a/be/src/runtime/runtime-state.h b/be/src/runtime/runtime-state.h
index 14f9d38..97014aa 100644
--- a/be/src/runtime/runtime-state.h
+++ b/be/src/runtime/runtime-state.h
@@ -104,6 +104,7 @@ class RuntimeState {
bool abort_on_default_limit_exceeded() const {
return query_options().abort_on_default_limit_exceeded;
}
+ bool decimal_v2() const { return query_options().decimal_v2; }
const TQueryCtx& query_ctx() const;
const TPlanFragmentInstanceCtx& instance_ctx() const { return *instance_ctx_; }
const TUniqueId& session_id() const { return query_ctx().session.session_id; }
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/service/frontend.cc
----------------------------------------------------------------------
diff --git a/be/src/service/frontend.cc b/be/src/service/frontend.cc
index b83d091..e48cb1e 100644
--- a/be/src/service/frontend.cc
+++ b/be/src/service/frontend.cc
@@ -82,7 +82,7 @@ Frontend::Frontend() {
{"getTableFiles", "([B)[B", &get_table_files_id_},
{"showCreateFunction", "([B)Ljava/lang/String;", &show_create_function_id_},
{"buildTestDescriptorTable", "([B)[B", &build_test_descriptor_table_id_}
-};
+ };
JNIEnv* jni_env = getJNIEnv();
// create instance of java class JniFrontend
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/udf/udf-internal.h
----------------------------------------------------------------------
diff --git a/be/src/udf/udf-internal.h b/be/src/udf/udf-internal.h
index 96d0fc7..907bb22 100644
--- a/be/src/udf/udf-internal.h
+++ b/be/src/udf/udf-internal.h
@@ -132,12 +132,53 @@ class FunctionContextImpl {
return arg_types_;
}
- // UDFs may manipulate DecimalVal arguments via SIMD instructions such as 'movaps'
- // that require 16-byte memory alignment.
+ RuntimeState* state() { return state_; }
+
+ /// Various static attributes of the UDF/UDA that can be injected as constants
+ /// by codegen. Note that the argument types refer to those in the UDF/UDA signature,
+ /// not the arguments of the C++ functions implementing the UDF/UDA. Any change to
+ /// this enum must be reflected in FunctionContextImpl::GetConstFnAttr().
+ enum ConstFnAttr {
+ /// RETURN_TYPE_*: properties of FunctionContext::GetReturnType()
+ RETURN_TYPE_SIZE, // int
+ RETURN_TYPE_PRECISION, // int
+ RETURN_TYPE_SCALE, // int
+ /// ARG_TYPE_* with parameter i: properties of FunctionContext::GetArgType(i)
+ ARG_TYPE_SIZE, // int[]
+ ARG_TYPE_PRECISION, // int[]
+ ARG_TYPE_SCALE, // int[]
+ /// True if decimal_v2 query option is set.
+ DECIMAL_V2,
+ };
+
+ /// This function returns the various static attributes of the UDF/UDA. Calls to this
+ /// function are replaced by constants injected by codegen. If codegen is disabled,
+ /// this function is interpreted as-is.
+ ///
+ /// 't' is the static function attribute defined in the ConstFnAttr enum above.
+ /// For function attributes of arguments, 'i' holds the argument number (0 indexed).
+ /// Please note that argument refers to the arguments in the signature of the UDF or UDA.
+ /// 'i' must always be an immediate integer value in order to utilize the constant
+ /// replacement when codegen is enabled. e.g., it cannot be a variable or an expression
+ /// like "1 + 1".
+ ///
+ int GetConstFnAttr(ConstFnAttr t, int i = -1);
+
+ /// Return the function attribute 't' defined in ConstFnAttr above.
+ static int GetConstFnAttr(const RuntimeState* state,
+ const impala_udf::FunctionContext::TypeDesc& return_type,
+ const std::vector<impala_udf::FunctionContext::TypeDesc>& arg_types,
+ ConstFnAttr t, int i = -1);
+
+ /// UDFs may manipulate DecimalVal arguments via SIMD instructions such as 'movaps'
+ /// that require 16-byte memory alignment.
static const int VARARGS_BUFFER_ALIGNMENT = 16;
+
+ /// The LLVM class name for FunctionContext. Used for handcrafted IR.
static const char* LLVM_FUNCTIONCONTEXT_NAME;
- RuntimeState* state() { return state_; }
+ /// FunctionContextImpl::GetConstFnAttr() symbol. Used for call sites replacement.
+ static const char* GET_CONST_FN_ATTR_SYMBOL;
private:
friend class impala_udf::FunctionContext;
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/udf/udf-test-harness.cc
----------------------------------------------------------------------
diff --git a/be/src/udf/udf-test-harness.cc b/be/src/udf/udf-test-harness.cc
index 1c3737d..d34b5ee 100644
--- a/be/src/udf/udf-test-harness.cc
+++ b/be/src/udf/udf-test-harness.cc
@@ -18,6 +18,7 @@
#include "udf/udf-test-harness.h"
#include <vector>
+#include "runtime/runtime-state.h"
#include "udf/udf-internal.h"
#include "common/names.h"
@@ -27,8 +28,8 @@ using namespace impala;
FunctionContext* UdfTestHarness::CreateTestContext(
const FunctionContext::TypeDesc& return_type,
- const vector<FunctionContext::TypeDesc>& arg_types) {
- return FunctionContextImpl::CreateContext(NULL, NULL, return_type, arg_types, 0, true);
+ const vector<FunctionContext::TypeDesc>& arg_types, RuntimeState* state) {
+ return FunctionContextImpl::CreateContext(state, NULL, return_type, arg_types, 0, true);
}
void UdfTestHarness::SetConstantArgs(
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/udf/udf-test-harness.h
----------------------------------------------------------------------
diff --git a/be/src/udf/udf-test-harness.h b/be/src/udf/udf-test-harness.h
index 67ba8fc..668a44d 100644
--- a/be/src/udf/udf-test-harness.h
+++ b/be/src/udf/udf-test-harness.h
@@ -24,6 +24,7 @@
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
+#include "runtime/runtime-state.h"
#include "udf/udf.h"
#include "udf/udf-debug.h"
@@ -36,7 +37,8 @@ class UdfTestHarness {
/// argument of the UDF not including the FunctionContext*. The caller is responsible
/// for calling delete on it. This context has additional debugging validation enabled.
static FunctionContext* CreateTestContext(const FunctionContext::TypeDesc& return_type,
- const std::vector<FunctionContext::TypeDesc>& arg_types);
+ const std::vector<FunctionContext::TypeDesc>& arg_types,
+ impala::RuntimeState* state = nullptr);
/// Use with test contexts to test use of IsArgConstant() and GetConstantArg().
/// constant_args should contain an AnyVal* for each argument of the UDF not including
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/be/src/udf/udf.cc
----------------------------------------------------------------------
diff --git a/be/src/udf/udf.cc b/be/src/udf/udf.cc
index cf1fa0f..c2a5270 100644
--- a/be/src/udf/udf.cc
+++ b/be/src/udf/udf.cc
@@ -82,7 +82,12 @@ class RuntimeState {
assert(false);
}
- bool abort_on_error() {
+ bool abort_on_error() const {
+ assert(false);
+ return false;
+ }
+
+ bool decimal_v2() const {
assert(false);
return false;
}
@@ -99,6 +104,7 @@ class RuntimeState {
}
#else
+#include "exprs/anyval-util.h"
#include "runtime/free-pool.h"
#include "runtime/mem-tracker.h"
#include "runtime/runtime-state.h"
@@ -114,6 +120,8 @@ using std::pair;
const int FunctionContextImpl::VARARGS_BUFFER_ALIGNMENT;
const char* FunctionContextImpl::LLVM_FUNCTIONCONTEXT_NAME =
"class.impala_udf::FunctionContext";
+const char* FunctionContextImpl::GET_CONST_FN_ATTR_SYMBOL =
+ "_ZN6impala19FunctionContextImpl14GetConstFnAttrENS0_11ConstFnAttrEi";
static const int MAX_WARNINGS = 1000;
@@ -501,3 +509,53 @@ const FunctionContext::TypeDesc* FunctionContext::GetArgType(int arg_idx) const
if (arg_idx < 0 || arg_idx >= impl_->arg_types_.size()) return NULL;
return &impl_->arg_types_[arg_idx];
}
+
+static int GetTypeByteSize(const FunctionContext::TypeDesc& type) {
+#if defined(IMPALA_UDF_SDK_BUILD) && IMPALA_UDF_SDK_BUILD
+ return 0;
+#else
+ return AnyValUtil::TypeDescToColumnType(type).GetByteSize();
+#endif
+}
+
+int FunctionContextImpl::GetConstFnAttr(FunctionContextImpl::ConstFnAttr t, int i) {
+ return GetConstFnAttr(state_, return_type_, arg_types_, t, i);
+}
+
+int FunctionContextImpl::GetConstFnAttr(const RuntimeState* state,
+ const FunctionContext::TypeDesc& return_type,
+ const vector<FunctionContext::TypeDesc>& arg_types,
+ ConstFnAttr t, int i) {
+ switch (t) {
+ case RETURN_TYPE_SIZE:
+ assert(i == -1);
+ return GetTypeByteSize(return_type);
+ case RETURN_TYPE_PRECISION:
+ assert(i == -1);
+ assert(return_type.type == FunctionContext::TYPE_DECIMAL);
+ return return_type.precision;
+ case RETURN_TYPE_SCALE:
+ assert(i == -1);
+ assert(return_type.type == FunctionContext::TYPE_DECIMAL);
+ return return_type.scale;
+ case ARG_TYPE_SIZE:
+ assert(i >= 0);
+ assert(i < arg_types.size());
+ return GetTypeByteSize(arg_types[i]);
+ case ARG_TYPE_PRECISION:
+ assert(i >= 0);
+ assert(i < arg_types.size());
+ assert(arg_types[i].type == FunctionContext::TYPE_DECIMAL);
+ return arg_types[i].precision;
+ case ARG_TYPE_SCALE:
+ assert(i >= 0);
+ assert(i < arg_types.size());
+ assert(arg_types[i].type == FunctionContext::TYPE_DECIMAL);
+ return arg_types[i].scale;
+ case DECIMAL_V2:
+ return state->decimal_v2();
+ default:
+ assert(false);
+ return -1;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/testdata/workloads/functional-query/queries/QueryTest/decimal.test
----------------------------------------------------------------------
diff --git a/testdata/workloads/functional-query/queries/QueryTest/decimal.test b/testdata/workloads/functional-query/queries/QueryTest/decimal.test
index 6e7cbae..4a1316b 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/decimal.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/decimal.test
@@ -449,3 +449,47 @@ NULL,0.0000
---- TYPES
DECIMAL, DECIMAL
====
+---- QUERY
+# Test casting behavior without decimal_v2 query option set.
+set decimal_v2=false;
+select cast(d3 as decimal(20, 3)) from functional.decimal_tbl;
+---- RESULTS
+1.234
+12.345
+123.456
+1234.567
+12345.678
+---- TYPES
+DECIMAL
+====
+---- QUERY
+# Test casting behavior with decimal_v2 query option set.
+set decimal_v2=true;
+select cast(d3 as decimal(20, 3)) from functional.decimal_tbl;
+---- RESULTS
+1.235
+12.346
+123.457
+1234.568
+12345.679
+---- TYPES
+DECIMAL
+====
+---- QUERY
+# Test casting behavior without decimal_v2 query option set.
+set decimal_v2=false;
+select sum(cast(d3 as DECIMAL(20,2)) + cast(d5 as DECIMAL(20,4))) from functional.decimal_tbl;
+---- RESULTS
+26078.2788
+---- TYPES
+DECIMAL
+====
+---- QUERY
+# Test casting behavior with decimal_v2 query option set.
+set decimal_v2=true;
+select sum(cast(d3 as DECIMAL(20,2)) + cast(d5 as DECIMAL(20,4))) from functional.decimal_tbl;
+---- RESULTS
+26078.3189
+---- TYPES
+DECIMAL
+====
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/f982c3f7/tests/query_test/test_decimal_casting.py
----------------------------------------------------------------------
diff --git a/tests/query_test/test_decimal_casting.py b/tests/query_test/test_decimal_casting.py
index b23e790..fac49c5 100644
--- a/tests/query_test/test_decimal_casting.py
+++ b/tests/query_test/test_decimal_casting.py
@@ -23,6 +23,7 @@ from metacomm.combinatorics.all_pairs2 import all_pairs2 as all_pairs
from random import randint
from tests.common.impala_test_suite import ImpalaTestSuite
+from tests.common.test_dimensions import create_exec_option_dimension_from_dict
from tests.common.test_vector import ImpalaTestDimension, ImpalaTestMatrix
class TestDecimalCasting(ImpalaTestSuite):
@@ -42,8 +43,8 @@ class TestDecimalCasting(ImpalaTestSuite):
# mimics test_vectors.py and takes a subset of all decimal types
'pairwise' : all_pairs([(p, s) for p in xrange(1, 39) for s in xrange(0, p + 1)])
}
- # We can cast for numerrics or string types.
- CAST_FROM = ['string', 'number']
+ # We can cast for numerics, string or decimal types.
+ CAST_FROM = ['string', 'number', 'decimal']
# Set the default precisin to 38 to operate on decimal values.
getcontext().prec = 38
# Represents a 0 in decimal
@@ -60,6 +61,8 @@ class TestDecimalCasting(ImpalaTestSuite):
*TestDecimalCasting.DECIMAL_TYPES_MAP[cls.exploration_strategy()]))
cls.ImpalaTestMatrix.add_dimension(
ImpalaTestDimension('cast_from', *TestDecimalCasting.CAST_FROM))
+ cls.ImpalaTestMatrix.add_dimension(create_exec_option_dimension_from_dict(
+ {'decimal_v2': ['false']}))
cls.iterations = 1
def setup_method(self, method):
@@ -79,15 +82,21 @@ class TestDecimalCasting(ImpalaTestSuite):
assert actual == expected, "Cast: {0}, Expected: {1}, Actual: {2}".format(cast,\
expected, actual)
- def _normalize_cast_expr(self, decimal_val, scale, from_string=False):
+ def _normalize_cast_expr(self, decimal_val, scale, cast_from):
"""Convert the decimal value to a string litetal to avoid overflow.
If an integer literal is greater than the max bigint supported by Impala, it
overflows. This methods replaces it with a string literal.
"""
- if (scale == 0 and abs(decimal_val) > self.max_bigint) or from_string:
- return "select cast('{0}' as Decimal({1}, {2}))"
- return "select cast({0} as Decimal({1}, {2}))"
+ # Decimal({1},{2}) is the target type to cast to. If casting from decimal,
+ # Decimal({3},{4}) is the intermediate type to cast {0} to.
+ if (scale == 0 and abs(decimal_val) > self.max_bigint) or (cast_from == 'string'):
+ return "select cast('{0}' as Decimal({1},{2}))"
+ elif cast_from == 'decimal':
+ base_cast = "cast('{0}' as Decimal({3},{4}))"
+ return "select cast(" + base_cast + " as Decimal({1},{2}))"
+ else:
+ return "select cast({0} as Decimal({1},{2}))"
def test_min_max_zero_null(self, vector):
"""Sanity test at limits.
@@ -98,20 +107,21 @@ class TestDecimalCasting(ImpalaTestSuite):
- NULL is expressible in all decimal types
"""
precision, scale = vector.get_value('decimal_type')
- from_string = vector.get_value('cast_from') == 'string'
dec_max = Decimal('{0}.{1}'.format('9' * (precision - scale), '9' * scale))
# Multiplying large values eith -1 can produce an overflow.
dec_min = Decimal('-{0}'.format(str(dec_max)))
- cast = self._normalize_cast_expr(dec_max, scale, from_string=from_string)
+ cast = self._normalize_cast_expr(dec_max, scale, vector.get_value('cast_from'))
# Test max
- res = Decimal(self.execute_scalar(cast.format(dec_max, precision, scale)))
+ res = Decimal(self.execute_scalar(\
+ cast.format(dec_max, precision, scale, precision, scale)))
self._assert_decimal_result(cast, res, dec_max)
# Test Min
- res = Decimal(self.execute_scalar(cast.format(dec_min, precision, scale)))
+ res = Decimal(self.execute_scalar(\
+ cast.format(dec_min, precision, scale, precision, scale)))
self._assert_decimal_result(cast, res, dec_min)
# Test zero
- res = Decimal(self.execute_scalar(cast.format(TestDecimalCasting.DECIMAL_ZERO,
- precision, scale)))
+ res = Decimal(self.execute_scalar(\
+ cast.format(TestDecimalCasting.DECIMAL_ZERO, precision, scale, precision, scale)))
self._assert_decimal_result(cast, res, TestDecimalCasting.DECIMAL_ZERO)
# Test NULL
null_cast = "select cast(NULL as Decimal({0}, {1}))".format(precision, scale)
@@ -122,11 +132,12 @@ class TestDecimalCasting(ImpalaTestSuite):
"""Test to verify that an exact representation of the desired Decimal type is
maintained."""
precision, scale = vector.get_value('decimal_type')
- from_string = vector.get_value('cast_from') == 'string'
+ if vector.get_value('cast_from') == 'decimal':
+ pytest.skip("Casting between the same decimal type isn't interesting")
for i in xrange(self.iterations):
val = self._gen_decimal_val(precision, scale)
- cast = self._normalize_cast_expr(val, scale, from_string=from_string)\
- .format(val, precision, scale)
+ cast = self._normalize_cast_expr(val, scale, vector.get_value('cast_from'))\
+ .format(val, precision, scale, precision, scale)
res = Decimal(self.execute_scalar(cast))
self._assert_decimal_result(cast, res, val)
@@ -134,12 +145,12 @@ class TestDecimalCasting(ImpalaTestSuite):
"""Test to verify that we always return NULL when trying to cast a number with greater
precision that its intended decimal type"""
precision, scale = vector.get_value('decimal_type')
- from_string = vector.get_value('cast_from') == 'string'
for i in xrange(self.iterations):
# Generate a decimal with a larger precision than the one we're casting to.
- val = self._gen_decimal_val(randint(precision + 1, 39), scale)
- cast = self._normalize_cast_expr(val, scale, from_string=from_string)\
- .format(val, precision, scale)
+ from_precision = randint(precision + 1, 39)
+ val = self._gen_decimal_val(from_precision, scale)
+ cast = self._normalize_cast_expr(val, scale, vector.get_value('cast_from'))\
+ .format(val, precision, scale, min(38, from_precision), scale)
res = self.execute_scalar(cast)
self._assert_decimal_result(cast, res, 'NULL')
@@ -148,16 +159,17 @@ class TestDecimalCasting(ImpalaTestSuite):
than the target decimal type (with no change in precision).
"""
precision, scale = vector.get_value('decimal_type')
- from_string = vector.get_value('cast_from') == 'string'
+ is_decimal_v2 = vector.get_value('exec_option')['decimal_v2'] == 'true'
if precision == scale:
pytest.skip("Cannot underflow scale when precision and scale are equal")
for i in xrange(self.iterations):
- new_scale = randint(scale + 1, precision)
- val = self._gen_decimal_val(precision, randint(new_scale, precision))
- # We don't need to normalize the cast expr because scale will never be zero
- cast = self._normalize_cast_expr(val, scale, from_string=from_string)\
- .format(val, precision, scale)
- res = Decimal(self.execute_scalar(cast))
- # Truncate the decimal value to its target scale with quantize.
- self._assert_decimal_result(cast, res, val.quantize(Decimal('0e-%s' % scale),
- rounding=ROUND_DOWN))
+ from_scale = randint(scale + 1, precision)
+ val = self._gen_decimal_val(precision, from_scale)
+ cast = self._normalize_cast_expr(val, scale, vector.get_value('cast_from'))\
+ .format(val, precision, scale, precision, from_scale)
+ res = Decimal(self.execute_scalar(cast, vector.get_value('exec_option')))
+ if is_decimal_v2:
+ expected_val = val.quantize(Decimal('0e-%s' % scale))
+ else:
+ expected_val = val.quantize(Decimal('0e-%s' % scale), rounding=ROUND_DOWN)
+ self._assert_decimal_result(cast, res, expected_val)