diff options
author | dcherednik <dcherednik@ydb.tech> | 2023-09-20 14:08:00 +0300 |
---|---|---|
committer | dcherednik <dcherednik@ydb.tech> | 2023-09-20 15:27:11 +0300 |
commit | fe3f3781595b6345ec4007cbc66b202dcc4a5c9b (patch) | |
tree | dfc24a01ea8fd67573dd926b898bc1b8103638e9 | |
parent | f532407f20a4453b989a50dc33449c80ed0b1cd9 (diff) | |
download | ydb-fe3f3781595b6345ec4007cbc66b202dcc4a5c9b.tar.gz |
Basic CREATE INDEX support for sql parser. KIKIMR-18527
-rw-r--r-- | ydb/core/kqp/ut/pg/kqp_pg_ut.cpp | 42 | ||||
-rw-r--r-- | ydb/library/yql/sql/pg/pg_sql.cpp | 104 |
2 files changed, 146 insertions, 0 deletions
diff --git a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp index 4b55196618..36a19abe2a 100644 --- a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp +++ b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp @@ -1429,6 +1429,48 @@ Y_UNIT_TEST_SUITE(KqpPg) { } } + Y_UNIT_TEST(CreateIndex) { + TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false)); + auto client = kikimr.GetTableClient(); + auto session = client.CreateSession().GetValueSync().GetSession(); + { + const auto query = Q_(R"( + --!syntax_pg + CREATE TABLE test( + id int8, + fk int8, + value char, + primary key(id) + ); + CREATE INDEX "test_fk_idx" ON test (fk); + CREATE INDEX "test_fk_idx_cover" ON test (fk) INCLUDE(value); + )"); + + auto result = session.ExecuteSchemeQuery(query).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } + { + const auto query = Q_(R"( + --!syntax_pg + CREATE INDEX "test_fk_idx" ON test (fk); + )"); + + auto result = session.ExecuteSchemeQuery(query).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::BAD_REQUEST, result.GetIssues().ToString()); + } +/* + { + const auto query = Q_(R"( + --!syntax_pg + CREATE INDEX IF NOT EXISTS "test_fk_idx" ON test (fk); + )"); + + auto result = session.ExecuteSchemeQuery(query).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + } +*/ + } + Y_UNIT_TEST(CreateUniqPgColumn) { TKikimrRunner kikimr(NKqp::TKikimrSettings().SetWithSampleTables(false)); auto client = kikimr.GetTableClient(); diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp index f43abbc10b..6e4e27b283 100644 --- a/ydb/library/yql/sql/pg/pg_sql.cpp +++ b/ydb/library/yql/sql/pg/pg_sql.cpp @@ -155,6 +155,11 @@ const Node* ListNodeNth(const List* list, int index) { return static_cast<const Node*>(list_nth(list, index)); } +const IndexElem* IndexElement(const Node* node) { + Y_ENSURE(node->type == T_IndexElem); + return ((const IndexElem*)node); +} + #define AT_LOCATION(node) \ TLocationGuard guard(this, node->location); @@ -390,6 +395,8 @@ public: return ParseVariableShowStmt(CAST_NODE(VariableShowStmt, node)) != nullptr; case T_TransactionStmt: return true; + case T_IndexStmt: + return ParseIndexStmt(CAST_NODE(IndexStmt, node)) != nullptr; default: NodeNotImplemented(value, node); return false; @@ -2106,6 +2113,26 @@ public: return {}; } + TMaybe<std::vector<TAstNode*>> ParseIndexElements(List* list) { + const auto length = ListLength(list); + std::vector<TAstNode*> columns; + columns.reserve(length); + + for (auto i = 0; i < length; ++i) { + auto node = ListNodeNth(list, i); + auto indexElem = IndexElement(node); + if (indexElem->expr || indexElem->indexcolname) { + AddError("index expression is not supported yet"); + return {}; + } + + columns.push_back(QA(indexElem->name)); + } + + return columns; + } + + [[nodiscard]] TAstNode* ParseVariableShowStmt(const VariableShowStmt* value) { const auto varName = to_lower(TString(value->name)); @@ -2140,6 +2167,83 @@ public: return Statements.back(); } + [[nodiscard]] + TAstNode* ParseIndexStmt(const IndexStmt* value) { + if (value->unique) { + AddError("unique index creation is not supported yet"); + return nullptr; + } + + if (value->primary) { + AddError("primary key creation is not supported yet"); + return nullptr; + } + + if (value->isconstraint || value->deferrable || value->initdeferred) { + AddError("constraint modification is not supported yet"); + return nullptr; + } + + if (value->whereClause) { + AddError("partial index is not supported yet"); + return nullptr; + } + + if (value->options) { + AddError("storage parameters for index is not supported yet"); + return nullptr; + } + + auto columns = ParseIndexElements(value->indexParams); + if (!columns) + return nullptr; + + auto coverColumns = ParseIndexElements(value->indexIncludingParams); + if (!coverColumns) + return nullptr; + + const auto [sink, key] = ParseWriteRangeVar(value->relation, true); + if (!sink || !key) { + return nullptr; + } + + //std::vector<TAstNode*> flags; + //flags.emplace_back(QA("pg")); + //if (value->if_not_exists) { + // flags.emplace_back(QA("ifNotExists")); + //} + + std::vector<TAstNode*> desc; + auto indexNameAtom = QA("indexName"); + if (value->idxname) { + desc.emplace_back(QL(indexNameAtom, QA(value->idxname))); + } else { + desc.emplace_back(QL(indexNameAtom)); + } + desc.emplace_back(QL(QA("indexType"), QA(value->unique ? "syncGlobalUnique" : "syncGlobal"))); + desc.emplace_back(QL(QA("indexColumns"), QVL(columns->data(), columns->size()))); + desc.emplace_back(QL(QA("dataColumns"), QVL(coverColumns->data(), coverColumns->size()))); + //desc.emplace_back(QL(QA("flags"), QVL(flags.data(), flags.size()))); + + Statements.push_back(L( + A("let"), + A("world"), + L( + A("Write!"), + A("world"), + sink, + key, + L(A("Void")), + QL( + QL(QA("mode"), QA("alter")), + QL(QA("actions"), QL(QL(QA("addIndex"), QVL(desc.data(), desc.size())))) + ) + ) + )); + + return Statements.back(); + } + TFromDesc ParseFromClause(const Node* node) { switch (NodeTag(node)) { case T_RangeVar: |