diff options
author | dcherednik <dcherednik@ydb.tech> | 2022-10-28 11:39:33 +0300 |
---|---|---|
committer | dcherednik <dcherednik@ydb.tech> | 2022-10-28 11:39:33 +0300 |
commit | 7d2f2555b228e6d9eb05fb8d3e42f9bedd717bbe (patch) | |
tree | a2485d467ab713cb511443541ce4fbb784a04a62 | |
parent | b1ebe898664fc5fdf6704ca0b252fce57faf901f (diff) | |
download | ydb-7d2f2555b228e6d9eb05fb8d3e42f9bedd717bbe.tar.gz |
Uuid support for c++ SDK.
20 files changed, 350 insertions, 134 deletions
diff --git a/ydb/core/kqp/provider/yql_kikimr_results.cpp b/ydb/core/kqp/provider/yql_kikimr_results.cpp index b1a5f90ea94..be8238bceeb 100644 --- a/ydb/core/kqp/provider/yql_kikimr_results.cpp +++ b/ydb/core/kqp/provider/yql_kikimr_results.cpp @@ -2,6 +2,7 @@ #include <ydb/library/binary_json/read.h> #include <ydb/library/dynumber/dynumber.h> +#include <ydb/library/uuid/uuid.h> #include <ydb/library/yql/providers/common/codec/yql_codec_results.h> #include <ydb/library/yql/providers/common/provider/yql_provider.h> @@ -49,7 +50,7 @@ void WriteValueToYson(const TStringStream& stream, NCommon::TYsonResultWriter& w } if (type.GetData().GetScheme() == NYql::NProto::TypeIds::Uuid) { - using NKikimr::NMiniKQL::UuidHalfsToByteString; + using NKikimr::NUuid::UuidHalfsToByteString; TStringStream stream; UuidHalfsToByteString(value.GetLow128(), value.GetHi128(), stream); diff --git a/ydb/library/CMakeLists.txt b/ydb/library/CMakeLists.txt index d0c39c49203..e6671974c27 100644 --- a/ydb/library/CMakeLists.txt +++ b/ydb/library/CMakeLists.txt @@ -26,6 +26,7 @@ add_subdirectory(protobuf_printer) add_subdirectory(schlab) add_subdirectory(security) add_subdirectory(testlib) +add_subdirectory(uuid) add_subdirectory(workload) add_subdirectory(yaml_config) add_subdirectory(ycloud) diff --git a/ydb/library/uuid/CMakeLists.txt b/ydb/library/uuid/CMakeLists.txt new file mode 100644 index 00000000000..4cda6e401bc --- /dev/null +++ b/ydb/library/uuid/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was gererated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(ydb-library-uuid) +target_link_libraries(ydb-library-uuid PUBLIC + contrib-libs-cxxsupp + yutil +) +target_sources(ydb-library-uuid PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/uuid/uuid.cpp +) diff --git a/ydb/library/uuid/uuid.cpp b/ydb/library/uuid/uuid.cpp new file mode 100644 index 00000000000..aa12c7664b4 --- /dev/null +++ b/ydb/library/uuid/uuid.cpp @@ -0,0 +1,58 @@ +#include "uuid.h" + +#include <util/stream/str.h> + +namespace NKikimr { +namespace NUuid { + +static void WriteHexDigit(ui8 digit, IOutputStream& out) { + if (digit <= 9) { + out << char('0' + digit); + } + else { + out << char('a' + digit - 10); + } +} + +static void WriteHex(ui16 bytes, IOutputStream& out, bool reverseBytes = false) { + if (reverseBytes) { + WriteHexDigit((bytes >> 4) & 0x0f, out); + WriteHexDigit(bytes & 0x0f, out); + WriteHexDigit((bytes >> 12) & 0x0f, out); + WriteHexDigit((bytes >> 8) & 0x0f, out); + } else { + WriteHexDigit((bytes >> 12) & 0x0f, out); + WriteHexDigit((bytes >> 8) & 0x0f, out); + WriteHexDigit((bytes >> 4) & 0x0f, out); + WriteHexDigit(bytes & 0x0f, out); + } +} + +void UuidToString(ui16 dw[8], IOutputStream& out) { + WriteHex(dw[1], out); + WriteHex(dw[0], out); + out << '-'; + WriteHex(dw[2], out); + out << '-'; + WriteHex(dw[3], out); + out << '-'; + WriteHex(dw[4], out, true); + out << '-'; + WriteHex(dw[5], out, true); + WriteHex(dw[6], out, true); + WriteHex(dw[7], out, true); +} + +void UuidHalfsToByteString(ui64 low, ui64 hi, IOutputStream& out) { + union { + char bytes[16]; + ui64 half[2]; + } buf; + buf.half[0] = low; + buf.half[1] = hi; + out.Write(buf.bytes, 16); +} + +} +} + diff --git a/ydb/library/uuid/uuid.h b/ydb/library/uuid/uuid.h new file mode 100644 index 00000000000..4c890903713 --- /dev/null +++ b/ydb/library/uuid/uuid.h @@ -0,0 +1,96 @@ +#pragma once +#include <util/system/types.h> + +#include <cctype> +#include <utility> + +class IOutputStream; + +namespace NKikimr { +namespace NUuid { + +void UuidToString(ui16 dw[8], IOutputStream& out); +void UuidHalfsToByteString(ui64 low, ui64 hi, IOutputStream& out); + +inline bool GetDigit(char c, ui32& digit) { + digit = 0; + if ('0' <= c && c <= '9') { + digit = c - '0'; + } + else if ('a' <= c && c <= 'f') { + digit = c - 'a' + 10; + } + else if ('A' <= c && c <= 'F') { + digit = c - 'A' + 10; + } + else { + return false; // non-hex character + } + return true; +} + +template<typename T> +inline bool IsValidUuid(const T& buf) { + if (buf.Size() != 36) { + return false; + } + + for (size_t i = 0; i < buf.Size(); ++i) { + const char c = buf.Data()[i]; + + if (c == '-') { + if (i != 8 && i != 13 && i != 18 && i != 23) { + return false; + } + } else if (!std::isxdigit(c)) { + return false; + } + } + + return true; +} + +template<typename T> +bool ParseUuidToArray(const T& buf, ui16* dw, bool shortForm) { + if (buf.Size() != (shortForm ? 32 : 36)) { + return false; + } + + size_t partId = 0; + ui64 partValue = 0; + size_t digitCount = 0; + + for (size_t i = 0; i < buf.Size(); ++i) { + const char c = buf.Data()[i]; + + if (!shortForm && (i == 8 || i == 13 || i == 18 || i == 23)) { + if (c == '-') { + continue; + } else { + return false; + } + } + + ui32 digit = 0; + if (!GetDigit(c, digit)) { + return false; + } + + partValue = partValue * 16 + digit; + + if (++digitCount == 4) { + dw[partId++] = partValue; + digitCount = 0; + } + } + + std::swap(dw[0], dw[1]); + for (ui32 i = 4; i < 8; ++i) { + dw[i] = ((dw[i] >> 8) & 0xff) | ((dw[i] & 0xff) << 8); + } + + return true; +} + +} +} diff --git a/ydb/library/yql/minikql/CMakeLists.txt b/ydb/library/yql/minikql/CMakeLists.txt index d3aab5921b0..e91dcfdbd71 100644 --- a/ydb/library/yql/minikql/CMakeLists.txt +++ b/ydb/library/yql/minikql/CMakeLists.txt @@ -41,6 +41,7 @@ target_link_libraries(library-yql-minikql PUBLIC yql-public-udf public-udf-tz library-yql-utils + ydb-library-uuid ) target_sources(library-yql-minikql PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/minikql/aligned_page_pool.cpp diff --git a/ydb/library/yql/minikql/mkql_type_ops.cpp b/ydb/library/yql/minikql/mkql_type_ops.cpp index 8b6fe3caa4e..8f092c63850 100644 --- a/ydb/library/yql/minikql/mkql_type_ops.cpp +++ b/ydb/library/yql/minikql/mkql_type_ops.cpp @@ -11,6 +11,7 @@ #include <ydb/library/binary_json/write.h> #include <ydb/library/binary_json/read.h> +#include <ydb/library/uuid/uuid.h> #include <ydb/library/dynumber/dynumber.h> #include <library/cpp/containers/stack_vector/stack_vec.h> @@ -311,54 +312,6 @@ bool WriteInterval(IOutputStream& out, i64 signedValue) { return true; } -static void WriteHexDigit(ui8 digit, IOutputStream& out) { - if (digit <= 9) { - out << char('0' + digit); - } - else { - out << char('a' + digit - 10); - } -} - -static void WriteHex(ui16 bytes, IOutputStream& out, bool reverseBytes = false) { - if (reverseBytes) { - WriteHexDigit((bytes >> 4) & 0x0f, out); - WriteHexDigit(bytes & 0x0f, out); - WriteHexDigit((bytes >> 12) & 0x0f, out); - WriteHexDigit((bytes >> 8) & 0x0f, out); - } else { - WriteHexDigit((bytes >> 12) & 0x0f, out); - WriteHexDigit((bytes >> 8) & 0x0f, out); - WriteHexDigit((bytes >> 4) & 0x0f, out); - WriteHexDigit(bytes & 0x0f, out); - } -} - -static void UuidToString(ui16 dw[8], IOutputStream& out) { - WriteHex(dw[1], out); - WriteHex(dw[0], out); - out << '-'; - WriteHex(dw[2], out); - out << '-'; - WriteHex(dw[3], out); - out << '-'; - WriteHex(dw[4], out, true); - out << '-'; - WriteHex(dw[5], out, true); - WriteHex(dw[6], out, true); - WriteHex(dw[7], out, true); -} - -} - -void UuidHalfsToByteString(ui64 low, ui64 hi, IOutputStream& out) { - union { - char bytes[16]; - ui64 half[2]; - } buf; - buf.half[0] = low; - buf.half[1] = hi; - out.Write(buf.bytes, 16); } NUdf::TUnboxedValuePod ValueToString(NUdf::EDataSlot type, NUdf::TUnboxedValuePod value) { @@ -417,7 +370,7 @@ NUdf::TUnboxedValuePod ValueToString(NUdf::EDataSlot type, NUdf::TUnboxedValuePo case NUdf::EDataSlot::Uuid: { ui16 dw[8]; std::memcpy(dw, value.AsStringRef().Data(), sizeof(dw)); - UuidToString(dw, out); + NUuid::UuidToString(dw, out); break; } @@ -969,89 +922,10 @@ ui32 ParseNumber(ui32& pos, NUdf::TStringRef buf, ui32& value, i8 dig_cnt) { return count; } -static bool GetDigit(char c, ui32& digit) { - digit = 0; - if ('0' <= c && c <= '9') { - digit = c - '0'; - } - else if ('a' <= c && c <= 'f') { - digit = c - 'a' + 10; - } - else if ('A' <= c && c <= 'F') { - digit = c - 'A' + 10; - } - else { - return false; // non-hex character - } - return true; -} - -bool IsValidUuid(NUdf::TStringRef buf) { - if (buf.Size() != 36) { - return false; - } - - for (size_t i = 0; i < buf.Size(); ++i) { - const char c = buf.Data()[i]; - - if (c == '-') { - if (i != 8 && i != 13 && i != 18 && i != 23) { - return false; - } - } else if (!std::isxdigit(c)) { - return false; - } - } - - return true; -} - - -static bool ParseUuidToArray(NUdf::TStringRef buf, ui16* dw, bool shortForm) { - if (buf.Size() != (shortForm ? 32 : 36)) { - return false; - } - - size_t partId = 0; - ui64 partValue = 0; - size_t digitCount = 0; - - for (size_t i = 0; i < buf.Size(); ++i) { - const char c = buf.Data()[i]; - - if (!shortForm && (i == 8 || i == 13 || i == 18 || i == 23)) { - if (c == '-') { - continue; - } else { - return false; - } - } - - ui32 digit = 0; - if (!GetDigit(c, digit)) { - return false; - } - - partValue = partValue * 16 + digit; - - if (++digitCount == 4) { - dw[partId++] = partValue; - digitCount = 0; - } - } - - std::swap(dw[0], dw[1]); - for (ui32 i = 4; i < 8; ++i) { - dw[i] = ((dw[i] >> 8) & 0xff) | ((dw[i] & 0xff) << 8); - } - - return true; -} - NUdf::TUnboxedValuePod ParseUuid(NUdf::TStringRef buf, bool shortForm) { ui16 dw[8]; - if (!ParseUuidToArray(buf, dw, shortForm)) { + if (!NUuid::ParseUuidToArray(buf, dw, shortForm)) { return NUdf::TUnboxedValuePod(); } @@ -1061,7 +935,7 @@ NUdf::TUnboxedValuePod ParseUuid(NUdf::TStringRef buf, bool shortForm) { bool ParseUuid(NUdf::TStringRef buf, void* out, bool shortForm) { ui16 dw[8]; - if (!ParseUuidToArray(buf, dw, shortForm)) { + if (!NUuid::ParseUuidToArray(buf, dw, shortForm)) { return false; } @@ -1685,7 +1559,7 @@ bool IsValidStringValue(NUdf::EDataSlot type, NUdf::TStringRef buf) { case NUdf::EDataSlot::JsonDocument: return NDom::IsValidJson(buf); case NUdf::EDataSlot::Uuid: - return IsValidUuid(buf); + return NUuid::IsValidUuid(buf); case NUdf::EDataSlot::DyNumber: return NDyNumber::IsValidDyNumberString(buf); diff --git a/ydb/library/yql/minikql/mkql_type_ops.h b/ydb/library/yql/minikql/mkql_type_ops.h index 8ff9b258ddf..4c30121e9ac 100644 --- a/ydb/library/yql/minikql/mkql_type_ops.h +++ b/ydb/library/yql/minikql/mkql_type_ops.h @@ -19,8 +19,6 @@ bool IsLeapYear(ui32 year); ui32 GetMonthLength(ui32 month, bool isLeap); -void UuidHalfsToByteString(ui64 low, ui64 hi, IOutputStream& out); - bool IsValidStringValue(NUdf::EDataSlot type, NUdf::TStringRef buf); NUdf::TUnboxedValuePod ValueFromString(NUdf::EDataSlot type, NUdf::TStringRef buf); diff --git a/ydb/public/lib/json_value/CMakeLists.txt b/ydb/public/lib/json_value/CMakeLists.txt index 5a8f7be33d7..704967228b5 100644 --- a/ydb/public/lib/json_value/CMakeLists.txt +++ b/ydb/public/lib/json_value/CMakeLists.txt @@ -16,6 +16,7 @@ target_link_libraries(public-lib-json_value PUBLIC cpp-string_utils-base64 cpp-client-ydb_result cpp-client-ydb_value + ydb-library-uuid ) target_sources(public-lib-json_value PRIVATE ${CMAKE_SOURCE_DIR}/ydb/public/lib/json_value/ydb_json_value.cpp diff --git a/ydb/public/lib/json_value/ydb_json_value.cpp b/ydb/public/lib/json_value/ydb_json_value.cpp index a8d48c77d45..dbfb05b315e 100644 --- a/ydb/public/lib/json_value/ydb_json_value.cpp +++ b/ydb/public/lib/json_value/ydb_json_value.cpp @@ -189,6 +189,9 @@ namespace NYdb { case EPrimitiveType::Json: Writer.WriteString(Parser.GetJson()); break; + case EPrimitiveType::Uuid: + Writer.WriteString(Parser.GetUuid().ToString()); + break; case EPrimitiveType::JsonDocument: Writer.WriteString(Parser.GetJsonDocument()); break; @@ -552,6 +555,10 @@ namespace { EnsureType(jsonValue, NJson::JSON_STRING); ValueBuilder.Json(jsonValue.GetString()); break; + case EPrimitiveType::Uuid: + EnsureType(jsonValue, NJson::JSON_STRING); + ValueBuilder.Uuid(jsonValue.GetString()); + break; case EPrimitiveType::JsonDocument: EnsureType(jsonValue, NJson::JSON_STRING); ValueBuilder.JsonDocument(jsonValue.GetString()); diff --git a/ydb/public/lib/yson_value/CMakeLists.txt b/ydb/public/lib/yson_value/CMakeLists.txt index 86f9e8efce5..737b5947458 100644 --- a/ydb/public/lib/yson_value/CMakeLists.txt +++ b/ydb/public/lib/yson_value/CMakeLists.txt @@ -15,6 +15,7 @@ target_link_libraries(public-lib-yson_value PUBLIC cpp-yson-node cpp-client-ydb_result cpp-client-ydb_value + ydb-library-uuid ) target_sources(public-lib-yson_value PRIVATE ${CMAKE_SOURCE_DIR}/ydb/public/lib/yson_value/ydb_yson_value.cpp diff --git a/ydb/public/lib/yson_value/ydb_yson_value.cpp b/ydb/public/lib/yson_value/ydb_yson_value.cpp index d73b1c41e7a..5658f1edbd5 100644 --- a/ydb/public/lib/yson_value/ydb_yson_value.cpp +++ b/ydb/public/lib/yson_value/ydb_yson_value.cpp @@ -79,6 +79,9 @@ static void PrimitiveValueToYson(EPrimitiveType type, TValueParser& parser, NYso case EPrimitiveType::JsonDocument: writer.OnStringScalar(parser.GetJsonDocument()); break; + case EPrimitiveType::Uuid: + writer.OnStringScalar(parser.GetUuid().ToString()); + break; case EPrimitiveType::DyNumber: writer.OnStringScalar(parser.GetDyNumber()); break; diff --git a/ydb/public/sdk/cpp/client/ydb_value/CMakeLists.txt b/ydb/public/sdk/cpp/client/ydb_value/CMakeLists.txt index b622bb115ee..5e1a1bd390b 100644 --- a/ydb/public/sdk/cpp/client/ydb_value/CMakeLists.txt +++ b/ydb/public/sdk/cpp/client/ydb_value/CMakeLists.txt @@ -19,6 +19,7 @@ target_link_libraries(cpp-client-ydb_value PUBLIC cpp-client-ydb_proto client-ydb_types-fatal_error_handlers yql-public-decimal + ydb-library-uuid ) target_sources(cpp-client-ydb_value PRIVATE ${CMAKE_SOURCE_DIR}/ydb/public/sdk/cpp/client/ydb_value/value.cpp diff --git a/ydb/public/sdk/cpp/client/ydb_value/value.cpp b/ydb/public/sdk/cpp/client/ydb_value/value.cpp index 25336625a07..c9c9a7edd59 100644 --- a/ydb/public/sdk/cpp/client/ydb_value/value.cpp +++ b/ydb/public/sdk/cpp/client/ydb_value/value.cpp @@ -13,6 +13,7 @@ #include <library/cpp/containers/stack_vector/stack_vec.h> #include <ydb/library/yql/public/decimal/yql_decimal.h> +#include <ydb/library/uuid/uuid.h> #include <util/generic/bitmap.h> #include <util/generic/map.h> @@ -950,6 +951,32 @@ bool TPgValue::IsText() const { //////////////////////////////////////////////////////////////////////////////// +TUuidValue::TUuidValue(const Ydb::Value& valueProto) { + Buf_.Halfs[0] = valueProto.low_128(); + Buf_.Halfs[1] = valueProto.high_128(); +} + +TUuidValue::TUuidValue(const TString& uuidString) { + ui16 dw[8]; + if (!NKikimr::NUuid::ParseUuidToArray(uuidString, dw, false)) { + ThrowFatalError(TStringBuilder() << "Unable to parse string as uuid"); + } + static_assert(sizeof(dw) == sizeof(Buf_.Bytes)); + std::memcpy(Buf_.Bytes, dw, sizeof(dw)); +} + +TString TUuidValue::ToString() const { + TStringStream s; + ui16 dw[8]; + static_assert(sizeof(dw) == sizeof(Buf_.Bytes)); + std::memcpy(dw, Buf_.Bytes, sizeof(dw)); + NKikimr::NUuid::UuidToString(dw, s); + return s.Str(); + +} + +//////////////////////////////////////////////////////////////////////////////// + class TValue::TImpl { public: TImpl(const TType& type, const Ydb::Value& valueProto) @@ -1135,6 +1162,11 @@ public: return GetProto().text_value(); } + TUuidValue GetUuid() const { + CheckPrimitive(NYdb::EPrimitiveType::Uuid); + return TUuidValue(GetProto()); + } + const TString& GetJsonDocument() const { CheckPrimitive(NYdb::EPrimitiveType::JsonDocument); return GetProto().text_value(); @@ -1491,6 +1523,8 @@ private: case NYdb::EPrimitiveType::JsonDocument: case NYdb::EPrimitiveType::DyNumber: return Ydb::Value::kTextValue; + case NYdb::EPrimitiveType::Uuid: + return Ydb::Value::kLow128; default: FatalError(TStringBuilder() << "Unexpected primitive type: " << primitiveTypeId); return Ydb::Value::kBytesValue; @@ -1620,6 +1654,10 @@ const TString& TValueParser::GetJson() const { return Impl_->GetJson(); } +TUuidValue TValueParser::GetUuid() const { + return Impl_->GetUuid(); +} + const TString& TValueParser::GetJsonDocument() const { return Impl_->GetJsonDocument(); } @@ -1732,6 +1770,10 @@ TMaybe<TString> TValueParser::GetOptionalJson() const { RET_OPT_VALUE(TString, Json); } +TMaybe<TUuidValue> TValueParser::GetOptionalUuid() const { + RET_OPT_VALUE(TUuidValue, Uuid); +} + TMaybe<TString> TValueParser::GetOptionalJsonDocument() const { RET_OPT_VALUE(TString, JsonDocument); } @@ -2008,6 +2050,12 @@ public: GetValue().set_text_value(value); } + void Uuid(const TUuidValue& value) { + FillPrimitiveType(EPrimitiveType::Uuid); + GetValue().set_low_128(value.Buf_.Halfs[0]); + GetValue().set_high_128(value.Buf_.Halfs[1]); + } + void JsonDocument(const TString& value) { FillPrimitiveType(EPrimitiveType::JsonDocument); GetValue().set_text_value(value); @@ -2707,6 +2755,12 @@ TDerived& TValueBuilderBase<TDerived>::Json(const TString& value) { } template<typename TDerived> +TDerived& TValueBuilderBase<TDerived>::Uuid(const TUuidValue& value) { + Impl_->Uuid(value); + return static_cast<TDerived&>(*this); +} + +template<typename TDerived> TDerived& TValueBuilderBase<TDerived>::JsonDocument(const TString& value) { Impl_->JsonDocument(value); return static_cast<TDerived&>(*this); @@ -2857,6 +2911,11 @@ TDerived& TValueBuilderBase<TDerived>::OptionalJson(const TMaybe<TString>& value } template<typename TDerived> +TDerived& TValueBuilderBase<TDerived>::OptionalUuid(const TMaybe<TUuidValue>& value) { + SET_OPT_VALUE_MAYBE(Uuid); +} + +template<typename TDerived> TDerived& TValueBuilderBase<TDerived>::OptionalJsonDocument(const TMaybe<TString>& value) { SET_OPT_VALUE_MAYBE(JsonDocument); } diff --git a/ydb/public/sdk/cpp/client/ydb_value/value.h b/ydb/public/sdk/cpp/client/ydb_value/value.h index 2a5a96d1826..0186260a984 100644 --- a/ydb/public/sdk/cpp/client/ydb_value/value.h +++ b/ydb/public/sdk/cpp/client/ydb_value/value.h @@ -237,6 +237,17 @@ struct TPgValue { TString Content_; }; +struct TUuidValue { + TString ToString() const; + TUuidValue(const Ydb::Value& uuidValueProto); + TUuidValue(const TString& uuidString); + + union { + char Bytes[16]; + ui64 Halfs[2]; + } Buf_; +}; + //! Representation of YDB value. class TValue { friend class TValueParser; @@ -290,6 +301,7 @@ public: const TString& GetJson() const; TDecimalValue GetDecimal() const; TPgValue GetPg() const; + TUuidValue GetUuid() const; const TString& GetJsonDocument() const; const TString& GetDyNumber() const; @@ -316,6 +328,7 @@ public: TMaybe<TString> GetOptionalYson() const; TMaybe<TString> GetOptionalJson() const; TMaybe<TDecimalValue> GetOptionalDecimal() const; + TMaybe<TUuidValue> GetOptionalUuid() const; TMaybe<TString> GetOptionalJsonDocument() const; TMaybe<TString> GetOptionalDyNumber() const; @@ -394,6 +407,7 @@ public: TDerived& Json(const TString& value); TDerived& Decimal(const TDecimalValue& value); TDerived& Pg(const TPgValue& value); + TDerived& Uuid(const TUuidValue& value); TDerived& JsonDocument(const TString& value); TDerived& DyNumber(const TString& value); @@ -419,6 +433,7 @@ public: TDerived& OptionalUtf8(const TMaybe<TString>& value); TDerived& OptionalYson(const TMaybe<TString>& value); TDerived& OptionalJson(const TMaybe<TString>& value); + TDerived& OptionalUuid(const TMaybe<TUuidValue>& value); TDerived& OptionalJsonDocument(const TMaybe<TString>& value); TDerived& OptionalDyNumber(const TMaybe<TString>& value); diff --git a/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp b/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp index 8f6b8553f9d..43c23dbbd69 100644 --- a/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp +++ b/ydb/public/sdk/cpp/client/ydb_value/value_ut.cpp @@ -1,6 +1,7 @@ #include <ydb/public/api/protos/ydb_value.pb.h> #include <ydb/public/sdk/cpp/client/ydb_proto/accessor.h> #include <ydb/public/sdk/cpp/client/ydb_value/value.h> +#include <ydb/public/sdk/cpp/client/ydb_types/exceptions/exceptions.h> #include <ydb/public/lib/json_value/ydb_json_value.h> #include <ydb/public/lib/yson_value/ydb_yson_value.h> @@ -1311,6 +1312,20 @@ Y_UNIT_TEST_SUITE(YdbValue) { UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), R"([{"Name":"Sergey","Value":1},null,[true],[[10,null]],"12.345"])"); } + + Y_UNIT_TEST(CorrectUuid) { + TString uuidStr = "5ca32c22-841b-11e8-adc0-fa7ae01bbebc"; + TUuidValue uuid(uuidStr); + UNIT_ASSERT_VALUES_EQUAL(uuidStr, uuid.ToString()); + } + + Y_UNIT_TEST(IncorrectUuid) { + UNIT_ASSERT_EXCEPTION(TUuidValue(""), TContractViolation); + UNIT_ASSERT_EXCEPTION(TUuidValue("0123456789abcdef0123456789abcdef0123456789abcdef"), TContractViolation); + UNIT_ASSERT_EXCEPTION(TUuidValue("5ca32c22+841b-11e8-adc0-fa7ae01bbebc"), TContractViolation); + UNIT_ASSERT_EXCEPTION(TUuidValue("5ca32-c22841b-11e8-adc0-fa7ae01bbebc"), TContractViolation); + } + } } // namespace NYdb diff --git a/ydb/services/ydb/ut/CMakeLists.darwin.txt b/ydb/services/ydb/ut/CMakeLists.darwin.txt index 1e8060eaff9..1fb9b5abfd9 100644 --- a/ydb/services/ydb/ut/CMakeLists.darwin.txt +++ b/ydb/services/ydb/ut/CMakeLists.darwin.txt @@ -30,6 +30,7 @@ target_link_libraries(ydb-services-ydb-ut PUBLIC yql-minikql-dom yql-minikql-jsonpath public-lib-experimental + public-lib-json_value public-lib-yson_value cpp-client-draft cpp-client-ydb_coordination diff --git a/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt b/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt index 65218c59d4f..346b86dd319 100644 --- a/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt +++ b/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt @@ -30,6 +30,7 @@ target_link_libraries(ydb-services-ydb-ut PUBLIC yql-minikql-dom yql-minikql-jsonpath public-lib-experimental + public-lib-json_value public-lib-yson_value cpp-client-draft cpp-client-ydb_coordination diff --git a/ydb/services/ydb/ut/CMakeLists.linux.txt b/ydb/services/ydb/ut/CMakeLists.linux.txt index b4c55437f16..82a7bd8b799 100644 --- a/ydb/services/ydb/ut/CMakeLists.linux.txt +++ b/ydb/services/ydb/ut/CMakeLists.linux.txt @@ -32,6 +32,7 @@ target_link_libraries(ydb-services-ydb-ut PUBLIC yql-minikql-dom yql-minikql-jsonpath public-lib-experimental + public-lib-json_value public-lib-yson_value cpp-client-draft cpp-client-ydb_coordination diff --git a/ydb/services/ydb/ydb_ut.cpp b/ydb/services/ydb/ydb_ut.cpp index acb0647aa61..fb6a522f67a 100644 --- a/ydb/services/ydb/ydb_ut.cpp +++ b/ydb/services/ydb/ydb_ut.cpp @@ -29,6 +29,9 @@ #include <ydb/public/sdk/cpp/client/ydb_table/table.h> #include <ydb/public/sdk/cpp/client/resources/ydb_resources.h> +#include <ydb/public/lib/yson_value/ydb_yson_value.h> +#include <ydb/public/lib/json_value/ydb_json_value.h> + #include "ydb_common_ut.h" #include <util/generic/ymath.h> @@ -1963,6 +1966,68 @@ tx_meta { } } + Y_UNIT_TEST(SdkUuid) { + TKikimrWithGrpcAndRootSchema server; + ui16 grpc = server.GetPort(); + + TString location = TStringBuilder() << "localhost:" << grpc; + + auto connection = NYdb::TDriver( + TDriverConfig() + .SetEndpoint(location)); + auto client = NYdb::NTable::TTableClient(connection); + auto session = client.CreateSession().ExtractValueSync().GetSession(); + + auto result = session.ExecuteDataQuery(R"( + SELECT CAST("5ca32c22-841b-11e8-adc0-fa7ae01bbebc" AS Uuid); + )", TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx()).ExtractValueSync(); + + UNIT_ASSERT(result.IsSuccess()); + + TString expectedJson = R"({"column0":"5ca32c22-841b-11e8-adc0-fa7ae01bbebc"} +)"; + UNIT_ASSERT_VALUES_EQUAL(expectedJson, NYdb::FormatResultSetJson(result.GetResultSet(0), NYdb::EBinaryStringEncoding::Base64)); + + UNIT_ASSERT_VALUES_EQUAL(R"([[["5ca32c22-841b-11e8-adc0-fa7ae01bbebc"]]])", NYdb::FormatResultSetYson(result.GetResultSet(0))); + } + + Y_UNIT_TEST(SdkUuidViaParams) { + TKikimrWithGrpcAndRootSchema server; + ui16 grpc = server.GetPort(); + + TString location = TStringBuilder() << "localhost:" << grpc; + + auto connection = NYdb::TDriver( + TDriverConfig() + .SetEndpoint(location)); + auto client = NYdb::NTable::TTableClient(connection); + auto session = client.CreateSession().ExtractValueSync().GetSession(); + + auto param = client.GetParamsBuilder() + .AddParam("$in") + .BeginList() + .AddListItem() + .BeginStruct() + .AddMember("u").Uuid(TUuidValue("5ca32c22-841b-11e8-adc0-fa7ae01bbebc")) + .EndStruct() + .EndList() + .Build() + .Build(); + auto result = session.ExecuteDataQuery(R"( + DECLARE $in AS List<Struct<u: Uuid>>; + SELECT * FROM AS_TABLE($in); + )", TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx(), param).ExtractValueSync(); + + UNIT_ASSERT(result.IsSuccess()); + + TString expectedJson = R"({"u":"5ca32c22-841b-11e8-adc0-fa7ae01bbebc"} +)"; + UNIT_ASSERT_VALUES_EQUAL(expectedJson, NYdb::FormatResultSetJson(result.GetResultSet(0), NYdb::EBinaryStringEncoding::Base64)); + + UNIT_ASSERT_VALUES_EQUAL(R"([["5ca32c22-841b-11e8-adc0-fa7ae01bbebc"]])", NYdb::FormatResultSetYson(result.GetResultSet(0))); + } + + Y_UNIT_TEST(ExecuteQueryWithParametersBadRequest) { TKikimrWithGrpcAndRootSchema server; ui16 grpc = server.GetPort(); |