From 78db890dbcaec10564dfc652f1b0eb0ece3a3558 Mon Sep 17 00:00:00 2001 From: Nikolay Shumkov Date: Mon, 5 Feb 2024 15:21:44 +0300 Subject: [PATCH 1/2] Initial commit --- ydb/library/yql/sql/v1/SQLv1.g.in | 2 +- ydb/library/yql/sql/v1/format/sql_format_ut.cpp | 3 ++- ydb/library/yql/sql/v1/node.h | 1 + ydb/library/yql/sql/v1/query.cpp | 4 ++++ ydb/library/yql/sql/v1/sql_query.cpp | 6 +++++- ydb/library/yql/sql/v1/sql_ut.cpp | 17 +++++++++++++++++ 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ydb/library/yql/sql/v1/SQLv1.g.in b/ydb/library/yql/sql/v1/SQLv1.g.in index d742f9114887..c6a70127a077 100644 --- a/ydb/library/yql/sql/v1/SQLv1.g.in +++ b/ydb/library/yql/sql/v1/SQLv1.g.in @@ -623,7 +623,7 @@ object_features: object_feature | LPAREN object_feature (COMMA object_feature)* object_type_ref: an_id_or_type; -create_table_stmt: CREATE (OR REPLACE)? (TABLE | TABLESTORE | EXTERNAL TABLE) (IF NOT EXISTS)? simple_table_ref LPAREN create_table_entry (COMMA create_table_entry)* COMMA? RPAREN +create_table_stmt: CREATE (OR REPLACE)? (TABLE | TABLESTORE | EXTERNAL TABLE | TEMP TABLE) (IF NOT EXISTS)? simple_table_ref LPAREN create_table_entry (COMMA create_table_entry)* COMMA? RPAREN table_inherits? table_partition_by? with_table_settings? diff --git a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp index cef8e235cc83..b8aec0b08b25 100644 --- a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp +++ b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp @@ -307,7 +307,8 @@ Y_UNIT_TEST_SUITE(CheckSqlFormatter) { ")\n" "PARTITION BY HASH (a, b, hash)\n" "WITH (tiering = 'some');\n"}, - {"create table if not exists user(user int32)", "CREATE TABLE IF NOT EXISTS user (\n\tuser int32\n);\n"} + {"create table if not exists user(user int32)", "CREATE TABLE IF NOT EXISTS user (\n\tuser int32\n);\n"}, + {"create temp table user(user int32)", "CREATE TEMP TABLE user (\n\tuser int32\n);\n"} }; TSetup setup; diff --git a/ydb/library/yql/sql/v1/node.h b/ydb/library/yql/sql/v1/node.h index 8bb0ba2030bd..26c0d1d30aff 100644 --- a/ydb/library/yql/sql/v1/node.h +++ b/ydb/library/yql/sql/v1/node.h @@ -1046,6 +1046,7 @@ namespace NSQLTranslationV1 { TVector Changefeeds; TTableSettings TableSettings; ETableType TableType = ETableType::Table; + bool Temporary = false; }; struct TAlterTableParameters { diff --git a/ydb/library/yql/sql/v1/query.cpp b/ydb/library/yql/sql/v1/query.cpp index 4ea558ead15c..a9185ddf3413 100644 --- a/ydb/library/yql/sql/v1/query.cpp +++ b/ydb/library/yql/sql/v1/query.cpp @@ -1140,6 +1140,10 @@ class TCreateTableNode final: public TAstListNode { break; } + if (Params.Temporary) { + opts = L(opts, Q(Y(Q("temporary")))); + } + Add("block", Q(Y( Y("let", "sink", Y("DataSink", BuildQuotedAtom(Pos, Table.Service), Scoped->WrapCluster(Table.Cluster, ctx))), Y("let", "world", Y(TString(WriteName), "world", "sink", keys, Y("Void"), Q(opts))), diff --git a/ydb/library/yql/sql/v1/sql_query.cpp b/ydb/library/yql/sql/v1/sql_query.cpp index 1b450cc64018..c1576fffe546 100644 --- a/ydb/library/yql/sql/v1/sql_query.cpp +++ b/ydb/library/yql/sql/v1/sql_query.cpp @@ -166,10 +166,14 @@ bool TSqlQuery::Statement(TVector& blocks, const TRule_sql_stmt_core& const auto& block = rule.GetBlock3(); ETableType tableType = ETableType::Table; + bool temporary = false; if (block.HasAlt2() && block.GetAlt2().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_TABLESTORE) { tableType = ETableType::TableStore; } else if (block.HasAlt3() && block.GetAlt3().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_EXTERNAL) { tableType = ETableType::ExternalTable; + } else if (block.HasAlt4() && block.GetAlt4().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_TEMP) { + temporary = true; + Y_DEBUG_ABORT_UNLESS(block.GetAlt4().GetToken2().GetId() == SQLv1LexerTokens::TOKEN_TABLE); } bool existingOk = false; @@ -193,7 +197,7 @@ bool TSqlQuery::Statement(TVector& blocks, const TRule_sql_stmt_core& return false; } - TCreateTableParameters params{.TableType=tableType}; + TCreateTableParameters params{.TableType=tableType, .Temporary=temporary}; if (!CreateTableEntry(rule.GetRule_create_table_entry7(), params)) { return false; } diff --git a/ydb/library/yql/sql/v1/sql_ut.cpp b/ydb/library/yql/sql/v1/sql_ut.cpp index b7e265d5203e..c2c9d67f7c4d 100644 --- a/ydb/library/yql/sql/v1/sql_ut.cpp +++ b/ydb/library/yql/sql/v1/sql_ut.cpp @@ -1007,6 +1007,23 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]); } + Y_UNIT_TEST(CreateTempTable) { + NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TEMP TABLE t (a int32, primary key(a));"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write!") { + UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, + line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) (Void) '('('mode 'create) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))) '('primarykey '('"a")) '('temporary))))__"), line); + } + }; + + TWordCountHive elementStat = {{TString("Write!"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]); + } + Y_UNIT_TEST(CreateTableDuplicatedPkColumnsFail) { NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32 not null, primary key(a, a));"); UNIT_ASSERT(!res.Root); From 449496b71cc9fbd68ff72547e448ca1f704200f3 Mon Sep 17 00:00:00 2001 From: Nikolay Shumkov Date: Wed, 7 Feb 2024 18:58:01 +0300 Subject: [PATCH 2/2] Fixes --- ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp | 131 ++++++++++++++++++ ydb/library/yql/sql/v1/SQLv1.g.in | 2 +- .../yql/sql/v1/format/sql_format_ut.cpp | 3 +- ydb/library/yql/sql/v1/sql_query.cpp | 4 +- ydb/library/yql/sql/v1/sql_ut.cpp | 17 +++ 5 files changed, 153 insertions(+), 4 deletions(-) diff --git a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp index 32181f5da43c..079a3d85a9e4 100644 --- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp +++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp @@ -860,6 +860,137 @@ Y_UNIT_TEST_SUITE(KqpQueryService) { UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); } + Y_UNIT_TEST(CreateTempTable) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true); + auto setting = NKikimrKqp::TKqpSetting(); + auto serverSettings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetKqpSettings({setting}); + TKikimrRunner kikimr( + serverSettings.SetWithSampleTables(false).SetEnableTempTables(true)); + auto clientConfig = NGRpcProxy::TGRpcClientConfig(kikimr.GetEndpoint()); + auto client = kikimr.GetQueryClient(); + { + auto session = client.GetSession().GetValueSync().GetSession(); + auto id = session.GetId(); + + const auto queryCreate = Q_(R"( + --!syntax_v1 + CREATE TEMP TABLE Temp ( + Key Uint64 NOT NULL, + Value String, + PRIMARY KEY (Key) + );)"); + + auto resultCreate = session.ExecuteQuery(queryCreate, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultCreate.IsSuccess(), resultCreate.GetIssues().ToString()); + + const auto querySelect = Q_(R"( + --!syntax_v1 + SELECT * FROM Temp; + )"); + + auto resultSelect = session.ExecuteQuery( + querySelect, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultSelect.IsSuccess(), resultSelect.GetIssues().ToString()); + + bool allDoneOk = true; + NTestHelpers::CheckDelete(clientConfig, id, Ydb::StatusIds::SUCCESS, allDoneOk); + + UNIT_ASSERT(allDoneOk); + } + + { + const auto querySelect = Q_(R"( + --!syntax_v1 + SELECT * FROM Temp; + )"); + + auto resultSelect = client.ExecuteQuery( + querySelect, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT(!resultSelect.IsSuccess()); + } + } + + Y_UNIT_TEST(TempTablesDrop) { + NKikimrConfig::TAppConfig appConfig; + appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true); + auto setting = NKikimrKqp::TKqpSetting(); + auto serverSettings = TKikimrSettings() + .SetAppConfig(appConfig) + .SetKqpSettings({setting}); + TKikimrRunner kikimr( + serverSettings.SetWithSampleTables(false).SetEnableTempTables(true)); + auto clientConfig = NGRpcProxy::TGRpcClientConfig(kikimr.GetEndpoint()); + auto client = kikimr.GetQueryClient(); + + auto session = client.GetSession().GetValueSync().GetSession(); + auto id = session.GetId(); + + const auto queryCreate = Q_(R"( + --!syntax_v1 + CREATE TEMPORARY TABLE Temp ( + Key Uint64 NOT NULL, + Value String, + PRIMARY KEY (Key) + );)"); + + auto resultCreate = session.ExecuteQuery(queryCreate, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultCreate.IsSuccess(), resultCreate.GetIssues().ToString()); + + { + const auto querySelect = Q_(R"( + --!syntax_v1 + SELECT * FROM Temp; + )"); + + auto resultSelect = session.ExecuteQuery( + querySelect, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultSelect.IsSuccess(), resultSelect.GetIssues().ToString()); + } + + const auto queryDrop = Q_(R"( + --!syntax_v1 + DROP TABLE Temp; + )"); + + auto resultDrop = session.ExecuteQuery( + queryDrop, NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_C(resultDrop.IsSuccess(), resultDrop.GetIssues().ToString()); + + { + const auto querySelect = Q_(R"( + --!syntax_v1 + SELECT * FROM Temp; + )"); + + auto resultSelect = session.ExecuteQuery( + querySelect, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT(!resultSelect.IsSuccess()); + } + + bool allDoneOk = true; + NTestHelpers::CheckDelete(clientConfig, id, Ydb::StatusIds::SUCCESS, allDoneOk); + + UNIT_ASSERT(allDoneOk); + + auto sessionAnother = client.GetSession().GetValueSync().GetSession(); + auto idAnother = sessionAnother.GetId(); + UNIT_ASSERT(id != idAnother); + + { + const auto querySelect = Q_(R"( + --!syntax_v1 + SELECT * FROM Temp; + )"); + + auto resultSelect = sessionAnother.ExecuteQuery( + querySelect, NYdb::NQuery::TTxControl::BeginTx().CommitTx()).ExtractValueSync(); + UNIT_ASSERT(!resultSelect.IsSuccess()); + } + } + Y_UNIT_TEST(DdlGroup) { NKikimrConfig::TAppConfig appConfig; appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true); diff --git a/ydb/library/yql/sql/v1/SQLv1.g.in b/ydb/library/yql/sql/v1/SQLv1.g.in index c6a70127a077..8994ceccf526 100644 --- a/ydb/library/yql/sql/v1/SQLv1.g.in +++ b/ydb/library/yql/sql/v1/SQLv1.g.in @@ -623,7 +623,7 @@ object_features: object_feature | LPAREN object_feature (COMMA object_feature)* object_type_ref: an_id_or_type; -create_table_stmt: CREATE (OR REPLACE)? (TABLE | TABLESTORE | EXTERNAL TABLE | TEMP TABLE) (IF NOT EXISTS)? simple_table_ref LPAREN create_table_entry (COMMA create_table_entry)* COMMA? RPAREN +create_table_stmt: CREATE (OR REPLACE)? (TABLE | TABLESTORE | EXTERNAL TABLE | TEMP TABLE | TEMPORARY TABLE) (IF NOT EXISTS)? simple_table_ref LPAREN create_table_entry (COMMA create_table_entry)* COMMA? RPAREN table_inherits? table_partition_by? with_table_settings? diff --git a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp index b8aec0b08b25..4952be3413b0 100644 --- a/ydb/library/yql/sql/v1/format/sql_format_ut.cpp +++ b/ydb/library/yql/sql/v1/format/sql_format_ut.cpp @@ -308,7 +308,8 @@ Y_UNIT_TEST_SUITE(CheckSqlFormatter) { "PARTITION BY HASH (a, b, hash)\n" "WITH (tiering = 'some');\n"}, {"create table if not exists user(user int32)", "CREATE TABLE IF NOT EXISTS user (\n\tuser int32\n);\n"}, - {"create temp table user(user int32)", "CREATE TEMP TABLE user (\n\tuser int32\n);\n"} + {"create temp table user(user int32)", "CREATE TEMP TABLE user (\n\tuser int32\n);\n"}, + {"create temporary table user(user int32)", "CREATE TEMPORARY TABLE user (\n\tuser int32\n);\n"} }; TSetup setup; diff --git a/ydb/library/yql/sql/v1/sql_query.cpp b/ydb/library/yql/sql/v1/sql_query.cpp index c1576fffe546..4b0666cf7a15 100644 --- a/ydb/library/yql/sql/v1/sql_query.cpp +++ b/ydb/library/yql/sql/v1/sql_query.cpp @@ -171,9 +171,9 @@ bool TSqlQuery::Statement(TVector& blocks, const TRule_sql_stmt_core& tableType = ETableType::TableStore; } else if (block.HasAlt3() && block.GetAlt3().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_EXTERNAL) { tableType = ETableType::ExternalTable; - } else if (block.HasAlt4() && block.GetAlt4().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_TEMP) { + } else if (block.HasAlt4() && block.GetAlt4().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_TEMP || + block.HasAlt5() && block.GetAlt5().GetToken1().GetId() == SQLv1LexerTokens::TOKEN_TEMPORARY) { temporary = true; - Y_DEBUG_ABORT_UNLESS(block.GetAlt4().GetToken2().GetId() == SQLv1LexerTokens::TOKEN_TABLE); } bool existingOk = false; diff --git a/ydb/library/yql/sql/v1/sql_ut.cpp b/ydb/library/yql/sql/v1/sql_ut.cpp index c2c9d67f7c4d..d640235bf2ed 100644 --- a/ydb/library/yql/sql/v1/sql_ut.cpp +++ b/ydb/library/yql/sql/v1/sql_ut.cpp @@ -1024,6 +1024,23 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]); } + Y_UNIT_TEST(CreateTemporaryTable) { + NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TEMPORARY TABLE t (a int32, primary key(a));"); + UNIT_ASSERT(res.Root); + + TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) { + if (word == "Write!") { + UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, + line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) (Void) '('('mode 'create) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))) '('primarykey '('"a")) '('temporary))))__"), line); + } + }; + + TWordCountHive elementStat = {{TString("Write!"), 0}}; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]); + } + Y_UNIT_TEST(CreateTableDuplicatedPkColumnsFail) { NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32 not null, primary key(a, a));"); UNIT_ASSERT(!res.Root);