diff options
author | snaury <snaury@ydb.tech> | 2022-09-12 18:47:58 +0300 |
---|---|---|
committer | snaury <snaury@ydb.tech> | 2022-09-12 18:47:58 +0300 |
commit | 00dfcee7413b85be81812a8b9482e0754ccabcea (patch) | |
tree | e00e7e15ed63816c804764ca3a82ef097b5914e7 | |
parent | f68b69214c16dbfdf12930b40f4e415abf2e4093 (diff) | |
download | ydb-00dfcee7413b85be81812a8b9482e0754ccabcea.tar.gz |
Fix ambiguous ranges in dynamic erase/update, add validation in debug builds
20 files changed, 330 insertions, 139 deletions
diff --git a/ydb/core/client/flat_ut.cpp b/ydb/core/client/flat_ut.cpp index e2e48c3ab0..4a4baba554 100644 --- a/ydb/core/client/flat_ut.cpp +++ b/ydb/core/client/flat_ut.cpp @@ -315,7 +315,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { ((return (AsList (SetResult 'x (SelectRange '"/dc-1/test/perf/FlatDaoPerfTestClient" - '('ExcFrom 'ExcTo '('ls (Utf8 '"") (Void))) + '('ExcFrom 'IncTo '('ls (Utf8 '"") (Void))) '('ls 'kg 'localId 'createdSeconds 'mode1) '('('BytesLimit (Uint64 '3000000))) ) @@ -1528,7 +1528,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { NKikimrClient::TResponse response; status = annoyingClient.FlatQueryRaw(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (Member (SelectRange '/dc-1/Dir/Table range '('Key 'Value) '()) 'List)) (let result (Filter data (lambda '(row) (Coalesce (NotEqual (Member row 'Key) (Uint32 '1)) (Bool 'false)) @@ -1855,6 +1855,33 @@ Y_UNIT_TEST_SUITE(TFlatTest) { return strResult; } + TString ReadFromTwoKeysTable(TFlatMsgBusClient& annoyingClient, TString table, ui32 fromKey = 0, ui32 fromKey2 = 0, bool follower = false) { + const char* readQuery = + "(" + "(let range1 '('IncFrom '('Key (Uint32 '%d) (Void)) '('Key2 (Uint32 '%d) (Void)) ))" + "(let select '('Key 'Key2 'Value 'Large))" + "(let options '())" + "(let pgmReturn (AsList" + " (SetResult 'range1 (SelectRange '%s range1 select options (Uint32 '%d)))" + "))" + "(return pgmReturn)" + ")"; + + TFlatMsgBusClient::TFlatQueryOptions opts; + NKikimrClient::TResponse response; + annoyingClient.FlatQueryRaw(Sprintf(readQuery, fromKey, fromKey2, table.data(), follower ? TReadTarget::Follower().GetMode() + : TReadTarget::Head().GetMode()), opts, response); + + UNIT_ASSERT_VALUES_EQUAL(response.GetStatus(), NMsgBusProxy::MSTATUS_OK); + UNIT_ASSERT(response.GetExecutionEngineResponseStatus() == ui32(NMiniKQL::IEngineFlat::EStatus::Complete)); + NKikimrMiniKQL::TResult result; + result.Swap(response.MutableExecutionEngineEvaluatedResponse()); + + TString strResult; + ::google::protobuf::TextFormat::PrintToString(result.GetValue(), &strResult); + return strResult; + } + template <class TSetType> void WaitForTabletsToBeDeletedInHive(TFlatMsgBusClient& annoyingClient, TTestActorRuntime* runtime, const TSetType& tabletIds, const TDuration& timeout = TDuration::Seconds(20)) { @@ -2332,12 +2359,12 @@ Y_UNIT_TEST_SUITE(TFlatTest) { WaitForTabletsToBeDeletedInHive(annoyingClient, cleverServer.GetRuntime(), datashards); } - void DoSplitMergeTable(TFlatMsgBusClient& annoyingClient, TString table, const TVector<ui64>& srcPartitions, const TVector<ui32>& splitPoints) { + void DoSplitMergeTable(TFlatMsgBusClient& annoyingClient, TString table, const TVector<ui64>& srcPartitions, const TVector<ui32>& splitPoints, bool twoKeys = false) { TVector<ui64> partitionsBefore; partitionsBefore = annoyingClient.GetTablePartitions(table); UNIT_ASSERT(partitionsBefore.size() > 0); - TString strResultBefore = ReadFromTable(annoyingClient, table); + TString strResultBefore = twoKeys ? ReadFromTwoKeysTable(annoyingClient, table) : ReadFromTable(annoyingClient, table); TStringStream splitDescr; for (ui32 src : srcPartitions) { @@ -2355,10 +2382,14 @@ Y_UNIT_TEST_SUITE(TFlatTest) { // TODO: check paritions that were not supposed to change //UNIT_ASSERT_VALUES_EQUAL(partitionsAfter.back(), partitionsBefore.back()); - TString strResultAfter = ReadFromTable(annoyingClient, table); + TString strResultAfter = twoKeys ? ReadFromTwoKeysTable(annoyingClient, table) : ReadFromTable(annoyingClient, table); UNIT_ASSERT_NO_DIFF(strResultBefore, strResultAfter); } + void SplitTwoKeysTable(TFlatMsgBusClient& annoyingClient, TString table, ui64 partitionIdx, const TVector<ui32>& splitPoints) { + DoSplitMergeTable(annoyingClient, table, {partitionIdx}, splitPoints, /* twoKeys */ true); + } + void SplitTable(TFlatMsgBusClient& annoyingClient, TString table, ui64 partitionIdx, const TVector<ui32>& splitPoints) { DoSplitMergeTable(annoyingClient, table, {partitionIdx}, splitPoints); } @@ -2614,7 +2645,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { cleverServer.GetRuntime()->SetLogPriority(NKikimrServices::FLAT_TX_SCHEMESHARD, NActors::NLog::PRI_DEBUG); cleverServer.GetRuntime()->SetLogPriority(NKikimrServices::TX_DATASHARD, NActors::NLog::PRI_DEBUG); - SplitTable(annoyingClient, "/dc-1/Dir/TableOld", 0, {splitKey}); + SplitTwoKeysTable(annoyingClient, "/dc-1/Dir/TableOld", 0, {splitKey}); } Y_UNIT_TEST(SplitThenMerge) { @@ -3267,7 +3298,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { client.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (Member (SelectRange '"/dc-1/test/BlobTable" range '('Key 'Value) '()) 'List)) (let result (Filter data (lambda '(row) (Coalesce (NotEqual (Member row 'Key) (Uint64 '1)) (Bool 'false)) @@ -3361,7 +3392,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (Member (SelectRange '"/dc-1/test/BlobTable" range '('Key 'Value) '()) 'List)) (let result (Take (Skip (Filter data (lambda '(row) (Coalesce (NotEqual (Member row 'Key) (Uint64 '1)) (Bool 'false)) @@ -3408,7 +3439,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (Member (SelectRange '"/dc-1/test/BlobTable" range '('Key 'Value) '()) 'List)) (let result (OrderedMap data (lambda '(row) (AddMember row 'Value2 (Member row 'Value)) @@ -3463,7 +3494,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (Member (SelectRange '"/dc-1/test/BlobTable" range '('Key 'Value) '()) 'List)) (let result (OrderedMap data (lambda '(row) (AddMember row 'Value2 (Member row 'Value)) @@ -3616,7 +3647,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { auto res = annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (SelectRange '"/dc-1/test/TestTable" range @@ -3677,7 +3708,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { auto res = annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (SelectRange '"/dc-1/test/TestTable" range @@ -3738,7 +3769,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { auto res = annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (SelectRange '"/dc-1/test/TestTable" range @@ -3812,7 +3843,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { Y_UNIT_TEST(SelectRangeSkipNullKeys) { auto res = CreateTableAndExecuteMkql(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key1 (Null) (Void)) '('Key2 (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key1 (Null) (Void)) '('Key2 (Null) (Void)))) (let data (SelectRange '"/dc-1/test/TestTable" range @@ -4012,7 +4043,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { auto res = annoyingClient.FlatQuery(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (SelectRange '"/dc-1/test/TestTable" range @@ -4080,7 +4111,7 @@ Y_UNIT_TEST_SUITE(TFlatTest) { auto res = annoyingClient.FlatQuery(Sprintf(R"( ( - (let range '('ExcFrom 'ExcTo '('Key (Null) (Void)))) + (let range '('ExcFrom 'IncTo '('Key (Null) (Void)))) (let data (SelectRange '"/dc-1/test/TestTable" range diff --git a/ydb/core/client/locks_ut.cpp b/ydb/core/client/locks_ut.cpp index a6e9a9bcb5..11b76611e3 100644 --- a/ydb/core/client/locks_ut.cpp +++ b/ydb/core/client/locks_ut.cpp @@ -245,7 +245,7 @@ struct TLocksTestOptions { Range0Begin = "(Uint32 '0)"; Range0End = BreakPoint; Range0OptKey = ""; - Range1Inc = "'ExcFrom 'ExcTo"; + Range1Inc = "'ExcFrom 'IncTo"; Range1Begin = BreakPoint; Range1End = "(Void)"; Range1OptKey = ""; @@ -264,7 +264,7 @@ struct TLocksTestOptions { Range0Begin = "(Uint32 '0)"; Range0End = BreakPoint; Range0OptKey = "'('keyX (Uint64 '0) (Void))"; - Range1Inc = "'ExcFrom 'ExcTo"; + Range1Inc = "'ExcFrom 'IncTo"; Range1Begin = BreakPoint; Range1End = "(Uint32 '4294967295)"; Range1OptKey = "'('keyX (Uint64 '0) (Void))"; @@ -283,7 +283,7 @@ struct TLocksTestOptions { Range0Begin = "(String '\"0\")"; Range0End = BreakPoint; Range0OptKey = ""; - Range1Inc = "'ExcFrom 'ExcTo"; + Range1Inc = "'ExcFrom 'IncTo"; Range1Begin = BreakPoint; Range1End = "(Void)"; Range1OptKey = ""; @@ -852,7 +852,7 @@ Y_UNIT_TEST(Range_BrokenLockMax) { TLocksTestOptions opts; opts.TestRange = true; opts.BreakKey = "'('key (Uint32 '4294967295))"; - opts.Range1Inc = "'ExcFrom 'ExcTo"; + opts.Range1Inc = "'ExcFrom 'IncTo"; opts.Break = true; TestLock<TLocksV1>(opts); TestLock<TLocksV2>(opts); @@ -1021,7 +1021,7 @@ Y_UNIT_TEST(Range_EmptyKey) { opts.SetOnly = true; //opts.TestErase = true; opts.TestRange = true; - opts.Range0Inc = "'IncFrom 'ExcTo"; + opts.Range0Inc = "'IncFrom 'IncTo"; opts.Range0Begin = "(String '\"\")"; opts.Range0End = "(Void)"; TestLock<TLocksV1>(opts); diff --git a/ydb/core/client/minikql_compile/yql_expr_minikql_compile_ut.cpp b/ydb/core/client/minikql_compile/yql_expr_minikql_compile_ut.cpp index 1a99dce069..df56ab1c27 100644 --- a/ydb/core/client/minikql_compile/yql_expr_minikql_compile_ut.cpp +++ b/ydb/core/client/minikql_compile/yql_expr_minikql_compile_ut.cpp @@ -203,7 +203,7 @@ Y_UNIT_TEST_SUITE(TTestYqlToMiniKQLCompile) { Y_UNIT_TEST(SelectRange) { auto programText = R"___( ( -(let range '('IncFrom 'ExcTo '('key (Uint32 '23) (Void)))) +(let range '('IncFrom 'IncTo '('key (Uint32 '23) (Void)))) (let select '('value)) (let options '('('ItemsLimit (Uint64 '2)) '('BytesLimit (Uint64 '1000)))) (let pgmReturn (AsList @@ -323,7 +323,7 @@ Y_UNIT_TEST_SUITE(TTestYqlToMiniKQLCompile) { Y_UNIT_TEST(Extract) { auto programText = R"___( ( -(let range '('IncFrom 'ExcTo '('key (Uint32 '23) (Void)))) +(let range '('IncFrom 'IncTo '('key (Uint32 '23) (Void)))) (let select '('key 'value)) (let options '('('ItemsLimit (Uint64 '2)))) (let tupleList (AsList '((Uint32 '1) (Uint32 '2)) '((Uint32 '3) (Uint32 '4)))) diff --git a/ydb/core/engine/kikimr_program_builder_ut.cpp b/ydb/core/engine/kikimr_program_builder_ut.cpp index 168e58422d..00c58c32b7 100644 --- a/ydb/core/engine/kikimr_program_builder_ut.cpp +++ b/ydb/core/engine/kikimr_program_builder_ut.cpp @@ -150,7 +150,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLProgramBuilderTest) { UNIT_ASSERT(tableKeys[0]->TableId.HasSamePath(TTableId(1, 2))); UNIT_ASSERT(tableKeys[0]->RowOperation == TKeyDesc::ERowOperation::Erase); UNIT_ASSERT(tableKeys[0]->Range.InclusiveFrom); - UNIT_ASSERT(!tableKeys[0]->Range.InclusiveTo); + UNIT_ASSERT(tableKeys[0]->Range.InclusiveTo); UNIT_ASSERT(!tableKeys[0]->Range.Point); UNIT_ASSERT(tableKeys[0]->Range.From.size() == 3); UNIT_ASSERT(tableKeys[0]->Range.From[0].IsNull()); @@ -192,7 +192,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLProgramBuilderTest) { UNIT_ASSERT(tableKeys[0]->TableId.HasSamePath(TTableId(1, 2))); UNIT_ASSERT(tableKeys[0]->RowOperation == TKeyDesc::ERowOperation::Erase); UNIT_ASSERT(tableKeys[0]->Range.InclusiveFrom); - UNIT_ASSERT(!tableKeys[0]->Range.InclusiveTo); + UNIT_ASSERT(tableKeys[0]->Range.InclusiveTo); UNIT_ASSERT(!tableKeys[0]->Range.Point); UNIT_ASSERT(tableKeys[0]->Range.From.size() == 2); UNIT_ASSERT(tableKeys[0]->Range.From[0].IsNull()); @@ -349,7 +349,7 @@ Y_UNIT_TEST_SUITE(TMiniKQLProgramBuilderTest) { UNIT_ASSERT(tableKeys[0]->TableId.HasSamePath(TTableId(1, 2))); UNIT_ASSERT(tableKeys[0]->RowOperation == TKeyDesc::ERowOperation::Update); UNIT_ASSERT(tableKeys[0]->Range.InclusiveFrom); - UNIT_ASSERT(!tableKeys[0]->Range.InclusiveTo); + UNIT_ASSERT(tableKeys[0]->Range.InclusiveTo); UNIT_ASSERT(!tableKeys[0]->Range.Point); UNIT_ASSERT(tableKeys[0]->Range.From.size() == 3); UNIT_ASSERT(tableKeys[0]->Range.From[0].IsNull()); diff --git a/ydb/core/engine/minikql/minikql_engine_host.cpp b/ydb/core/engine/minikql/minikql_engine_host.cpp index 6966fb700f..d362d93806 100644 --- a/ydb/core/engine/minikql/minikql_engine_host.cpp +++ b/ydb/core/engine/minikql/minikql_engine_host.cpp @@ -231,6 +231,10 @@ void TEngineHost::PinPages(const TVector<THolder<TKeyDesc>>& keys, ui64 pageFaul ui64 localTid = LocalTableId(key.TableId); Y_VERIFY(localTid, "table not exist"); const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(localTid); + + Y_VERIFY_DEBUG(!key.Range.IsAmbiguous(tableInfo->KeyColumns.size()), + "%s", key.Range.IsAmbiguousReason(tableInfo->KeyColumns.size())); + TSmallVec<TRawTypeValue> keyFrom; TSmallVec<TRawTypeValue> keyTo; ConvertKeys(tableInfo, key.Range.From, keyFrom); @@ -654,6 +658,9 @@ public: const TScheme::TTableInfo* tableInfo = Scheme.GetTableInfo(LocalTid); auto tableRange = RangeHolder.ToTableRange(); + Y_VERIFY_DEBUG(!tableRange.IsAmbiguous(tableInfo->KeyColumns.size()), + "%s", tableRange.IsAmbiguousReason(tableInfo->KeyColumns.size())); + TSmallVec<TRawTypeValue> keyFrom; TSmallVec<TRawTypeValue> keyTo; ConvertTableKeys(Scheme, tableInfo, tableRange.From, keyFrom, nullptr); diff --git a/ydb/core/engine/mkql_engine_flat_ut.cpp b/ydb/core/engine/mkql_engine_flat_ut.cpp index e355bf3d8b..84fcf280cb 100644 --- a/ydb/core/engine/mkql_engine_flat_ut.cpp +++ b/ydb/core/engine/mkql_engine_flat_ut.cpp @@ -1059,7 +1059,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1130,7 +1130,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewNull(); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1220,7 +1220,7 @@ Value { rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1337,7 +1337,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.ItemsLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(1); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1448,7 +1448,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewNull(); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.ItemsLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(1); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1563,7 +1563,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.BytesLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(32); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1685,7 +1685,7 @@ Value { rowFrom[0] = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(43); auto options = pgmBuilder.GetDefaultTableRangeOptions(); - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.FromColumns = rowFrom; auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -1809,7 +1809,7 @@ Value { auto options = pgmBuilder.GetDefaultTableRangeOptions(); options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>( TReadRangeOptions::TFlags::ExcludeInitValue | - TReadRangeOptions::TFlags::ExcludeTermValue); + TReadRangeOptions::TFlags::IncludeTermValue); options.FromColumns = rowFrom; auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -3277,7 +3277,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -3475,7 +3475,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -3601,7 +3601,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.ItemsLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(1); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -3731,7 +3731,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); const ui64 RowOverheadBytes = 8; options.BytesLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(4 + RowOverheadBytes); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); @@ -3865,7 +3865,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.Reverse = pgmBuilder.TProgramBuilder::NewDataLiteral<bool>(true); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto pgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("myRes", value))); @@ -4012,7 +4012,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.ItemsLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(1); options.Reverse = pgmBuilder.TProgramBuilder::NewDataLiteral<bool>(true); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); @@ -4139,7 +4139,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.ItemsLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(2); options.Reverse = pgmBuilder.TProgramBuilder::NewDataLiteral<bool>(true); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); @@ -4273,7 +4273,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); options.ItemsLimit = pgmBuilder.TProgramBuilder::NewDataLiteral<ui64>(3); options.Reverse = pgmBuilder.TProgramBuilder::NewDataLiteral<bool>(true); auto value = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); @@ -4778,7 +4778,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); TVector<TStringBuf> filterNullColumns {"Value"}; @@ -4856,7 +4856,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); auto mapped = pgmBuilder.Map(list, [&pgmBuilder](TRuntimeNode item) { @@ -4926,7 +4926,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); auto mapped = pgmBuilder.Map(list, [&pgmBuilder, keyTypes, columns](TRuntimeNode item) { @@ -4990,7 +4990,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); auto filtered = pgmBuilder.OrderedFilter(list, [&pgmBuilder, &okValue](TRuntimeNode item) { @@ -5078,7 +5078,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); auto mapped = pgmBuilder.Map(list, [&pgmBuilder](TRuntimeNode item) { @@ -5123,7 +5123,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui64>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table2Id), keyTypes, columns, options); auto checkpgm = pgmBuilder.Build(pgmBuilder.AsList(pgmBuilder.SetResult("Result", range))); @@ -5186,7 +5186,7 @@ Value { TRuntimeNode::TList rowFrom1(1); rowFrom1[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options1.FromColumns = rowFrom1; - options1.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options1.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range1 = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes1, columns1, options1); auto list1 = pgmBuilder.Member(range1, "List"); @@ -5201,7 +5201,7 @@ Value { TRuntimeNode::TList rowFrom2(1); rowFrom2[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui64>::Id); options2.FromColumns = rowFrom2; - options2.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options2.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range2 = pgmBuilder.SelectRange(TTableId(OwnerId, Table2Id), keyTypes2, columns2, options2); auto list2 = pgmBuilder.Member(range2, "List"); @@ -5280,7 +5280,7 @@ Value { TRuntimeNode::TList rowFrom1(1); rowFrom1[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options1.FromColumns = rowFrom1; - options1.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options1.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range1 = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes1, columns1, options1); auto list1 = pgmBuilder.Member(range1, "List"); @@ -5295,7 +5295,7 @@ Value { TRuntimeNode::TList rowFrom2(1); rowFrom2[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui64>::Id); options2.FromColumns = rowFrom2; - options2.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options2.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range2 = pgmBuilder.SelectRange(TTableId(OwnerId, Table2Id), keyTypes2, columns2, options2); auto list2 = pgmBuilder.Member(range2, "List"); @@ -5388,7 +5388,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -5504,7 +5504,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -5615,7 +5615,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -5699,7 +5699,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -5777,7 +5777,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -5858,7 +5858,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -5947,7 +5947,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -6034,7 +6034,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -6125,7 +6125,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -6220,7 +6220,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, columns, options); auto list = pgmBuilder.Member(range, "List"); @@ -6289,7 +6289,7 @@ Value { TRuntimeNode::TList rowFrom(1); rowFrom[0] = pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id); options.FromColumns = rowFrom; - options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), keyTypes, {}, options); auto list = pgmBuilder.Member(range, "List"); auto length = pgmBuilder.Length(list); @@ -6367,7 +6367,7 @@ Value { TRuntimeNode::TList fromColumns1{pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui32>::Id)}; auto options1 = pgmBuilder.GetDefaultTableRangeOptions(); options1.FromColumns = fromColumns1; - options1.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options1.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range1 = pgmBuilder.SelectRange(TTableId(OwnerId, Table1Id), {(ui32)NUdf::TDataType<ui32>::Id}, columns1, options1); auto list1 = pgmBuilder.Member(range1, "List"); @@ -6390,7 +6390,7 @@ Value { TRuntimeNode::TList fromColumns2{pgmBuilder.NewEmptyOptionalDataLiteral(NUdf::TDataType<ui64>::Id)}; auto options2 = pgmBuilder.GetDefaultTableRangeOptions(); options2.FromColumns = fromColumns2; - options2.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::ExcludeTermValue); + options2.Flags = pgmBuilder.TProgramBuilder::NewDataLiteral<ui32>(TReadRangeOptions::TFlags::IncludeTermValue); auto range2 = pgmBuilder.SelectRange(TTableId(OwnerId, Table2Id), {(ui32)NUdf::TDataType<ui64>::Id}, columns2, options2); auto list2 = pgmBuilder.Member(range2, "List"); diff --git a/ydb/core/engine/mkql_keys.cpp b/ydb/core/engine/mkql_keys.cpp index 91d5f35a9a..720e00325e 100644 --- a/ydb/core/engine/mkql_keys.cpp +++ b/ydb/core/engine/mkql_keys.cpp @@ -70,7 +70,6 @@ THolder<TKeyDesc> ExtractKeyTuple(const TTableId& tableId, TTupleLiteral* tuple, if (!hasImmediateData) { MKQL_ENSURE(!requireStaticKey, "Expected static key components"); point = false; - inclusiveTo = false; continue; } diff --git a/ydb/core/scheme/scheme_tabledefs.cpp b/ydb/core/scheme/scheme_tabledefs.cpp index 3ea0f6dd81..672957e1fc 100644 --- a/ydb/core/scheme/scheme_tabledefs.cpp +++ b/ydb/core/scheme/scheme_tabledefs.cpp @@ -32,6 +32,48 @@ bool TTableRange::IsFullRange(ui32 columnsCount) const { return true; } +namespace { + // There are many places that use a non-inclusive -inf/+inf + // We special case empty keys anyway, so the requirement is temporarily relaxed + static constexpr bool RelaxEmptyKeys = true; +} + +const char* TTableRange::IsAmbiguousReason(size_t keyColumnsCount) const noexcept { + if (Point) { + if (Y_UNLIKELY(From.size() != keyColumnsCount)) { + return "Ambiguous table point: does not match key columns count"; + } + + return nullptr; + } + + if (!From) { + if (Y_UNLIKELY(!InclusiveFrom) && !RelaxEmptyKeys) { + return "Ambiguous table range: empty From must be inclusive"; + } + } else if (From.size() < keyColumnsCount) { + if (Y_UNLIKELY(InclusiveFrom)) { + return "Ambiguous table range: incomplete From must be non-inclusive (any/+inf is ambiguous otherwise)"; + } + } else if (Y_UNLIKELY(From.size() > keyColumnsCount)) { + return "Ambiguous table range: From is too large"; + } + + if (!To) { + if (Y_UNLIKELY(!InclusiveTo && !RelaxEmptyKeys)) { + return "Ambiguous table range: empty To must be inclusive"; + } + } else if (To.size() < keyColumnsCount) { + if (Y_UNLIKELY(!InclusiveTo)) { + return "Ambiguous table range: incomplete To must be inclusive (any/+inf is ambiguous otherwise)"; + } + } else if (Y_UNLIKELY(To.size() > keyColumnsCount)) { + return "Ambiguous table range: To is too large"; + } + + return nullptr; +} + bool TSerializedTableRange::IsEmpty(TConstArrayRef<NScheme::TTypeId> type) const { auto cmp = CompareBorders<true, false>(To.GetCells(), From.GetCells(), ToInclusive, FromInclusive, type); diff --git a/ydb/core/scheme/scheme_tabledefs.h b/ydb/core/scheme/scheme_tabledefs.h index ccf0b73f29..d7206c301f 100644 --- a/ydb/core/scheme/scheme_tabledefs.h +++ b/ydb/core/scheme/scheme_tabledefs.h @@ -181,6 +181,12 @@ public: bool IsEmptyRange(TConstArrayRef<const NScheme::TTypeId> cellTypeIds) const; bool IsFullRange(ui32 columnsCount) const; + + bool IsAmbiguous(size_t keyColumnsCount) const noexcept { + return IsAmbiguousReason(keyColumnsCount) != nullptr; + } + + const char* IsAmbiguousReason(size_t keyColumnsCount) const noexcept; }; class TSerializedTableRange { diff --git a/ydb/core/tablet_flat/flat_database.cpp b/ydb/core/tablet_flat/flat_database.cpp index 9a1db399d0..6d705ab3de 100644 --- a/ydb/core/tablet_flat/flat_database.cpp +++ b/ydb/core/tablet_flat/flat_database.cpp @@ -88,6 +88,44 @@ TAutoPtr<TTableIt> TDatabase::IterateExact(ui32 table, TRawVals key, TTagsRef ta return iter; } +namespace { + // There are many places that use a non-inclusive -inf/+inf + // We special case empty keys anyway, so the requirement is temporarily relaxed + static constexpr bool RelaxEmptyKeys = true; + + const char* IsAmbiguousRangeReason(const TKeyRange& range, ui32 keyColumnsCount) { + if (!range.MinKey) { + if (Y_UNLIKELY(!range.MinInclusive) && !RelaxEmptyKeys) { + return "Ambiguous table range: empty MinKey must be inclusive"; + } + } else if (range.MinKey.size() < keyColumnsCount) { + if (Y_UNLIKELY(range.MinInclusive)) { + return "Ambiguous table range: incomplete MinKey must be non-inclusive (any/+inf is ambiguous otherwise)"; + } + } else if (Y_UNLIKELY(range.MinKey.size() > keyColumnsCount)) { + return "Ambiguous table range: MinKey is too large"; + } + + if (!range.MaxKey) { + if (Y_UNLIKELY(!range.MaxInclusive) && !RelaxEmptyKeys) { + return "Ambiguous table range: empty MaxKey must be inclusive"; + } + } else if (range.MaxKey.size() < keyColumnsCount) { + if (Y_UNLIKELY(!range.MaxInclusive)) { + return "Ambiguous table range: incomplete MaxKey must be inclusive (any/+inf is ambiguous otherwise)"; + } + } else if (Y_UNLIKELY(range.MaxKey.size() > keyColumnsCount)) { + return "Ambiguous table range: MaxKey is too large"; + } + + return nullptr; + } + + bool IsAmbiguousRange(const TKeyRange& range, ui32 keyColumnsCount) { + return IsAmbiguousRangeReason(range, keyColumnsCount) != nullptr; + } +} + TAutoPtr<TTableIt> TDatabase::IterateRange(ui32 table, const TKeyRange& range, TTagsRef tags, TRowVersion snapshot, const ITransactionMapPtr& visible, @@ -95,6 +133,9 @@ TAutoPtr<TTableIt> TDatabase::IterateRange(ui32 table, const TKeyRange& range, T { Y_VERIFY(!NoMoreReadsFlag, "Trying to read after reads prohibited, table %u", table); + Y_VERIFY_DEBUG(!IsAmbiguousRange(range, Require(table)->GetScheme()->Keys->Size()), + "%s", IsAmbiguousRangeReason(range, Require(table)->GetScheme()->Keys->Size())); + IteratedTables.insert(table); ESeek seek = !range.MinKey || range.MinInclusive ? ESeek::Lower : ESeek::Upper; @@ -121,6 +162,9 @@ TAutoPtr<TTableReverseIt> TDatabase::IterateRangeReverse(ui32 table, const TKeyR { Y_VERIFY(!NoMoreReadsFlag, "Trying to read after reads prohibited, table %u", table); + Y_VERIFY_DEBUG(!IsAmbiguousRange(range, Require(table)->GetScheme()->Keys->Size()), + "%s", IsAmbiguousRangeReason(range, Require(table)->GetScheme()->Keys->Size())); + IteratedTables.insert(table); ESeek seek = !range.MaxKey || range.MaxInclusive ? ESeek::Lower : ESeek::Upper; diff --git a/ydb/core/tx/datashard/datashard__read_iterator.cpp b/ydb/core/tx/datashard/datashard__read_iterator.cpp index 3145f6f50e..97f7107c56 100644 --- a/ydb/core/tx/datashard/datashard__read_iterator.cpp +++ b/ydb/core/tx/datashard/datashard__read_iterator.cpp @@ -931,42 +931,6 @@ public: } } - // TODO: remove later, when we sure that key prefix is properly - // interpreted same way everywhere: i.e. treated as 0 at the left and - // inf on the right. - // We really do weird transformations here, not sure if we can do better though - for (size_t i = 0; i < Request->Ranges.size(); ++i) { - auto& range = Request->Ranges[i]; - auto& keyFrom = range.From; - auto& keyTo = Request->Ranges[i].To; - - if (range.FromInclusive && keyFrom.GetCells().size() != TableInfo.KeyColumnCount) { - keyFrom = ExtendWithNulls(keyFrom, TableInfo.KeyColumnCount); - } - - if (!range.ToInclusive && keyTo.GetCells().size() != TableInfo.KeyColumnCount) { - keyTo = ExtendWithNulls(keyTo, TableInfo.KeyColumnCount); - } - } - - // TODO: remove later, when we sure that key prefix is properly - // interpreted same way everywhere: i.e. treated as 0 at the left and - // inf on the right. - // We really do weird transformations here, not sure if we can do better though - for (size_t i = 0; i < Request->Keys.size(); ++i) { - const auto& key = Request->Keys[i]; - if (key.GetCells().size() == TableInfo.KeyColumnCount) - continue; - - if (state.Keys.size() != Request->Keys.size()) { - state.Keys.resize(Request->Keys.size()); - } - - // we can safely use cells referencing original Request->Keys[x], - // because request will live until the end - state.Keys[i] = ExtendWithNulls(key, TableInfo.KeyColumnCount); - } - userTableInfo->Stats.AccessTime = TAppData::TimeProvider->Now(); } else { // DS is owner, read system table @@ -984,6 +948,36 @@ public: TableInfo = TShortTableInfo(state.PathId.LocalPathId, *schema); } + // Make ranges in the new 'any' form compatible with the old '+inf' form + for (size_t i = 0; i < Request->Ranges.size(); ++i) { + auto& range = Request->Ranges[i]; + auto& keyFrom = range.From; + auto& keyTo = Request->Ranges[i].To; + + if (range.FromInclusive && keyFrom.GetCells().size() != TableInfo.KeyColumnCount) { + keyFrom = ExtendWithNulls(keyFrom, TableInfo.KeyColumnCount); + } + + if (!range.ToInclusive && keyTo.GetCells().size() != TableInfo.KeyColumnCount) { + keyTo = ExtendWithNulls(keyTo, TableInfo.KeyColumnCount); + } + } + + // Make prefixes in the new 'any' form compatible with the old '+inf' form + for (size_t i = 0; i < Request->Keys.size(); ++i) { + const auto& key = Request->Keys[i]; + if (key.GetCells().size() == TableInfo.KeyColumnCount) + continue; + + if (state.Keys.size() != Request->Keys.size()) { + state.Keys.resize(Request->Keys.size()); + } + + // we can safely use cells referencing original Request->Keys[x], + // because request will live until the end + state.Keys[i] = ExtendWithNulls(key, TableInfo.KeyColumnCount); + } + state.Columns.reserve(record.ColumnsSize()); for (auto col: record.GetColumns()) { auto it = TableInfo.Columns.find(col); @@ -1004,7 +998,12 @@ public: Y_ASSERT(Result); - PrepareValidationInfo(ctx, state); + if (state.PathId.OwnerId != Self->TabletID()) { + PrepareValidationInfo(ctx, state); + } else { + // There should be no keys when reading sysm tables + ValidationInfo.Loaded = true; + } } void SendResult(const TActorContext& ctx) override { diff --git a/ydb/core/tx/datashard/datashard__s3.cpp b/ydb/core/tx/datashard/datashard__s3.cpp index 2f7a74bbab..f5dfe0d65e 100644 --- a/ydb/core/tx/datashard/datashard__s3.cpp +++ b/ydb/core/tx/datashard/datashard__s3.cpp @@ -62,6 +62,7 @@ public: TVector<TRawTypeValue> key; TVector<TRawTypeValue> endKey; + bool endKeyInclusive = true; // TODO: check prefix column count against key column count const TSerializedCellVec prefixColumns(Ev->Get()->Record.GetSerializedKeyPrefix()); @@ -113,6 +114,10 @@ public: const TString pathEndPrefix = NextPrefix(pathPrefix); if (pathEndPrefix) { endKey.emplace_back(pathEndPrefix.data(), pathEndPrefix.size(), NScheme::NTypeIds::Utf8); + while (endKey.size() < tableInfo.KeyColumnTypes.size()) { + endKey.emplace_back(); + } + endKeyInclusive = false; } LOG_DEBUG_S(ctx, NKikimrServices::TX_DATASHARD, Self->TabletID() << " S3 Listing: start at key (" @@ -135,7 +140,7 @@ public: keyRange.MinKey = key; keyRange.MinInclusive = suffixColumns.GetCells().empty(); keyRange.MaxKey = endKey; - keyRange.MaxInclusive = false; + keyRange.MaxInclusive = endKeyInclusive; if (LastPath) { // Don't include the last key in case of restart diff --git a/ydb/core/tx/datashard/datashard_dep_tracker.cpp b/ydb/core/tx/datashard/datashard_dep_tracker.cpp index 9e46cb3604..1a35cb5092 100644 --- a/ydb/core/tx/datashard/datashard_dep_tracker.cpp +++ b/ydb/core/tx/datashard/datashard_dep_tracker.cpp @@ -3,6 +3,8 @@ #include "const.h" +#include <util/string/escape.h> + namespace NKikimr { namespace NDataShard { @@ -181,6 +183,14 @@ void TDependencyTracker::TDefaultDependencyTrackingLogic::AddOperation(const TOp const auto& k = *vk.Key; if (Parent.Self->IsUserTable(k.TableId)) { const ui64 tableId = k.TableId.PathId.LocalPathId; + Y_VERIFY_DEBUG_S(!k.Range.IsAmbiguous(Parent.Self->GetUserTables().at(tableId)->KeyColumnTypes.size()), + (vk.IsWrite ? "Write" : "Read") + << " From# \"" << EscapeC(TSerializedCellVec::Serialize(k.Range.From)) << "\"" + << " To# \"" << EscapeC(TSerializedCellVec::Serialize(k.Range.To)) << "\"" + << " InclusiveFrom# " << (k.Range.InclusiveFrom ? "true" : "false") + << " InclusiveTo# " << (k.Range.InclusiveTo ? "true" : "false") + << " Point# " << (k.Range.Point ? "true" : "false") + << ": " << k.Range.IsAmbiguousReason(Parent.Self->GetUserTables().at(tableId)->KeyColumnTypes.size())); if (!tooManyKeys && ++keysCount > MAX_REORDER_TX_KEYS) { tooManyKeys = true; } @@ -617,6 +627,14 @@ void TDependencyTracker::TMvccDependencyTrackingLogic::AddOperation(const TOpera const auto& k = *vk.Key; if (Parent.Self->IsUserTable(k.TableId)) { const ui64 tableId = k.TableId.PathId.LocalPathId; + Y_VERIFY_DEBUG_S(!k.Range.IsAmbiguous(Parent.Self->GetUserTables().at(tableId)->KeyColumnTypes.size()), + (vk.IsWrite ? "Write" : "Read") + << " From# \"" << EscapeC(TSerializedCellVec::Serialize(k.Range.From)) << "\"" + << " To# \"" << EscapeC(TSerializedCellVec::Serialize(k.Range.To)) << "\"" + << " InclusiveFrom# " << (k.Range.InclusiveFrom ? "true" : "false") + << " InclusiveTo# " << (k.Range.InclusiveTo ? "true" : "false") + << " Point# " << (k.Range.Point ? "true" : "false") + << ": " << k.Range.IsAmbiguousReason(Parent.Self->GetUserTables().at(tableId)->KeyColumnTypes.size())); if (!tooManyKeys && ++keysCount > MAX_REORDER_TX_KEYS) { tooManyKeys = true; } diff --git a/ydb/core/tx/datashard/datashard_ut_minikql.cpp b/ydb/core/tx/datashard/datashard_ut_minikql.cpp index 7974e47486..b788107f87 100644 --- a/ydb/core/tx/datashard/datashard_ut_minikql.cpp +++ b/ydb/core/tx/datashard/datashard_ut_minikql.cpp @@ -537,7 +537,7 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) - (let r2 '('key2 (Void) (Void))) + (let r2 '('key2 (Nothing (OptionalType (DataType 'Utf8))) (Nothing (OptionalType (DataType 'Utf8))))) (let range '('IncFrom 'ExcTo r1 r2)) (let select '('key1 'key2 'value)) (let options '()) @@ -557,18 +557,18 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { UNIT_ASSERT_EQUAL(rsl.Size(), 2); TValue row1 = rsl[0]; TValue row2 = rsl[1]; - UNIT_ASSERT_EQUAL(ui32(row1["key1"]), 346); - UNIT_ASSERT_EQUAL(ui32(row2["key1"]), 347); - UNIT_ASSERT_EQUAL(TString(row1["key2"]), "id345"); - UNIT_ASSERT_EQUAL(TString(row2["key2"]), "idXYZ"); - UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); - UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); + UNIT_ASSERT_EQUAL(ui32(row1["key1"]), 345); + UNIT_ASSERT_EQUAL(ui32(row2["key1"]), 346); + UNIT_ASSERT_EQUAL(TString(row1["key2"]), "id123"); + UNIT_ASSERT_EQUAL(TString(row2["key2"]), "id345"); + UNIT_ASSERT_EQUAL(TString(row1["value"]), "Robert"); + UNIT_ASSERT_EQUAL(TString(row2["value"]), "Tables"); } { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) - (let r2 '('key2 (Void) (Void))) + (let r2 '('key2 (Void) (Nothing (OptionalType (DataType 'Utf8))))) (let range '('ExcFrom 'ExcTo r1 r2)) (let select '('key1 'key2 'value)) (let options '()) @@ -585,21 +585,17 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { TValue rs0 = value["myRes"]; UNIT_ASSERT_EQUAL(bool(rs0["Truncated"]), false); TValue rsl = rs0["List"]; - UNIT_ASSERT_EQUAL(rsl.Size(), 2); + UNIT_ASSERT_EQUAL(rsl.Size(), 1); TValue row1 = rsl[0]; - TValue row2 = rsl[1]; UNIT_ASSERT_EQUAL(ui32(row1["key1"]), 346); - UNIT_ASSERT_EQUAL(ui32(row2["key1"]), 347); UNIT_ASSERT_EQUAL(TString(row1["key2"]), "id345"); - UNIT_ASSERT_EQUAL(TString(row2["key2"]), "idXYZ"); UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); - UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); } { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) - (let r2 '('key2 (Void) (Void))) + (let r2 '('key2 (Nothing (OptionalType (DataType 'Utf8))) (Void))) (let range '('IncFrom 'IncTo r1 r2)) (let select '('key1 'key2 'value)) (let options '()) @@ -616,22 +612,26 @@ Y_UNIT_TEST(SelectRangeWithNotFullKey) { auto rs0 = value["myRes"]; UNIT_ASSERT_EQUAL(bool(rs0["Truncated"]), false); auto rsl = rs0["List"]; - UNIT_ASSERT_EQUAL(rsl.Size(), 2); + UNIT_ASSERT_EQUAL(rsl.Size(), 3); auto row1 = rsl[0]; auto row2 = rsl[1]; - UNIT_ASSERT_EQUAL(ui32(row1["key1"]), 346); - UNIT_ASSERT_EQUAL(ui32(row2["key1"]), 347); - UNIT_ASSERT_EQUAL(TString(row1["key2"]), "id345"); - UNIT_ASSERT_EQUAL(TString(row2["key2"]), "idXYZ"); - UNIT_ASSERT_EQUAL(TString(row1["value"]), "Tables"); - UNIT_ASSERT_EQUAL(TString(row2["value"]), "Paulson"); + auto row3 = rsl[2]; + UNIT_ASSERT_EQUAL(ui32(row1["key1"]), 345); + UNIT_ASSERT_EQUAL(ui32(row2["key1"]), 346); + UNIT_ASSERT_EQUAL(ui32(row3["key1"]), 347); + UNIT_ASSERT_EQUAL(TString(row1["key2"]), "id123"); + UNIT_ASSERT_EQUAL(TString(row2["key2"]), "id345"); + UNIT_ASSERT_EQUAL(TString(row3["key2"]), "idXYZ"); + UNIT_ASSERT_EQUAL(TString(row1["value"]), "Robert"); + UNIT_ASSERT_EQUAL(TString(row2["value"]), "Tables"); + UNIT_ASSERT_EQUAL(TString(row3["value"]), "Paulson"); } // (345,inf).. (347,inf) { auto programText = R"___(( (let r1 '('key1 (Uint32 '345) (Uint32 '347))) - (let range '('IncFrom 'ExcTo r1)) + (let range '('ExcFrom 'IncTo r1)) (let select '('key1 'key2 'value)) (let options '()) (let pgmReturn (AsList diff --git a/ydb/core/tx/datashard/datashard_ut_order.cpp b/ydb/core/tx/datashard/datashard_ut_order.cpp index b64b30c167..4b21b7a23a 100644 --- a/ydb/core/tx/datashard/datashard_ut_order.cpp +++ b/ydb/core/tx/datashard/datashard_ut_order.cpp @@ -1193,6 +1193,9 @@ Y_UNIT_TEST_WITH_MVCC(ScanFollowedByUpdate) { auto &tx = *dataTransaction.MutableReadTableTransaction(); tx.MutableTableId()->SetOwnerId(FAKE_SCHEMESHARD_TABLET_ID); tx.MutableTableId()->SetTableId(13); + auto &range = *tx.MutableRange(); + range.SetFromInclusive(true); + range.SetToInclusive(true); auto &c = *tx.AddColumns(); c.SetId(56); c.SetName("value"); diff --git a/ydb/core/tx/datashard/datashard_ut_rs.cpp b/ydb/core/tx/datashard/datashard_ut_rs.cpp index 06c5e83b37..6442648fdc 100644 --- a/ydb/core/tx/datashard/datashard_ut_rs.cpp +++ b/ydb/core/tx/datashard/datashard_ut_rs.cpp @@ -17,7 +17,7 @@ ui64 GetRSCount(TTestActorRuntime &runtime, TActorId sender, ui64 shard) { auto request = MakeHolder<TEvTablet::TEvLocalMKQL>(); TString miniKQL = R"___(( - (let range '('IncFrom '('TxId (Uint64 '0) (Void)))) + (let range '('ExcFrom '('TxId (Uint64 '0) (Void)))) (let select '('TxId)) (let options '()) (let pgmReturn (AsList @@ -158,7 +158,7 @@ Y_UNIT_TEST_SUITE(TDataShardRSTest) { { auto request = MakeHolder<TEvTablet::TEvLocalMKQL>(); TString miniKQL = R"___(( - (let range '('IncFrom '('TxId (Uint64 '0) (Void)))) + (let range '('ExcFrom '('TxId (Uint64 '0) (Void)))) (let select '('TxId)) (let options '()) (let pgmReturn (AsList diff --git a/ydb/core/tx/schemeshard/ut_restore.cpp b/ydb/core/tx/schemeshard/ut_restore.cpp index 42272ebe11..422f4cb6a8 100644 --- a/ydb/core/tx/schemeshard/ut_restore.cpp +++ b/ydb/core/tx/schemeshard/ut_restore.cpp @@ -269,19 +269,20 @@ namespace { NKikimrMiniKQL::TResult ReadTable(TTestActorRuntime& runtime, ui64 tabletId, const TString& table = "Table", const TReadKeyDesc& keyDesc = {"key", "Utf8", "\"\""}, - const TVector<TString>& columns = {"key", "value"}) { + const TVector<TString>& columns = {"key", "value"}, + const TString& rangeFlags = "") { const auto rangeFmt = Sprintf("'%s (%s '%s)", keyDesc.Name.data(), keyDesc.Type.data(), keyDesc.Atom.data()); const auto columnsFmt = "'" + JoinSeq(" '", columns); return ReadTableImpl(runtime, tabletId, Sprintf(R"( ( - (let range '( '(%s (Void) ))) + (let range '(%s '(%s (Void) ))) (let columns '(%s) ) (let result (SelectRange '__user__%s range columns '())) (return (AsList (SetResult 'Result result) )) ) - )", rangeFmt.data(), columnsFmt.data(), table.data())); + )", rangeFlags.c_str(), rangeFmt.data(), columnsFmt.data(), table.data())); } using TDelayFunc = std::function<bool(TAutoPtr<IEventHandle>&)>; @@ -1592,7 +1593,7 @@ Y_UNIT_TEST_SUITE(TImportTests) { for (ui32 i = 0; i < indexes; ++i) { auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1 + i, - "indexImplTable", {"value", "Utf8", "\"\""}, {"value", "key"}); + "indexImplTable", {"value", "Utf8", "\"\""}, {"value", "key"}, "'ExcFrom"); NKqp::CompareYson(data.Data[0].YsonStr, content); } } diff --git a/ydb/core/tx/tx_proxy/datareq.cpp b/ydb/core/tx/tx_proxy/datareq.cpp index c933a19412..cd37e9c42a 100644 --- a/ydb/core/tx/tx_proxy/datareq.cpp +++ b/ydb/core/tx/tx_proxy/datareq.cpp @@ -1166,6 +1166,14 @@ void TDataReq::ProcessReadTableResolve(NSchemeCache::TSchemeCacheRequest *cacheR auto &range = *tx.MutableRange(); ReadTableRequest->KeySpace.GetSpace().Serialize(range); + // Normalize range's From/ToInclusive + if (range.GetFrom().empty() && !range.GetFromInclusive()) { + range.SetFromInclusive(true); + } + if (range.GetTo().empty() && !range.GetToInclusive()) { + range.SetToInclusive(true); + } + if (!ReadTableRequest->Snapshot.IsMax()) { tx.SetSnapshotStep(ReadTableRequest->Snapshot.Step); tx.SetSnapshotTxId(ReadTableRequest->Snapshot.TxId); @@ -1561,6 +1569,13 @@ void TDataReq::Handle(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr &ev, return Die(ctx); } + if (!ReadTableRequest->FromValues.GetCells() && !ReadTableRequest->Range.HasFromInclusive()) { + fromInclusive = true; // default to inclusive -inf + } + if (!ReadTableRequest->ToValues.GetCells() && !ReadTableRequest->Range.HasToInclusive()) { + toInclusive = true; // default to inclusive +inf + } + TTableRange range(ReadTableRequest->FromValues.GetCells(), fromInclusive, ReadTableRequest->ToValues.GetCells(), diff --git a/ydb/core/tx/tx_proxy/read_table_impl.cpp b/ydb/core/tx/tx_proxy/read_table_impl.cpp index 3cb6dfb87d..f2d7539787 100644 --- a/ydb/core/tx/tx_proxy/read_table_impl.cpp +++ b/ydb/core/tx/tx_proxy/read_table_impl.cpp @@ -578,8 +578,8 @@ private: return ReplyAndDie(TEvTxUserProxy::TEvProposeTransactionStatus::EStatus::ResolveError, NKikimrIssues::TStatusIds::SCHEME_ERROR, ctx); } - const bool fromInclusive = Settings.KeyRange.GetFromInclusive(); - const bool toInclusive = Settings.KeyRange.GetToInclusive(); + bool fromInclusive = Settings.KeyRange.GetFromInclusive(); + bool toInclusive = Settings.KeyRange.GetToInclusive(); const EParseRangeKeyExp fromExpand = ( Settings.KeyRange.HasFrom() ? (fromInclusive ? EParseRangeKeyExp::TO_NULL : EParseRangeKeyExp::NONE) @@ -601,6 +601,16 @@ private: return ReplyAndDie(TEvTxUserProxy::TEvProposeTransactionStatus::EStatus::ResolveError, NKikimrIssues::TStatusIds::QUERY_ERROR, ctx); } + if (KeyFromValues.GetCells().size() < keyTypes.size() && !Settings.KeyRange.HasFromInclusive()) { + // Default: non-inclusive for incomplete From, except when From is empty + fromInclusive = KeyFromValues.GetCells().size() == 0; + } + + if (KeyToValues.GetCells().size() < keyTypes.size() && !Settings.KeyRange.HasToInclusive()) { + // Default: inclusive for incomplete To + toInclusive = true; + } + TTableRange range( KeyFromValues.GetCells(), fromInclusive, KeyToValues.GetCells(), toInclusive); @@ -1428,6 +1438,14 @@ private: auto& txRange = *tx.MutableRange(); state.Ranges.front().Serialize(txRange); + // Normalize range's From/ToInclusive + if (txRange.GetFrom().empty() && !txRange.GetFromInclusive()) { + txRange.SetFromInclusive(true); + } + if (txRange.GetTo().empty() && !txRange.GetToInclusive()) { + txRange.SetToInclusive(true); + } + if (Settings.ReadVersion.IsMax()) { // Use snapshot that we have created tx.SetSnapshotStep(PlanStep); diff --git a/ydb/public/lib/deprecated/kicli/cpp_ut.cpp b/ydb/public/lib/deprecated/kicli/cpp_ut.cpp index cb7dc3ed6d..a4f5e480ba 100644 --- a/ydb/public/lib/deprecated/kicli/cpp_ut.cpp +++ b/ydb/public/lib/deprecated/kicli/cpp_ut.cpp @@ -1472,9 +1472,9 @@ Y_UNIT_TEST_SUITE(ClientLib) { '('Rank rank) '('UrlHash urlHash))) (let column1 '('UrlHash)) - (let range '('IncFrom '('ShardId shardId (Void)) - '('HostTitleHash hostTitleHash (Void)) - '('GroupSimHash groupSimHash (Void)) + (let range '('ExcFrom 'IncTo '('ShardId shardId (Void)) + '('HostTitleHash hostTitleHash (Void)) + '('GroupSimHash groupSimHash (Void)) )) (let column2 '('UrlHash)) (let options '('('ItemsLimit (Uint64 '1)))) @@ -1510,6 +1510,9 @@ Y_UNIT_TEST_SUITE(ClientLib) { { using namespace NClient; + Y_UNUSED(includeFrom); + Y_UNUSED(includeTo); + auto rawq = kikimr.Query( Sprintf(R"___( ( @@ -1524,8 +1527,8 @@ Y_UNIT_TEST_SUITE(ClientLib) { (return pgmReturn) ) )___", - includeFrom ? "IncFrom" : "ExcFrom", - includeTo ? "IncTo" : "ExcTo" + "ExcFrom" /* incomplete From is always non-inclusive */, + "IncTo" /* incomplete To is always inclusive */ )); auto q = rawq.SyncPrepare(); UNIT_ASSERT_VALUES_EQUAL_C(q.GetStatus(), NMsgBusProxy::MSTATUS_OK, q.GetError().GetMessage().c_str()); |