Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 466979e

Browse files
committed
Replace lateral references to removed rels in subqueries
This commit introduces a new field 'sublevels_up' in ReplaceVarnoContext, and enhances replace_varno_walker() to: 1) recurse into subselects with sublevels_up increased, and 2) perform the replacement only when varlevelsup is equal to sublevels_up. This commit also fixes some outdated comments. And besides adding relevant test cases, it makes some unification over existing SJE test cases. Discussion: https://postgr.es/m/CAMbWs4-%3DPO6Mm9gNnySbx0VHyXjgnnYYwbN9dth%3DTLQweZ-M%2Bg%40mail.gmail.com Author: Richard Guo Reviewed-by: Andrei Lepikhov, Alexander Korotkov
1 parent a6b2a51 commit 466979e

File tree

3 files changed

+337
-306
lines changed

3 files changed

+337
-306
lines changed

src/backend/optimizer/plan/analyzejoins.c

+76-71
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,6 @@
3434
#include "optimizer/tlist.h"
3535
#include "utils/lsyscache.h"
3636

37-
/*
38-
* The context for replace_varno_walker() containing source and target relids.
39-
*/
40-
typedef struct
41-
{
42-
int from;
43-
int to;
44-
} ReplaceVarnoContext;
45-
4637
/*
4738
* The struct containing self-join candidate. Used to find duplicate reloids.
4839
*/
@@ -75,13 +66,11 @@ static bool is_innerrel_unique_for(PlannerInfo *root,
7566
JoinType jointype,
7667
List *restrictlist,
7768
List **extra_clauses);
78-
static Bitmapset *replace_relid(Relids relids, int oldId, int newId);
7969
static void replace_varno(Node *node, int from, int to);
80-
static bool replace_varno_walker(Node *node, ReplaceVarnoContext *ctx);
70+
static Bitmapset *replace_relid(Relids relids, int oldId, int newId);
8171
static int self_join_candidates_cmp(const void *a, const void *b);
8272

8373

84-
8574
/*
8675
* remove_useless_joins
8776
* Check for relations that don't actually need to be joined at all,
@@ -367,7 +356,8 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
367356
ListCell *l;
368357

369358
/*
370-
* Remove references to the rel from other baserels' attr_needed arrays.
359+
* Remove references to the rel from other baserels' attr_needed arrays
360+
* and lateral_vars lists.
371361
*/
372362
for (rti = 1; rti < root->simple_rel_array_size; rti++)
373363
{
@@ -394,35 +384,8 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
394384
replace_relid(otherrel->attr_needed[attroff], ojrelid, subst);
395385
}
396386

397-
/* Update lateral references. */
398-
if (root->hasLateralRTEs)
399-
{
400-
RangeTblEntry *rte = root->simple_rte_array[rti];
401-
ReplaceVarnoContext ctx = {.from = relid,.to = subst};
402-
403-
if (rte->lateral)
404-
{
405-
replace_varno((Node *) otherrel->lateral_vars, relid, subst);
406-
407-
/*
408-
* Although we pass root->parse through cleanup procedure, but
409-
* parse->rtable and rte contains refs to different copies of
410-
* the subquery.
411-
*/
412-
if (otherrel->rtekind == RTE_SUBQUERY)
413-
query_tree_walker(rte->subquery, replace_varno_walker, &ctx,
414-
QTW_EXAMINE_SORTGROUP);
415-
#ifdef USE_ASSERT_CHECKING
416-
/* Just check possibly hidden non-replaced relids */
417-
Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->tablesample)));
418-
Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->functions)));
419-
Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->tablefunc)));
420-
Assert(!bms_is_member(relid, pull_varnos(root, (Node *) rte->values_lists)));
421-
#endif
422-
}
423-
}
424-
425-
387+
/* Update lateral_vars list. */
388+
replace_varno((Node *) otherrel->lateral_vars, relid, subst);
426389
}
427390

428391
/*
@@ -1462,35 +1425,32 @@ is_innerrel_unique_for(PlannerInfo *root,
14621425
}
14631426

14641427
/*
1465-
* Replace each occurrence of removing relid with the keeping one
1428+
* replace_varno - find in the given tree any Vars, PlaceHolderVar, and Relids
1429+
* that reference the removing relid, and change them to the reference to
1430+
* the replacement relid.
1431+
*
1432+
* NOTE: although this has the form of a walker, we cheat and modify the
1433+
* nodes in-place.
14661434
*/
1467-
static void
1468-
replace_varno(Node *node, int from, int to)
1469-
{
1470-
ReplaceVarnoContext ctx;
1471-
1472-
if (to <= 0)
1473-
return;
14741435

1475-
ctx.from = from;
1476-
ctx.to = to;
1477-
replace_varno_walker(node, &ctx);
1478-
}
1436+
typedef struct
1437+
{
1438+
int from;
1439+
int to;
1440+
int sublevels_up;
1441+
} ReplaceVarnoContext;
14791442

