Skip to content

ORCA: accept coerced join alias vars in USING joins - #2148

Open
yjhjstz wants to merge 2 commits into
apache:mainfrom
yjhjstz:fix/orca-using-join-relabeltype
Open

yjhjstz wants to merge 2 commits into
apache:mainfrom
yjhjstz:fix/orca-using-join-relabeltype

Conversation

@yjhjstz

@yjhjstz yjhjstz commented Oct 16, 2026

Copy link
Copy Markdown
Member

The merged column of a USING join is the left input coerced to the common type when the two input types differ. For binary-compatible types such as varchar vs text or int vs oid the parser emits a RelabelType, which CTranslatorQueryToDXL::TranslateJoinExprInFromToDXL rejected with an assertion that only allowed Var, FuncExpr and CoalesceExpr. On assert-enabled builds every such query fell back to the Postgres planner:

CTranslatorQueryToDXL.cpp:4145: Failed assertion:
IsA(join_alias_node, Var) || IsA(join_alias_node, FuncExpr) ||
IsA(join_alias_node, CoalesceExpr)

References to join alias columns are flattened by
CQueryMutators::NormalizeQuery before the join itself is translated, which is why the FuncExpr case already worked without any special handling. The projection element only has to be an expression the scalar translator understands, so drop the enumeration. Nodes the scalar translator does not support still raise the regular unsupported-feature exception and fall back cleanly.

Add a regression case to join_gp covering varchar/text and int/oid USING columns, including the nested left join shape from the aggregates test.

Fixes #ISSUE_Number

What does this PR do?

Type of Change

  • Bug fix (non-breaking change)
  • New feature (non-breaking change)
  • Breaking change (fix or feature with breaking changes)
  • Documentation update

Breaking Changes

Test Plan

  • Unit tests added/updated
  • Integration tests added/updated
  • Passed make installcheck
  • Passed make -C src/test installcheck-cbdb-parallel

Impact

Performance:

User-facing changes:

Dependencies:

Checklist

Additional Context

CI Skip Instructions


