diff options
author | Nikolay Shumkov <shumkovnd@ydb.tech> | 2025-04-01 18:49:48 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-01 15:49:48 +0000 |
commit | 81a0068ec4e9a9879d92bcfadefbda26ce5d475f (patch) | |
tree | 03f262ee8a489529c16c9691164be5d146c644de | |
parent | f97bb919937b9452311ffecb5c296ef82db98653 (diff) | |
download | ydb-81a0068ec4e9a9879d92bcfadefbda26ce5d475f.tar.gz |
Show create table (Column-oriented tables) (#16509)
-rw-r--r-- | ydb/core/sys_view/show_create/create_table_formatter.cpp | 314 | ||||
-rw-r--r-- | ydb/core/sys_view/show_create/create_table_formatter.h | 9 | ||||
-rw-r--r-- | ydb/core/sys_view/show_create/show_create.cpp | 44 | ||||
-rw-r--r-- | ydb/core/sys_view/show_create/ya.make | 1 | ||||
-rw-r--r-- | ydb/core/sys_view/ut_common.cpp | 7 | ||||
-rw-r--r-- | ydb/core/sys_view/ut_kqp.cpp | 243 | ||||
-rw-r--r-- | ydb/core/sys_view/ya.make | 1 | ||||
-rw-r--r-- | ydb/core/ydb_convert/table_description.cpp | 107 | ||||
-rw-r--r-- | ydb/core/ydb_convert/table_description.h | 3 |
9 files changed, 664 insertions, 65 deletions
diff --git a/ydb/core/sys_view/show_create/create_table_formatter.cpp b/ydb/core/sys_view/show_create/create_table_formatter.cpp index 50678cfb940..ab9b40f509e 100644 --- a/ydb/core/sys_view/show_create/create_table_formatter.cpp +++ b/ydb/core/sys_view/show_create/create_table_formatter.cpp @@ -612,10 +612,11 @@ bool TCreateTableFormatter::Format(const TFamilyDescription& familyDesc) { compression = "off"; break; case NKikimrSchemeOp::ColumnCodecLZ4: - compression = "lz4"; + compression = "lz4"; break; case NKikimrSchemeOp::ColumnCodecZSTD: - ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "ZSTD COMPRESSION codec is not supported"); + compression = "zstd"; + break; } } else if (familyDesc.HasCodec()) { if (familyDesc.GetCodec() == 1) { @@ -643,7 +644,7 @@ bool TCreateTableFormatter::Format(const TFamilyDescription& familyDesc) { del = ", "; } - if (dataName) { + if (compression) { Stream << del << "COMPRESSION = " << "\"" << compression << "\""; } @@ -884,5 +885,312 @@ bool TCreateTableFormatter::Format(const Ydb::Table::TtlSettings& ttlSettings, T return true; } +TCreateTableFormatter::TResult TCreateTableFormatter::Format(const TString& tablePath, const TColumnTableDescription& tableDesc, bool temporary) { + Stream.Clear(); + + TStringStreamWrapper wrapper(Stream); + + Ydb::Table::CreateTableRequest createRequest; + if (temporary) { + Stream << "CREATE TEMPORARY TABLE "; + } else { + Stream << "CREATE TABLE "; + } + EscapeName(tablePath); + Stream << " (\n"; + + const auto& schema = tableDesc.GetSchema(); + + std::map<ui32, const TOlapColumnDescription*> columns; + for (const auto& column : schema.GetColumns()) { + columns[column.GetId()] = &column; + } + + try { + auto it = columns.cbegin(); + Format(*it->second); + std::advance(it, 1); + for (; it != columns.end(); ++it) { + Stream << ",\n"; + Format(*it->second); + } + } catch (const TFormatFail& ex) { + return TResult(ex.Status, ex.Error); + } catch (const yexception& e) { + return TResult(Ydb::StatusIds::UNSUPPORTED, e.what()); + } + Stream << ",\n"; + + if (!schema.GetIndexes().empty()) { + return TResult(Ydb::StatusIds::UNSUPPORTED, "Indexes are not supported yet for column tables."); + } + + bool isFamilyPrinted = false; + if (!schema.GetColumnFamilies().empty()) { + try { + isFamilyPrinted = Format(schema.GetColumnFamilies(0)); + for (int i = 1; i < schema.GetColumnFamilies().size(); i++) { + if (isFamilyPrinted) { + Stream << ",\n"; + } + isFamilyPrinted = Format(schema.GetColumnFamilies(i)); + } + } catch (const TFormatFail& ex) { + return TResult(ex.Status, ex.Error); + } catch (const yexception& e) { + return TResult(Ydb::StatusIds::UNSUPPORTED, e.what()); + } + } + + Y_ENSURE(!schema.GetKeyColumnNames().empty()); + if (isFamilyPrinted) { + Stream << ",\n"; + } + Stream << "\tPRIMARY KEY ("; + EscapeName(schema.GetKeyColumnNames(0)); + for (int i = 1; i < schema.GetKeyColumnNames().size(); i++) { + Stream << ", "; + EscapeName(schema.GetKeyColumnNames(i)); + } + Stream << ")\n"; + Stream << ") "; + + if (schema.HasOptions()) { + const auto& options = schema.GetOptions(); + if (options.GetSchemeNeedActualization()) { + return TResult(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: SCHEME_NEED_ACTUALIZATION"); + } + if (options.HasScanReaderPolicyName() && !options.GetScanReaderPolicyName().empty()) { + return TResult(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: SCAN_READER_POLICY_NAME"); + } + if (options.HasCompactionPlannerConstructor()) { + return TResult(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: COMPACTION_PLANNER"); + } + if (options.HasMetadataManagerConstructor()) { + return TResult(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: METADATA_MEMORY_MANAGER"); + } + } + + if (tableDesc.HasSharding()) { + Format(tableDesc.GetSharding()); + } + + Stream << "WITH (\n"; + Stream << "\tSTORE = COLUMN"; + + if (tableDesc.HasColumnShardCount()) { + Stream << ",\n"; + Stream << "\tAUTO_PARTITIONING_MIN_PARTITIONS_COUNT = " << tableDesc.GetColumnShardCount(); + } + + if (tableDesc.HasTtlSettings()) { + Format(tableDesc.GetTtlSettings()); + } + + Stream << "\n);"; + + TString statement = Stream.Str(); + TString formattedStatement; + NYql::TIssues issues; + if (!NYdb::NDump::Format(statement, formattedStatement, issues)) { + return TResult(Ydb::StatusIds::INTERNAL_ERROR, issues.ToString()); + } + + auto result = TResult(std::move(formattedStatement)); + + return result; +} + +void TCreateTableFormatter::Format(const TOlapColumnDescription& olapColumnDesc) { + Stream << "\t"; + EscapeName(olapColumnDesc.GetName()); + Stream << " " << olapColumnDesc.GetType(); + + if (olapColumnDesc.HasColumnFamilyName()) { + Stream << " FAMILY "; + EscapeName(olapColumnDesc.GetColumnFamilyName()); + } + if (olapColumnDesc.GetNotNull()) { + Stream << " NOT NULL"; + } + if (olapColumnDesc.HasDefaultValue()) { + Format(olapColumnDesc.GetDefaultValue()); + } + + if (olapColumnDesc.HasStorageId() && !olapColumnDesc.GetStorageId().empty()) { + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: STORAGE_ID"); + } + + if (olapColumnDesc.HasDataAccessorConstructor()) { + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: DATA_ACCESSOR_CONSTRUCTOR"); + } + + if (olapColumnDesc.HasDictionaryEncoding()) { + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "Unsupported setting: ENCODING.DICTIONARY"); + } +} + +void TCreateTableFormatter::Format(const NKikimrColumnShardColumnDefaults::TColumnDefault& defaultValue) { + if (!defaultValue.HasScalar()) { + return; + } + + Stream << " DEFAULT "; + + TGuard<NMiniKQL::TScopedAlloc> guard(Alloc); + const auto& scalar = defaultValue.GetScalar(); + if (scalar.HasBool()) { + if (scalar.GetBool() == true) { + Stream << "true"; + } else { + Stream << "false"; + } + } else if (scalar.HasUint8()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Uint8, NUdf::TUnboxedValuePod(scalar.GetUint8())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasUint16()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Uint16, NUdf::TUnboxedValuePod(scalar.GetUint16())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasUint32()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Uint32, NUdf::TUnboxedValuePod(scalar.GetUint32())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasUint64()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Uint64, NUdf::TUnboxedValuePod(static_cast<ui64>(scalar.GetUint64()))); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasInt8()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Int8, NUdf::TUnboxedValuePod(scalar.GetInt8())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasInt16()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Int16, NUdf::TUnboxedValuePod(scalar.GetInt16())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasInt32()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Int32, NUdf::TUnboxedValuePod(scalar.GetInt32())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasInt64()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Int64, NUdf::TUnboxedValuePod(static_cast<i64>(scalar.GetInt64()))); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasDouble()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Double, NUdf::TUnboxedValuePod(scalar.GetDouble())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasFloat()) { + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Float, NUdf::TUnboxedValuePod(scalar.GetFloat())); + Y_ENSURE(str.HasValue()); + Stream << TString(str.AsStringRef()); + } else if (scalar.HasTimestamp()) { + ui64 value = scalar.GetTimestamp().GetValue(); + arrow::TimeUnit::type unit = arrow::TimeUnit::type(scalar.GetTimestamp().GetUnit()); + switch (unit) { + case arrow::TimeUnit::SECOND: + value *= 1000000; + break; + case arrow::TimeUnit::MILLI: + value *= 1000; + break; + case arrow::TimeUnit::MICRO: + break; + case arrow::TimeUnit::NANO: + value /= 1000; + break; + } + Stream << "TIMESTAMP("; + const NUdf::TUnboxedValue str = NMiniKQL::ValueToString(NUdf::EDataSlot::Timestamp, NUdf::TUnboxedValuePod(value)); + Y_ENSURE(str.HasValue()); + EscapeString(TString(str.AsStringRef())); + Stream << ")"; + } else if (scalar.HasString()) { + EscapeString(TString(scalar.GetString())); + } else { + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "Unsupported type for default value"); + } +} + +void TCreateTableFormatter::Format(const NKikimrSchemeOp::TColumnTableSharding& sharding) { + switch (sharding.GetMethodCase()) { + case NKikimrSchemeOp::TColumnTableSharding::kHashSharding: { + const auto& hashSharding = sharding.GetHashSharding(); + Y_ENSURE(!hashSharding.GetColumns().empty()); + Stream << "PARTITION BY HASH("; + EscapeName(hashSharding.GetColumns(0)); + for (int i = 1; i < hashSharding.GetColumns().size(); i++) { + Stream << ", "; + EscapeName(hashSharding.GetColumns(i)); + } + Stream << ")\n"; + break; + } + case NKikimrSchemeOp::TColumnTableSharding::kRandomSharding: + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "Random sharding is not supported yet."); + default: + ythrow TFormatFail(Ydb::StatusIds::INTERNAL_ERROR, "Unsupported unit"); + } +} + +void TCreateTableFormatter::Format(const NKikimrSchemeOp::TColumnDataLifeCycle& ttlSettings) { + if (!ttlSettings.HasEnabled()) { + return; + } + + const auto& enabled = ttlSettings.GetEnabled(); + + if (enabled.HasExpireAfterBytes()) { + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "TTL by size is not supported."); + } + + Stream << ",\n"; + Stream << "\tTTL =\n\t "; + bool first = true; + + if (!enabled.TiersSize()) { + Y_ENSURE(enabled.HasExpireAfterSeconds()); + Format(enabled.GetExpireAfterSeconds()); + } else { + for (const auto& tier : enabled.GetTiers()) { + if (!first) { + Stream << ", "; + } + switch (tier.GetActionCase()) { + case NKikimrSchemeOp::TTTLSettings::TTier::ActionCase::kDelete: + Format(tier.GetApplyAfterSeconds()); + break; + case NKikimrSchemeOp::TTTLSettings::TTier::ActionCase::kEvictToExternalStorage: + Format(tier.GetApplyAfterSeconds(), tier.GetEvictToExternalStorage().GetStorage()); + break; + case NKikimrSchemeOp::TTTLSettings::TTier::ActionCase::ACTION_NOT_SET: + ythrow TFormatFail(Ydb::StatusIds::UNSUPPORTED, "Undefined tier action"); + } + first = false; + } + } + + Stream << "\n\t ON " << enabled.GetColumnName(); + switch (enabled.GetColumnUnit()) { + case NKikimrSchemeOp::TTTLSettings::UNIT_AUTO: + break; + case NKikimrSchemeOp::TTTLSettings::UNIT_SECONDS: + Stream << " AS SECONDS"; + break; + case NKikimrSchemeOp::TTTLSettings::UNIT_MILLISECONDS: + Stream << " AS MILLISECONDS"; + break; + case NKikimrSchemeOp::TTTLSettings::UNIT_MICROSECONDS: + Stream << " AS MICROSECONDS"; + break; + case NKikimrSchemeOp::TTTLSettings::UNIT_NANOSECONDS: + Stream << " AS NANOSECONDS"; + break; + default: + ythrow TFormatFail(Ydb::StatusIds::INTERNAL_ERROR, "Unsupported unit"); + } +} + } // NSysView } // NKikimr diff --git a/ydb/core/sys_view/show_create/create_table_formatter.h b/ydb/core/sys_view/show_create/create_table_formatter.h index a34d5dcf4d5..249ef6e0fd4 100644 --- a/ydb/core/sys_view/show_create/create_table_formatter.h +++ b/ydb/core/sys_view/show_create/create_table_formatter.h @@ -4,6 +4,8 @@ #include <ydb/core/protos/flat_scheme_op.pb.h> +#include <ydb/core/tx/columnshard/engines/scheme/defaults/protos/data.pb.h> + #include <ydb/public/api/protos/ydb_table.pb.h> #include <yql/essentials/minikql/mkql_alloc.h> @@ -74,6 +76,7 @@ public: } TResult Format(const TString& tablePath, const NKikimrSchemeOp::TTableDescription& tableDesc, bool temporary); + TResult Format(const TString& tablePath, const NKikimrSchemeOp::TColumnTableDescription& tableDesc, bool temporary); private: @@ -88,6 +91,12 @@ private: void Format(ui64 expireAfterSeconds, std::optional<TString> storage = std::nullopt); + void Format(const NKikimrSchemeOp::TOlapColumnDescription& olapColumnDesc); + void Format(const NKikimrSchemeOp::TColumnTableSharding& tableSharding); + void Format(const NKikimrSchemeOp::TColumnDataLifeCycle& ttlSettings); + + void Format(const NKikimrColumnShardColumnDefaults::TColumnDefault& defaultValue); + void Format(const Ydb::TypedValue& value, bool isPartition = false); void FormatValue(NYdb::TValueParser& parser, bool isPartition = false, TString del = ""); void FormatPrimitive(NYdb::TValueParser& parser); diff --git a/ydb/core/sys_view/show_create/show_create.cpp b/ydb/core/sys_view/show_create/show_create.cpp index 9706e10cce4..2c9f4d3df51 100644 --- a/ydb/core/sys_view/show_create/show_create.cpp +++ b/ydb/core/sys_view/show_create/show_create.cpp @@ -136,13 +136,12 @@ private: switch (status) { case NKikimrScheme::StatusSuccess: { const auto& pathDescription = record.GetPathDescription(); - if (pathDescription.GetSelf().GetPathType() != NKikimrSchemeOp::EPathTypeTable) { + if (pathDescription.GetSelf().GetPathType() != NKikimrSchemeOp::EPathTypeTable + && pathDescription.GetSelf().GetPathType() != NKikimrSchemeOp::EPathTypeColumnTable) { ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, "Invalid path type"); return; } - const auto& tableDesc = pathDescription.GetTable(); - std::pair<TString, TString> pathPair; { @@ -173,14 +172,37 @@ private: temporary = true; } - TCreateTableFormatter formatter; - auto formatterResult = formatter.Format(tablePath, tableDesc, temporary); - if (formatterResult.IsSuccess()) { - path = tablePath; - statement = formatterResult.ExtractOut(); - } else { - ReplyErrorAndDie(formatterResult.GetStatus(), formatterResult.GetError()); - return; + switch (pathDescription.GetSelf().GetPathType()) { + case NKikimrSchemeOp::EPathTypeTable: { + const auto& tableDesc = pathDescription.GetTable(); + TCreateTableFormatter formatter; + auto formatterResult = formatter.Format(tablePath, tableDesc, temporary); + if (formatterResult.IsSuccess()) { + path = tablePath; + statement = formatterResult.ExtractOut(); + } else { + ReplyErrorAndDie(formatterResult.GetStatus(), formatterResult.GetError()); + return; + } + break; + } + case NKikimrSchemeOp::EPathTypeColumnTable: { + const auto& columnTableDesc = pathDescription.GetColumnTableDescription(); + TCreateTableFormatter formatter; + auto formatterResult = formatter.Format(tablePath, columnTableDesc, temporary); + if (formatterResult.IsSuccess()) { + path = tablePath; + statement = formatterResult.ExtractOut(); + } else { + ReplyErrorAndDie(formatterResult.GetStatus(), formatterResult.GetError()); + return; + } + break; + } + default: { + ReplyErrorAndDie(Ydb::StatusIds::SCHEME_ERROR, "Invalid path type"); + return; + } } break; } diff --git a/ydb/core/sys_view/show_create/ya.make b/ydb/core/sys_view/show_create/ya.make index bf35ce0f8a1..16fad0e331b 100644 --- a/ydb/core/sys_view/show_create/ya.make +++ b/ydb/core/sys_view/show_create/ya.make @@ -11,6 +11,7 @@ PEERDIR( ydb/core/base ydb/core/kqp/runtime ydb/core/protos + ydb/core/tx/columnshard/engines/scheme/defaults/protos ydb/core/sys_view/common ydb/core/tx/schemeshard ydb/core/tx/tx_proxy diff --git a/ydb/core/sys_view/ut_common.cpp b/ydb/core/sys_view/ut_common.cpp index 8bc695a239b..3705a1900a2 100644 --- a/ydb/core/sys_view/ut_common.cpp +++ b/ydb/core/sys_view/ut_common.cpp @@ -1,5 +1,6 @@ #include "ut_common.h" #include <ydb/core/persqueue/ut/common/pq_ut_common.h> +#include <ydb/core/wrappers/fake_storage.h> namespace NKikimr { namespace NSysView { @@ -46,6 +47,9 @@ TTestEnv::TTestEnv(ui32 staticNodes, ui32 dynamicNodes, const TTestEnvSettings& featureFlags.SetEnableResourcePools(true); featureFlags.SetEnableFollowerStats(true); featureFlags.SetEnableVectorIndex(true); + featureFlags.SetEnableTieringInColumnShard(true); + featureFlags.SetEnableExternalDataSources(true); + Settings->SetFeatureFlags(featureFlags); Settings->SetEnablePersistentQueryStats(settings.EnableSVP); @@ -56,6 +60,7 @@ TTestEnv::TTestEnv(ui32 staticNodes, ui32 dynamicNodes, const TTestEnvSettings& NKikimrConfig::TAppConfig appConfig; *appConfig.MutableFeatureFlags() = Settings->FeatureFlags; + appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("ObjectStorage"); Settings->SetAppConfig(appConfig); for (ui32 i : xrange(settings.StoragePools)) { @@ -97,6 +102,8 @@ TTestEnv::TTestEnv(ui32 staticNodes, ui32 dynamicNodes, const TTestEnvSettings& Driver = MakeHolder<NYdb::TDriver>(DriverConfig); Server->GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); + + Singleton<NKikimr::NWrappers::NExternalStorage::TFakeExternalStorage>()->SetSecretKey("fakeSecret"); } TTestEnv::~TTestEnv() { diff --git a/ydb/core/sys_view/ut_kqp.cpp b/ydb/core/sys_view/ut_kqp.cpp index 2dedc8b4c48..c5bb53a373a 100644 --- a/ydb/core/sys_view/ut_kqp.cpp +++ b/ydb/core/sys_view/ut_kqp.cpp @@ -266,7 +266,10 @@ public: : Env(env) , QueryClient(NQuery::TQueryClient(Env.GetDriver())) , TableClient(TTableClient(Env.GetDriver())) - {} + { + CreateTier("tier1"); + CreateTier("tier2"); + } void CheckShowCreateTable(const std::string& query, const std::string& tableName, TString formatQuery = "", bool temporary = false) { auto session = QueryClient.GetSession().GetValueSync().GetSession(); @@ -283,16 +286,16 @@ public: UNIT_ASSERT_VALUES_EQUAL_C(UnescapeC(formatQuery), UnescapeC(showCreateTableQuery), UnescapeC(showCreateTableQuery)); } - auto tableDescOrig = DescribeTable(tableName, sessionId); + auto describeResultOrig = DescribeTable(tableName, sessionId); DropTable(session, tableName); CreateTable(session, showCreateTableQuery); - auto tableDescNew = DescribeTable(tableName, sessionId); + auto describeResultNew = DescribeTable(tableName, sessionId); DropTable(session, tableName); - CompareDescriptions(std::move(tableDescOrig), std::move(tableDescNew), showCreateTableQuery); + CompareDescriptions(std::move(describeResultOrig), std::move(describeResultNew), showCreateTableQuery); } private: @@ -302,7 +305,24 @@ private: UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } - NKikimrSchemeOp::TTableDescription DescribeTable(const std::string& tableName, + void CreateTier(const TString& tierName) { + auto session = TableClient.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteSchemeQuery(R"( + UPSERT OBJECT `accessKey` (TYPE SECRET) WITH (value = `secretAccessKey`); + UPSERT OBJECT `secretKey` (TYPE SECRET) WITH (value = `fakeSecret`); + CREATE EXTERNAL DATA SOURCE `)" + tierName + R"(` WITH ( + SOURCE_TYPE="ObjectStorage", + LOCATION="http://fake.fake/olap-)" + tierName + R"(", + AUTH_METHOD="AWS", + AWS_ACCESS_KEY_ID_SECRET_NAME="accessKey", + AWS_SECRET_ACCESS_KEY_SECRET_NAME="secretKey", + AWS_REGION="ru-central1" + ); + )").GetValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } + + Ydb::Table::CreateTableRequest DescribeTable(const std::string& tableName, std::optional<TString> sessionId = std::nullopt) { auto describeTable = [this](const TString& path) { @@ -317,7 +337,19 @@ private: runtime.Send(new IEventHandle(MakeTxProxyID(), sender, request.Release())); auto reply = runtime.GrabEdgeEventRethrow<NSchemeShard::TEvSchemeShard::TEvDescribeSchemeResult>(handle); - return reply->GetRecord().GetPathDescription().GetTable(); + if (reply->GetRecord().GetPathDescription().HasColumnTableDescription()) { + const auto& tableDescription = reply->GetRecord().GetPathDescription().GetColumnTableDescription(); + + return *GetCreateTableRequest(tableDescription); + } + + if (!reply->GetRecord().GetPathDescription().HasTable()) { + UNIT_ASSERT_C(false, "Invalid path type"); + } + + const auto& tableDescription = reply->GetRecord().GetPathDescription().GetTable(); + + return *GetCreateTableRequest(tableDescription); }; TString tablePath = TString(tableName); @@ -383,14 +415,11 @@ private: UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } - void CompareDescriptions(NKikimrSchemeOp::TTableDescription origDesc, NKikimrSchemeOp::TTableDescription newDesc, const std::string& showCreateTableQuery) { - Ydb::Table::CreateTableRequest requestFirst = *GetCreateTableRequest(origDesc); - Ydb::Table::CreateTableRequest requestSecond = *GetCreateTableRequest(newDesc); - + void CompareDescriptions(Ydb::Table::CreateTableRequest describeResultOrig, Ydb::Table::CreateTableRequest describeResultNew, const std::string& showCreateTableQuery) { TString first; - ::google::protobuf::TextFormat::PrintToString(requestFirst, &first); + ::google::protobuf::TextFormat::PrintToString(describeResultOrig, &first); TString second; - ::google::protobuf::TextFormat::PrintToString(requestSecond, &second); + ::google::protobuf::TextFormat::PrintToString(describeResultNew, &second); UNIT_ASSERT_VALUES_EQUAL_C(first, second, showCreateTableQuery); } @@ -430,6 +459,15 @@ private: return scheme; } + TMaybe<Ydb::Table::CreateTableRequest> GetCreateTableRequest(const NKikimrSchemeOp::TColumnTableDescription& tableDesc) { + Ydb::Table::CreateTableRequest scheme; + + FillColumnDescription(scheme, tableDesc); + FillColumnFamilies(scheme, tableDesc); + + return scheme; + } + private: TTestEnv& Env; NQuery::TQueryClient QueryClient; @@ -942,8 +980,109 @@ R"(CREATE TABLE `test_show_create` ( PRIMARY KEY (`BoolValue`, `Int32Value`, `Uint32Value`, `Int64Value`, `Uint64Value`, `StringValue`, `Utf8Value`) ) WITH (PARTITION_AT_KEYS = ((FALSE), (FALSE, 1, 2), (TRUE, 1, 1, 1, 1, 'str'), (TRUE, 1, 1, 100, 0, 'str', 'utf'))); -)", - true); +)" + ); + } + + Y_UNIT_TEST(ShowCreateTablePartitionByHash) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_EXECUTER, NActors::NLog::PRI_DEBUG); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_COMPILE_SERVICE, NActors::NLog::PRI_DEBUG); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); + + TShowCreateTableChecker checker(env); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key1 Uint64 NOT NULL, + Key2 String NOT NULL, + Value String, + PRIMARY KEY (Key1, Key2) + ) + PARTITION BY HASH(Key1, Key2) + WITH ( + STORE = COLUMN + ); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key1` Uint64 NOT NULL, + `Key2` String NOT NULL, + `Value` String, + PRIMARY KEY (`Key1`, `Key2`) +) +PARTITION BY HASH (`Key1`, `Key2`) +WITH ( + STORE = COLUMN, + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 64 +); +)" + ); + } + + Y_UNIT_TEST(ShowCreateTableColumn) { + TTestEnv env(1, 4, {.StoragePools = 3, .ShowCreateTable = true}); + + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_EXECUTER, NActors::NLog::PRI_DEBUG); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_COMPILE_SERVICE, NActors::NLog::PRI_DEBUG); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); + env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); + + TShowCreateTableChecker checker(env); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key1 Uint64 NOT NULL, + Key2 Utf8 NOT NULL, + Key3 Int32 NOT NULL, + Value1 Utf8 FAMILY Family1, + Value2 Int16 FAMILY Family2, + Value3 String FAMILY Family2, + PRIMARY KEY (Key1, Key2, Key3), + FAMILY default ( + COMPRESSION = "zstd" + ), + FAMILY Family1 ( + COMPRESSION = "off" + ), + FAMILY Family2 ( + COMPRESSION = "lz4" + ) + ) + PARTITION BY HASH(`Key1`, `Key2`) + WITH ( + STORE = COLUMN, + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 100, + TTL = + Interval("PT10S") TO EXTERNAL DATA SOURCE `/Root/tier1`, + Interval("PT1H") DELETE + ON Key1 AS SECONDS + ); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key1` Uint64 NOT NULL, + `Key2` Utf8 NOT NULL, + `Key3` Int32 NOT NULL, + `Value1` Utf8, + `Value2` Int16, + `Value3` String, + FAMILY `default` (COMPRESSION = 'zstd'), + FAMILY `Family1` (COMPRESSION = 'off'), + FAMILY `Family2` (COMPRESSION = 'lz4'), + PRIMARY KEY (`Key1`, `Key2`, `Key3`) +) +PARTITION BY HASH (`Key1`, `Key2`) +WITH ( + STORE = COLUMN, + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 100, + TTL = + INTERVAL('PT10S') TO EXTERNAL DATA SOURCE `/Root/tier1`, + INTERVAL('PT1H') DELETE + ON Key1 AS SECONDS +); +)" + ); } Y_UNIT_TEST(ShowCreateTablePartitionSettings) { @@ -1090,6 +1229,82 @@ R"(CREATE TABLE `test_show_create` ( WITH (TTL = INTERVAL('PT1H') DELETE ON Key AS SECONDS); )" ); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Uint32 NOT NULL, + Value String, + PRIMARY KEY (Key) + ) + PARTITION BY HASH(`Key`) + WITH ( + STORE = COLUMN, + TTL = INTERVAL('PT1H') DELETE ON Key AS MILLISECONDS + ); + )", "test_show_create"); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Uint32 NOT NULL, + Value String, + PRIMARY KEY (Key) + ) + PARTITION BY HASH(`Key`) + WITH ( + STORE = COLUMN, + TTL = + INTERVAL('PT1H') TO EXTERNAL DATA SOURCE `/Root/tier2`, + INTERVAL('PT3H') DELETE + ON Key AS NANOSECONDS + ); + )", "test_show_create"); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Uint64 NOT NULL, + Value String, + PRIMARY KEY (Key) + ) + PARTITION BY HASH(`Key`) + WITH ( + STORE = COLUMN, + TTL = INTERVAL('PT1H') TO EXTERNAL DATA SOURCE `/Root/tier2` ON Key AS MICROSECONDS + ); + )", "test_show_create"); + + checker.CheckShowCreateTable(R"( + CREATE TABLE test_show_create ( + Key Timestamp NOT NULL, + Value String, + PRIMARY KEY (Key) + ) + PARTITION BY HASH(`Key`) + WITH ( + STORE = COLUMN, + TTL = + Interval("PT10S") TO EXTERNAL DATA SOURCE `/Root/tier1`, + Interval("PT1M") TO EXTERNAL DATA SOURCE `/Root/tier2`, + Interval("PT1H") DELETE + ON Key + ); + )", "test_show_create", +R"(CREATE TABLE `test_show_create` ( + `Key` Timestamp NOT NULL, + `Value` String, + PRIMARY KEY (`Key`) +) +PARTITION BY HASH (`Key`) +WITH ( + STORE = COLUMN, + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 64, + TTL = + INTERVAL('PT10S') TO EXTERNAL DATA SOURCE `/Root/tier1`, + INTERVAL('PT1M') TO EXTERNAL DATA SOURCE `/Root/tier2`, + INTERVAL('PT1H') DELETE + ON Key +); +)" + ); } Y_UNIT_TEST(ShowCreateTableTemporary) { diff --git a/ydb/core/sys_view/ya.make b/ydb/core/sys_view/ya.make index eb813f4dbae..8d0c77be404 100644 --- a/ydb/core/sys_view/ya.make +++ b/ydb/core/sys_view/ya.make @@ -23,6 +23,7 @@ PEERDIR( ydb/core/sys_view/tablets ydb/core/tx/schemeshard ydb/core/tx/tx_proxy + ydb/core/wrappers ) YQL_LAST_ABI_VERSION() diff --git a/ydb/core/ydb_convert/table_description.cpp b/ydb/core/ydb_convert/table_description.cpp index 94041248b9a..a676d8f018c 100644 --- a/ydb/core/ydb_convert/table_description.cpp +++ b/ydb/core/ydb_convert/table_description.cpp @@ -560,12 +560,17 @@ void FillColumnDescription(Ydb::Table::CreateTableRequest& out, FillColumnDescriptionImpl(out, splitKeyType, in); } -void FillColumnDescription(Ydb::Table::DescribeTableResult& out, const NKikimrSchemeOp::TColumnTableDescription& in) { +template <typename TYdbProto> +void FillColumnDescriptionImpl(TYdbProto& out, const NKikimrSchemeOp::TColumnTableDescription& in) { auto& schema = in.GetSchema(); for (const auto& column : schema.GetColumns()) { auto newColumn = out.add_columns(); AddColumn(newColumn, column); + + if (column.HasColumnFamilyName()) { + newColumn->set_family(column.GetColumnFamilyName()); + } } for (auto& name : schema.GetKeyColumnNames()) { @@ -592,6 +597,14 @@ void FillColumnDescription(Ydb::Table::DescribeTableResult& out, const NKikimrSc out.set_store_type(Ydb::Table::StoreType::STORE_TYPE_COLUMN); } +void FillColumnDescription(Ydb::Table::DescribeTableResult& out, const NKikimrSchemeOp::TColumnTableDescription& in) { + FillColumnDescriptionImpl(out, in); +} + +void FillColumnDescription(Ydb::Table::CreateTableRequest& out, const NKikimrSchemeOp::TColumnTableDescription& in) { + FillColumnDescriptionImpl(out, in); +} + bool ExtractColumnTypeInfo(NScheme::TTypeInfo& outTypeInfo, TString& outTypeMod, const Ydb::Type& inType, Ydb::StatusIds::StatusCode& status, TString& error) { @@ -1415,6 +1428,50 @@ void FillStorageSettings(Ydb::Table::CreateTableRequest& out, FillStorageSettingsImpl(out, in); } +void FillColumnFamily(Ydb::Table::ColumnFamily& out, const NKikimrSchemeOp::TFamilyDescription& in, bool isColumnTable) { + if (in.HasName() && !in.GetName().empty()) { + out.set_name(in.GetName()); + } else if (IsDefaultFamily(in)) { + out.set_name("default"); + } else if (in.HasId()) { + out.set_name(TStringBuilder() << "<id: " << in.GetId() << ">"); + } else { + out.set_name(in.GetName()); + } + + if (!isColumnTable && in.HasStorageConfig() && in.GetStorageConfig().HasData()) { + FillStoragePool(&out, &Ydb::Table::ColumnFamily::mutable_data, in.GetStorageConfig().GetData()); + } + + if (in.HasColumnCodec()) { + switch (in.GetColumnCodec()) { + case NKikimrSchemeOp::ColumnCodecPlain: + out.set_compression(Ydb::Table::ColumnFamily::COMPRESSION_NONE); + break; + case NKikimrSchemeOp::ColumnCodecLZ4: + out.set_compression(Ydb::Table::ColumnFamily::COMPRESSION_LZ4); + break; + case NKikimrSchemeOp::ColumnCodecZSTD: { + if (!isColumnTable) { + break; // FIXME: not supported + } + out.set_compression(Ydb::Table::ColumnFamily::COMPRESSION_ZSTD); + break; + } + } + } else if (in.GetCodec() == 1) { + // Legacy setting, see datashard + out.set_compression(Ydb::Table::ColumnFamily::COMPRESSION_LZ4); + } else { + out.set_compression(Ydb::Table::ColumnFamily::COMPRESSION_NONE); + } + + // Check legacy settings for permanent in-memory cache + if (in.GetInMemory() || in.GetColumnCache() == NKikimrSchemeOp::ColumnCacheEver) { + out.set_keep_in_memory(Ydb::FeatureFlag::ENABLED); + } +} + template <typename TYdbProto> void FillColumnFamiliesImpl(TYdbProto& out, const NKikimrSchemeOp::TTableDescription& in) { @@ -1432,42 +1489,7 @@ void FillColumnFamiliesImpl(TYdbProto& out, const auto& family = partConfig.GetColumnFamilies(i); auto* r = out.add_column_families(); - if (family.HasName() && !family.GetName().empty()) { - r->set_name(family.GetName()); - } else if (IsDefaultFamily(family)) { - r->set_name("default"); - } else if (family.HasId()) { - r->set_name(TStringBuilder() << "<id: " << family.GetId() << ">"); - } else { - r->set_name(family.GetName()); - } - - if (family.HasStorageConfig() && family.GetStorageConfig().HasData()) { - FillStoragePool(r, &Ydb::Table::ColumnFamily::mutable_data, family.GetStorageConfig().GetData()); - } - - if (family.HasColumnCodec()) { - switch (family.GetColumnCodec()) { - case NKikimrSchemeOp::ColumnCodecPlain: - r->set_compression(Ydb::Table::ColumnFamily::COMPRESSION_NONE); - break; - case NKikimrSchemeOp::ColumnCodecLZ4: - r->set_compression(Ydb::Table::ColumnFamily::COMPRESSION_LZ4); - break; - case NKikimrSchemeOp::ColumnCodecZSTD: - break; // FIXME: not supported - } - } else if (family.GetCodec() == 1) { - // Legacy setting, see datashard - r->set_compression(Ydb::Table::ColumnFamily::COMPRESSION_LZ4); - } else { - r->set_compression(Ydb::Table::ColumnFamily::COMPRESSION_NONE); - } - - // Check legacy settings for permanent in-memory cache - if (family.GetInMemory() || family.GetColumnCache() == NKikimrSchemeOp::ColumnCacheEver) { - r->set_keep_in_memory(Ydb::FeatureFlag::ENABLED); - } + FillColumnFamily(*r, family, false); } } @@ -1481,6 +1503,17 @@ void FillColumnFamilies(Ydb::Table::CreateTableRequest& out, FillColumnFamiliesImpl(out, in); } +void FillColumnFamilies(Ydb::Table::CreateTableRequest& out, + const NKikimrSchemeOp::TColumnTableDescription& in) { + const auto& schema = in.GetSchema(); + for (size_t i = 0; i < schema.ColumnFamiliesSize(); ++i) { + const auto& family = schema.GetColumnFamilies(i); + auto* r = out.add_column_families(); + + FillColumnFamily(*r, family, true); + } +} + void FillAttributes(Ydb::Table::DescribeTableResult& out, const NKikimrSchemeOp::TPathDescription& in) { FillAttributesImpl(out, in); diff --git a/ydb/core/ydb_convert/table_description.h b/ydb/core/ydb_convert/table_description.h index 2b73db84abc..b403707168d 100644 --- a/ydb/core/ydb_convert/table_description.h +++ b/ydb/core/ydb_convert/table_description.h @@ -57,6 +57,7 @@ void FillColumnDescription(Ydb::Table::DescribeTableResult& out, void FillColumnDescription(Ydb::Table::CreateTableRequest& out, NKikimrMiniKQL::TType& splitKeyType, const NKikimrSchemeOp::TTableDescription& in); void FillColumnDescription(Ydb::Table::DescribeTableResult& out, const NKikimrSchemeOp::TColumnTableDescription& in); +void FillColumnDescription(Ydb::Table::CreateTableRequest& out, const NKikimrSchemeOp::TColumnTableDescription& in); // in bool FillColumnDescription(NKikimrSchemeOp::TTableDescription& out, const google::protobuf::RepeatedPtrField<Ydb::Table::ColumnMeta>& in, Ydb::StatusIds::StatusCode& status, TString& error); @@ -108,6 +109,8 @@ void FillColumnFamilies(Ydb::Table::DescribeTableResult& out, const NKikimrSchemeOp::TTableDescription& in); void FillColumnFamilies(Ydb::Table::CreateTableRequest& out, const NKikimrSchemeOp::TTableDescription& in); +void FillColumnFamilies(Ydb::Table::CreateTableRequest& out, + const NKikimrSchemeOp::TColumnTableDescription& in); // out void FillAttributes(Ydb::Table::DescribeTableResult& out, |