123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- #include "mkql_frombytes.h"
- #include <yql/essentials/minikql/computation/mkql_computation_node_holders.h>
- #include <yql/essentials/minikql/mkql_node_builder.h>
- #include <yql/essentials/minikql/mkql_node_cast.h>
- #include <yql/essentials/public/udf/tz/udf_tz.h>
- #include <yql/essentials/utils/swap_bytes.h>
- #include <yql/essentials/types/binary_json/read.h>
- #include <util/system/unaligned_mem.h>
- namespace NKikimr {
- namespace NMiniKQL {
- namespace {
- using NYql::SwapBytes;
- template <bool IsOptional>
- class TFromBytesWrapper : public TMutableComputationNode<TFromBytesWrapper<IsOptional>> {
- typedef TMutableComputationNode<TFromBytesWrapper<IsOptional>> TBaseComputation;
- public:
- TFromBytesWrapper(TComputationMutables& mutables, IComputationNode* data, NUdf::TDataTypeId schemeType, ui32 param1, ui32 param2)
- : TBaseComputation(mutables)
- , Data(data)
- , SchemeType(NUdf::GetDataSlot(schemeType))
- , Param1(param1)
- , Param2(param2)
- {
- if (SchemeType == NUdf::EDataSlot::Decimal) {
- DecimalBound = NYql::NDecimal::TInt128(1);
- NYql::NDecimal::TInt128 ten(10U);
- for (ui32 i = 0; i < Param1; ++i) {
- DecimalBound *= ten;
- }
- NegDecimalBound = -DecimalBound;
- }
- }
- NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
- auto data = Data->GetValue(ctx);
- if (IsOptional && !data) {
- return NUdf::TUnboxedValuePod();
- }
- switch (SchemeType) {
- case NUdf::EDataSlot::TzDate: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 4) {
- return NUdf::TUnboxedValuePod();
- }
- auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
- auto value = SwapBytes(data.Get<ui16>());
- if (value < NUdf::MAX_DATE && tzId < NUdf::GetTimezones().size()) {
- auto ret = NUdf::TUnboxedValuePod(value);
- ret.SetTimezoneId(tzId);
- return ret;
- }
- return NUdf::TUnboxedValuePod();
- }
- case NUdf::EDataSlot::TzDatetime: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 6) {
- return NUdf::TUnboxedValuePod();
- }
- auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
- auto value = SwapBytes(data.Get<ui32>());
- if (value < NUdf::MAX_DATETIME && tzId < NUdf::GetTimezones().size()) {
- auto ret = NUdf::TUnboxedValuePod(value);
- ret.SetTimezoneId(tzId);
- return ret;
- }
- return NUdf::TUnboxedValuePod();
- }
- case NUdf::EDataSlot::TzTimestamp: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 10) {
- return NUdf::TUnboxedValuePod();
- }
- auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
- auto value = SwapBytes(data.Get<ui64>());
- if (value < NUdf::MAX_TIMESTAMP && tzId < NUdf::GetTimezones().size()) {
- auto ret = NUdf::TUnboxedValuePod(value);
- ret.SetTimezoneId(tzId);
- return ret;
- }
- return NUdf::TUnboxedValuePod();
- }
- case NUdf::EDataSlot::TzDate32: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 6) {
- return NUdf::TUnboxedValuePod();
- }
- auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
- auto value = SwapBytes(data.Get<i32>());
- if (value >= NUdf::MIN_DATE32 && value <= NUdf::MAX_DATE32 && tzId < NUdf::GetTimezones().size()) {
- auto ret = NUdf::TUnboxedValuePod(value);
- ret.SetTimezoneId(tzId);
- return ret;
- }
- return NUdf::TUnboxedValuePod();
- }
- case NUdf::EDataSlot::TzDatetime64: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 10) {
- return NUdf::TUnboxedValuePod();
- }
- auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
- auto value = SwapBytes(data.Get<i64>());
- if (value >= NUdf::MIN_DATETIME64 && value <= NUdf::MAX_DATETIME64 && tzId < NUdf::GetTimezones().size()) {
- auto ret = NUdf::TUnboxedValuePod(value);
- ret.SetTimezoneId(tzId);
- return ret;
- }
- return NUdf::TUnboxedValuePod();
- }
- case NUdf::EDataSlot::TzTimestamp64: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 10) {
- return NUdf::TUnboxedValuePod();
- }
- auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
- auto value = SwapBytes(data.Get<i64>());
- if (value >= NUdf::MIN_TIMESTAMP64 && value <= NUdf::MAX_TIMESTAMP64 && tzId < NUdf::GetTimezones().size()) {
- auto ret = NUdf::TUnboxedValuePod(value);
- ret.SetTimezoneId(tzId);
- return ret;
- }
- return NUdf::TUnboxedValuePod();
- }
- case NUdf::EDataSlot::JsonDocument: {
- if (!NBinaryJson::IsValidBinaryJson(TStringBuf(data.AsStringRef()))) {
- return NUdf::TUnboxedValuePod();
- }
- return data.Release();
- }
- case NUdf::EDataSlot::Decimal: {
- const auto& ref = data.AsStringRef();
- if (ref.Size() != 15) {
- return NUdf::TUnboxedValuePod();
- }
- NYql::NDecimal::TInt128 v = 0;
- ui8* p = (ui8*)&v;
- memcpy(p, ref.Data(), 15);
- p[0xF] = (p[0xE] & 0x80) ? 0xFF : 0x00;
- if (NYql::NDecimal::IsError(v)) {
- return NUdf::TUnboxedValuePod();
- }
- if (!NYql::NDecimal::IsNormal(v)) {
- return NUdf::TUnboxedValuePod(v);
- }
- if (v >= DecimalBound) {
- return NUdf::TUnboxedValuePod(NYql::NDecimal::Inf());
- }
- if (v <= NegDecimalBound) {
- return NUdf::TUnboxedValuePod(-NYql::NDecimal::Inf());
- }
- return NUdf::TUnboxedValuePod(v);
- }
- default:
- if (IsValidValue(SchemeType, data)) {
- return data.Release();
- } else {
- return NUdf::TUnboxedValuePod();
- }
- }
- }
- private:
- void RegisterDependencies() const final {
- this->DependsOn(Data);
- }
- IComputationNode* const Data;
- const NUdf::EDataSlot SchemeType;
- const ui32 Param1;
- const ui32 Param2;
- NYql::NDecimal::TInt128 DecimalBound, NegDecimalBound;
- };
- }
- IComputationNode* WrapFromBytes(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
- MKQL_ENSURE(callable.GetInputsCount() == 2 || callable.GetInputsCount() == 4, "Expected 2 or 4 args");
- bool isOptional;
- const auto dataType = UnpackOptionalData(callable.GetInput(0), isOptional);
- MKQL_ENSURE(dataType->GetSchemeType() == NUdf::TDataType<char*>::Id, "Expected String");
- const auto schemeTypeData = AS_VALUE(TDataLiteral, callable.GetInput(1));
- const auto schemeType = schemeTypeData->AsValue().Get<ui32>();
- ui32 param1 = 0;
- ui32 param2 = 0;
- if (schemeType == NUdf::TDataType<NUdf::TDecimal>::Id) {
- MKQL_ENSURE(callable.GetInputsCount() == 4, "Expected 4 args");
- const auto param1Data = AS_VALUE(TDataLiteral, callable.GetInput(2));
- param1 = param1Data->AsValue().Get<ui32>();
- const auto param2Data = AS_VALUE(TDataLiteral, callable.GetInput(3));
- param2 = param2Data->AsValue().Get<ui32>();
- } else {
- MKQL_ENSURE(callable.GetInputsCount() == 2, "Expected 2 args");
- }
- const auto data = LocateNode(ctx.NodeLocator, callable, 0);
- if (isOptional) {
- return new TFromBytesWrapper<true>(ctx.Mutables, data, static_cast<NUdf::TDataTypeId>(schemeType), param1, param2);
- } else {
- return new TFromBytesWrapper<false>(ctx.Mutables, data, static_cast<NUdf::TDataTypeId>(schemeType), param1, param2);
- }
- }
- }
- }
|