aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Shumkov <shumkovnd@ydb.tech>2025-04-01 18:49:48 +0300
committerGitHub <noreply@github.com>2025-04-01 15:49:48 +0000
commit81a0068ec4e9a9879d92bcfadefbda26ce5d475f (patch)
tree03f262ee8a489529c16c9691164be5d146c644de
parentf97bb919937b9452311ffecb5c296ef82db98653 (diff)
downloadydb-81a0068ec4e9a9879d92bcfadefbda26ce5d475f.tar.gz
Show create table (Column-oriented tables) (#16509)
-rw-r--r--ydb/core/sys_view/show_create/create_table_formatter.cpp314
-rw-r--r--ydb/core/sys_view/show_create/create_table_formatter.h9
-rw-r--r--ydb/core/sys_view/show_create/show_create.cpp44
-rw-r--r--ydb/core/sys_view/show_create/ya.make1
-rw-r--r--ydb/core/sys_view/ut_common.cpp7
-rw-r--r--ydb/core/sys_view/ut_kqp.cpp243
-rw-r--r--ydb/core/sys_view/ya.make1
-rw-r--r--ydb/core/ydb_convert/table_description.cpp107
-rw-r--r--ydb/core/ydb_convert/table_description.h3
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,