summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniil Timižev <[email protected]>2026-07-01 13:12:00 +0300
committerGitHub <[email protected]>2026-07-01 10:12:00 +0000
commitd61eaf8a44444a54145492941973a4773ea987a5 (patch)
tree5f075162732ea3c139f5ac296ec206dd183c323c
parent336c5b67bf6ffc5d6c721191c918d8850a3dfbee (diff)
Inline literal DEFAULT column values into the query plan (#45049)
-rw-r--r--ydb/core/kqp/opt/kqp_opt_kql.cpp127
-rw-r--r--ydb/core/kqp/opt/ya.make2
-rw-r--r--ydb/core/kqp/ut/scheme/kqp_constraints_ut.cpp1699
-rw-r--r--ydb/core/protos/table_service_config.proto3
4 files changed, 1794 insertions, 37 deletions
diff --git a/ydb/core/kqp/opt/kqp_opt_kql.cpp b/ydb/core/kqp/opt/kqp_opt_kql.cpp
index 97207777041..a3e4a396be5 100644
--- a/ydb/core/kqp/opt/kqp_opt_kql.cpp
+++ b/ydb/core/kqp/opt/kqp_opt_kql.cpp
@@ -5,10 +5,16 @@
#include <ydb/core/kqp/common/kqp_yql.h>
#include <ydb/core/kqp/provider/yql_kikimr_provider_impl.h>
#include <ydb/core/kqp/provider/yql_kikimr_settings.h>
+#include <ydb/library/mkql_proto/mkql_proto.h>
#include <ydb/library/yql/providers/dq/common/yql_dq_settings.h>
#include <yql/essentials/core/dq_integration/yql_dq_integration.h>
#include <yql/essentials/core/yql_opt_utils.h>
+#include <yql/essentials/minikql/computation/mkql_computation_node_holders.h>
+#include <yql/essentials/minikql/mkql_alloc.h>
+#include <yql/essentials/minikql/mkql_mem_info.h>
+#include <yql/essentials/providers/common/codec/yql_codec.h>
+#include <yql/essentials/providers/common/mkql/yql_type_mkql.h>
#include <yql/essentials/providers/common/provider/yql_provider.h>
#include <library/cpp/containers/absl_flat_hash/flat_hash_set.h>
@@ -129,6 +135,86 @@ std::pair<TExprBase, TCoAtomList> ExtendInputRowsWithAbsentNullColumns(const TKi
return {writeData, columnList};
}
+TExprBase BuildYqlLiteralFromTypedValue(const Ydb::TypedValue& proto, TPositionHandle pos, TExprContext& ctx) {
+ NMiniKQL::TScopedAlloc alloc(__LOCATION__);
+ NMiniKQL::TTypeEnvironment typeEnv(alloc);
+ NMiniKQL::TMemoryUsageInfo memInfo("BuildYqlLiteralFromTypedValue");
+ NMiniKQL::THolderFactory holderFactory(alloc.Ref(), memInfo);
+
+ auto guard = typeEnv.BindAllocator();
+ auto [mkqlType, unboxedValue] = NMiniKQL::ImportValueFromProto(proto.type(), proto.value(), typeEnv, holderFactory);
+ const TTypeAnnotationNode* typeAnnotation = NYql::NCommon::ConvertMiniKQLType(ctx.GetPosition(pos), mkqlType, ctx);
+ return TExprBase(NYql::NCommon::ValueToExprLiteral(typeAnnotation, unboxedValue, ctx, pos));
+}
+
+// Appends DEFAULT_KIND_LITERAL column values to every row in the input stream.
+std::pair<TExprBase, TCoAtomList> ExtendInputRowsWithDefaultLiteralColumns(const TExprBase& input, const TCoAtomList& inputColumns,
+ const TCoAtomList& literalDefaultColumns, const TKikimrTableDescription& tableDesc, TPositionHandle pos, TExprContext& ctx)
+{
+ if (literalDefaultColumns.Ref().ChildrenSize() == 0) {
+ return {input, inputColumns};
+ }
+
+ auto rowArg = Build<TCoArgument>(ctx, pos).Name("row").Done();
+
+ TVector<TCoAtom> allColumns;
+ TVector<TExprBase> allMembers;
+
+ for (const auto& col : inputColumns) {
+ allColumns.push_back(col);
+ allMembers.push_back(
+ Build<TCoNameValueTuple>(ctx, pos)
+ .Name(col)
+ .Value<TCoMember>()
+ .Struct(rowArg)
+ .Name().Build(col.Value())
+ .Build()
+ .Done());
+ }
+
+ for (const auto& col : literalDefaultColumns) {
+ TString colName = TString(col.Value());
+ const auto* colMeta = tableDesc.Metadata->Columns.FindPtr(colName);
+ YQL_ENSURE(colMeta && colMeta->IsDefaultFromLiteral());
+
+ TExprBase literalExpr = BuildYqlLiteralFromTypedValue(colMeta->DefaultFromLiteral, pos, ctx);
+
+ const auto* colType = tableDesc.GetColumnType(colName);
+ YQL_ENSURE(colType);
+
+ TExprBase memberValue = literalExpr;
+ if (colType->IsOptionalOrNull()) {
+ memberValue = Build<TCoJust>(ctx, pos)
+ .Input(literalExpr)
+ .Done();
+ }
+
+ auto nameAtom = TCoAtom(ctx.NewAtom(pos, colName));
+ allColumns.push_back(nameAtom);
+ allMembers.push_back(
+ Build<TCoNameValueTuple>(ctx, pos)
+ .Name(nameAtom)
+ .Value(memberValue)
+ .Done());
+ }
+
+ auto writeData = Build<TCoMap>(ctx, pos)
+ .Input(input)
+ .Lambda()
+ .Args({rowArg})
+ .Body<TCoAsStruct>()
+ .Add(allMembers)
+ .Build()
+ .Build()
+ .Done();
+
+ auto columnList = Build<TCoAtomList>(ctx, pos)
+ .Add(allColumns)
+ .Done();
+
+ return {writeData, columnList};
+}
+
bool HasIndexesToWrite(const TKikimrTableDescription& tableData) {
bool hasIndexesToWrite = false;
YQL_ENSURE(tableData.Metadata->Indexes.size() == tableData.Metadata->ImplTables.size());
@@ -315,22 +401,51 @@ std::pair<TExprBase, TCoAtomList> BuildWriteInput(const TKiWriteTable& write, co
const TCoAtomList& inputColumns, const TCoAtomList& autoIncrement, const bool /*isSink*/,
TPositionHandle pos, TExprContext& ctx, TKqpOptimizeContext& kqpCtx)
{
- auto input = write.Input();
+ TExprBase input = write.Input();
+ std::optional<TCoAtomList> inputCols;
+
+ // Split autoIncrement into sequence columns (handled at runtime by TKqlSequencer) and
+ // literal defaults (inlined at compile time into the row struct via TCoMap/TCoAsStruct).
+ if (kqpCtx.Config->GetEnableCompileTimeDefaults()) {
+ TVector<TExprNode::TPtr> sequenceColNodes;
+ TVector<TExprNode::TPtr> literalDefaultColNodes;
+
+ for (const auto& colAtom : autoIncrement) {
+ const auto* colMeta = table.Metadata->Columns.FindPtr(TString(colAtom.Value()));
+ if (colMeta && colMeta->IsDefaultFromLiteral() && !colMeta->DefaultFromLiteral.type().has_pg_type()) {
+ literalDefaultColNodes.push_back(colAtom.Ptr());
+ } else {
+ sequenceColNodes.push_back(colAtom.Ptr());
+ }
+ }
- TCoAtomList inputCols = BuildUpsertInputColumns(inputColumns, autoIncrement, pos, ctx);
+ auto sequenceCols = Build<TCoAtomList>(ctx, pos).Add(sequenceColNodes).Done();
+ auto literalDefaultCols = Build<TCoAtomList>(ctx, pos).Add(literalDefaultColNodes).Done();
- if (autoIncrement.Ref().ChildrenSize() > 0) {
- input = BuildKqlSequencer(input, table, inputCols, autoIncrement, pos, ctx);
+ TCoAtomList inputColsAfterSequencer = BuildUpsertInputColumns(inputColumns, sequenceCols, pos, ctx);
+
+ if (sequenceCols.Ref().ChildrenSize() > 0) {
+ input = BuildKqlSequencer(input, table, inputColsAfterSequencer, sequenceCols, pos, ctx);
+ }
+
+ std::tie(input, inputCols) = ExtendInputRowsWithDefaultLiteralColumns(input, inputColsAfterSequencer,
+ literalDefaultCols, table, pos, ctx);
+ } else {
+ inputCols = BuildUpsertInputColumns(inputColumns, autoIncrement, pos, ctx);
+ if (autoIncrement.Ref().ChildrenSize() > 0) {
+ input = BuildKqlSequencer(input, table, inputCols.value(), autoIncrement, pos, ctx);
+ }
}
- std::tie(input, inputCols) = ExtendInputRowsWithAbsentNullColumns(write, input, inputCols, table, write.Pos(), ctx, kqpCtx);
+ YQL_ENSURE(inputCols.has_value());
+ std::tie(input, inputCols) = ExtendInputRowsWithAbsentNullColumns(write, input, inputCols.value(), table, write.Pos(), ctx, kqpCtx);
auto baseInput = Build<TKqpWriteConstraint>(ctx, pos)
.Input(input)
.Columns(GetPgNotNullColumns(table, pos, ctx))
.Done();
- return {baseInput, inputCols};
+ return {baseInput, inputCols.value()};
}
diff --git a/ydb/core/kqp/opt/ya.make b/ydb/core/kqp/opt/ya.make
index 17206198003..0564f0e11af 100644
--- a/ydb/core/kqp/opt/ya.make
+++ b/ydb/core/kqp/opt/ya.make
@@ -28,6 +28,7 @@ PEERDIR(
ydb/core/kqp/opt/peephole
ydb/core/kqp/opt/physical
ydb/core/kqp/opt/rbo
+ ydb/library/mkql_proto
ydb/library/yql/dq/common
ydb/library/yql/dq/opt
ydb/library/yql/dq/type_ann
@@ -37,6 +38,7 @@ PEERDIR(
ydb/core/kqp/provider
ydb/library/formats/arrow/protos
ydb/library/json_index
+ yql/essentials/providers/common/mkql
)
YQL_LAST_ABI_VERSION()
diff --git a/ydb/core/kqp/ut/scheme/kqp_constraints_ut.cpp b/ydb/core/kqp/ut/scheme/kqp_constraints_ut.cpp
index 1d79de6107c..ba864d7ec50 100644
--- a/ydb/core/kqp/ut/scheme/kqp_constraints_ut.cpp
+++ b/ydb/core/kqp/ut/scheme/kqp_constraints_ut.cpp
@@ -12,6 +12,64 @@ using namespace NYdb;
using namespace NYdb::NQuery;
using namespace NYdb::NTopic;
+namespace {
+
+void TestCompileTimeDefaultsPlan(const std::string& operation, bool enabled) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(enabled);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+ auto settings = TExecuteQuerySettings().ExecMode(EExecMode::Explain);
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ Value String DEFAULT "first_default",
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ {
+ // Implicit default value
+ const std::string query = std::format(R"(
+ {} INTO TestTable (Key) VALUES (1);
+ )", operation);
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx(), settings).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ const auto ast = result.GetStats()->GetAst();
+ if (enabled) {
+ // DEFAULT value is inlined into the plan
+ UNIT_ASSERT_C(!ast->contains("KqpCnSequencer"), ast);
+ } else {
+ // Runtime substitution of DEFAULT value
+ UNIT_ASSERT_C(ast->contains("KqpCnSequencer"), ast);
+ }
+ }
+
+ {
+ // Explicit default value -> without sequencer
+ const std::string query = std::format(R"(
+ {} INTO TestTable (Key, Value) VALUES (2, "value2");
+ )", operation);
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx(), settings).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ const auto ast = result.GetStats()->GetAst();
+ // DEFAULT value is inlined into the plan
+ UNIT_ASSERT_C(!ast->contains("KqpCnSequencer"), ast);
+ }
+}
+
+} // namespace
+
Y_UNIT_TEST_SUITE(KqpConstraints) {
Y_UNIT_TEST(SerialTypeNegative1) {
TKikimrRunner kikimr(TKikimrSettings()
@@ -321,8 +379,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(DefaultsAndDeleteAndUpdate) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(DefaultsAndDeleteAndUpdate, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -378,8 +438,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableAddColumnWithDefaultValue) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(AlterTableAddColumnWithDefaultValue, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -468,8 +530,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(DefaultValuesForTable) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(DefaultValuesForTable, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -1037,8 +1101,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
])");
}
- Y_UNIT_TEST(IndexedTableAndNotNullColumnAddNotNullColumn) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(IndexedTableAndNotNullColumnAddNotNullColumn, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetEnableParameterizedDecimal(true)
.SetWithSampleTables(false));
@@ -1264,8 +1330,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(DefaultAndIndexesTestDefaultColumnNotIncludedInIndex) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(DefaultAndIndexesTestDefaultColumnNotIncludedInIndex, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -1319,8 +1387,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
)"));
}
- Y_UNIT_TEST(Utf8AndDefault) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(Utf8AndDefault, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -1397,8 +1467,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableAddNotNullWithDefault) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(AlterTableAddNotNullWithDefault, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -1606,8 +1678,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(DefaultColumnAndBulkUpsert) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(DefaultColumnAndBulkUpsert, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto queryClient = kikimr.GetQueryClient();
@@ -1829,8 +1903,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::PRECONDITION_FAILED, result.GetIssues().ToString());
}
- Y_UNIT_TEST(AlterTableSetDefaultLiteral) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDefaultLiteral, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -1878,8 +1953,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDefaultInt) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDefaultInt, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -1927,8 +2003,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableDropDefault) {
+ Y_UNIT_TEST_TWIN(AlterTableDropDefault, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2179,8 +2256,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetAndDropDefaultOnNotNullColumn) {
+ Y_UNIT_TEST_TWIN(AlterTableSetAndDropDefaultOnNotNullColumn, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2315,8 +2393,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDropDefaultMultipleColumns) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDropDefaultMultipleColumns, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2566,8 +2645,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDefaultOnPK) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDefaultOnPK, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2619,8 +2699,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableDropDefaultOnPK) {
+ Y_UNIT_TEST_TWIN(AlterTableDropDefaultOnPK, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2736,8 +2817,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDropDefaultBulkUpsert) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDropDefaultBulkUpsert, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2810,8 +2892,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDropDefaultAsyncIndexOnColumn) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDropDefaultAsyncIndexOnColumn, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2904,8 +2987,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDropDefaultAsyncIndexCoverColumn) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDropDefaultAsyncIndexCoverColumn, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -2998,8 +3082,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableDefaultConstantExpression) {
+ Y_UNIT_TEST_TWIN(AlterTableDefaultConstantExpression, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -3123,8 +3208,10 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableAddColumnDefaultWithChangefeed) {
- TKikimrRunner kikimr(TKikimrSettings()
+ Y_UNIT_TEST_TWIN(AlterTableAddColumnDefaultWithChangefeed, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+ TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
auto db = kikimr.GetQueryClient();
@@ -3246,8 +3333,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(AlterTableSetDropDefaultWithChangefeed) {
+ Y_UNIT_TEST_TWIN(AlterTableSetDropDefaultWithChangefeed, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -3880,8 +3968,9 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
}
}
- Y_UNIT_TEST(SetDefaultMultipleTimes) {
+ Y_UNIT_TEST_TWIN(SetDefaultMultipleTimes, EnableCompileTimeDefaults) {
NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
TKikimrRunner kikimr(TKikimrSettings(appConfig)
.SetWithSampleTables(false));
@@ -3980,6 +4069,1554 @@ Y_UNIT_TEST_SUITE(KqpConstraints) {
])");
}
}
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_Ast_Upsert, EnableCompileTimeDefaults) {
+ TestCompileTimeDefaultsPlan("UPSERT", EnableCompileTimeDefaults);
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_Ast_Replace, EnableCompileTimeDefaults) {
+ TestCompileTimeDefaultsPlan("REPLACE", EnableCompileTimeDefaults);
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_Ast_Insert, EnableCompileTimeDefaults) {
+ TestCompileTimeDefaultsPlan("INSERT", EnableCompileTimeDefaults);
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_Write_Upsert, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ Value String DEFAULT "default_value",
+ Value2 String,
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateTable = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, Value, Value2 FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // Upsert new row, without default, without nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (1) RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#]
+ ])");
+ }
+
+ // Upsert new row, with default, without nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (2, "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["explicit"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#]
+ ])");
+ }
+
+ // Upsert new row, without default, with nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value2) VALUES (3, "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["default_value"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]]
+ ])");
+ }
+
+ // Upsert new row, with default, with nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value, Value2) VALUES (4, "explicit", "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["explicit"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["explicit"];["explicit"]]
+ ])");
+ }
+
+ // Upsert old row, without default, without nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (4) RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["explicit"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["explicit"];["explicit"]]
+ ])");
+ }
+
+ // Upsert old row, with default, without nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (4, "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["updated"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["updated"];["explicit"]]
+ ])");
+ }
+
+ // Upsert old row, without default, with nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value2) VALUES (4, "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["updated"];["updated"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["updated"];["updated"]]
+ ])");
+ }
+
+ // Upsert old row, with default, with nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value, Value2) VALUES (3, "updated", "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["updated"];["updated"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["updated"];["updated"]];
+ [[4];["updated"];["updated"]]
+ ])");
+ }
+
+ // Upsert batch, without default, without nullable
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (5), (6), (7), (8)
+ RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[5];["default_value"];#];
+ [[6];["default_value"];#];
+ [[7];["default_value"];#];
+ [[8];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["updated"];["updated"]];
+ [[4];["updated"];["updated"]];
+ [[5];["default_value"];#];
+ [[6];["default_value"];#];
+ [[7];["default_value"];#];
+ [[8];["default_value"];#]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_Write_Replace, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ Value String DEFAULT "default_value",
+ Value2 String,
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateTable = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, Value, Value2 FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // Replace new row, without default, without nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key) VALUES (1) RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#]
+ ])");
+ }
+
+ // Replace new row, with default, without nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value) VALUES (2, "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["explicit"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#]
+ ])");
+ }
+
+ // Replace new row, without default, with nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value2) VALUES (3, "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["default_value"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]]
+ ])");
+ }
+
+ // Replace new row, with default, with nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value, Value2) VALUES (4, "explicit", "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["explicit"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["explicit"];["explicit"]]
+ ])");
+ }
+
+ // Replace old row, without default, without nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key) VALUES (4) RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["default_value"];#]
+ ])");
+ }
+
+ // Replace old row, with default, without nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value) VALUES (4, "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["updated"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["updated"];#]
+ ])");
+ }
+
+ // Replace old row, without default, with nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value2) VALUES (4, "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["default_value"];["updated"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["default_value"];["updated"]]
+ ])");
+ }
+
+ // Replace old row, with default, with nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value, Value2) VALUES (3, "updated", "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["updated"];["updated"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["updated"];["updated"]];
+ [[4];["default_value"];["updated"]]
+ ])");
+ }
+
+ // Replace batch, without default, without nullable
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key) VALUES (5), (6), (7), (8)
+ RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[5];["default_value"];#];
+ [[6];["default_value"];#];
+ [[7];["default_value"];#];
+ [[8];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["updated"];["updated"]];
+ [[4];["default_value"];["updated"]];
+ [[5];["default_value"];#];
+ [[6];["default_value"];#];
+ [[7];["default_value"];#];
+ [[8];["default_value"];#]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_Write_Insert, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ Value String DEFAULT "default_value",
+ Value2 String,
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateTable = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, Value, Value2 FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // Insert new row, without default, without nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (1) RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#]
+ ])");
+ }
+
+ // Insert new row, with default, without nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value) VALUES (2, "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["explicit"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#]
+ ])");
+ }
+
+ // Insert new row, without default, with nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value2) VALUES (3, "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["default_value"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]]
+ ])");
+ }
+
+ // Insert new row, with default, with nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value, Value2) VALUES (4, "explicit", "explicit") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["explicit"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["explicit"];["explicit"]]
+ ])");
+ }
+
+ // Insert old row, without default, without nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (4) RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ // Insert old row, with default, without nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value) VALUES (4, "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ // Insert old row, without default, with nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value2) VALUES (4, "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ // Insert old row, with default, with nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value, Value2) VALUES (3, "updated", "updated") RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ // Insert batch, without default, without nullable
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (5), (6), (7), (8)
+ RETURNING Key, Value, Value2;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[5];["default_value"];#];
+ [[6];["default_value"];#];
+ [[7];["default_value"];#];
+ [[8];["default_value"];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"];#];
+ [[2];["explicit"];#];
+ [[3];["default_value"];["explicit"]];
+ [[4];["explicit"];["explicit"]];
+ [[5];["default_value"];#];
+ [[6];["default_value"];#];
+ [[7];["default_value"];#];
+ [[8];["default_value"];#]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST(CompileTimeDefaults_AllTypes) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(true);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE AllTypesDefaultTest (
+ Key Int32,
+ BoolCol Bool DEFAULT True,
+ Int8Col Int8 DEFAULT -100,
+ Int16Col Int16 DEFAULT -200,
+ Int32Col Int32 DEFAULT -300,
+ Int64Col Int64 DEFAULT -400,
+ Uint8Col Uint8 DEFAULT 10,
+ Uint16Col Uint16 DEFAULT 20,
+ Uint32Col Uint32 DEFAULT 30,
+ Uint64Col Uint64 DEFAULT 40,
+ FloatCol Float DEFAULT 1.5f,
+ DoubleCol Double DEFAULT 2.5,
+ StringCol String DEFAULT "hello",
+ Utf8Col Utf8 DEFAULT Utf8("world"),
+ DateCol Date DEFAULT Date("2021-01-01"),
+ DatetimeCol Datetime DEFAULT Datetime("2021-01-01T00:00:00Z"),
+ TimestampCol Timestamp DEFAULT Timestamp("2021-01-01T00:00:00.000000Z"),
+ IntervalCol Interval DEFAULT Interval("P1D"),
+ Date32Col Date32 DEFAULT Date32("2021-01-01"),
+ Datetime64Col Datetime64 DEFAULT Datetime64("2021-01-01T00:00:00Z"),
+ Timestamp64Col Timestamp64 DEFAULT Timestamp64("2021-01-01T00:00:00.000000Z"),
+ Interval64Col Interval64 DEFAULT Interval64("P1D"),
+ JsonCol Json DEFAULT Json("[0]"),
+ YsonCol Yson DEFAULT Yson("[1]"),
+ JsonDocumentCol JsonDocument DEFAULT JsonDocument("[2]"),
+ UuidCol Uuid DEFAULT Uuid("65df9ecc-a97d-47b2-ae56-3c023da6ee8c"),
+ DecimalCol Decimal(22,9) DEFAULT Decimal("1.11", 22, 9),
+ DyNumberCol DyNumber DEFAULT DyNumber("3.14"),
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ {
+ const std::string query = R"(
+ UPSERT INTO AllTypesDefaultTest (Key) VALUES (1)
+ RETURNING
+ Key, BoolCol,
+ Int8Col, Int16Col, Int32Col, Int64Col,
+ Uint8Col, Uint16Col, Uint32Col, Uint64Col,
+ FloatCol, DoubleCol,
+ StringCol, Utf8Col,
+ DateCol, DatetimeCol, TimestampCol, IntervalCol,
+ Date32Col, Datetime64Col, Timestamp64Col, Interval64Col,
+ JsonCol, YsonCol, JsonDocumentCol, UuidCol,
+ DecimalCol, DyNumberCol;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];[%true];
+ [-100];[-200];[-300];[-400];
+ [10u];[20u];[30u];[40u];
+ [1.5];[2.5];
+ ["hello"];["world"];
+ [18628u];[1609459200u];[1609459200000000u];[86400000000];
+ [18628];[1609459200];[1609459200000000];[86400000000];
+ ["[0]"];["[1]"];["[2]"];
+ ["65df9ecc-a97d-47b2-ae56-3c023da6ee8c"];
+ ["1.11"];
+ [".314e1"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+ }
+
+ {
+ const std::string query = R"(
+ SELECT
+ Key, BoolCol,
+ Int8Col, Int16Col, Int32Col, Int64Col,
+ Uint8Col, Uint16Col, Uint32Col, Uint64Col,
+ FloatCol, DoubleCol,
+ StringCol, Utf8Col,
+ DateCol, DatetimeCol, TimestampCol, IntervalCol,
+ Date32Col, Datetime64Col, Timestamp64Col, Interval64Col,
+ JsonCol, YsonCol, JsonDocumentCol, UuidCol,
+ DecimalCol, DyNumberCol
+ FROM AllTypesDefaultTest;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];[%true];
+ [-100];[-200];[-300];[-400];
+ [10u];[20u];[30u];[40u];
+ [1.5];[2.5];
+ ["hello"];["world"];
+ [18628u];[1609459200u];[1609459200000000u];[86400000000];
+ [18628];[1609459200];[1609459200000000];[86400000000];
+ ["[0]"];["[1]"];["[2]"];
+ ["65df9ecc-a97d-47b2-ae56-3c023da6ee8c"];
+ ["1.11"];
+ [".314e1"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_NotNullDefault, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ Value String NOT NULL DEFAULT "default_value",
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateTable = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, Value FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // UPSERT new row without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (1) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];"default_value"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"]
+ ])");
+ }
+
+ // UPSERT new row with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (2, "explicit") RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];"explicit"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"explicit"]
+ ])");
+ }
+
+ // UPSERT old row without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (2) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];"explicit"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ // Storage is always correct regardless of RETURNING
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"explicit"]
+ ])");
+ }
+
+ // UPSERT old row with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (2, "updated") RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];"updated"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"updated"]
+ ])");
+ }
+
+ // REPLACE old row without default
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key) VALUES (2) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];"default_value"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"default_value"]
+ ])");
+ }
+
+ // REPLACE old row with default
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value) VALUES (2, "explicit") RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];"explicit"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"explicit"]
+ ])");
+ }
+
+ // INSERT new row without default
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (3) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];"default_value"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"explicit"];
+ [[3];"default_value"]
+ ])");
+ }
+
+ // INSERT new row with default
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value) VALUES (4, "explicit") RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];"explicit"]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"explicit"];
+ [[3];"default_value"];
+ [[4];"explicit"]
+ ])");
+ }
+
+ // INSERT duplicate key
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (4);
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+
+ validateTable(R"([
+ [[1];"default_value"];
+ [[2];"explicit"];
+ [[3];"default_value"];
+ [[4];"explicit"]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_NullableDefault, EnableCompileTimeDefaults) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(EnableCompileTimeDefaults);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ Value String DEFAULT "default_value",
+ PRIMARY KEY (Key)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateTable = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, Value FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // UPSERT new row without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (1) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]]
+ ])");
+ }
+
+ // UPSERT new row with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (2, "explicit") RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]]
+ ])");
+ }
+
+ // UPSERT new row with NULL
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (3, NULL) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#]
+ ])");
+ }
+
+ // UPSERT old row without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key) VALUES (3) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ // Storage is always correct regardless of RETURNING
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#]
+ ])");
+ }
+
+ // UPSERT old row with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (3, "updated") RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["updated"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];["updated"]]
+ ])");
+ }
+
+ // UPSERT old row with NULL
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, Value) VALUES (3, NULL) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#]
+ ])");
+ }
+
+ // REPLACE old row without default
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key) VALUES (3) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];["default_value"]]
+ ])");
+ }
+
+ // REPLACE old row with NULL
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, Value) VALUES (3, NULL) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#]
+ ])");
+ }
+
+ // INSERT new row without default
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (4) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[4];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#];
+ [[4];["default_value"]]
+ ])");
+ }
+
+ // INSERT new row with NULL
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, Value) VALUES (5, NULL) RETURNING Key, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[5];#]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#];
+ [[4];["default_value"]];
+ [[5];#]
+ ])");
+ }
+
+ // INSERT duplicate key
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key) VALUES (5);
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+
+ validateTable(R"([
+ [[1];["default_value"]];
+ [[2];["explicit"]];
+ [[3];#];
+ [[4];["default_value"]];
+ [[5];#]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_WithGlobalSyncIndex, EnableIndexStreamWrite) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(true);
+ appConfig.MutableTableServiceConfig()->SetEnableIndexStreamWrite(EnableIndexStreamWrite);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ IndexCol String,
+ Value String DEFAULT "default_value",
+ PRIMARY KEY (Key),
+ INDEX ByIndexCol GLOBAL ON (IndexCol) COVER (Value)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateMain = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, IndexCol, Value FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ const auto validateIndex = [&](const std::string& indexColVal, const TString& expected) {
+ const std::string query = "SELECT Key, Value FROM TestTable VIEW ByIndexCol WHERE IndexCol = \"" + indexColVal + "\" ORDER BY Key;";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // UPSERT without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, IndexCol) VALUES (1, "idx1") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["idx1"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]]
+ ])");
+ validateIndex("idx1", R"([
+ [[1];["default_value"]]
+ ])");
+ }
+
+ // UPSERT with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, IndexCol, Value) VALUES (2, "idx2", "explicit") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["idx2"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["explicit"]]
+ ])");
+ validateIndex("idx2", R"([
+ [[2];["explicit"]]
+ ])");
+ }
+
+ // REPLACE without default
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, IndexCol) VALUES (2, "idx2") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["idx2"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]]
+ ])");
+ validateIndex("idx2", R"([
+ [[2];["default_value"]]
+ ])");
+ }
+
+ // INSERT without default
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, IndexCol) VALUES (3, "idx3") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["idx3"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]];
+ [[3];["idx3"];["default_value"]]
+ ])");
+ validateIndex("idx3", R"([
+ [[3];["default_value"]]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_WithGlobalAsyncIndex, EnableIndexStreamWrite) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(true);
+ appConfig.MutableTableServiceConfig()->SetEnableIndexStreamWrite(EnableIndexStreamWrite);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ IndexCol String,
+ Value String DEFAULT "default_value",
+ PRIMARY KEY (Key),
+ INDEX ByIndexCol GLOBAL ASYNC ON (IndexCol) COVER (Value)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateMain = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, IndexCol, Value FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ const auto validateIndex = [&](const std::string& indexColVal, const TString& expected) {
+ const std::string query = "SELECT Key, Value FROM TestTable VIEW ByIndexCol WHERE IndexCol = \"" + indexColVal + "\" ORDER BY Key;";
+ auto result = session.ExecuteQuery(query, TTxControl::BeginTx(TTxSettings::StaleRO()).CommitTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // UPSERT without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, IndexCol) VALUES (1, "idx1") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["idx1"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]]
+ ])");
+ validateIndex("idx1", R"([
+ [[1];["default_value"]]
+ ])");
+ }
+
+ // UPSERT with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, IndexCol, Value) VALUES (2, "idx2", "explicit") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["idx2"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["explicit"]]
+ ])");
+ validateIndex("idx2", R"([
+ [[2];["explicit"]]
+ ])");
+ }
+
+ // REPLACE without default
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, IndexCol) VALUES (2, "idx2") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["idx2"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]]
+ ])");
+ validateIndex("idx2", R"([
+ [[2];["default_value"]]
+ ])");
+ }
+
+ // INSERT without default
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, IndexCol) VALUES (3, "idx3") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["idx3"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]];
+ [[3];["idx3"];["default_value"]]
+ ])");
+ validateIndex("idx3", R"([
+ [[3];["default_value"]]
+ ])");
+ }
+ }
+
+ Y_UNIT_TEST_TWIN(CompileTimeDefaults_WithGlobalSyncUniqueIndex, EnableIndexStreamWrite) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnableCompileTimeDefaults(true);
+ appConfig.MutableTableServiceConfig()->SetEnableIndexStreamWrite(EnableIndexStreamWrite);
+
+ TKikimrRunner kikimr(TKikimrSettings(appConfig).SetWithSampleTables(false));
+
+ auto db = kikimr.GetQueryClient();
+ auto session = db.GetSession().GetValueSync().GetSession();
+
+ {
+ const std::string query = R"(
+ CREATE TABLE TestTable (
+ Key Int32,
+ IndexCol String,
+ Value String DEFAULT "default_value",
+ PRIMARY KEY (Key),
+ INDEX ByIndexCol GLOBAL UNIQUE SYNC ON (IndexCol) COVER (Value)
+ );
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ const auto validateMain = [&](const TString& expected) {
+ const std::string query = R"(
+ SELECT Key, IndexCol, Value FROM TestTable ORDER BY Key;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ const auto validateIndex = [&](const std::string& indexColVal, const TString& expected) {
+ const std::string query = "SELECT Key, Value FROM TestTable VIEW ByIndexCol WHERE IndexCol = \"" + indexColVal + "\" ORDER BY Key;";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ CompareYson(expected, FormatResultSetYson(result.GetResultSet(0)));
+ };
+
+ // UPSERT without default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, IndexCol) VALUES (1, "idx1") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[1];["idx1"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]]
+ ])");
+ validateIndex("idx1", R"([
+ [[1];["default_value"]]
+ ])");
+ }
+
+ // UPSERT with default
+ {
+ const std::string query = R"(
+ UPSERT INTO TestTable (Key, IndexCol, Value) VALUES (2, "idx2", "explicit") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["idx2"];["explicit"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["explicit"]]
+ ])");
+ validateIndex("idx2", R"([
+ [[2];["explicit"]]
+ ])");
+ }
+
+ // REPLACE without default
+ {
+ const std::string query = R"(
+ REPLACE INTO TestTable (Key, IndexCol) VALUES (2, "idx2") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[2];["idx2"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]]
+ ])");
+ validateIndex("idx2", R"([
+ [[2];["default_value"]]
+ ])");
+ }
+
+ // INSERT without default
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, IndexCol) VALUES (3, "idx3") RETURNING Key, IndexCol, Value;
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ CompareYson(R"([
+ [[3];["idx3"];["default_value"]]
+ ])", FormatResultSetYson(result.GetResultSet(0)));
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]];
+ [[3];["idx3"];["default_value"]]
+ ])");
+ validateIndex("idx3", R"([
+ [[3];["default_value"]]
+ ])");
+ }
+
+ // INSERT duplicate key
+ {
+ const std::string query = R"(
+ INSERT INTO TestTable (Key, IndexCol) VALUES (4, "idx1");
+ )";
+ auto result = session.ExecuteQuery(query, TTxControl::NoTx()).GetValueSync();
+ UNIT_ASSERT_C(!result.IsSuccess(), result.GetIssues().ToString());
+
+ validateMain(R"([
+ [[1];["idx1"];["default_value"]];
+ [[2];["idx2"];["default_value"]];
+ [[3];["idx3"];["default_value"]]
+ ])");
+ validateIndex("idx1", R"([
+ [[1];["default_value"]]
+ ])");
+ }
+ }
}
} // namespace NKikimr::NKqp
diff --git a/ydb/core/protos/table_service_config.proto b/ydb/core/protos/table_service_config.proto
index b0844537c13..8b5402fe254 100644
--- a/ydb/core/protos/table_service_config.proto
+++ b/ydb/core/protos/table_service_config.proto
@@ -539,4 +539,7 @@ message TTableServiceConfig {
optional bool EnableHybridSearch = 135 [default = true, (InvalidateCompileCache) = true];
optional bool EnableStrictSerializableIsolation = 136 [default = false, (InvalidateCompileCache) = true];
+
+ // Remove KqpSequencer from query plan for tables with DEFAULT columns during write operations.
+ optional bool EnableCompileTimeDefaults = 137 [default = false, (InvalidateCompileCache) = true];
};