diff options
author | vitya-smirnov <[email protected]> | 2025-07-13 10:57:03 +0300 |
---|---|---|
committer | vitya-smirnov <[email protected]> | 2025-07-13 11:13:18 +0300 |
commit | 50fb38c344d3976f79badaef61cb8040ecdc404f (patch) | |
tree | d802f56c25b770c8c42ca181aadc678957f08183 /yql/essentials/sql | |
parent | d28a870061b49d7c985cd453eb01954173e4ffd0 (diff) |
YQL-17269: Fix UNION/EXCEPT/INTERSECT precedence
There was a mistake, because actually EXCEPT
has the same precedence as UNION. INTERSECT has
higher precedence than.
commit_hash:20375ef498861c6704571161fa3c4eebf54e895c
Diffstat (limited to 'yql/essentials/sql')
-rw-r--r-- | yql/essentials/sql/v1/SQLv1.g.in | 4 | ||||
-rw-r--r-- | yql/essentials/sql/v1/SQLv1Antlr4.g.in | 4 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_select.cpp | 25 | ||||
-rw-r--r-- | yql/essentials/sql/v1/sql_select.h | 4 |
4 files changed, 22 insertions, 15 deletions
diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in index d9fd70f8ab4..c70730210a5 100644 --- a/yql/essentials/sql/v1/SQLv1.g.in +++ b/yql/essentials/sql/v1/SQLv1.g.in @@ -375,9 +375,9 @@ select_unparenthesized_stmt_intersect: select_kind_partial (intersect_op select_ select_kind_parenthesis: select_kind_partial | LPAREN select_kind_partial RPAREN; -union_op: UNION (DISTINCT | ALL)?; +union_op: (UNION | EXCEPT) (DISTINCT | ALL)?; -intersect_op: (INTERSECT | EXCEPT) (DISTINCT | ALL)?; +intersect_op: INTERSECT (DISTINCT | ALL)?; select_kind_partial: select_kind (LIMIT expr ((OFFSET | COMMA) expr)?)? diff --git a/yql/essentials/sql/v1/SQLv1Antlr4.g.in b/yql/essentials/sql/v1/SQLv1Antlr4.g.in index 95db5bbc5f6..5ef063d226e 100644 --- a/yql/essentials/sql/v1/SQLv1Antlr4.g.in +++ b/yql/essentials/sql/v1/SQLv1Antlr4.g.in @@ -374,9 +374,9 @@ select_unparenthesized_stmt_intersect: select_kind_partial (intersect_op select_ select_kind_parenthesis: select_kind_partial | LPAREN select_kind_partial RPAREN; -union_op: UNION (DISTINCT | ALL)?; +union_op: (UNION | EXCEPT) (DISTINCT | ALL)?; -intersect_op: (INTERSECT | EXCEPT) (DISTINCT | ALL)?; +intersect_op: INTERSECT (DISTINCT | ALL)?; select_kind_partial: select_kind (LIMIT expr ((OFFSET | COMMA) expr)?)? diff --git a/yql/essentials/sql/v1/sql_select.cpp b/yql/essentials/sql/v1/sql_select.cpp index fd5aa8d96c2..b2ae4916924 100644 --- a/yql/essentials/sql/v1/sql_select.cpp +++ b/yql/essentials/sql/v1/sql_select.cpp @@ -1374,7 +1374,7 @@ template <typename TRule> std::same_as<TRule, TRule_select_unparenthesized_stmt> TSourcePtr TSqlSelect::BuildStmt(const TRule& node, TPosition& pos) { TBuildExtra extra; - auto result = BuildUnion(node, pos, extra); + auto result = BuildUnionException(node, pos, extra); pos = extra.FirstPos; if (!result) { return nullptr; @@ -1423,7 +1423,7 @@ TSourcePtr TSqlSelect::BuildStmt(const TRule& node, TPosition& pos) { template <typename TRule> requires std::same_as<TRule, TRule_select_stmt> || std::same_as<TRule, TRule_select_unparenthesized_stmt> -TSourcePtr TSqlSelect::BuildUnion(const TRule& node, TPosition& pos, TSqlSelect::TBuildExtra& extra) { +TSourcePtr TSqlSelect::BuildUnionException(const TRule& node, TPosition& pos, TSqlSelect::TBuildExtra& extra) { const TSelectKindPlacement firstPlacement = { .IsFirstInSelectOp = true, .IsLastInSelectOp = node.GetBlock2().empty(), @@ -1431,9 +1431,9 @@ TSourcePtr TSqlSelect::BuildUnion(const TRule& node, TPosition& pos, TSqlSelect: TSourcePtr first; if constexpr (std::is_same_v<TRule, TRule_select_stmt>) { - first = BuildExceptionIntersection(node.GetRule_select_stmt_intersect1(), pos, firstPlacement, extra); + first = BuildIntersection(node.GetRule_select_stmt_intersect1(), pos, firstPlacement, extra); } else if constexpr (std::is_same_v<TRule, TRule_select_unparenthesized_stmt>) { - first = BuildExceptionIntersection(node.GetRule_select_unparenthesized_stmt_intersect1(), pos, firstPlacement, extra); + first = BuildIntersection(node.GetRule_select_unparenthesized_stmt_intersect1(), pos, firstPlacement, extra); } else { static_assert(false, "Change implementation according to grammar changes."); } @@ -1443,25 +1443,31 @@ TSourcePtr TSqlSelect::BuildUnion(const TRule& node, TPosition& pos, TSqlSelect: } TVector<TSourcePtr> sources = {std::move(first)}; + TString lastOp = ""; bool isLastAllQualified = false; const auto& tail = node.GetBlock2(); for (int i = 0; i < tail.size(); ++i) { const auto& nextBlock = tail[i]; + TString nextOp = ToLowerUTF8(Token(nextBlock.GetRule_union_op1().GetToken1())); bool isNextAllQualified = IsAllQualifiedOp(nextBlock.GetRule_union_op1()); TSelectKindPlacement nextPlacement = { .IsFirstInSelectOp = false, .IsLastInSelectOp = (i + 1 == tail.size()), }; - TSourcePtr next = BuildExceptionIntersection(nextBlock.GetRule_select_stmt_intersect2(), pos, nextPlacement, extra); + TSourcePtr next = BuildIntersection(nextBlock.GetRule_select_stmt_intersect2(), pos, nextPlacement, extra); if (!next) { return nullptr; } - if (i != 0 && isLastAllQualified != isNextAllQualified) { - auto source = BuildSelectOp(pos, std::move(sources), "union", isLastAllQualified, /* settings = */ {}); + bool areArgsInflattable = ((isLastAllQualified != isNextAllQualified) || + (lastOp != nextOp) || + (nextOp != "union")); + + if ((i != 0) && areArgsInflattable) { + auto source = BuildSelectOp(pos, std::move(sources), lastOp, isLastAllQualified, /* settings = */ {}); Y_ENSURE(source); sources.clear(); @@ -1469,6 +1475,7 @@ TSourcePtr TSqlSelect::BuildUnion(const TRule& node, TPosition& pos, TSqlSelect: } sources.emplace_back(std::move(next)); + lastOp = std::move(nextOp); isLastAllQualified = isNextAllQualified; } @@ -1483,13 +1490,13 @@ TSourcePtr TSqlSelect::BuildUnion(const TRule& node, TPosition& pos, TSqlSelect: outermostSettings.Label = extra.Last.Settings.Label; } - return BuildSelectOp(pos, std::move(sources), "union", isLastAllQualified, outermostSettings); + return BuildSelectOp(pos, std::move(sources), lastOp, isLastAllQualified, outermostSettings); } template <typename TRule> requires std::same_as<TRule, TRule_select_stmt_intersect> || std::same_as<TRule, TRule_select_unparenthesized_stmt_intersect> -TSourcePtr TSqlSelect::BuildExceptionIntersection( +TSourcePtr TSqlSelect::BuildIntersection( const TRule& node, TPosition& pos, TSelectKindPlacement placement, diff --git a/yql/essentials/sql/v1/sql_select.h b/yql/essentials/sql/v1/sql_select.h index 3224a3ca3b3..f4097396745 100644 --- a/yql/essentials/sql/v1/sql_select.h +++ b/yql/essentials/sql/v1/sql_select.h @@ -81,12 +81,12 @@ private: template <typename TRule> requires std::same_as<TRule, TRule_select_stmt> || std::same_as<TRule, TRule_select_unparenthesized_stmt> - TSourcePtr BuildUnion(const TRule& node, TPosition& pos, TBuildExtra& extra); + TSourcePtr BuildUnionException(const TRule& node, TPosition& pos, TBuildExtra& extra); template <typename TRule> requires std::same_as<TRule, TRule_select_stmt_intersect> || std::same_as<TRule, TRule_select_unparenthesized_stmt_intersect> - TSourcePtr BuildExceptionIntersection(const TRule& node, TPosition& pos, TSelectKindPlacement placement, TBuildExtra& extra); + TSourcePtr BuildIntersection(const TRule& node, TPosition& pos, TSelectKindPlacement placement, TBuildExtra& extra); template <typename TRule> requires std::same_as<TRule, TRule_select_kind_parenthesis> || |