aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordcherednik <dcherednik@ydb.tech>2023-09-20 14:08:00 +0300
committerdcherednik <dcherednik@ydb.tech>2023-09-20 15:27:11 +0300
commitfe3f3781595b6345ec4007cbc66b202dcc4a5c9b (patch)
treedfc24a01ea8fd67573dd926b898bc1b8103638e9
parentf532407f20a4453b989a50dc33449c80ed0b1cd9 (diff)
downloadydb-fe3f3781595b6345ec4007cbc66b202dcc4a5c9b.tar.gz
Basic CREATE INDEX support for sql parser. KIKIMR-18527
-rw-r--r--ydb/core/kqp/ut/pg/kqp_pg_ut.cpp42
-rw-r--r--ydb/library/yql/sql/pg/pg_sql.cpp104
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: