mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Allow partitionwise join to handle nested FULL JOIN USING cases.
This case didn't work because columns merged by FULL JOIN USING are represented in the parse tree by COALESCE expressions, and the logic for recognizing a partitionable join failed to match upper-level join clauses to such expressions. To fix, synthesize suitable COALESCE expressions and add them to the nullable_partexprs lists. This is pretty ugly and brute-force, but it gets the job done. (I have ambitions of rethinking the way outer-join output Vars are represented, so maybe that will provide a cleaner solution someday. For now, do this.) Amit Langote, reviewed by Justin Pryzby, Richard Guo, and myself Discussion: https://postgr.es/m/CA+HiwqG2WVUGmLJqtR0tPFhniO=H=9qQ+Z3L_ZC+Y3-EVQHFGg@mail.gmail.com
This commit is contained in:
@ -17,6 +17,7 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "optimizer/appendinfo.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
@ -1875,7 +1876,8 @@ set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel, RelOptInfo *inner_rel,
|
||||
JoinType jointype)
|
||||
{
|
||||
int partnatts = joinrel->part_scheme->partnatts;
|
||||
PartitionScheme part_scheme = joinrel->part_scheme;
|
||||
int partnatts = part_scheme->partnatts;
|
||||
|
||||
joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
|
||||
joinrel->nullable_partexprs =
|
||||
@ -1884,7 +1886,8 @@ set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
|
||||
/*
|
||||
* The joinrel's partition expressions are the same as those of the input
|
||||
* rels, but we must properly classify them as nullable or not in the
|
||||
* joinrel's output.
|
||||
* joinrel's output. (Also, we add some more partition expressions if
|
||||
* it's a FULL JOIN.)
|
||||
*/
|
||||
for (int cnt = 0; cnt < partnatts; cnt++)
|
||||
{
|
||||
@ -1895,6 +1898,7 @@ set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
|
||||
const List *inner_null_expr = inner_rel->nullable_partexprs[cnt];
|
||||
List *partexpr = NIL;
|
||||
List *nullable_partexpr = NIL;
|
||||
ListCell *lc;
|
||||
|
||||
switch (jointype)
|
||||
{
|
||||
@ -1954,6 +1958,43 @@ set_joinrel_partition_key_exprs(RelOptInfo *joinrel,
|
||||
outer_null_expr);
|
||||
nullable_partexpr = list_concat(nullable_partexpr,
|
||||
inner_null_expr);
|
||||
|
||||
/*
|
||||
* Also add CoalesceExprs corresponding to each possible
|
||||
* full-join output variable (that is, left side coalesced to
|
||||
* right side), so that we can match equijoin expressions
|
||||
* using those variables. We really only need these for
|
||||
* columns merged by JOIN USING, and only with the pairs of
|
||||
* input items that correspond to the data structures that
|
||||
* parse analysis would build for such variables. But it's
|
||||
* hard to tell which those are, so just make all the pairs.
|
||||
* Extra items in the nullable_partexprs list won't cause big
|
||||
* problems. (It's possible that such items will get matched
|
||||
* to user-written COALESCEs, but it should still be valid to
|
||||
* partition on those, since they're going to be either the
|
||||
* partition column or NULL; it's the same argument as for
|
||||
* partitionwise nesting of any outer join.) We assume no
|
||||
* type coercions are needed to make the coalesce expressions,
|
||||
* since columns of different types won't have gotten
|
||||
* classified as the same PartitionScheme.
|
||||
*/
|
||||
foreach(lc, list_concat_copy(outer_expr, outer_null_expr))
|
||||
{
|
||||
Node *larg = (Node *) lfirst(lc);
|
||||
ListCell *lc2;
|
||||
|
||||
foreach(lc2, list_concat_copy(inner_expr, inner_null_expr))
|
||||
{
|
||||
Node *rarg = (Node *) lfirst(lc2);
|
||||
CoalesceExpr *c = makeNode(CoalesceExpr);
|
||||
|
||||
c->coalescetype = exprType(larg);
|
||||
c->coalescecollid = exprCollation(larg);
|
||||
c->args = list_make2(larg, rarg);
|
||||
c->location = -1;
|
||||
nullable_partexpr = lappend(nullable_partexpr, c);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
Reference in New Issue
Block a user