Skip to content

MDEV-39522 Query with UNION fails in Oracle sql_mode with ER_BAD_FIELD_ERROR/ER_UNKNOWN_TABLE - #5461

Merged
forkfun merged 1 commit into
10.11from
10.11-MDEV-39522
Jul 27, 2026
Merged

MDEV-39522 Query with UNION fails in Oracle sql_mode with ER_BAD_FIELD_ERROR/ER_UNKNOWN_TABLE#5461
forkfun merged 1 commit into
10.11from
10.11-MDEV-39522

Conversation

@forkfun

@forkfun forkfun commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

MDEV-37325 unconditionally wrapped union subqueries in derived tables,
breaking name resolution of outer-scope/correlated references inside
the unions (producing ER_UNKNOWN_TABLE errors).

Delay the wrap until a following operator has a different linkage.
In Oracle mode all set operators share one priority and bind
left-to-right, so wrapping the accumulated prefix on each operator
change enforces it. This also corrects the row multiplicity of mixed
set operations toward left-to-right order.

create_priority_nest(): when the nest covers the whole prefix, point
the wrapper's first_nested at itself. Cut the prefix with
cut_next() before wrapping and re-register it on the outer unit;

Aleksey Midenkov:

In Oracle mode optimize_bag_operation() returns early, so union_distinct is
never recomputed and the stale value reaches execution.
Register the wrapper first, then run fix_distinct(): reset_distinct() now
scans the new outer chain (the wrapper alone) and correctly leaves
union_distinct NULL; a following DISTINCT operand re-establishes it.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

…D_ERROR/ER_UNKNOWN_TABLE

MDEV-37325 unconditionally wrapped union subqueries in derived tables,
breaking name resolution of outer-scope/correlated references inside
the unions (producing ER_UNKNOWN_TABLE errors).

Delay the wrap until a following operator has a different linkage.
In Oracle mode all set operators share one priority and bind
left-to-right, so wrapping the accumulated prefix on each operator
change enforces it. This also corrects the row multiplicity of mixed
set operations toward left-to-right order.

create_priority_nest(): when the nest covers the whole prefix, point
the wrapper's first_nested at itself. Cut the prefix with
cut_next() before wrapping and re-register it on the outer unit;

Aleksey Midenkov:

In Oracle mode optimize_bag_operation() returns early, so union_distinct is
never recomputed and the stale value reaches execution.
Register the wrapper first, then run fix_distinct(): reset_distinct() now
scans the new outer chain (the wrapper alone) and correctly leaves
union_distinct NULL; a following DISTINCT operand re-establishes it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes set-operator parsing/rewriting in Oracle sql_mode to avoid incorrect derived-table wrapping that breaks correlated name resolution in UNION subqueries (e.g., ER_UNKNOWN_TABLE) and to ensure union_distinct is recomputed correctly after wrapping so execution doesn’t incorrectly de-duplicate results.

Changes:

  • Adjusts LEX::parsed_select_expr_*() logic to delay/condition wrapping in Oracle mode and to re-register the wrapped prefix before recalculating DISTINCT state.
  • Tweaks LEX::create_priority_nest() handling of first_nested when wrapping a whole prefix.
  • Updates/extends Oracle-mode MTR coverage and refreshes multiple expected-result files to match the new query plan/rendering behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
sql/sql_lex.cc Updates Oracle-mode set-operator wrapping and DISTINCT tracking to preserve correlated name resolution and correct execution semantics.
mysql-test/suite/compat/oracle/r/table_value_constr.result Refreshes expected EXPLAIN/SHOW output for TVC + set-operator cases after wrapping changes.
mysql-test/suite/compat/oracle/r/empty_string_literal.result Updates expected SHOW CREATE VIEW output (no longer wrapped into derived tables).
mysql-test/main/set_operation_oracle.test Adds a regression test for MDEV-39522 plus Oracle-vs-non-Oracle precedence checks and a recursive CTE case.
mysql-test/main/set_operation_oracle.result Updates expected output for set-operator Oracle-mode behavior (including new test output).
mysql-test/main/intersect_all.result Refreshes expected EXPLAIN/SHOW output for Oracle-mode intersect/union combinations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +106 to +109
set sql_mode='oracle';
create table t1 (id varchar(10));
select 1 from t1 where exists (select 1 from dual union select 1 from dual where t1.id=1);
drop table t1;
@forkfun
forkfun merged commit 9d8ed0c into 10.11 Jul 27, 2026
17 of 18 checks passed
@grooverdan
grooverdan deleted the 10.11-MDEV-39522 branch July 28, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants