diff options
author | kniv <kniv@yandex-team.ru> | 2022-02-16 17:06:26 +0300 |
---|---|---|
committer | kniv <kniv@yandex-team.ru> | 2022-02-16 17:06:26 +0300 |
commit | 2a29aa7f66e39a293579f425cb40800ef5c93c9e (patch) | |
tree | afb16d2cb54bec76df271ec9a07dc41c8cc5801a | |
parent | a4d7f7581d62e2c8eb3a463e5c080d43b6c2248f (diff) | |
download | ydb-2a29aa7f66e39a293579f425cb40800ef5c93c9e.tar.gz |
YQL-10211: into_table_stmt: Pass arbitrary write hints into AST
YQL-10211: into_table_stmt: Pass arbitrary write hints into AST
Example:
USE plato;
INSERT INTO Output WITH (TRUNCATE, COMPRESSION_ALGO="zstd", COMPRESSION_LVL="8", TRUNCATE)
SELECT
key as key,
"" as subkey,
"value:" || value as value
FROM Input WITH (TRUNCATE, LOG)
WHERE key < "100"
ORDER BY key;
ref:ccceedbf2611c4ca5a9fce3afb205082cdc1499f
-rw-r--r-- | ydb/library/yql/sql/v1/SQLv1.g.in | 2 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/node.h | 1 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/query.cpp | 55 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/sql.cpp | 28 |
4 files changed, 72 insertions, 14 deletions
diff --git a/ydb/library/yql/sql/v1/SQLv1.g.in b/ydb/library/yql/sql/v1/SQLv1.g.in index 5975aa0d79..63b69ac2c2 100644 --- a/ydb/library/yql/sql/v1/SQLv1.g.in +++ b/ydb/library/yql/sql/v1/SQLv1.g.in @@ -575,7 +575,7 @@ table_key: id_table_or_type (VIEW an_id)?; table_arg: AT? named_expr (VIEW an_id)?; table_hints: WITH (table_hint | LPAREN table_hint (COMMA table_hint)* RPAREN); table_hint: - an_id_hint + an_id_hint (EQUALS type_name_tag)? | (SCHEMA | COLUMNS) type_name_or_bind | SCHEMA LPAREN (struct_arg_as (COMMA struct_arg_as)*)? COMMA? RPAREN ; diff --git a/ydb/library/yql/sql/v1/node.h b/ydb/library/yql/sql/v1/node.h index de82b45a23..b228ca9212 100644 --- a/ydb/library/yql/sql/v1/node.h +++ b/ydb/library/yql/sql/v1/node.h @@ -1312,6 +1312,7 @@ namespace NSQLTranslationV1 { EWriteColumnMode ToWriteColumnsMode(ESQLWriteColumnMode sqlWriteColumnMode); TNodePtr BuildEraseColumns(TPosition pos, const TVector<TString>& columns); + TNodePtr BuildIntoTableOptions(TPosition pos, const TVector<TString>& eraseColumns, const TTableHints& hints); TNodePtr BuildWriteColumns(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, EWriteColumnMode mode, TSourcePtr values, TNodePtr options = nullptr); TNodePtr BuildUpdateColumns(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr values, TSourcePtr source); TNodePtr BuildDelete(TPosition pos, TScopedStatePtr scoped, const TTableRef& table, TSourcePtr source); diff --git a/ydb/library/yql/sql/v1/query.cpp b/ydb/library/yql/sql/v1/query.cpp index 725356b9f5..964f15f9dd 100644 --- a/ydb/library/yql/sql/v1/query.cpp +++ b/ydb/library/yql/sql/v1/query.cpp @@ -505,6 +505,61 @@ TNodePtr BuildInputOptions(TPosition pos, const TTableHints& hints) { return new TInputOptions(pos, hints); } +class TIntoTableOptions: public TAstListNode { +public: + TIntoTableOptions(TPosition pos, const TVector<TString>& columns, const TTableHints& hints) + : TAstListNode(pos) + , Columns(columns) + , Hints(hints) + { + } + + bool DoInit(TContext& ctx, ISource* src) override { + Y_UNUSED(ctx); + Y_UNUSED(src); + + TNodePtr options = Y(); + for (const auto& column: Columns) { + options->Add(Q(column)); + } + if (Columns) { + Add(Q(Y(Q("erase_columns"), Q(options)))); + } + + for (const auto& hint : Hints) { + TString hintName = hint.first; + TMaybe<TIssue> normalizeError = NormalizeName(Pos, hintName); + if (!normalizeError.Empty()) { + ctx.Error() << normalizeError->Message; + ctx.IncrementMonCounter("sql_errors", "NormalizeHintError"); + return false; + } + TNodePtr option = Y(BuildQuotedAtom(Pos, hintName)); + for (auto& x : hint.second) { + if (!x->Init(ctx, src)) { + return false; + } + option = L(option, x); + } + Add(Q(option)); + } + + return true; + } + + TNodePtr DoClone() const final { + return new TIntoTableOptions(GetPos(), Columns, Hints); + } + +private: + TVector<TString> Columns; + TTableHints Hints; +}; + +TNodePtr BuildIntoTableOptions(TPosition pos, const TVector<TString>& eraseColumns, const TTableHints& hints) { + return new TIntoTableOptions(pos, eraseColumns, hints); +} + class TInputTablesNode final: public TAstListNode { public: TInputTablesNode(TPosition pos, const TTableList& tables, bool inSubquery, TScopedStatePtr scoped) diff --git a/ydb/library/yql/sql/v1/sql.cpp b/ydb/library/yql/sql/v1/sql.cpp index 2b0c817870..00358cf342 100644 --- a/ydb/library/yql/sql/v1/sql.cpp +++ b/ydb/library/yql/sql/v1/sql.cpp @@ -2945,18 +2945,23 @@ TNodePtr TSqlTranslation::StructLiteral(const TRule_struct_literal& node) { bool TSqlTranslation::TableHintImpl(const TRule_table_hint& rule, TTableHints& hints) { // table_hint: - // an_id_hint + // an_id_hint (EQUALS type_name_tag)? // | (SCHEMA | COLUMNS) type_name_or_bind // | SCHEMA LPAREN (struct_arg_as (COMMA struct_arg_as)*)? COMMA? RPAREN switch (rule.Alt_case()) { case TRule_table_hint::kAltTableHint1: { - const TString id = Id(rule.GetAlt_table_hint1().GetRule_an_id_hint1(), *this); + const auto& alt = rule.GetAlt_table_hint1(); + const TString id = Id(alt.GetRule_an_id_hint1(), *this); const auto idLower = to_lower(id); if (idLower == "schema" || idLower == "columns") { Error() << "Expected type after " << to_upper(id); return false; } - hints[id] = {}; + TVector<TNodePtr> hint_val; + if (alt.HasBlock2()) { + hint_val.push_back(TypeNameTag(alt.GetBlock2().GetRule_type_name_tag2())); + } + hints[id] = hint_val; break; } @@ -8023,21 +8028,20 @@ TNodePtr TSqlIntoTable::Build(const TRule_into_table_stmt& node) { } bool withTruncate = false; + TTableHints tableHints; if (tableRef.HasBlock2()) { auto hints = TableHintsImpl(tableRef.GetBlock2().GetRule_table_hints1()); if (!hints) { Ctx.Error() << "Failed to parse table hints"; return nullptr; } - for (const auto& hint : *hints) { if (to_upper(hint.first) == "TRUNCATE") { withTruncate = true; - } else { - Ctx.Error() << "Unsupported hint: " << hint.first; - return nullptr; } } + std::erase_if(*hints, [](const auto &hint) { return to_upper(hint.first) == "TRUNCATE"; }); + tableHints = std::move(*hints); } TVector<TString> eraseColumns; @@ -8068,6 +8072,7 @@ TNodePtr TSqlIntoTable::Build(const TRule_into_table_stmt& node) { TNodePtr tableKey = BuildTableKey(pos, service, cluster, nameOrAt.second, nameOrAt.first ? "@" : ""); TTableRef table(Ctx.MakeName("table"), service, cluster, tableKey); + Ctx.IncrementMonCounter("sql_insert_clusters", table.Cluster.GetLiteral() ? *table.Cluster.GetLiteral() : "unknown"); auto values = TSqlIntoValues(Ctx, Mode).Build(node.GetRule_into_values_source4(), SqlIntoUserModeStr); @@ -8079,12 +8084,9 @@ TNodePtr TSqlIntoTable::Build(const TRule_into_table_stmt& node) { } Ctx.IncrementMonCounter("sql_features", SqlIntoModeStr); - TNodePtr options; - if (eraseColumns) { - options = BuildEraseColumns(pos, std::move(eraseColumns)); - } - - return BuildWriteColumns(pos, Ctx.Scoped, table, ToWriteColumnsMode(SqlIntoMode), std::move(values), std::move(options)); + return BuildWriteColumns(pos, Ctx.Scoped, table, + ToWriteColumnsMode(SqlIntoMode), std::move(values), + BuildIntoTableOptions(pos, eraseColumns, tableHints)); } bool TSqlIntoTable::ValidateServiceName(const TRule_into_table_stmt& node, const TTableRef& table, |