123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- #pragma once
- #include "udf_value.h"
- #include "udf_registrator.h"
- #include "udf_value_builder.h"
- #include "udf_terminator.h"
- #include "udf_type_builder.h"
- #include "udf_type_inspection.h"
- #include "udf_version.h"
- #include "udf_type_printer.h"
- #include <util/generic/yexception.h>
- #include <util/generic/string.h>
- #include <util/generic/strbuf.h>
- #include <util/string/builder.h>
- namespace NYql {
- namespace NUdf {
- inline TSourcePosition GetSourcePosition(IFunctionTypeInfoBuilder& builder) {
- #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 9)
- return builder.GetSourcePosition();
- #else
- Y_UNUSED(builder);
- return {};
- #endif
- }
- TString LoadResourceOnce(TStringBuf resourceId);
- inline void SetIRImplementation(IFunctionTypeInfoBuilder& builder, TStringBuf resourceId, TStringBuf functionName) {
- #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 16)
- if (functionName) {
- builder.IRImplementation(LoadResourceOnce(resourceId), resourceId, functionName);
- }
- #else
- Y_UNUSED(builder);
- Y_UNUSED(resourceId);
- Y_UNUSED(functionName);
- #endif
- }
- }
- }
- #define UDF_IMPL_EX(udfName, typeBody, members, init, irResourceId, irFunctionName, blockType, create_impl) \
- class udfName: public ::NYql::NUdf::TBoxedValue { \
- public: \
- using TBlockType = blockType; \
- explicit udfName(::NYql::NUdf::IFunctionTypeInfoBuilder& builder) \
- : Pos_(GetSourcePosition(builder)) \
- { \
- init \
- } \
- static const ::NYql::NUdf::TStringRef& Name() { \
- static auto name = ::NYql::NUdf::TStringRef::Of(#udfName).Substring(1, 256); \
- return name; \
- } \
- inline ::NYql::NUdf::TUnboxedValue RunImpl( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const; \
- ::NYql::NUdf::TUnboxedValue Run( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const override { \
- try { \
- return RunImpl(valueBuilder, args); \
- } catch (const std::exception&) { \
- TStringBuilder sb; \
- sb << Pos_ << " "; \
- sb << CurrentExceptionMessage(); \
- sb << Endl << "[" << TStringBuf(Name()) << "]" ; \
- UdfTerminate(sb.c_str()); \
- } \
- } \
- static bool DeclareSignature( \
- const ::NYql::NUdf::TStringRef& name, \
- ::NYql::NUdf::TType* userType, \
- ::NYql::NUdf::IFunctionTypeInfoBuilder& builder, \
- bool typesOnly) { \
- Y_UNUSED(userType); \
- if (Name() == name) { \
- typeBody if (!typesOnly) { \
- create_impl \
- SetIRImplementation(builder, irResourceId, irFunctionName); \
- } \
- return true; \
- } \
- return false; \
- } \
- ::NYql::NUdf::TSourcePosition GetPos() const { return Pos_; } \
- private: \
- ::NYql::NUdf::TSourcePosition Pos_; \
- members \
- }; \
- ::NYql::NUdf::TUnboxedValue udfName::RunImpl( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const
- #define UDF_IMPL(udfName, typeBody, members, init, irResourceId, irFunctionName, blockType) \
- UDF_IMPL_EX(udfName, typeBody, members, init, irResourceId, irFunctionName, blockType, builder.Implementation(new udfName(builder));)
- #define UDF(udfName, typeBody) UDF_IMPL(udfName, typeBody, ;, ;, "", "", void)
- #define UDF_RUN_IMPL(udfName, typeBody, members, init, irResourceId, irFunctionName) \
- struct udfName##Members { \
- members \
- }; \
- \
- class udfName: public ::NYql::NUdf::TBoxedValue, public udfName##Members { \
- public: \
- explicit udfName(::NYql::NUdf::IFunctionTypeInfoBuilder& builder) \
- : Pos_(GetSourcePosition(builder)) \
- { \
- init \
- } \
- static const ::NYql::NUdf::TStringRef& Name() { \
- static auto name = ::NYql::NUdf::TStringRef::Of(#udfName).Substring(1, 256); \
- return name; \
- } \
- class TImpl: public TBoxedValue, public udfName##Members { \
- public: \
- TImpl(const udfName##Members& parent, \
- const ::NYql::NUdf::TUnboxedValuePod& runConfig, \
- ::NYql::NUdf::TSourcePosition pos) \
- : udfName##Members(parent) \
- , RunConfig(::NYql::NUdf::TUnboxedValuePod(runConfig)) \
- , Pos_(pos) \
- {} \
- inline ::NYql::NUdf::TUnboxedValue RunImpl( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const; \
- ::NYql::NUdf::TUnboxedValue Run( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const override { \
- try { \
- return RunImpl(valueBuilder, args); \
- } catch (const std::exception&) { \
- TStringBuilder sb; \
- sb << Pos_ << " "; \
- sb << CurrentExceptionMessage(); \
- sb << Endl << "[" << TStringBuf(Name()) << "]" ; \
- UdfTerminate(sb.c_str()); \
- } \
- } \
- \
- private: \
- ::NYql::NUdf::TUnboxedValue RunConfig; \
- ::NYql::NUdf::TSourcePosition Pos_; \
- }; \
- ::NYql::NUdf::TUnboxedValue Run( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const override { \
- Y_UNUSED(valueBuilder); \
- return ::NYql::NUdf::TUnboxedValuePod(new TImpl(*this, args[0], Pos_)); \
- } \
- static bool DeclareSignature( \
- const ::NYql::NUdf::TStringRef& name, \
- ::NYql::NUdf::TType* userType, \
- ::NYql::NUdf::IFunctionTypeInfoBuilder& builder, \
- bool typesOnly) { \
- Y_UNUSED(userType); \
- if (Name() == name) { \
- typeBody if (!typesOnly) { \
- builder.Implementation(new udfName(builder)); \
- SetIRImplementation(builder, irResourceId, irFunctionName); \
- } \
- return true; \
- } \
- return false; \
- } \
- private: \
- ::NYql::NUdf::TSourcePosition Pos_; \
- }; \
- ::NYql::NUdf::TUnboxedValue udfName::TImpl::RunImpl( \
- const ::NYql::NUdf::IValueBuilder* valueBuilder, \
- const ::NYql::NUdf::TUnboxedValuePod* args) const
- #define UDF_RUN(udfName, typeBody) UDF_RUN_IMPL(udfName, typeBody, ;, ;, "", "")
- #define SIMPLE_UDF_IMPL_EX(udfName, typeBody, signature, irResourceId, irFunctionName, blockType, create_impl) \
- UDF_IMPL_EX(udfName, typeBody, const ::NYql::NUdf::TType* ReturnType_;, ReturnType_ = ::NYql::NUdf::NImpl::TSimpleSignatureHelper<signature>::BuildReturnType(builder);, irResourceId, irFunctionName, blockType, create_impl)
- #define SIMPLE_UDF_IMPL(udfName, typeBody, signature, irResourceId, irFunctionName, blockType) \
- SIMPLE_UDF_IMPL_EX(udfName, typeBody, signature, irResourceId, irFunctionName, blockType, builder.Implementation(new udfName(builder));)
- #define SIMPLE_UDF(udfName, signature) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>();, signature, "", "", void)
- #define SIMPLE_STRICT_UDF(udfName, signature) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>().IsStrict();, signature, "", "", void)
- #define SIMPLE_STRICT_UDF_WITH_IR(udfName, signature, optionalArgsCount, irResourceId, irFunctionName) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>().OptionalArgs(optionalArgsCount).IsStrict();, signature, irResourceId, irFunctionName, void)
- #define SIMPLE_UDF_WITH_CREATE_IMPL(udfName, signature, create_impl) \
- SIMPLE_UDF_IMPL_EX(udfName, builder.SimpleSignature<signature>();, signature, "", "", void, create_impl)
- #define SIMPLE_UDF_OPTIONS(udfName, signature, options) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>(); options;, signature, "", "", void)
- #define SIMPLE_UDF_WITH_OPTIONAL_ARGS(udfName, signature, optionalArgsCount) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>().OptionalArgs(optionalArgsCount);, signature, "", "", void)
- #define SIMPLE_STRICT_UDF_OPTIONS(udfName, signature, options) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>().IsStrict(); options;, signature, "", "", void)
- #define SIMPLE_STRICT_UDF_WITH_OPTIONAL_ARGS(udfName, signature, optionalArgsCount) \
- SIMPLE_UDF_IMPL(udfName, builder.SimpleSignature<signature>().OptionalArgs(optionalArgsCount).IsStrict();, signature, "", "", void)
- #define SIMPLE_UDF_RUN_OPTIONS(udfName, signature, options) \
- UDF_RUN(udfName, builder.SimpleSignature<signature>(); options;)
- #define SIMPLE_UDF_RUN(udfName, signature, runConfigSignature) \
- SIMPLE_UDF_RUN_OPTIONS(udfName, signature, builder.RunConfig<runConfigSignature>())
- #define SIMPLE_MODULE(moduleName, ...) \
- class moduleName: public ::NYql::NUdf::TSimpleUdfModuleHelper<__VA_ARGS__> { \
- public: \
- ::NYql::NUdf::TStringRef Name() const { \
- auto name = ::NYql::NUdf::TStringRef::Of(#moduleName); \
- return name.Substring(1, name.Size() - 7); \
- } \
- };
- #define EMPTY_RESULT_ON_EMPTY_ARG(n) \
- if (!args[n]) { \
- return ::NYql::NUdf::TUnboxedValue(); \
- }
- namespace NYql {
- namespace NUdf {
- template<bool CheckOptional, bool CheckBlock, const char* TFuncName, template<class> class TFunc, typename... TUserTypes>
- class TUserDataTypeFuncFactory : public ::NYql::NUdf::TBoxedValue {
- public:
- typedef bool TTypeAwareMarker;
- public:
- static const ::NYql::NUdf::TStringRef& Name() {
- static auto name = ::NYql::NUdf::TStringRef(TFuncName, std::strlen(TFuncName));
- return name;
- }
- static const TType* ExtractArgFromUserType(::NYql::NUdf::TType const* userType, ::NYql::NUdf::IFunctionTypeInfoBuilder& builder) {
- if constexpr (CheckBlock) {
- #if UDF_ABI_COMPATIBILITY_VERSION_CURRENT >= UDF_ABI_COMPATIBILITY_VERSION(2, 26)
- TBlockTypeInspector block(*builder.TypeInfoHelper(), userType);
- if (block) {
- userType = block.GetItemType();
- }
- #endif
- }
- if constexpr (CheckOptional) {
- TOptionalTypeInspector optionalTypeInspector(*builder.TypeInfoHelper(), userType);
- if (optionalTypeInspector) {
- userType = optionalTypeInspector.GetItemType();
- }
- }
- return userType;
- }
- template<typename TUserType>
- static bool DeclareSignatureImpl(
- const ::NYql::NUdf::TStringRef& name,
- TDataTypeId typeId,
- ::NYql::NUdf::TType* userType,
- ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
- bool typesOnly)
- {
- if (TDataType<TUserType>::Id != typeId) {
- return false;
- }
- TFunc<TUserType>::DeclareSignature(name, userType, builder, typesOnly);
- return true;
- }
- template<typename TUserType, typename THead, typename... TTail>
- static bool DeclareSignatureImpl(
- const ::NYql::NUdf::TStringRef& name,
- TDataTypeId typeId,
- ::NYql::NUdf::TType* userType,
- ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
- bool typesOnly)
- {
- if (DeclareSignatureImpl<TUserType>(name, typeId, userType, builder, typesOnly)) {
- return true;
- }
- return DeclareSignatureImpl<THead, TTail...>(name, typeId, userType, builder, typesOnly);
- }
- static bool DeclareSignature(
- const ::NYql::NUdf::TStringRef& name,
- ::NYql::NUdf::TType* userType,
- ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
- bool typesOnly)
- {
- if (Name() != name) {
- // the only case when we return false
- return false;
- }
- if (!userType) {
- builder.SetError("User type is not specified");
- return true;
- }
- auto typeHelper = builder.TypeInfoHelper();
- auto userTypeInspector = TTupleTypeInspector(*typeHelper, userType);
- if (!userTypeInspector || userTypeInspector.GetElementsCount() < 1) {
- builder.SetError("Missing or invalid user type");
- return true;
- }
- auto argsTypeInspector = TTupleTypeInspector(*typeHelper, userTypeInspector.GetElementType(0));
- if (!argsTypeInspector || argsTypeInspector.GetElementsCount() < 1) {
- builder.SetError("Missing or invalid user type arguments");
- return true;
- }
- auto argType = ExtractArgFromUserType(argsTypeInspector.GetElementType(0), builder);
- TDataTypeInspector dataTypeInspector(*typeHelper, argType);
- if (!dataTypeInspector) {
- TStringStream ss;
- NUdf::TTypePrinter p(*typeHelper, argType);
- p.Out(ss);
- builder.SetError("User type must be a data type. Got: " + ss.Str());
- return true;
- }
- builder.UserType(userType);
- auto typeId = dataTypeInspector.GetTypeId();
- if (!DeclareSignatureImpl<TUserTypes...>(name, typeId, userType, builder, typesOnly)) {
- TStringBuilder sb;
- sb << "User type " << NYql::NUdf::GetDataTypeInfo(NYql::NUdf::GetDataSlot(typeId)).Name << " is not supported";
- builder.SetError(sb);
- }
- return true;
- }
- };
- template<typename... TUdfs>
- class TSimpleUdfModuleHelper : public IUdfModule
- {
- Y_HAS_SUBTYPE(TTypeAwareMarker);
- Y_HAS_SUBTYPE(TBlockType);
- public:
- void CleanupOnTerminate() const override {
- }
- template<typename TUdfType>
- void GetAllFunctionsImpl(IFunctionNamesSink& names) const {
- auto r = names.Add(TUdfType::Name());
- if (THasTTypeAwareMarker<TUdfType>::value) {
- r->SetTypeAwareness();
- }
- if constexpr (THasTBlockType<TUdfType>::value) {
- if constexpr (!std::is_same_v<typename TUdfType::TBlockType, void>) {
- auto rBlocks = names.Add(TUdfType::TBlockType::Name());
- rBlocks->SetTypeAwareness();
- }
- }
- }
- template<typename THead1, typename THead2, typename... TTail>
- void GetAllFunctionsImpl(IFunctionNamesSink& names) const {
- GetAllFunctionsImpl<THead1>(names);
- GetAllFunctionsImpl<THead2, TTail...>(names);
- }
- template<typename TUdfType>
- bool BuildFunctionTypeInfoImpl(
- const TStringRef& name,
- TType* userType,
- const TStringRef& typeConfig,
- ui32 flags,
- IFunctionTypeInfoBuilder& builder) const
- {
- Y_UNUSED(typeConfig);
- bool typesOnly = (flags & TFlags::TypesOnly);
- bool found = TUdfType::DeclareSignature(name, userType, builder, typesOnly);
- if (!found) {
- if constexpr (THasTBlockType<TUdfType>::value) {
- if constexpr (!std::is_same_v<typename TUdfType::TBlockType, void>) {
- found = TUdfType::TBlockType::DeclareSignature(name, userType, builder, typesOnly);
- }
- }
- }
- return found;
- }
- template<typename THead1, typename THead2, typename... TTail>
- bool BuildFunctionTypeInfoImpl(
- const TStringRef& name,
- TType* userType,
- const TStringRef& typeConfig,
- ui32 flags,
- IFunctionTypeInfoBuilder& builder) const
- {
- bool found = BuildFunctionTypeInfoImpl<THead1>(name, userType, typeConfig, flags, builder);
- if (!found) {
- found = BuildFunctionTypeInfoImpl<THead2, TTail...>(name, userType, typeConfig, flags, builder);
- }
- return found;
- }
- void GetAllFunctions(IFunctionsSink& sink) const final {
- GetAllFunctionsImpl<TUdfs...>(sink);
- }
- void BuildFunctionTypeInfo(
- const TStringRef& name,
- TType* userType,
- const TStringRef& typeConfig,
- ui32 flags,
- IFunctionTypeInfoBuilder& builder) const override
- {
- try {
- bool found = BuildFunctionTypeInfoImpl<TUdfs...>(name, userType, typeConfig, flags, builder);
- if (!found) {
- TStringBuilder sb;
- sb << "Unknown function: " << name.Data();
- builder.SetError(sb);
- }
- } catch (const std::exception&) {
- builder.SetError(CurrentExceptionMessage());
- }
- }
- };
- } // namspace NUdf
- } // namspace NYql
|