diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp index 4e4208987d28..babd9316bb0b 100644 --- a/ydb/library/yql/sql/pg/pg_sql.cpp +++ b/ydb/library/yql/sql/pg/pg_sql.cpp @@ -495,6 +495,8 @@ class TConverter : public IPGParseEvents { return ParseTransactionStmt(CAST_NODE(TransactionStmt, node)); case T_IndexStmt: return ParseIndexStmt(CAST_NODE(IndexStmt, node)) != nullptr; + case T_CreateSeqStmt: + return ParseCreateSeqStmt(CAST_NODE(CreateSeqStmt, node)) != nullptr; default: NodeNotImplemented(value, node); return false; @@ -2650,6 +2652,88 @@ class TConverter : public IPGParseEvents { return State.Statements.back(); } + [[nodiscard]] + TAstNode* ParseCreateSeqStmt(const CreateSeqStmt* value) { + + std::vector options; + + TString mode = (value->if_not_exists) ? "create_if_not_exists" : "create"; + options.push_back(QL(QA("mode"), QA(mode))); + + auto [sink, key] = ParseQualifiedPgObjectName( + value->sequence->catalogname, + value->sequence->schemaname, + value->sequence->relname, + "pgSequence" + ); + + if (!sink || !key) { + return nullptr; + } + + const auto relPersistence = static_cast(value->sequence->relpersistence); + switch (relPersistence) { + case NPg::ERelPersistence::Temp: + options.push_back(QL(QA("temporary"))); + break; + case NPg::ERelPersistence::Unlogged: + AddError("UNLOGGED sequence not supported"); + return nullptr; + break; + case NPg::ERelPersistence::Permanent: + break; + } + + for (int i = 0; i < ListLength(value->options); ++i) { + auto rawNode = ListNodeNth(value->options, i); + + switch (NodeTag(rawNode)) { + case T_DefElem: { + const auto* defElem = CAST_NODE(DefElem, rawNode); + TStringBuf nameElem = defElem->defname; + if (defElem->arg) { + switch (NodeTag(defElem->arg)) + { + case T_Integer: + options.emplace_back(QL(QA(nameElem), QA(ToString(intVal(defElem->arg))))); + break; + case T_Float: + options.emplace_back(QL(QA(nameElem), QA(strVal(defElem->arg)))); + break; + case T_TypeName: { + const auto* typeName = reinterpret_cast(defElem->arg); + options.emplace_back(QL(QA(nameElem), + QA(StrVal(ListNodeNth(typeName->names, ListLength(typeName->names) - 1))))); + break; + } + default: + AddError("storage parameters for index is not supported yet:" + TString(nameElem)); + NodeNotImplemented(defElem->arg); + return nullptr; + } + } + break; + } + default: + NodeNotImplemented(rawNode); + return nullptr; + } + } + + if (value->for_identity) { + options.push_back(QL(QA("for_identity"))); + } + + options.push_back(QL(QA("owner_id"), QA(ToString(value->ownerId)))); + + State.Statements.push_back( + L(A("let"), A("world"), + L(A("Write!"), A("world"), sink, key, L(A("Void")), + QVL(options.data(), options.size())))); + + return State.Statements.back(); + } + TFromDesc ParseFromClause(const Node* node) { switch (NodeTag(node)) { case T_RangeVar: @@ -4780,7 +4864,7 @@ TVector PGToYqlStatements(const TString& query, const NSQ TConverter converter(results, settings, query, stmtParseInfo, true); NYql::PGParse(query, converter); for (auto& res : results) { - res.ActualSyntaxType = NYql::ESyntaxType::Pg; + res.ActualSyntaxType = NYql::ESyntaxType::Pg; } return results; } diff --git a/ydb/library/yql/sql/pg/pg_sql_ut.cpp b/ydb/library/yql/sql/pg/pg_sql_ut.cpp index fec158773aa1..785dbd34389c 100644 --- a/ydb/library/yql/sql/pg/pg_sql_ut.cpp +++ b/ydb/library/yql/sql/pg/pg_sql_ut.cpp @@ -166,7 +166,7 @@ Y_UNIT_TEST_SUITE(PgSqlParsingOnly) { )"; const auto expectedAst = NYql::ParseAst(program); UNIT_ASSERT_STRINGS_EQUAL(res.Root->ToString(), expectedAst.Root->ToString()); - } + } Y_UNIT_TEST(CreateTableStmt_PKAndNotNull) { auto res = PgSqlToYql("CREATE TABLE t (a int PRIMARY KEY NOT NULL, b text)"); @@ -265,6 +265,23 @@ Y_UNIT_TEST_SUITE(PgSqlParsingOnly) { UNIT_ASSERT_STRINGS_EQUAL(res.Root->ToString(), expectedAst.Root->ToString()); } + Y_UNIT_TEST(CreateSeqStmt) { + auto res = PgSqlToYql( + "CREATE TEMP SEQUENCE IF NOT EXISTS seq AS integer START WITH 10 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 3;"); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TString program = R"( + ( + (let world (Configure! world (DataSource 'config) 'OrderedColumns)) + (let world (Write! world (DataSink '"kikimr" '"") (Key '('pgObject (String 'seq) (String 'pgSequence))) (Void) '('('mode 'create_if_not_exists) '('temporary) '('as 'int4) '('start '10) '('increment '2) '('cache '3) '('owner_id '0)))) + (let world (CommitAll! world)) + (return world) + ) + )"; + const auto expectedAst = NYql::ParseAst(program); + UNIT_ASSERT_STRINGS_EQUAL(res.Root->ToString(), expectedAst.Root->ToString()); + } + Y_UNIT_TEST(VariableShowStmt) { auto res = PgSqlToYql("Show server_version_num"); UNIT_ASSERT(res.Root); @@ -482,7 +499,7 @@ SELECT COUNT(*) FROM public.t;"); settings); UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString()); UNIT_ASSERT(res.Root); - + res = SqlToYqlWithMode( R"(select oid, typinput::int4 as typinput, @@ -514,7 +531,7 @@ from pg_catalog.pg_type)", settings); UNIT_ASSERT(res.IsOk()); UNIT_ASSERT(res.Root); - + res = SqlToYqlWithMode( R"(select set_config('search_path', 'public', false);)", NSQLTranslation::ESqlMode::QUERY,