mkql_frombytes.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #include "mkql_frombytes.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_holders.h>
  3. #include <yql/essentials/minikql/mkql_node_builder.h>
  4. #include <yql/essentials/minikql/mkql_node_cast.h>
  5. #include <yql/essentials/public/udf/tz/udf_tz.h>
  6. #include <yql/essentials/utils/swap_bytes.h>
  7. #include <yql/essentials/types/binary_json/read.h>
  8. #include <util/system/unaligned_mem.h>
  9. namespace NKikimr {
  10. namespace NMiniKQL {
  11. namespace {
  12. using NYql::SwapBytes;
  13. template <bool IsOptional>
  14. class TFromBytesWrapper : public TMutableComputationNode<TFromBytesWrapper<IsOptional>> {
  15. typedef TMutableComputationNode<TFromBytesWrapper<IsOptional>> TBaseComputation;
  16. public:
  17. TFromBytesWrapper(TComputationMutables& mutables, IComputationNode* data, NUdf::TDataTypeId schemeType, ui32 param1, ui32 param2)
  18. : TBaseComputation(mutables)
  19. , Data(data)
  20. , SchemeType(NUdf::GetDataSlot(schemeType))
  21. , Param1(param1)
  22. , Param2(param2)
  23. {
  24. if (SchemeType == NUdf::EDataSlot::Decimal) {
  25. DecimalBound = NYql::NDecimal::TInt128(1);
  26. NYql::NDecimal::TInt128 ten(10U);
  27. for (ui32 i = 0; i < Param1; ++i) {
  28. DecimalBound *= ten;
  29. }
  30. NegDecimalBound = -DecimalBound;
  31. }
  32. }
  33. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  34. auto data = Data->GetValue(ctx);
  35. if (IsOptional && !data) {
  36. return NUdf::TUnboxedValuePod();
  37. }
  38. switch (SchemeType) {
  39. case NUdf::EDataSlot::TzDate: {
  40. const auto& ref = data.AsStringRef();
  41. if (ref.Size() != 4) {
  42. return NUdf::TUnboxedValuePod();
  43. }
  44. auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
  45. auto value = SwapBytes(data.Get<ui16>());
  46. if (value < NUdf::MAX_DATE && tzId < NUdf::GetTimezones().size()) {
  47. auto ret = NUdf::TUnboxedValuePod(value);
  48. ret.SetTimezoneId(tzId);
  49. return ret;
  50. }
  51. return NUdf::TUnboxedValuePod();
  52. }
  53. case NUdf::EDataSlot::TzDatetime: {
  54. const auto& ref = data.AsStringRef();
  55. if (ref.Size() != 6) {
  56. return NUdf::TUnboxedValuePod();
  57. }
  58. auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
  59. auto value = SwapBytes(data.Get<ui32>());
  60. if (value < NUdf::MAX_DATETIME && tzId < NUdf::GetTimezones().size()) {
  61. auto ret = NUdf::TUnboxedValuePod(value);
  62. ret.SetTimezoneId(tzId);
  63. return ret;
  64. }
  65. return NUdf::TUnboxedValuePod();
  66. }
  67. case NUdf::EDataSlot::TzTimestamp: {
  68. const auto& ref = data.AsStringRef();
  69. if (ref.Size() != 10) {
  70. return NUdf::TUnboxedValuePod();
  71. }
  72. auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
  73. auto value = SwapBytes(data.Get<ui64>());
  74. if (value < NUdf::MAX_TIMESTAMP && tzId < NUdf::GetTimezones().size()) {
  75. auto ret = NUdf::TUnboxedValuePod(value);
  76. ret.SetTimezoneId(tzId);
  77. return ret;
  78. }
  79. return NUdf::TUnboxedValuePod();
  80. }
  81. case NUdf::EDataSlot::TzDate32: {
  82. const auto& ref = data.AsStringRef();
  83. if (ref.Size() != 6) {
  84. return NUdf::TUnboxedValuePod();
  85. }
  86. auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
  87. auto value = SwapBytes(data.Get<i32>());
  88. if (value >= NUdf::MIN_DATE32 && value <= NUdf::MAX_DATE32 && tzId < NUdf::GetTimezones().size()) {
  89. auto ret = NUdf::TUnboxedValuePod(value);
  90. ret.SetTimezoneId(tzId);
  91. return ret;
  92. }
  93. return NUdf::TUnboxedValuePod();
  94. }
  95. case NUdf::EDataSlot::TzDatetime64: {
  96. const auto& ref = data.AsStringRef();
  97. if (ref.Size() != 10) {
  98. return NUdf::TUnboxedValuePod();
  99. }
  100. auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
  101. auto value = SwapBytes(data.Get<i64>());
  102. if (value >= NUdf::MIN_DATETIME64 && value <= NUdf::MAX_DATETIME64 && tzId < NUdf::GetTimezones().size()) {
  103. auto ret = NUdf::TUnboxedValuePod(value);
  104. ret.SetTimezoneId(tzId);
  105. return ret;
  106. }
  107. return NUdf::TUnboxedValuePod();
  108. }
  109. case NUdf::EDataSlot::TzTimestamp64: {
  110. const auto& ref = data.AsStringRef();
  111. if (ref.Size() != 10) {
  112. return NUdf::TUnboxedValuePod();
  113. }
  114. auto tzId = SwapBytes(ReadUnaligned<ui16>(ref.Data() + ref.Size() - sizeof(ui16)));
  115. auto value = SwapBytes(data.Get<i64>());
  116. if (value >= NUdf::MIN_TIMESTAMP64 && value <= NUdf::MAX_TIMESTAMP64 && tzId < NUdf::GetTimezones().size()) {
  117. auto ret = NUdf::TUnboxedValuePod(value);
  118. ret.SetTimezoneId(tzId);
  119. return ret;
  120. }
  121. return NUdf::TUnboxedValuePod();
  122. }
  123. case NUdf::EDataSlot::JsonDocument: {
  124. if (!NBinaryJson::IsValidBinaryJson(TStringBuf(data.AsStringRef()))) {
  125. return NUdf::TUnboxedValuePod();
  126. }
  127. return data.Release();
  128. }
  129. case NUdf::EDataSlot::Decimal: {
  130. const auto& ref = data.AsStringRef();
  131. if (ref.Size() != 15) {
  132. return NUdf::TUnboxedValuePod();
  133. }
  134. NYql::NDecimal::TInt128 v = 0;
  135. ui8* p = (ui8*)&v;
  136. memcpy(p, ref.Data(), 15);
  137. p[0xF] = (p[0xE] & 0x80) ? 0xFF : 0x00;
  138. if (NYql::NDecimal::IsError(v)) {
  139. return NUdf::TUnboxedValuePod();
  140. }
  141. if (!NYql::NDecimal::IsNormal(v)) {
  142. return NUdf::TUnboxedValuePod(v);
  143. }
  144. if (v >= DecimalBound) {
  145. return NUdf::TUnboxedValuePod(NYql::NDecimal::Inf());
  146. }
  147. if (v <= NegDecimalBound) {
  148. return NUdf::TUnboxedValuePod(-NYql::NDecimal::Inf());
  149. }
  150. return NUdf::TUnboxedValuePod(v);
  151. }
  152. default:
  153. if (IsValidValue(SchemeType, data)) {
  154. return data.Release();
  155. } else {
  156. return NUdf::TUnboxedValuePod();
  157. }
  158. }
  159. }
  160. private:
  161. void RegisterDependencies() const final {
  162. this->DependsOn(Data);
  163. }
  164. IComputationNode* const Data;
  165. const NUdf::EDataSlot SchemeType;
  166. const ui32 Param1;
  167. const ui32 Param2;
  168. NYql::NDecimal::TInt128 DecimalBound, NegDecimalBound;
  169. };
  170. }
  171. IComputationNode* WrapFromBytes(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  172. MKQL_ENSURE(callable.GetInputsCount() == 2 || callable.GetInputsCount() == 4, "Expected 2 or 4 args");
  173. bool isOptional;
  174. const auto dataType = UnpackOptionalData(callable.GetInput(0), isOptional);
  175. MKQL_ENSURE(dataType->GetSchemeType() == NUdf::TDataType<char*>::Id, "Expected String");
  176. const auto schemeTypeData = AS_VALUE(TDataLiteral, callable.GetInput(1));
  177. const auto schemeType = schemeTypeData->AsValue().Get<ui32>();
  178. ui32 param1 = 0;
  179. ui32 param2 = 0;
  180. if (schemeType == NUdf::TDataType<NUdf::TDecimal>::Id) {
  181. MKQL_ENSURE(callable.GetInputsCount() == 4, "Expected 4 args");
  182. const auto param1Data = AS_VALUE(TDataLiteral, callable.GetInput(2));
  183. param1 = param1Data->AsValue().Get<ui32>();
  184. const auto param2Data = AS_VALUE(TDataLiteral, callable.GetInput(3));
  185. param2 = param2Data->AsValue().Get<ui32>();
  186. } else {
  187. MKQL_ENSURE(callable.GetInputsCount() == 2, "Expected 2 args");
  188. }
  189. const auto data = LocateNode(ctx.NodeLocator, callable, 0);
  190. if (isOptional) {
  191. return new TFromBytesWrapper<true>(ctx.Mutables, data, static_cast<NUdf::TDataTypeId>(schemeType), param1, param2);
  192. } else {
  193. return new TFromBytesWrapper<false>(ctx.Mutables, data, static_cast<NUdf::TDataTypeId>(schemeType), param1, param2);
  194. }
  195. }
  196. }
  197. }