summaryrefslogtreecommitdiffstats
path: root/yql/essentials
diff options
context:
space:
mode:
authordeminds <[email protected]>2025-06-04 12:36:47 +0300
committerdeminds <[email protected]>2025-06-04 12:51:33 +0300
commit14c42c6f9a85a081cde9ba58db0b008b3ade11f7 (patch)
tree7d76d30ab6610e938b0399956cd45fcc5105854b /yql/essentials
parent62b27c7d93a63b7c2ab41fe6882cbcbdfc5218a6 (diff)
support database settings in ALTER DATABASE
The main goal is to enable setting SchemeLimits (ShardsLimit and PathsLimit) via YQL. Issue: - https://github.com/ydb-platform/ydb/issues/16742 commit_hash:e873849e3b4bb494e349ccebbb1ff6d51655c5d1
Diffstat (limited to 'yql/essentials')
-rw-r--r--yql/essentials/sql/v1/SQLv1.g.in14
-rw-r--r--yql/essentials/sql/v1/SQLv1Antlr4.g.in14
-rw-r--r--yql/essentials/sql/v1/format/sql_format_ut.h2
-rw-r--r--yql/essentials/sql/v1/node.h1
-rw-r--r--yql/essentials/sql/v1/object_processing.cpp2
-rw-r--r--yql/essentials/sql/v1/query.cpp24
-rw-r--r--yql/essentials/sql/v1/sql_query.cpp45
-rw-r--r--yql/essentials/sql/v1/sql_translation.cpp82
-rw-r--r--yql/essentials/sql/v1/sql_translation.h2
-rw-r--r--yql/essentials/sql/v1/sql_ut_common.h39
10 files changed, 208 insertions, 17 deletions
diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in
index ed04c337507..96013b9a7fa 100644
--- a/yql/essentials/sql/v1/SQLv1.g.in
+++ b/yql/essentials/sql/v1/SQLv1.g.in
@@ -693,7 +693,19 @@ table_tablestore: TABLESTORE simple_table_ref_core;
table_settings_entry: an_id EQUALS table_setting_value;
table_as_source: AS values_source;
-alter_database_stmt: ALTER DATABASE an_id_schema OWNER TO role_name;
+alter_database_stmt: ALTER DATABASE an_id_schema alter_database_action;
+alter_database_action:
+ OWNER TO role_name
+ | set_database_settings
+;
+set_database_settings: SET LPAREN database_settings RPAREN;
+database_settings: database_setting (COMMA database_setting)*;
+database_setting: an_id EQUALS database_setting_value;
+database_setting_value:
+ bool_value
+ | integer
+ | STRING_VALUE
+;
alter_table_stmt: ALTER TABLE simple_table_ref alter_table_action (COMMA alter_table_action)*;
alter_table_action:
diff --git a/yql/essentials/sql/v1/SQLv1Antlr4.g.in b/yql/essentials/sql/v1/SQLv1Antlr4.g.in
index 6bfdf3820f7..5ac9de84998 100644
--- a/yql/essentials/sql/v1/SQLv1Antlr4.g.in
+++ b/yql/essentials/sql/v1/SQLv1Antlr4.g.in
@@ -685,7 +685,19 @@ backup_collection_settings_entry: an_id EQUALS table_setting_value;
backup_stmt: BACKUP object_ref (INCREMENTAL)?;
restore_stmt: RESTORE object_ref (AT STRING_VALUE)?;
-alter_database_stmt: ALTER DATABASE an_id_schema OWNER TO role_name;
+alter_database_stmt: ALTER DATABASE an_id_schema alter_database_action;
+alter_database_action:
+ OWNER TO role_name
+ | set_database_settings
+;
+set_database_settings: SET LPAREN database_settings RPAREN;
+database_settings: database_setting (COMMA database_setting)*;
+database_setting: an_id EQUALS database_setting_value;
+database_setting_value:
+ bool_value
+ | integer
+ | STRING_VALUE
+;
table_inherits: INHERITS LPAREN simple_table_ref_core (COMMA simple_table_ref_core)* RPAREN;
table_partition_by: PARTITION BY HASH pure_column_list;
diff --git a/yql/essentials/sql/v1/format/sql_format_ut.h b/yql/essentials/sql/v1/format/sql_format_ut.h
index da60492b238..b61cc593936 100644
--- a/yql/essentials/sql/v1/format/sql_format_ut.h
+++ b/yql/essentials/sql/v1/format/sql_format_ut.h
@@ -23,6 +23,8 @@ Y_UNIT_TEST(DotAfterDigits) {
Y_UNIT_TEST(AlterDatabase) {
TCases cases {
{"use plato;alter database `/Root/test` owner to user1;", "USE plato;\n\nALTER DATABASE `/Root/test` OWNER TO user1;\n"},
+ {"use plato;alter database `/Root/test` set (key1 = 1);", "USE plato;\n\nALTER DATABASE `/Root/test` SET (key1 = 1);\n"},
+ {"use plato;alter database `/Root/test` set (\n\tkey1 = 1,\n\tkey2 = \"2\"\n);", "USE plato;\n\nALTER DATABASE `/Root/test` SET (key1 = 1, key2 = '2');\n"}
};
TSetup setup;
diff --git a/yql/essentials/sql/v1/node.h b/yql/essentials/sql/v1/node.h
index c0e9e838ca7..bb4448df2aa 100644
--- a/yql/essentials/sql/v1/node.h
+++ b/yql/essentials/sql/v1/node.h
@@ -1281,6 +1281,7 @@ namespace NSQLTranslationV1 {
struct TAlterDatabaseParameters {
TDeferredAtom DbPath;
std::optional<TDeferredAtom> Owner;
+ THashMap<TString, TNodePtr> DatabaseSettings;
};
struct TTableRef;
diff --git a/yql/essentials/sql/v1/object_processing.cpp b/yql/essentials/sql/v1/object_processing.cpp
index 69d6ae342a4..fed6b422195 100644
--- a/yql/essentials/sql/v1/object_processing.cpp
+++ b/yql/essentials/sql/v1/object_processing.cpp
@@ -59,7 +59,7 @@ INode::TPtr TCreateObject::FillFeatures(INode::TPtr options) const {
namespace {
-bool InitFeatures(TContext& ctx, ISource* src, std::map<TString, TDeferredAtom>& features) {
+bool InitFeatures(TContext& ctx, ISource* src, const std::map<TString, TDeferredAtom>& features) {
for (auto& [key, value] : features) {
if (value.HasNode() && !value.Build()->Init(ctx, src)) {
return false;
diff --git a/yql/essentials/sql/v1/query.cpp b/yql/essentials/sql/v1/query.cpp
index 40caf8b34de..631aa097b58 100644
--- a/yql/essentials/sql/v1/query.cpp
+++ b/yql/essentials/sql/v1/query.cpp
@@ -1317,6 +1317,19 @@ TNodePtr BuildCreateTable(TPosition pos, const TTableRef& tr, bool existingOk, b
return new TCreateTableNode(pos, tr, existingOk, replaceIfExists, params, std::move(values), scoped);
}
+namespace {
+
+bool InitDatabaseSettings(TContext& ctx, ISource* src, const THashMap<TString, TNodePtr>& settings) {
+ for (const auto& [setting, value] : settings) {
+ if (!value || !value->Init(ctx, src)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
+
class TAlterDatabaseNode final : public TAstListNode {
public:
TAlterDatabaseNode(
@@ -1343,6 +1356,10 @@ public:
if (Params.Owner.has_value()) {
options = L(options, Q(Y(Q("owner"), Params.Owner.value().Build())));
}
+ if (!InitDatabaseSettings(ctx, src, Params.DatabaseSettings)) {
+ return false;
+ }
+ AddDatabaseSettings(options, Params.DatabaseSettings);
Add("block", Q(Y(
Y("let", "sink", Y("DataSink", BuildQuotedAtom(Pos, Service), cluster)),
@@ -1362,6 +1379,13 @@ private:
TScopedStatePtr Scoped;
TDeferredAtom Cluster;
TString Service;
+
+ void AddDatabaseSettings(TNodePtr& options, const THashMap<TString, TNodePtr>& settings) {
+ for (const auto& [setting, value] : settings) {
+ options = L(options, Q(Y(BuildQuotedAtom(Pos, setting), value)));
+ }
+ }
+
};
TNodePtr BuildAlterDatabase(
diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp
index 8ba4226d684..d852fee277f 100644
--- a/yql/essentials/sql/v1/sql_query.cpp
+++ b/yql/essentials/sql/v1/sql_query.cpp
@@ -1937,26 +1937,45 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core&
break;
}
case TRule_sql_stmt_core::kAltSqlStmtCore61: {
- // alter_database_stmt: ALTER DATABASE an_id_schema OWNER TO role_name
- auto& node = core.GetAlt_sql_stmt_core61().GetRule_alter_database_stmt1();
-
- TDeferredAtom roleName;
- {
- bool allowSystemRoles = true;
- if (!RoleNameClause(node.GetRule_role_name6(), roleName, allowSystemRoles)) {
- return false;
+ // alter_database_stmt: ALTER DATABASE an_id_schema alter_database_action
+ const auto& node = core.GetAlt_sql_stmt_core61().GetRule_alter_database_stmt1();
+ const auto& action = node.GetRule_alter_database_action4();
+
+ TAlterDatabaseParameters params;
+ params.DbPath = TDeferredAtom(Ctx.Pos(), Id(node.GetRule_an_id_schema3(), *this));
+
+ switch (action.GetAltCase()) {
+ case TRule_alter_database_action::kAltAlterDatabaseAction1: {
+ // OWNER TO role_name
+ const auto& ownerAction = action.GetAlt_alter_database_action1();
+ TDeferredAtom roleName;
+ {
+ bool allowSystemRoles = true;
+ if (!RoleNameClause(ownerAction.GetRule_role_name3(), roleName, allowSystemRoles)) {
+ return false;
+ }
+ }
+ params.Owner = roleName;
+ break;
}
+ case TRule_alter_database_action::kAltAlterDatabaseAction2: {
+ // SET ( database_settings )
+ const auto& settings = action.GetAlt_alter_database_action2().GetRule_set_database_settings1().GetRule_database_settings3();
+ if (!ParseDatabaseSettings(settings, params.DatabaseSettings)) {
+ return false;
+ }
+ break;
+ }
+ case TRule_alter_database_action::ALT_NOT_SET:
+ AltNotImplemented("alter_database_action", action);
+ return false;
}
- TAlterDatabaseParameters alterDatabaseParams;
- alterDatabaseParams.Owner = roleName;
- alterDatabaseParams.DbPath = TDeferredAtom(Ctx.Pos(), Id(node.GetRule_an_id_schema3(), *this));
-
const TPosition pos = Ctx.Pos();
TString service = Ctx.Scoped->CurrService;
TDeferredAtom cluster = Ctx.Scoped->CurrCluster;
- auto stmt = BuildAlterDatabase(pos, service, cluster, alterDatabaseParams, Ctx.Scoped);
+ auto stmt = BuildAlterDatabase(pos, service, cluster, params, Ctx.Scoped);
AddStatementToBlocks(blocks, stmt);
break;
}
diff --git a/yql/essentials/sql/v1/sql_translation.cpp b/yql/essentials/sql/v1/sql_translation.cpp
index 264601ed460..e96096ccbda 100644
--- a/yql/essentials/sql/v1/sql_translation.cpp
+++ b/yql/essentials/sql/v1/sql_translation.cpp
@@ -745,6 +745,88 @@ bool TSqlTranslation::CreateTableIndex(const TRule_table_index& node, TVector<TI
return true;
}
+bool TSqlTranslation::ParseDatabaseSettings(const TRule_database_settings& in, THashMap<TString, TNodePtr>& out) {
+ if (!ParseDatabaseSetting(in.GetRule_database_setting1(), out)) {
+ return false;
+ }
+ for (const auto& setting : in.GetBlock2()) {
+ if (!ParseDatabaseSetting(setting.GetRule_database_setting2(), out)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+namespace {
+
+TMaybe<bool> ParseBool(TContext& ctx, const TRule_bool_value& node) {
+ bool value = false;
+ const TString& token = ctx.Token(node.GetToken1());
+ if (!TryFromString<bool>(token, value)) {
+ ctx.Error() << "Cannot parse bool from " << token;
+ return Nothing();
+ }
+ return value;
+}
+
+TMaybe<ui64> ParseInteger(TContext& ctx, const TRule_integer& node) {
+ ui64 value = 0;
+ const TString& token = ctx.Token(node.GetToken1());
+ TString suffix;
+ if (!ParseNumbers(ctx, token, value, suffix)) {
+ ctx.Error() << "Cannot parse integer from " << token;
+ return Nothing();
+ }
+ return value;
+}
+
+TNodePtr ParseDatabaseSettingValue(TContext& ctx, const TRule_database_setting_value& node) {
+ switch (node.GetAltCase()) {
+ case TRule_database_setting_value::kAltDatabaseSettingValue1:
+ // bool
+ if (auto result = ParseBool(ctx, node.GetAlt_database_setting_value1().GetRule_bool_value1())) {
+ return BuildLiteralBool(ctx.Pos(), *result);
+ }
+ return nullptr;
+
+ case TRule_database_setting_value::kAltDatabaseSettingValue2:
+ // integer
+ if (auto result = ParseInteger(ctx, node.GetAlt_database_setting_value2().GetRule_integer1())) {
+ return MakeIntrusive<TLiteralNumberNode<ui64>>(ctx.Pos(), "Uint64", ToString(*result));
+ }
+ return nullptr;
+
+ case TRule_database_setting_value::kAltDatabaseSettingValue3: {
+ // string
+ const auto& token = node.GetAlt_database_setting_value3().GetToken1();
+ if (auto result = BuildLiteralSmartString(ctx, ctx.Token(token))) {
+ return result;
+ }
+ return nullptr;
+ }
+ case TRule_database_setting_value::ALT_NOT_SET:
+ YQL_ENSURE(false, "You should change implementation according to grammar changes.");
+ }
+}
+
+}
+
+bool TSqlTranslation::ParseDatabaseSetting(const TRule_database_setting& in, THashMap<TString, TNodePtr>& out) {
+ const auto setting = to_upper(Id(in.GetRule_an_id1(), *this));
+
+ if (out.contains(setting)) {
+ Ctx.Error() << "Duplicate setting: " << setting;
+ return false;
+ }
+
+ auto node = ParseDatabaseSettingValue(Ctx, in.GetRule_database_setting_value3());
+ if (!node) {
+ return false;
+ }
+ out[setting] = node;
+ return true;
+}
+
bool TSqlTranslation::CreateIndexSettings(const TRule_with_index_settings& settingsNode,
TIndexDescription::EType indexType,
TIndexDescription::TIndexSettings& indexSettings) {
diff --git a/yql/essentials/sql/v1/sql_translation.h b/yql/essentials/sql/v1/sql_translation.h
index a052f1979b0..99192e4e102 100644
--- a/yql/essentials/sql/v1/sql_translation.h
+++ b/yql/essentials/sql/v1/sql_translation.h
@@ -267,6 +267,8 @@ protected:
TVector<TDeferredAtom>& removeTables,
const TRule_alter_backup_collection_entries& entries);
bool ParseTransferLambda(TString& lambdaText, const TRule_lambda_or_parameter& lambdaOrParameter);
+ bool ParseDatabaseSettings(const TRule_database_settings& in, THashMap<TString, TNodePtr>& out);
+ bool ParseDatabaseSetting(const TRule_database_setting& in, THashMap<TString, TNodePtr>& out);
bool ValidateAuthMethod(const std::map<TString, TDeferredAtom>& result);
bool ValidateExternalTable(const TCreateTableParameters& params);
diff --git a/yql/essentials/sql/v1/sql_ut_common.h b/yql/essentials/sql/v1/sql_ut_common.h
index d4f9285a9e3..8b33aa8be0d 100644
--- a/yql/essentials/sql/v1/sql_ut_common.h
+++ b/yql/essentials/sql/v1/sql_ut_common.h
@@ -1192,7 +1192,7 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
Y_UNIT_TEST(AlterDatabaseAst) {
NYql::TAstParseResult request = SqlToYql("USE plato; ALTER DATABASE `/Root/test` OWNER TO user1;");
- UNIT_ASSERT(request.IsOk());
+ UNIT_ASSERT_C(request.IsOk(), request.Issues.ToString());
TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
Y_UNUSED(word);
@@ -1207,6 +1207,43 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) {
UNIT_ASSERT_VALUES_EQUAL(1, elementStat["\'mode \'alterDatabase"]);
}
+ Y_UNIT_TEST(AlterDatabaseSetting) {
+ NYql::TAstParseResult res = SqlToYql("USE plato; ALTER DATABASE `/Root/test` SET (key1 = 1);");
+ UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString());
+
+ TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
+ if (word == "Write!") {
+ UNIT_ASSERT_STRING_CONTAINS(line, "(Key '('databasePath (String '\"/Root/test\")))");
+ UNIT_ASSERT_STRING_CONTAINS(line, "'('('mode 'alterDatabase) '('\"KEY1\" (Uint64 '\"1\")))");
+ }
+ };
+
+ TWordCountHive elementStat = { {"Write!"} };
+ VerifyProgram(res, elementStat, verifyLine);
+
+ UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
+ }
+
+ Y_UNIT_TEST(AlterDatabaseSettings) {
+ NYql::TAstParseResult res = SqlToYql("USE plato; ALTER DATABASE `/Root/test` SET (key1 = 1, key2 = \"2\", key3 = true);");
+ UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString());
+
+ TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
+ if (word == "Write!") {
+ UNIT_ASSERT_STRING_CONTAINS(line, "(Key '('databasePath (String '\"/Root/test\")))");
+ UNIT_ASSERT_STRING_CONTAINS(line, "'('mode 'alterDatabase)");
+ UNIT_ASSERT_STRING_CONTAINS(line, "'('\"KEY1\" (Uint64 '\"1\"))");
+ UNIT_ASSERT_STRING_CONTAINS(line, "'('\"KEY2\" (String '\"2\"))");
+ UNIT_ASSERT_STRING_CONTAINS(line, "'('\"KEY3\" (Bool '\"true\"))");
+ }
+ };
+
+ TWordCountHive elementStat = { {"Write!"} };
+ VerifyProgram(res, elementStat, verifyLine);
+
+ UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
+ }
+
Y_UNIT_TEST(CreateTableNonNullableYqlTypeAstCorrect) {
NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32 not null);");
UNIT_ASSERT(res.Root);