Просмотр исходного кода

KIKIMR-18864: fix column order for index table reading result

ulya-sidorina 1 год назад
Родитель
Сommit
8f78e24286

+ 18 - 16
ydb/core/kqp/opt/logical/kqp_opt_log_indexes.cpp

@@ -16,43 +16,45 @@ using namespace NYql::NNodes;
 namespace {
 namespace {
 
 
 TCoAtomList BuildKeyColumnsList(const TKikimrTableDescription& table, TPositionHandle pos, TExprContext& ctx) {
 TCoAtomList BuildKeyColumnsList(const TKikimrTableDescription& table, TPositionHandle pos, TExprContext& ctx) {
-    TVector<TExprBase> columnsToSelect;
-    columnsToSelect.reserve(table.Metadata->KeyColumnNames.size());
-    for (auto key : table.Metadata->KeyColumnNames) {
-        auto value = table.Metadata->Columns.at(key);
+    TSet<TString> columnsToSelect(table.Metadata->KeyColumnNames.begin(), table.Metadata->KeyColumnNames.end());
+    TVector<TExprBase> columnsList;
+    columnsList.reserve(columnsToSelect.size());
+    for (auto column : columnsToSelect) {
         auto atom = Build<TCoAtom>(ctx, pos)
         auto atom = Build<TCoAtom>(ctx, pos)
-            .Value(value.Name)
+            .Value(column)
             .Done();
             .Done();
 
 
-        columnsToSelect.push_back(atom);
+        columnsList.emplace_back(std::move(atom));
     }
     }
 
 
     return Build<TCoAtomList>(ctx, pos)
     return Build<TCoAtomList>(ctx, pos)
-        .Add(columnsToSelect)
+        .Add(columnsList)
         .Done();
         .Done();
 }
 }
 
 
 TCoAtomList MergeColumns(const NNodes::TCoAtomList& col1, const TVector<TString>& col2, TExprContext& ctx) {
 TCoAtomList MergeColumns(const NNodes::TCoAtomList& col1, const TVector<TString>& col2, TExprContext& ctx) {
-    TVector<TCoAtom> columns;
-    THashSet<TString> uniqColumns;
-    columns.reserve(col1.Size() + col2.size());
-
+    TMap<TString, TCoAtom> columns;
     for (const auto& c : col1) {
     for (const auto& c : col1) {
-        YQL_ENSURE(uniqColumns.emplace(c.StringValue()).second);
-        columns.push_back(c);
+        YQL_ENSURE(columns.insert({c.StringValue(), c}).second);
     }
     }
 
 
     for (const auto& c : col2) {
     for (const auto& c : col2) {
-        if (uniqColumns.emplace(c).second) {
+        if (!columns.contains(c)) {
             auto atom = Build<TCoAtom>(ctx, col1.Pos())
             auto atom = Build<TCoAtom>(ctx, col1.Pos())
                 .Value(c)
                 .Value(c)
                 .Done();
                 .Done();
-            columns.push_back(atom);
+            columns.insert({c, std::move(atom)});
         }
         }
     }
     }
 
 
+    TVector<TCoAtom> columnsList;
+    columnsList.reserve(columns.size());
+    for (auto [_, column] : columns) {
+        columnsList.emplace_back(std::move(column));
+    }
+
     return Build<TCoAtomList>(ctx, col1.Pos())
     return Build<TCoAtomList>(ctx, col1.Pos())
-        .Add(columns)
+        .Add(columnsList)
         .Done();
         .Done();
 }
 }
 
 

+ 94 - 0
ydb/core/kqp/ut/scan/kqp_scan_ut.cpp

@@ -1823,6 +1823,100 @@ Y_UNIT_TEST_SUITE(KqpScan) {
         }
         }
     }
     }
 
 