@yjhjstz yjhjstz added the type: Bug Something isn't working label Oct 16, 2026
@Alena0704
Alena0704 self-requested a review October 21, 2026 09:40
{
continue;
}
GPOS_ASSERT(IsA(join_alias_node, Var) ||

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi! Thank you for working on it!
Removing the assertion does not fully fix coerced USING columns. NormalizeQuery does not flatten join aliases in WHERE or JOIN ... ON conditions: flatten_join_alias_var_optimizer intentionally skips quals.
For RelabelType, the translator allocates a new colid and records it in the mapping, but only CoalesceExpr is added to the computed projection. A condition can therefore reference a column that is never computed, causing GPORCA to fall back with: DXL-to-Expr Translation: Attribute number 21 not found in project list

Bug reproduction:

SET optimizer = on;
SET optimizer_trace_fallback = on;

CREATE TABLE using_coerce_t1(k varchar(10), f2 int)
DISTRIBUTED BY (f2);
CREATE TABLE using_coerce_t2(k text, f2 oid)
DISTRIBUTED BY (f2);

INSERT INTO using_coerce_t1 VALUES ('a', 1), ('b', 2);
INSERT INTO using_coerce_t2 VALUES ('a', 1), ('c', 3);

EXPLAIN (COSTS OFF)
SELECT k
FROM using_coerce_t1
LEFT JOIN using_coerce_t2 USING (k)
WHERE k = 'a';

output:

pr2148=# SET optimizer = on;
SET
pr2148=# SET optimizer_trace_fallback = on;
SET
pr2148=# EXPLAIN (COSTS OFF)
pr2148# SELECT k
pr2148# FROM using_coerce_t1
pr2148# LEFT JOIN using_coerce_t2 USING (k)
pr2148# WHERE k = 'a';
INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
DETAIL:  DXL-to-Expr Translation: Attribute number 21 not found in project list
                          QUERY PLAN                           
---------------------------------------------------------------
 Gather Motion 3:1  (slice1; segments: 3)
   ->  Nested Loop Left Join
         ->  Seq Scan on using_coerce_t1
               Filter: ((k)::text = 'a'::text)
         ->  Materialize
               ->  Broadcast Motion 3:3  (slice2; segments: 3)
                     ->  Seq Scan on using_coerce_t2
                           Filter: (k = 'a'::text)
 Optimizer: Postgres query optimizer
(9 rows)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks, you are right — and it is worse than the RelabelType case: the same hole already exists on main for FuncExpr.

TranslateExprToDXLProject reuses the input colid only for a plain Var; every other expression gets a fresh colid from m_colid_counter. LoadProjectElements then records that colid for <query level, rtindex, attno>, but only the CoalesceExpr branch pushed the proj element into project_list_computed_cols_dxlnode. So for any coerced merged column the mapping points at a column nothing produces, and as you say flatten_join_alias_var_optimizer deliberately skips quals, so a predicate on the merged column reaches it.

Pre-existing repro on main, no RelabelType involved (int vs bigint ⇒ FuncExpr):

CREATE TABLE uf1(k int, v int) DISTRIBUTED BY (v);
CREATE TABLE uf2(k bigint, v int) DISTRIBUTED BY (v);
EXPLAIN (COSTS OFF) SELECT k FROM uf1 LEFT JOIN uf2 USING (k) WHERE k = 1;
INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
DETAIL:  DXL-to-Expr Translation: Attribute number 21 not found in project list

Fixed in 59f8233 by making the computed-columns projection cover every non-Var join alias instead of enumerating node tags:

		if (!IsA(join_alias_node, Var))
		{
			project_elem_dxlnode->AddRef();
			project_list_computed_cols_dxlnode->AddChild(project_elem_dxlnode);
		}

Both of your queries and the int/bigint shape now plan in GPORCA:

 Gather Motion 3:1  (slice1; segments: 3)
   ->  Hash Left Join
         Hash Cond: ((using_coerce_t1.k)::text = using_coerce_t2.k)
         ->  Seq Scan on using_coerce_t1
               Filter: ((k)::text = 'a'::text)
         ->  Hash
               ->  Broadcast Motion 3:3  (slice2; segments: 3)
                     ->  Seq Scan on using_coerce_t2
 Optimizer: GPORCA

join_gp is extended with predicates on the merged column for the varchar/text, int/oid and int/bigint shapes, and passes with optimizer=on and optimizer=off.

The merged column of a USING join is the left input coerced to the
common type when the two input types differ. For binary-compatible
types such as varchar vs text or int vs oid the parser emits a
RelabelType, which CTranslatorQueryToDXL::TranslateJoinExprInFromToDXL
rejected with an assertion that only allowed Var, FuncExpr and
CoalesceExpr. On assert-enabled builds every such query fell back to
the Postgres planner:

  CTranslatorQueryToDXL.cpp:4145: Failed assertion:
  IsA(join_alias_node, Var) || IsA(join_alias_node, FuncExpr) ||
  IsA(join_alias_node, CoalesceExpr)

References to join alias columns are flattened by
CQueryMutators::NormalizeQuery before the join itself is translated,
which is why the FuncExpr case already worked without any special
handling. The projection element only has to be an expression the
scalar translator understands, so drop the enumeration. Nodes the
scalar translator does not support still raise the regular
unsupported-feature exception and fall back cleanly.

Add a regression case to join_gp covering varchar/text and int/oid
USING columns, including the nested left join shape from the
aggregates test.
TranslateJoinExprInFromToDXL only added the CoalesceExpr flavour of a
merged USING column to the computed-columns project list, but
TranslateExprToDXLProject allocates a fresh colid for every join alias
var that is not a plain Var.  The <query level, varno, varattno>
mapping loaded right below therefore pointed at a column no operator
produced for the coercion flavours (FuncExpr, RelabelType, ...).

Target list references were unaffected because
flatten_join_alias_var_optimizer rewrites them to the base relation
columns, but it deliberately leaves quals alone, so a predicate on the
merged column still goes through the mapping and ORCA bailed out with

  DXL-to-Expr Translation: Attribute number 21 not found in project
  list

This is a pre-existing bug for the FuncExpr case (int vs bigint USING
columns) and would newly be reachable for RelabelType.  Add the project
element for any non-Var join alias instead of enumerating node tags.

Extend the join_gp cases with predicates on the merged column for both
the RelabelType (varchar/text, int/oid) and the FuncExpr (int/bigint)
shapes.

Reported-by: Alena Rybakina
@yjhjstz
yjhjstz force-pushed the fix/orca-using-join-relabeltype branch from 59f8233 to c52e695 Compare October 22, 2026 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants