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

Lines changed: 76 additions & 71 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy