From 09dea2bdc63b856a9d9586fa2b237669abe7ee37 Mon Sep 17 00:00:00 2001 From: wyl4pd Date: Fri, 12 Apr 2024 18:54:42 +0800 Subject: [PATCH 01/18] feat: variadic udf for feature signature --- cases/plan/error_query.yaml | 24 +++ cases/plan/feature_signature_query.yaml | 44 +++++ cases/query/feature_signature_query.yaml | 153 ++++++++++++++ hybridse/include/node/node_enum.h | 1 + hybridse/include/node/node_manager.h | 5 +- hybridse/include/node/sql_node.h | 58 ++++++ hybridse/src/codegen/udf_ir_builder.cc | 48 ++++- hybridse/src/codegen/udf_ir_builder.h | 5 + hybridse/src/node/expr_node.cc | 14 ++ hybridse/src/node/node_manager.cc | 8 + hybridse/src/node/sql_node.cc | 21 ++ .../physical/batch_request_optimize_test.cc | 3 + hybridse/src/testing/engine_test_base.cc | 2 + .../udf/default_defs/feature_signature_def.cc | 59 ++++++ hybridse/src/udf/default_udf_library.cc | 1 + hybridse/src/udf/default_udf_library.h | 1 + hybridse/src/udf/udf_library.h | 8 + hybridse/src/udf/udf_registry.cc | 85 ++++++++ hybridse/src/udf/udf_registry.h | 186 ++++++++++++++++++ hybridse/src/vm/runner_test.cc | 3 + hybridse/src/vm/sql_compiler_test.cc | 3 + .../src/vm/transform_request_mode_test.cc | 2 + src/sdk/sql_sdk_test.h | 3 + 23 files changed, 735 insertions(+), 2 deletions(-) create mode 100644 cases/plan/feature_signature_query.yaml create mode 100644 cases/query/feature_signature_query.yaml create mode 100644 hybridse/src/udf/default_defs/feature_signature_def.cc diff --git a/cases/plan/error_query.yaml b/cases/plan/error_query.yaml index 4d9a6ef8e77..bc0045e9c47 100644 --- a/cases/plan/error_query.yaml +++ b/cases/plan/error_query.yaml @@ -78,3 +78,27 @@ cases: success: false msg: | SHOW JOB statement require a target name following + - id: 10 + desc: feature signature error select multiple label + sql: | + select binary_label(1), binary_label(1); + expect: + success: false + - id: 11 + desc: feature signature error select miss signature + sql: | + select binary_label(1), 1; + expect: + success: false + - id: 12 + desc: feature signature error select with order + sql: | + select binary_label(col1) from t1 order by col1 + expect: + success: false + - id: 13 + desc: feature signature error select with order + sql: | + select binary_label(col1) from t1 order by instance + expect: + success: false diff --git a/cases/plan/feature_signature_query.yaml b/cases/plan/feature_signature_query.yaml new file mode 100644 index 00000000000..2c50eac898c --- /dev/null +++ b/cases/plan/feature_signature_query.yaml @@ -0,0 +1,44 @@ +# Copyright 2021 4Paradigm +# +# Licensed 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. + +cases: + - id: 0 + desc: feature signature select const + mode: request-unsupport + sql: | + select + numeric(1), + continuous(2), + category(3), + discrete("x", 1), + binary_label(true), + numeric(5.5), + continuous(6.6); + - id: 1 + desc: feature signature select const no label + mode: request-unsupport + sql: | + select + numeric(1), + continuous(2), + category(3, 1), + discrete("x", 1), + numeric(5.5), + continuous(numeric(true)); + - id: 2 + desc: feature signature select from + db: db1 + sql: | + SELECT multiclass_label(col1), numeric(int(col0)), numeric(abs(col1)), category(col6, 1) + FROM t1; diff --git a/cases/query/feature_signature_query.yaml b/cases/query/feature_signature_query.yaml new file mode 100644 index 00000000000..29d6bcb796a --- /dev/null +++ b/cases/query/feature_signature_query.yaml @@ -0,0 +1,153 @@ +# Copyright 2021 4Paradigm +# +# Licensed 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. + +cases: + - id: 0 + desc: feature signature select const + db: db1 + sql: | + select + numeric(1), + continuous(2), + category(3), + discrete("x", 1), + binary_label(true), + numeric(5.5), + continuous(6.6); + expect: + schema: instance:string + data: | + 1| 1:0:1 2:0:2 3:2681491882390849628 4:0 5:0:5.500000 6:0:6.600000 + - id: 1 + desc: feature signature select const no label + db: db1 + sql: | + select + numeric(1), + continuous(2), + category(3, 1), + discrete("x", 1), + numeric(5.5), + continuous(numeric(true)); + expect: + schema: instance:string + data: | + | 1:0:1 2:0:2 3:0 4:0 5:0:5.500000 6:0:1 + - id: 2 + desc: feature signature zero bucket size + db: db1 + sql: | + select + category(3, 0), + expect: + schema: instance:string + data: | + | 1:2681491882390849628 + - id: 3 + desc: feature signature nagative bucket size + db: db1 + sql: | + select + category(3, -1), + category(3, 0), + expect: + schema: instance:string + data: | + | 1:2681491882390849628 2:2681491882390849628 + - id: 4 + desc: feature signature null + db: db1 + sql: | + select + regression_label(int("notint")), + numeric(1), + category(int("notint")), + category(3), + numeric(int("notint")); + expect: + schema: instance:string + data: | + | 1:0:1 3:2681491882390849628 + - id: 5 + desc: feature signature select from + db: db1 + sql: | + SELECT multiclass_label(col1), numeric(int(col0)), numeric(abs(col1)), category(col6, 1) + FROM t1; + inputs: + - name: t1 + schema: col0:string, col1:int32, col2:int16, col3:float, col4:double, col5:int64, col6:string + index: index2:col2:col5 + data: | + 0, 1, 5, 1.1, 11.1, 1, 1 + expect: + schema: instance:string + data: | + 1| 1:0:0 2:0:1 3:0 + - id: 6 + desc: feature signature select from + mode: request-unsupport + db: db1 + sql: | + SELECT multiclass_label(col1), numeric(int(col0)), numeric(abs(col1)), category(col6, 1) + FROM t1; + inputs: + - name: t1 + schema: col0:string, col1:int32, col2:int16, col3:float, col4:double, col5:int64, col6:string + index: index2:col2:col5 + data: | + 0, 1, 5, 1.1, 11.1, 1, 1 + 0, 2, 5, 2.2, 22.2, 2, 22 + 1, 3, 55, 3.3, 33.3, 1, 333 + 1, 4, 55, 4.4, 44.4, 2, 4444 + 2, 5, 55, 5.5, 55.5, 3, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + expect: + schema: instance:string + order: instance + data: | + 1| 1:0:0 2:0:1 3:0 + 2| 1:0:0 2:0:2 3:0 + 3| 1:0:1 2:0:3 3:0 + 4| 1:0:1 2:0:4 3:0 + 5| 1:0:2 2:0:5 3:0 + - id: 7 + desc: feature signature select from join + mode: request-unsupport + db: db1 + sql: | + SELECT multiclass_label(t1.col1), numeric(-abs(t1.col1)), category(t2.col6, 1) + FROM t1 last join t2 on t1.col1=t2.col1; + inputs: + - name: t1 + resource: cases/resource/simple_t1.yaml + - name: t2 + resource: cases/resource/simple_t1.yaml + expect: + schema: instance:string + order: instance + data: | + 1| 1:0:-1 2:0 + 2| 1:0:-2 2:0 + 3| 1:0:-3 2:0 + 4| 1:0:-4 2:0 + 5| 1:0:-5 2:0 + - id: 8 + desc: feature signature select const + db: db1 + sql: | + select variadic_concat("a", 1, 3.5) as col1; + expect: + schema: col1:string + data: | + a 1 3.500000 diff --git a/hybridse/include/node/node_enum.h b/hybridse/include/node/node_enum.h index ad8f03bf422..eda518f691e 100644 --- a/hybridse/include/node/node_enum.h +++ b/hybridse/include/node/node_enum.h @@ -76,6 +76,7 @@ enum SqlNodeType { kUdfByCodeGenDef, kUdafDef, kLambdaDef, + kVariadicUdfDef, kPartitionMeta, kReplicaNum, kDistributions, diff --git a/hybridse/include/node/node_manager.h b/hybridse/include/node/node_manager.h index fdee40b20e9..e47635062db 100644 --- a/hybridse/include/node/node_manager.h +++ b/hybridse/include/node/node_manager.h @@ -386,7 +386,10 @@ class NodeManager { FnDefNode *merge_func, FnDefNode *output_func); LambdaNode *MakeLambdaNode(const std::vector &args, ExprNode *body); - + VariadicUdfDefNode *MakeVariadicUdfDefNode(const std::string &name, + FnDefNode *init_func, + const std::vector& update_func, + FnDefNode *output_func); SqlNode *MakePartitionMetaNode(RoleType role_type, const std::string &endpoint); diff --git a/hybridse/include/node/sql_node.h b/hybridse/include/node/sql_node.h index ee81c222714..cd6344f15dd 100644 --- a/hybridse/include/node/sql_node.h +++ b/hybridse/include/node/sql_node.h @@ -2868,6 +2868,64 @@ class UdafDefNode : public FnDefNode { FnDefNode *output_; }; +class VariadicUdfDefNode : public FnDefNode { + public: + VariadicUdfDefNode(const std::string &name, + FnDefNode *init_func, + const std::vector& update_func, + FnDefNode *output_func) + : FnDefNode(kVariadicUdfDef), + name_(name), + init_(init_func), + update_(update_func), + output_(output_func) {} + + const std::string GetName() const override { return name_; } + const TypeNode *GetReturnType() const override { return output_->GetReturnType(); } + bool IsReturnNullable() const override { return output_->IsReturnNullable(); } + size_t GetArgSize() const override { + return init_->GetArgSize() + update_.size(); + } + const TypeNode *GetArgType(size_t i) const override { + if (i < init_->GetArgSize()) { + return init_->GetArgType(i); + } else { + return update_[i - init_->GetArgSize()]->GetArgType(1); + } + } + bool IsArgNullable(size_t i) const override { + if (i < init_->GetArgSize()) { + return init_->IsArgNullable(i); + } else { + return update_[i - init_->GetArgSize()]->IsArgNullable(1); + } + } + + base::Status Validate(const std::vector &arg_types) const override { + return Status::OK(); + } + + void Print(std::ostream &output, const std::string &tab) const override; + bool Equals(const SqlNode *node) const override; + + VariadicUdfDefNode *ShadowCopy(NodeManager *) const override; + VariadicUdfDefNode *DeepCopy(NodeManager *) const override; + + FnDefNode *init_func() const { return init_; } + const std::vector &update_func() const { return update_; } + FnDefNode *output_func() const { return output_; } + + private: + std::string name_; + std::vector arg_types_; + std::vector arg_nullable_; + const node::TypeNode *ret_type_; + bool ret_nullable_; + FnDefNode *init_; + std::vector update_; + FnDefNode *output_; +}; + class PartitionMetaNode : public SqlNode { public: PartitionMetaNode() : SqlNode(kPartitionMeta, 0, 0), endpoint_(""), role_type_() {} diff --git a/hybridse/src/codegen/udf_ir_builder.cc b/hybridse/src/codegen/udf_ir_builder.cc index c9f613e5748..517aa5330d1 100644 --- a/hybridse/src/codegen/udf_ir_builder.cc +++ b/hybridse/src/codegen/udf_ir_builder.cc @@ -77,6 +77,10 @@ Status UdfIRBuilder::BuildCall( auto node = dynamic_cast(fn); return BuildLambdaCall(node, args, output); } + case node::kVariadicUdfDef: { + auto node = dynamic_cast(fn); + return BuildVariadicUdfCall(node, arg_types, args, output); + } default: return Status(common::kCodegenError, "Unknown function def type"); } @@ -465,7 +469,7 @@ Status UdfIRBuilder::BuildExternCall( // set i16 signext attr for extern call // https://releases.llvm.org/9.0.0/docs/LangRef.html#parameter-attributes auto function = ctx_->GetModule()->getFunction(fn->function_name()); - CHECK_TRUE(function != nullptr, kCodegenError); + CHECK_TRUE(function != nullptr, kCodegenError, "wyldebug" + fn->function_name()); auto int16_ty = ::llvm::Type::getInt16Ty(function->getContext()); auto sext_attr = ::llvm::Attribute::AttrKind::SExt; for (size_t i = 0; i < func_ty->getNumParams(); ++i) { @@ -748,5 +752,47 @@ Status UdfIRBuilder::BuildUdafCall( return Status::OK(); } +Status UdfIRBuilder::BuildVariadicUdfCall(const node::VariadicUdfDefNode* fn, + const std::vector& arg_types, + const std::vector& args, + NativeValue* output) { + CHECK_TRUE(arg_types.size() == args.size(), kCodegenError); + CHECK_TRUE(fn->GetArgSize() == args.size(), kCodegenError); + std::vector cur_state_values(1 + fn->update_func().size()); + std::vector init_arg_types; + std::vector init_args; + for (size_t i = 0; i < fn->init_func()->GetArgSize(); ++i) { + CHECK_TRUE(i <= args.size(), kCodegenError); + init_arg_types.push_back(arg_types[i]); + init_args.push_back(args[i]); + } + UdfIRBuilder sub_udf_builder_init(ctx_, frame_arg_, frame_); + CHECK_STATUS(sub_udf_builder_init.BuildCall(fn->init_func(), + init_arg_types, init_args, &cur_state_values[0])); + + const node::TypeNode* cur_state_value_type = fn->init_func()->GetReturnType(); + for (size_t i = 0; i < fn->update_func().size(); ++i) { + std::vector update_arg_types = { + cur_state_value_type, arg_types[fn->init_func()->GetArgSize() + i] + }; + std::vector update_args = { + cur_state_values[i], args[fn->init_func()->GetArgSize() + i] + }; + UdfIRBuilder sub_udf_builder_update(ctx_, frame_arg_, frame_); + CHECK_STATUS(sub_udf_builder_update.BuildCall(fn->update_func()[i], + update_arg_types, update_args, &cur_state_values[i + 1])); + cur_state_value_type = fn->update_func()[i]->GetReturnType(); + } + + NativeValue local_output; + std::vector output_arg_types = {cur_state_value_type}; + std::vector output_args = {cur_state_values.back()}; + UdfIRBuilder sub_udf_builder_output(ctx_, frame_arg_, frame_); + CHECK_STATUS(sub_udf_builder_output.BuildCall(fn->output_func(), + output_arg_types, output_args, &local_output)); + *output = local_output; + return Status::OK(); +} + } // namespace codegen } // namespace hybridse diff --git a/hybridse/src/codegen/udf_ir_builder.h b/hybridse/src/codegen/udf_ir_builder.h index 9e33837bf96..ef3ff8976b5 100644 --- a/hybridse/src/codegen/udf_ir_builder.h +++ b/hybridse/src/codegen/udf_ir_builder.h @@ -62,6 +62,11 @@ class UdfIRBuilder { const std::vector& args, NativeValue* output); + Status BuildVariadicUdfCall(const node::VariadicUdfDefNode* fn, + const std::vector& arg_types, + const std::vector& args, + NativeValue* output); + Status GetUdfCallee(const node::UdfDefNode* fn, ::llvm::FunctionCallee* callee, bool* return_by_arg); diff --git a/hybridse/src/node/expr_node.cc b/hybridse/src/node/expr_node.cc index 94b7613d3cc..18d32ff5634 100644 --- a/hybridse/src/node/expr_node.cc +++ b/hybridse/src/node/expr_node.cc @@ -1149,6 +1149,20 @@ UdafDefNode* UdafDefNode::DeepCopy(NodeManager* nm) const { new_merge, new_output); } +VariadicUdfDefNode* VariadicUdfDefNode::ShadowCopy(NodeManager* nm) const { + return nm->MakeVariadicUdfDefNode(name_, init_, update_, output_); +} + +VariadicUdfDefNode* VariadicUdfDefNode::DeepCopy(NodeManager* nm) const { + FnDefNode* new_init = init_ ? init_->DeepCopy(nm) : nullptr; + std::vector new_update; + for (FnDefNode* update_func: update_) { + new_update.push_back(update_func ? update_func->DeepCopy(nm): nullptr); + } + FnDefNode* new_output = output_ ? output_->DeepCopy(nm) : nullptr; + return nm->MakeVariadicUdfDefNode(name_, new_init, new_update, new_output); +} + // Default expr deep copy: shadow copy self and deep copy children ExprNode* ExprNode::DeepCopy(NodeManager* nm) const { auto root = this->ShadowCopy(nm); diff --git a/hybridse/src/node/node_manager.cc b/hybridse/src/node/node_manager.cc index 5b1d18e5973..7acba697ee9 100644 --- a/hybridse/src/node/node_manager.cc +++ b/hybridse/src/node/node_manager.cc @@ -1008,6 +1008,14 @@ LambdaNode *NodeManager::MakeLambdaNode(const std::vector &args, E return RegisterNode(new node::LambdaNode(args, body)); } +node::VariadicUdfDefNode *NodeManager::MakeVariadicUdfDefNode(const std::string &name, + FnDefNode *init_func, + const std::vector& update_func, + FnDefNode *output_func) { + return RegisterNode(new node::VariadicUdfDefNode(name, init_func, update_func, output_func)); +} + + CondExpr *NodeManager::MakeCondExpr(ExprNode *condition, ExprNode *left, ExprNode *right) { return RegisterNode(new CondExpr(condition, left, right)); } diff --git a/hybridse/src/node/sql_node.cc b/hybridse/src/node/sql_node.cc index 478805c5f05..69f380c51e0 100644 --- a/hybridse/src/node/sql_node.cc +++ b/hybridse/src/node/sql_node.cc @@ -1159,6 +1159,7 @@ static absl::flat_hash_map CreateSqlNodeTypeToNa {kUdfByCodeGenDef, "kUdfByCodeGenDef"}, {kUdafDef, "kUdafDef"}, {kLambdaDef, "kLambdaDef"}, + {kVariadicUdfDef, "kVariadicUdfDef"}, {kPartitionMeta, "kPartitionMeta"}, {kCreateIndexStmt, "kCreateIndexStmt"}, {kInsertStmt, "kInsertStmt"}, @@ -2549,6 +2550,26 @@ void UdafDefNode::Print(std::ostream &output, const std::string &org_tab) const PrintSqlNode(output, tab, output_, "output", true); } +void VariadicUdfDefNode::Print(std::ostream &output, const std::string &tab) const { + output << tab << "[kVariadicUdfDef] " << name_; +} + +bool VariadicUdfDefNode::Equals(const SqlNode *node) const { + auto other = dynamic_cast(node); + if (other != nullptr) { + return false; + } + if (name_ != other->name_ || update_.size() != other->update_.size()) { + return false; + } + for (size_t i = 0; i < update_.size(); ++i) { + if (!FnDefEquals(update_[i], other->update_[i])) { + return false; + } + } + return FnDefEquals(init_, other->init_) && FnDefEquals(output_, other->output_); +} + void CondExpr::Print(std::ostream &output, const std::string &org_tab) const { output << org_tab << "[kCondExpr]" << "\n"; diff --git a/hybridse/src/passes/physical/batch_request_optimize_test.cc b/hybridse/src/passes/physical/batch_request_optimize_test.cc index 48259b68ed4..223de7db80c 100644 --- a/hybridse/src/passes/physical/batch_request_optimize_test.cc +++ b/hybridse/src/passes/physical/batch_request_optimize_test.cc @@ -48,6 +48,9 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( BatchRequestUdafQuery, BatchRequestOptimizeTest, testing::ValuesIn(sqlcase::InitCases("cases/query/udaf_query.yaml"))); +INSTANTIATE_TEST_SUITE_P( + BatchRequestFeatureSignatureQuery, BatchRequestOptimizeTest, + testing::ValuesIn(sqlcase::InitCases("cases/query/feature_signature_query.yaml"))); INSTANTIATE_TEST_SUITE_P( BatchRequestExtreamQuery, BatchRequestOptimizeTest, testing::ValuesIn(sqlcase::InitCases("cases/query/extream_query.yaml"))); diff --git a/hybridse/src/testing/engine_test_base.cc b/hybridse/src/testing/engine_test_base.cc index 3aebea8f2de..6c5e68879f9 100644 --- a/hybridse/src/testing/engine_test_base.cc +++ b/hybridse/src/testing/engine_test_base.cc @@ -528,6 +528,8 @@ INSTANTIATE_TEST_SUITE_P(EngineParameterizedQuery, EngineTest, testing::ValuesIn(sqlcase::InitCases("cases/query/parameterized_query.yaml"))); INSTANTIATE_TEST_SUITE_P(EngineUdafQuery, EngineTest, testing::ValuesIn(sqlcase::InitCases("cases/query/udaf_query.yaml"))); +INSTANTIATE_TEST_SUITE_P(EngineFeatureSignatureQuery, EngineTest, + testing::ValuesIn(sqlcase::InitCases("cases/query/feature_signature_query.yaml"))); INSTANTIATE_TEST_SUITE_P(EngineExtreamQuery, EngineTest, testing::ValuesIn(sqlcase::InitCases("cases/query/extream_query.yaml"))); diff --git a/hybridse/src/udf/default_defs/feature_signature_def.cc b/hybridse/src/udf/default_defs/feature_signature_def.cc new file mode 100644 index 00000000000..a964ae71678 --- /dev/null +++ b/hybridse/src/udf/default_defs/feature_signature_def.cc @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2022 4Paradigm Authors + * + * Licensed 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 "absl/strings/str_split.h" +#include "udf/default_udf_library.h" +#include "udf/udf.h" +#include "udf/udf_registry.h" + +namespace hybridse { +namespace udf { + +namespace v1 { + +struct VariadicConcat { + static void Init(StringRef* value, std::string* addr) { + new (addr) std::string(value->data_); + } + + template + static std::string* Update(std::string* state, V value) { + state->append(" ").append(std::to_string(value)); + return state; + } + + static void Output(std::string* state, StringRef* output) { + char* buffer = AllocManagedStringBuf(state->size() + 1); + memcpy(buffer, state->c_str(), state->size()); + buffer[state->size()] = 0; + output->data_ = buffer; + output->size_ = state->size(); + state->~basic_string(); + } +}; + +} // namespace v1 + +void DefaultUdfLibrary::InitFeatureSignature() { + RegisterVariadicUdf("variadic_concat").init(v1::VariadicConcat::Init) + .update, int32_t>(v1::VariadicConcat::Update) + .update, float>(v1::VariadicConcat::Update) + .update, double>(v1::VariadicConcat::Update) + .output>(v1::VariadicConcat::Output); +} + +} // namespace udf +} // namespace hybridse diff --git a/hybridse/src/udf/default_udf_library.cc b/hybridse/src/udf/default_udf_library.cc index 265a1e09250..0ab0171695b 100644 --- a/hybridse/src/udf/default_udf_library.cc +++ b/hybridse/src/udf/default_udf_library.cc @@ -662,6 +662,7 @@ void DefaultUdfLibrary::Init() { InitWindowFunctions(); InitUdaf(); + InitFeatureSignature(); InitFeatureZero(); InitArrayUdfs(); diff --git a/hybridse/src/udf/default_udf_library.h b/hybridse/src/udf/default_udf_library.h index 92152649fa0..bb90e9cf278 100644 --- a/hybridse/src/udf/default_udf_library.h +++ b/hybridse/src/udf/default_udf_library.h @@ -47,6 +47,7 @@ class DefaultUdfLibrary : public UdfLibrary { void InitMinByCateUdafs(); void initMaxByCateUdaFs(); void InitAvgByCateUdafs(); + void InitFeatureSignature(); void InitFeatureZero(); // Array Udf defines, udfs either accept array as parameter or returns array diff --git a/hybridse/src/udf/udf_library.h b/hybridse/src/udf/udf_library.h index 5122a85a697..f70d7e8c962 100644 --- a/hybridse/src/udf/udf_library.h +++ b/hybridse/src/udf/udf_library.h @@ -65,6 +65,9 @@ class UdafTemplateRegistryHelper; template