blob: 805e11089d65dd8fcf66136a768ff6ad0fdba52c [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "exprs/expr-context.h"
#include <sstream>
#include "common/object-pool.h"
#include "exprs/expr.h"
#include "runtime/decimal-value.inline.h"
#include "runtime/mem-pool.h"
#include "runtime/raw-value.inline.h"
#include "runtime/runtime-state.h"
#include "udf/udf-internal.h"
#include "common/names.h"
using namespace impala;
using namespace impala_udf;
const char* ExprContext::LLVM_CLASS_NAME = "class.impala::ExprContext";
ExprContext::ExprContext(Expr* root)
: fn_contexts_ptr_(NULL),
root_(root),
is_clone_(false),
prepared_(false),
opened_(false),
closed_(false) {
}
ExprContext::~ExprContext() {
DCHECK(!prepared_ || closed_);
for (int i = 0; i < fn_contexts_.size(); ++i) {
delete fn_contexts_[i];
}
}
Status ExprContext::Prepare(RuntimeState* state, const RowDescriptor& row_desc,
MemTracker* tracker) {
DCHECK(tracker != NULL);
DCHECK(pool_.get() == NULL);
prepared_ = true;
pool_.reset(new MemPool(tracker));
return root_->Prepare(state, row_desc, this);
}
Status ExprContext::Open(RuntimeState* state) {
DCHECK(prepared_);
if (opened_) return Status::OK();
opened_ = true;
// Fragment-local state is only initialized for original contexts. Clones inherit the
// original's fragment state and only need to have thread-local state initialized.
FunctionContext::FunctionStateScope scope =
is_clone_? FunctionContext::THREAD_LOCAL : FunctionContext::FRAGMENT_LOCAL;
return root_->Open(state, this, scope);
}
void ExprContext::Close(RuntimeState* state) {
if (closed_) return;
FunctionContext::FunctionStateScope scope =
is_clone_ ? FunctionContext::THREAD_LOCAL : FunctionContext::FRAGMENT_LOCAL;
root_->Close(state, this, scope);
for (int i = 0; i < fn_contexts_.size(); ++i) {
fn_contexts_[i]->impl()->Close();
}
// pool_ can be NULL if Prepare() was never called
if (pool_ != NULL) pool_->FreeAll();
closed_ = true;
}
int ExprContext::Register(RuntimeState* state,
const impala_udf::FunctionContext::TypeDesc& return_type,
const vector<impala_udf::FunctionContext::TypeDesc>& arg_types,
int varargs_buffer_size) {
fn_contexts_.push_back(FunctionContextImpl::CreateContext(
state, pool_.get(), return_type, arg_types, varargs_buffer_size));
fn_contexts_ptr_ = &fn_contexts_[0];
return fn_contexts_.size() - 1;
}
Status ExprContext::Clone(RuntimeState* state, ExprContext** new_ctx) {
DCHECK(prepared_);
DCHECK(opened_);
DCHECK(*new_ctx == NULL);
*new_ctx = state->obj_pool()->Add(new ExprContext(root_));
(*new_ctx)->pool_.reset(new MemPool(pool_->mem_tracker()));
for (int i = 0; i < fn_contexts_.size(); ++i) {
(*new_ctx)->fn_contexts_.push_back(
fn_contexts_[i]->impl()->Clone((*new_ctx)->pool_.get()));
}
(*new_ctx)->fn_contexts_ptr_ = &((*new_ctx)->fn_contexts_[0]);
(*new_ctx)->is_clone_ = true;
(*new_ctx)->prepared_ = true;
(*new_ctx)->opened_ = true;
return root_->Open(state, *new_ctx, FunctionContext::THREAD_LOCAL);
}
bool ExprContext::HasLocalAllocations(const vector<ExprContext*>& ctxs) {
for (int i = 0; i < ctxs.size(); ++i) {
if (ctxs[i]->HasLocalAllocations()) return true;
}
return false;
}
bool ExprContext::HasLocalAllocations() {
return HasLocalAllocations(fn_contexts_);
}
bool ExprContext::HasLocalAllocations(const std::vector<FunctionContext*>& fn_ctxs) {
for (int i = 0; i < fn_ctxs.size(); ++i) {
if (fn_ctxs[i]->impl()->closed()) continue;
if (fn_ctxs[i]->impl()->HasLocalAllocations()) return true;
}
return false;
}
void ExprContext::FreeLocalAllocations(const vector<ExprContext*>& ctxs) {
for (int i = 0; i < ctxs.size(); ++i) {
ctxs[i]->FreeLocalAllocations();
}
}
void ExprContext::FreeLocalAllocations() {
FreeLocalAllocations(fn_contexts_);
}
void ExprContext::FreeLocalAllocations(const vector<FunctionContext*>& fn_ctxs) {
for (int i = 0; i < fn_ctxs.size(); ++i) {
if (fn_ctxs[i]->impl()->closed()) continue;
fn_ctxs[i]->impl()->FreeLocalAllocations();
}
}
void ExprContext::EvaluateWithoutRow(TColumnValue* col_val) {
DCHECK_EQ(0, root_->GetSlotIds());
void* value = GetValue(NULL);
if (value == NULL) return;
StringValue* string_val = NULL;
string tmp;
switch (root_->type_.type) {
case TYPE_BOOLEAN:
col_val->__set_bool_val(*reinterpret_cast<bool*>(value));
break;
case TYPE_TINYINT:
col_val->__set_byte_val(*reinterpret_cast<int8_t*>(value));
break;
case TYPE_SMALLINT:
col_val->__set_short_val(*reinterpret_cast<int16_t*>(value));
break;
case TYPE_INT:
col_val->__set_int_val(*reinterpret_cast<int32_t*>(value));
break;
case TYPE_BIGINT:
col_val->__set_long_val(*reinterpret_cast<int64_t*>(value));
break;
case TYPE_FLOAT:
col_val->__set_double_val(*reinterpret_cast<float*>(value));
break;
case TYPE_DOUBLE:
col_val->__set_double_val(*reinterpret_cast<double*>(value));
break;
case TYPE_DECIMAL:
switch (root_->type_.GetByteSize()) {
case 4:
col_val->string_val =
reinterpret_cast<Decimal4Value*>(value)->ToString(root_->type_);
break;
case 8:
col_val->string_val =
reinterpret_cast<Decimal8Value*>(value)->ToString(root_->type_);
break;
case 16:
col_val->string_val =
reinterpret_cast<Decimal16Value*>(value)->ToString(root_->type_);
break;
default:
DCHECK(false) << "Bad Type: " << root_->type_;
}
col_val->__isset.string_val = true;
break;
case TYPE_STRING:
case TYPE_VARCHAR:
string_val = reinterpret_cast<StringValue*>(value);
tmp.assign(static_cast<char*>(string_val->ptr), string_val->len);
col_val->binary_val.swap(tmp);
col_val->__isset.binary_val = true;
break;
case TYPE_CHAR:
tmp.assign(StringValue::CharSlotToPtr(value, root_->type_), root_->type_.len);
col_val->binary_val.swap(tmp);
col_val->__isset.binary_val = true;
break;
case TYPE_TIMESTAMP: {
uint8_t* uint8_val = reinterpret_cast<uint8_t*>(value);
col_val->binary_val.assign(uint8_val, uint8_val + root_->type_.GetSlotSize());
col_val->__isset.binary_val = true;
RawValue::PrintValue(
value, root_->type_, root_->output_scale_, &col_val->string_val);
col_val->__isset.string_val = true;
break;
}
default:
DCHECK(false) << "bad GetValue() type: " << root_->type_.DebugString();
}
}
void* ExprContext::GetValue(const TupleRow* row) {
return GetValue(root_, row);
}
void* ExprContext::GetValue(Expr* e, const TupleRow* row) {
switch (e->type_.type) {
case TYPE_BOOLEAN: {
impala_udf::BooleanVal v = e->GetBooleanVal(this, row);
if (v.is_null) return NULL;
result_.bool_val = v.val;
return &result_.bool_val;
}
case TYPE_TINYINT: {
impala_udf::TinyIntVal v = e->GetTinyIntVal(this, row);
if (v.is_null) return NULL;
result_.tinyint_val = v.val;
return &result_.tinyint_val;
}
case TYPE_SMALLINT: {
impala_udf::SmallIntVal v = e->GetSmallIntVal(this, row);
if (v.is_null) return NULL;
result_.smallint_val = v.val;
return &result_.smallint_val;
}
case TYPE_INT: {
impala_udf::IntVal v = e->GetIntVal(this, row);
if (v.is_null) return NULL;
result_.int_val = v.val;
return &result_.int_val;
}
case TYPE_BIGINT: {
impala_udf::BigIntVal v = e->GetBigIntVal(this, row);
if (v.is_null) return NULL;
result_.bigint_val = v.val;
return &result_.bigint_val;
}
case TYPE_FLOAT: {
impala_udf::FloatVal v = e->GetFloatVal(this, row);
if (v.is_null) return NULL;
result_.float_val = v.val;
return &result_.float_val;
}
case TYPE_DOUBLE: {
impala_udf::DoubleVal v = e->GetDoubleVal(this, row);
if (v.is_null) return NULL;
result_.double_val = v.val;
return &result_.double_val;
}
case TYPE_STRING:
case TYPE_VARCHAR: {
impala_udf::StringVal v = e->GetStringVal(this, row);
if (v.is_null) return NULL;
result_.string_val.ptr = reinterpret_cast<char*>(v.ptr);
result_.string_val.len = v.len;
return &result_.string_val;
}
case TYPE_CHAR: {
impala_udf::StringVal v = e->GetStringVal(this, row);
if (v.is_null) return NULL;
result_.string_val.ptr = reinterpret_cast<char*>(v.ptr);
result_.string_val.len = v.len;
if (e->type_.IsVarLenStringType()) {
return &result_.string_val;
} else {
return result_.string_val.ptr;
}
}
case TYPE_TIMESTAMP: {
impala_udf::TimestampVal v = e->GetTimestampVal(this, row);
if (v.is_null) return NULL;
result_.timestamp_val = TimestampValue::FromTimestampVal(v);
return &result_.timestamp_val;
}
case TYPE_DECIMAL: {
DecimalVal v = e->GetDecimalVal(this, row);
if (v.is_null) return NULL;
switch (e->type_.GetByteSize()) {
case 4:
result_.decimal4_val = v.val4;
return &result_.decimal4_val;
case 8:
result_.decimal8_val = v.val8;
return &result_.decimal8_val;
case 16:
result_.decimal16_val = v.val16;
return &result_.decimal16_val;
default:
DCHECK(false) << e->type_.GetByteSize();
return NULL;
}
}
case TYPE_ARRAY:
case TYPE_MAP: {
impala_udf::CollectionVal v = e->GetCollectionVal(this, row);
if (v.is_null) return NULL;
result_.collection_val.ptr = v.ptr;
result_.collection_val.num_tuples = v.num_tuples;
return &result_.collection_val;
}
default:
DCHECK(false) << "Type not implemented: " << e->type_.DebugString();
return NULL;
}
}
void ExprContext::PrintValue(const TupleRow* row, string* str) {
RawValue::PrintValue(GetValue(row), root_->type(), root_->output_scale_, str);
}
void ExprContext::PrintValue(void* value, string* str) {
RawValue::PrintValue(value, root_->type(), root_->output_scale_, str);
}
void ExprContext::PrintValue(void* value, stringstream* stream) {
RawValue::PrintValue(value, root_->type(), root_->output_scale_, stream);
}
void ExprContext::PrintValue(const TupleRow* row, stringstream* stream) {
RawValue::PrintValue(GetValue(row), root_->type(), root_->output_scale_, stream);
}
BooleanVal ExprContext::GetBooleanVal(TupleRow* row) {
return root_->GetBooleanVal(this, row);
}
TinyIntVal ExprContext::GetTinyIntVal(TupleRow* row) {
return root_->GetTinyIntVal(this, row);
}
SmallIntVal ExprContext::GetSmallIntVal(TupleRow* row) {
return root_->GetSmallIntVal(this, row);
}
IntVal ExprContext::GetIntVal(TupleRow* row) {
return root_->GetIntVal(this, row);
}
BigIntVal ExprContext::GetBigIntVal(TupleRow* row) {
return root_->GetBigIntVal(this, row);
}
FloatVal ExprContext::GetFloatVal(TupleRow* row) {
return root_->GetFloatVal(this, row);
}
DoubleVal ExprContext::GetDoubleVal(TupleRow* row) {
return root_->GetDoubleVal(this, row);
}
StringVal ExprContext::GetStringVal(TupleRow* row) {
return root_->GetStringVal(this, row);
}
CollectionVal ExprContext::GetCollectionVal(TupleRow* row) {
return root_->GetCollectionVal(this, row);
}
TimestampVal ExprContext::GetTimestampVal(TupleRow* row) {
return root_->GetTimestampVal(this, row);
}
DecimalVal ExprContext::GetDecimalVal(TupleRow* row) {
return root_->GetDecimalVal(this, row);
}