1480-
/*
1481-
* Walker function for replace_varno()
1482-
*/
14831443
static bool
14841444
replace_varno_walker(Node *node, ReplaceVarnoContext *ctx)
14851445
{
14861446
if (node == NULL)
14871447
return false;
1488-
14891448
if (IsA(node, Var))
14901449
{
14911450
Var *var = (Var *) node;
14921451

1493-
if (var->varno == ctx->from)
1452+
if (var->varno == ctx->from &&
1453+
var->varlevelsup == ctx->sublevels_up)
14941454
{
14951455
var->varno = ctx->to;
14961456
var->varnosyn = ctx->to;
@@ -1501,11 +1461,29 @@ replace_varno_walker(Node *node, ReplaceVarnoContext *ctx)
15011461
{
15021462
PlaceHolderVar *phv = (PlaceHolderVar *) node;
15031463

1504-
phv->phrels = replace_relid(phv->phrels, ctx->from, ctx->to);
1505-
phv->phnullingrels = replace_relid(phv->phnullingrels, ctx->from, ctx->to);
1464+
if (phv->phlevelsup == ctx->sublevels_up)
1465+
{
1466+
phv->phrels =
1467+
replace_relid(phv->phrels, ctx->from, ctx->to);
1468+
phv->phnullingrels =
1469+
replace_relid(phv->phnullingrels, ctx->from, ctx->to);
1470+
}
15061471

15071472
/* fall through to recurse into the placeholder's expression */
15081473
}
1474+
else if (IsA(node, Query))
1475+
{
1476+
/* Recurse into subselects */
1477+
bool result;
1478+
1479+
ctx->sublevels_up++;
1480+
result = query_tree_walker((Query *) node,
1481+
replace_varno_walker,
1482+
(void *) ctx,
1483+
QTW_EXAMINE_SORTGROUP);
1484+
ctx->sublevels_up--;
1485+
return result;
1486+
}
15091487
else if (IsA(node, RestrictInfo))
15101488
{
15111489
RestrictInfo *rinfo = (RestrictInfo *) node;
@@ -1517,18 +1495,24 @@ replace_varno_walker(Node *node, ReplaceVarnoContext *ctx)
15171495
{
15181496
replace_varno((Node *) rinfo->clause, ctx->from, ctx->to);
15191497
replace_varno((Node *) rinfo->orclause, ctx->from, ctx->to);
1520-
rinfo->clause_relids = replace_relid(rinfo->clause_relids, ctx->from, ctx->to);
1521-
rinfo->left_relids = replace_relid(rinfo->left_relids, ctx->from, ctx->to);
1522-
rinfo->right_relids = replace_relid(rinfo->right_relids, ctx->from, ctx->to);
1498+
rinfo->clause_relids =
1499+
replace_relid(rinfo->clause_relids, ctx->from, ctx->to);
1500+
rinfo->left_relids =
1501+
replace_relid(rinfo->left_relids, ctx->from, ctx->to);
1502+
rinfo->right_relids =
1503+
replace_relid(rinfo->right_relids, ctx->from, ctx->to);
15231504
}
15241505

15251506
if (is_req_equal)
15261507
rinfo->required_relids = rinfo->clause_relids;
15271508
else
1528-
rinfo->required_relids = replace_relid(rinfo->required_relids, ctx->from, ctx->to);
1509+
rinfo->required_relids =
1510+
replace_relid(rinfo->required_relids, ctx->from, ctx->to);
15291511

1530-
rinfo->outer_relids = replace_relid(rinfo->outer_relids, ctx->from, ctx->to);
1531-
rinfo->incompatible_relids = replace_relid(rinfo->incompatible_relids, ctx->from, ctx->to);
1512+
rinfo->outer_relids =
1513+
replace_relid(rinfo->outer_relids, ctx->from, ctx->to);
1514+
rinfo->incompatible_relids =
1515+
replace_relid(rinfo->incompatible_relids, ctx->from, ctx->to);
15321516

15331517
if (rinfo->mergeopfamilies &&
15341518
bms_get_singleton_member(rinfo->clause_relids, &relid) &&
@@ -1556,7 +1540,30 @@ replace_varno_walker(Node *node, ReplaceVarnoContext *ctx)
15561540

15571541
return false;
15581542
}
1559-
return expression_tree_walker(node, replace_varno_walker, (void *) ctx);
1543+
1544+
return expression_tree_walker(node, replace_varno_walker,
1545+
(void *) ctx);
1546+
}
1547+
1548+
static void
1549+
replace_varno(Node *node, int from, int to)
1550+
{
1551+
ReplaceVarnoContext ctx;
1552+
1553+
if (to <= 0)
1554+
return;
1555+
1556+
ctx.from = from;
1557+
ctx.to = to;
1558+
ctx.sublevels_up = 0;
1559+
1560+
/*
1561+
* Must be prepared to start with a Query or a bare expression tree.
1562+
*/
1563+
query_or_expression_tree_walker(node,
1564+
replace_varno_walker,
1565+
(void *) &ctx,
1566+
QTW_EXAMINE_SORTGROUP);
15601567
}
15611568

15621569
/*
@@ -1748,7 +1755,6 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
17481755
int i;
17491756
List *jinfo_candidates = NIL;
17501757
List *binfo_candidates = NIL;
1751-
ReplaceVarnoContext ctx = {.from = toRemove->relid,.to = toKeep->relid};
17521758

17531759
Assert(toKeep->relid != -1);
17541760

@@ -1925,8 +1931,7 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
19251931
}
19261932

19271933
/* Replace varno in all the query structures */
1928-
query_tree_walker(root->parse, replace_varno_walker, &ctx,
1929-
QTW_EXAMINE_SORTGROUP);
1934+
replace_varno((Node *) root->parse, toRemove->relid, toKeep->relid);
19301935

19311936
/* See remove_self_joins_one_group() */
19321937
Assert(root->parse->resultRelation != toRemove->relid);

0 commit comments

Comments
 (0)