+    Y_UNIT_TEST(SecondaryIndexCustomColumnOrder) {
+        TKikimrRunner kikimr;
+        auto db = kikimr.GetTableClient();
+        auto session = db.CreateSession().GetValueSync().GetSession();
+
+        CreateSampleTablesWithIndex(session);
+
+        {  // prepare table
+            auto res = session.ExecuteSchemeQuery(R"(
+                --!syntax_v1
+                CREATE TABLE `/Root/SecondaryKeysCustomOrder` (
+                    Key2 Int32,
+                    Key1 String,
+                    Fk2 Int32,
+                    Fk1 String,
+                    Value String,
+                    PRIMARY KEY (Key2, Key1),
+                    INDEX Index GLOBAL ON (Fk2, Fk1)
+                );
+            )").GetValueSync();
+            UNIT_ASSERT_C(res.IsSuccess(), res.GetIssues().ToString());
+
+            auto result = session.ExecuteDataQuery(R"(
+
+            REPLACE INTO `/Root/SecondaryKeysCustomOrder` (Key2, Key1, Fk2, Fk1, Value) VALUES
+                (1u, "One", 1u, "Fk1", "Value1"),
+                (2u, "Two", 2u, "Fk2", "Value2"),
+                (3u, "Three", 3u, "Fk3", Null),
+                (NULL, "Four", 4u, Null, "Value4"),
+                (5u, Null, 5u, "Fk5",  "Value5");
+            )", TTxControl::BeginTx().CommitTx()).GetValueSync();
+            UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+        }
+
+        {
+            auto itIndex = db.StreamExecuteScanQuery(R"(
+                SELECT Value, Fk1
+                FROM `/Root/SecondaryKeysCustomOrder` VIEW Index
+                WHERE Fk2 = 2u;
+            )").GetValueSync();
+
+            UNIT_ASSERT_C(itIndex.IsSuccess(), itIndex.GetIssues().ToString());
+            CompareYson(R"([
+                [["Value2"];["Fk2"]]
+            ])", StreamResultToYson(itIndex));
+        }
+
+        {
+            auto itIndex = db.StreamExecuteScanQuery(R"(
+                SELECT Value, Fk1, Key2
+                FROM `/Root/SecondaryKeysCustomOrder` VIEW Index
+                WHERE Fk2 >= 4u AND Fk1 IS NULL;
+            )").GetValueSync();
+
+            UNIT_ASSERT_C(itIndex.IsSuccess(), itIndex.GetIssues().ToString());
+            CompareYson(R"([
+                [["Value4"];#;#]
+            ])", StreamResultToYson(itIndex));
+        }
+
+        {
+            auto itIndex = db.StreamExecuteScanQuery(R"(
+                PRAGMA AnsiInForEmptyOrNullableItemsCollections;
+                SELECT Value, Fk1, Key1
+                FROM `/Root/SecondaryKeysCustomOrder` VIEW Index
+                WHERE (Fk2, Fk1) IN AsList((1u, "Fk1"), (2u, "Fk2"), (5u, "Fk5"))
+                ORDER BY Value;
+            )").GetValueSync();
+
+            UNIT_ASSERT_C(itIndex.IsSuccess(), itIndex.GetIssues().ToString());
+            CompareYson(R"([
+                [["Value1"];["Fk1"];["One"]];
+                [["Value2"];["Fk2"];["Two"]];
+                [["Value5"];["Fk5"];#]
+            ])", StreamResultToYson(itIndex));
+        }
+
+        {
+            auto itIndex = db.StreamExecuteScanQuery(R"(
+                SELECT r.Value, l.Value
+                FROM `/Root/SecondaryKeys` VIEW Index AS l
+                INNER JOIN `/Root/SecondaryKeysCustomOrder` VIEW Index AS r
+                ON l.Fk = r.Fk2 ORDER BY r.Value;
+            )").GetValueSync();
+
+            UNIT_ASSERT_C(itIndex.IsSuccess(), itIndex.GetIssues().ToString());
+            CompareYson(R"([
+                [["Value1"];["Payload1"]];
+                [["Value2"];["Payload2"]];
+                [["Value5"];["Payload5"]]
+            ])", StreamResultToYson(itIndex));
+        }
+    }
+
     Y_UNIT_TEST(BoolFlag) {
     Y_UNIT_TEST(BoolFlag) {
         auto kikimr = DefaultKikimrRunner({}, AppCfg());
         auto kikimr = DefaultKikimrRunner({}, AppCfg());
 
 

+ 2 - 2
ydb/tests/functional/canonical/canondata/test_sql.TestCanonicalFolder1.test_case_index_topsort_index_with_nonselector_aliases.sql-plan_/index_topsort_index_with_nonselector_aliases.sql.plan

@@ -22,9 +22,9 @@
             "reads": [
             "reads": [
                 {
                 {
                     "columns": [
                     "columns": [
-                        "Key1",
                         "Index1A",
                         "Index1A",
-                        "Index1B"
+                        "Index1B",
+                        "Key1"
                     ],
                     ],
                     "limit": "2",
                     "limit": "2",
                     "reverse": true,
                     "reverse": true,

+ 2 - 2
ydb/tests/functional/canonical/canondata/test_sql.TestCanonicalFolder1.test_case_index_topsort_index_with_selector_aliases.sql-plan_/index_topsort_index_with_selector_aliases.sql.plan

@@ -22,9 +22,9 @@
             "reads": [
             "reads": [
                 {
                 {
                     "columns": [
                     "columns": [
-                        "Key1",
                         "Index1A",
                         "Index1A",
-                        "Index1B"
+                        "Index1B",
+                        "Key1"
                     ],
                     ],
                     "limit": "2",
                     "limit": "2",
                     "reverse": true,
                     "reverse": true,