blob: 4b692337a72c139ed9ed6fa807b92c878ded0774 [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/hive-udf-call.h"
#include <sstream>
#include "exprs/anyval-util.h"
#include "exprs/scalar-expr-evaluator.h"
#include "runtime/string-value.h"
#include "util/jni-util.h"
namespace impala {
FunctionContext* HiveUdfCall::GetFunctionContext(
ScalarExprEvaluator* eval, int fn_ctx_idx) {
return eval->fn_context(fn_ctx_idx);
}
HiveUdfCall::JniContext* HiveUdfCall::GetJniContext(FunctionContext* fn_ctx) {
JniContext* jni_ctx = reinterpret_cast<JniContext*>(
fn_ctx->GetFunctionState(FunctionContext::THREAD_LOCAL));
DCHECK(jni_ctx != nullptr);
return jni_ctx;
}
void HiveUdfCall::JniContext::SetInputNullsBufferElement(
JniContext* jni_ctx, int index, uint8_t value) {
jni_ctx->input_nulls_buffer[index] = value;
}
uint8_t* HiveUdfCall::JniContext::GetInputValuesBufferAtOffset(
JniContext* jni_ctx, int offset) {
return &jni_ctx->input_values_buffer[offset];
}
AnyVal* HiveUdfCall::CallJavaAndStoreResult(const ColumnType* type,
FunctionContext* fn_ctx, JniContext* jni_ctx) {
DCHECK(jni_ctx != nullptr);
JNIEnv* env = jni_ctx->jni_env;
DCHECK(env != nullptr);
// Using this version of Call has the lowest overhead. This eliminates the
// vtable lookup and setting up return stacks.
env->CallNonvirtualVoidMethodA(
jni_ctx->executor, executor_cl_, executor_evaluate_id_, nullptr);
Status status = JniUtil::GetJniExceptionMsg(env);
if (!status.ok()) {
if (!jni_ctx->warning_logged) {
std::stringstream ss;
ss << "Hive UDF path=" << jni_ctx->hdfs_location << " class="
<< jni_ctx->scalar_fn_symbol << " failed due to: " << status.GetDetail();
fn_ctx->AddWarning(ss.str().c_str());
jni_ctx->warning_logged = true;
}
jni_ctx->output_anyval->is_null = true;
return jni_ctx->output_anyval;
}
// Write output_value_buffer to output_anyval
if (jni_ctx->output_null_value) {
jni_ctx->output_anyval->is_null = true;
} else {
AnyValUtil::SetAnyVal(jni_ctx->output_value_buffer, *type, jni_ctx->output_anyval);
if (type->type == TYPE_STRING) {
// Copy the string into a result allocation with the usual lifetime for expr
// results. Needed because the UDF output buffer is owned by the Java UDF executor
// and may be freed or reused by the next call into the Java UDF executor.
StringVal* str_val = static_cast<StringVal*>(jni_ctx->output_anyval);
const StringVal temp = StringVal::CopyFrom(fn_ctx, str_val->ptr, str_val->len);
*str_val = temp;
}
}
return jni_ctx->output_anyval;
}
} // namespace impala