PostgreSQL Source Code  git master
tidpath.c File Reference
Include dependency graph for tidpath.c:

Go to the source code of this file.

Functions

static bool IsCTIDVar (Var *var, RelOptInfo *rel)
 
static bool IsTidEqualClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static bool IsTidEqualAnyClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static bool IsCurrentOfClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static ListTidQualFromRestrictInfo (RestrictInfo *rinfo, RelOptInfo *rel)
 
static ListTidQualFromRestrictInfoList (List *rlist, RelOptInfo *rel)
 
static void BuildParameterizedTidPaths (PlannerInfo *root, RelOptInfo *rel, List *clauses)
 
static bool ec_member_matches_ctid (PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
 
void create_tidscan_paths (PlannerInfo *root, RelOptInfo *rel)
 

Function Documentation

◆ BuildParameterizedTidPaths()

static void BuildParameterizedTidPaths ( PlannerInfo root,
RelOptInfo rel,
List clauses 
)
static

Definition at line 313 of file tidpath.c.

References add_path(), bms_del_member(), bms_union(), create_tidscan_path(), IsTidEqualClause(), join_clause_is_movable_to(), RelOptInfo::lateral_relids, lfirst_node, list_make1, RestrictInfo::pseudoconstant, RelOptInfo::relid, RestrictInfo::required_relids, and restriction_is_securely_promotable().

Referenced by create_tidscan_paths().

314 {
315  ListCell *l;
316 
317  foreach(l, clauses)
318  {
320  List *tidquals;
321  Relids required_outer;
322 
323  /*
324  * Validate whether each clause is actually usable; we must check this
325  * even when examining clauses generated from an EquivalenceClass,
326  * since they might not satisfy the restriction on not having Vars of
327  * our rel on the other side, or somebody might've built an operator
328  * class that accepts type "tid" but has other operators in it.
329  *
330  * We currently consider only TidEqual join clauses. In principle we
331  * might find a suitable ScalarArrayOpExpr in the rel's joininfo list,
332  * but it seems unlikely to be worth expending the cycles to check.
333  * And we definitely won't find a CurrentOfExpr here. Hence, we don't
334  * use TidQualFromRestrictInfo; but this must match that function
335  * otherwise.
336  */
337  if (rinfo->pseudoconstant ||
338  !restriction_is_securely_promotable(rinfo, rel) ||
339  !IsTidEqualClause(rinfo, rel))
340  continue;
341 
342  /*
343  * Check if clause can be moved to this rel; this is probably
344  * redundant when considering EC-derived clauses, but we must check it
345  * for "loose" join clauses.
346  */
347  if (!join_clause_is_movable_to(rinfo, rel))
348  continue;
349 
350  /* OK, make list of clauses for this path */
351  tidquals = list_make1(rinfo);
352 
353  /* Compute required outer rels for this path */
354  required_outer = bms_union(rinfo->required_relids, rel->lateral_relids);
355  required_outer = bms_del_member(required_outer, rel->relid);
356 
357  add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
358  required_outer));
359  }
360 }
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:423
Relids required_relids
Definition: pathnodes.h:1961
bool pseudoconstant
Definition: pathnodes.h:1951
#define list_make1(x1)
Definition: pg_list.h:227
Relids lateral_relids
Definition: pathnodes.h:666
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Index relid
Definition: pathnodes.h:669
static bool IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:73
bool restriction_is_securely_promotable(RestrictInfo *restrictinfo, RelOptInfo *rel)
Definition: restrictinfo.c:376
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
bool join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
Definition: restrictinfo.c:504
TidPath * create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
Definition: pathnode.c:1152
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:773
Definition: pg_list.h:50

◆ create_tidscan_paths()

void create_tidscan_paths ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 385 of file tidpath.c.

References add_path(), RelOptInfo::baserestrictinfo, BuildParameterizedTidPaths(), create_tidscan_path(), ec_member_matches_ctid(), generate_implied_equalities_for_column(), RelOptInfo::has_eclass_joins, RelOptInfo::joininfo, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, and TidQualFromRestrictInfoList().

Referenced by set_plain_rel_pathlist().

386 {
387  List *tidquals;
388 
389  /*
390  * If any suitable quals exist in the rel's baserestrict list, generate a
391  * plain (unparameterized) TidPath with them.
392  */
393  tidquals = TidQualFromRestrictInfoList(rel->baserestrictinfo, rel);
394 
395  if (tidquals)
396  {
397  /*
398  * This path uses no join clauses, but it could still have required
399  * parameterization due to LATERAL refs in its tlist.
400  */
401  Relids required_outer = rel->lateral_relids;
402 
403  add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
404  required_outer));
405  }
406 
407  /*
408  * Try to generate parameterized TidPaths using equality clauses extracted
409  * from EquivalenceClasses. (This is important since simple "t1.ctid =
410  * t2.ctid" clauses will turn into ECs.)
411  */
412  if (rel->has_eclass_joins)
413  {
414  List *clauses;
415 
416  /* Generate clauses, skipping any that join to lateral_referencers */
418  rel,
420  NULL,
421  rel->lateral_referencers);
422 
423  /* Generate a path for each usable join clause */
424  BuildParameterizedTidPaths(root, rel, clauses);
425  }
426 
427  /*
428  * Also consider parameterized TidPaths using "loose" join quals. Quals
429  * of the form "t1.ctid = t2.ctid" would turn into these if they are outer
430  * join quals, for example.
431  */
432  BuildParameterizedTidPaths(root, rel, rel->joininfo);
433 }
bool has_eclass_joins
Definition: pathnodes.h:709
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:423
List * baserestrictinfo
Definition: pathnodes.h:703
static bool ec_member_matches_ctid(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
Definition: tidpath.c:368
Relids lateral_relids
Definition: pathnodes.h:666
static void BuildParameterizedTidPaths(PlannerInfo *root, RelOptInfo *rel, List *clauses)
Definition: tidpath.c:313
List * joininfo
Definition: pathnodes.h:707
Relids lateral_referencers
Definition: pathnodes.h:677
static List * TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
Definition: tidpath.c:230
TidPath * create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
Definition: pathnode.c:1152
Definition: pg_list.h:50
List * generate_implied_equalities_for_column(PlannerInfo *root, RelOptInfo *rel, ec_matches_callback_type callback, void *callback_arg, Relids prohibited_rels)
Definition: equivclass.c:2362

◆ ec_member_matches_ctid()

static bool ec_member_matches_ctid ( PlannerInfo root,
RelOptInfo rel,
EquivalenceClass ec,
EquivalenceMember em,
void *  arg 
)
static

Definition at line 368 of file tidpath.c.

References EquivalenceMember::em_expr, IsA, and IsCTIDVar().

Referenced by create_tidscan_paths().

371 {
372  if (em->em_expr && IsA(em->em_expr, Var) &&
373  IsCTIDVar((Var *) em->em_expr, rel))
374  return true;
375  return false;
376 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: primnodes.h:167
static bool IsCTIDVar(Var *var, RelOptInfo *rel)
Definition: tidpath.c:53

◆ IsCTIDVar()

static bool IsCTIDVar ( Var var,
RelOptInfo rel 
)
inlinestatic

Definition at line 53 of file tidpath.c.

References RelOptInfo::relid, SelfItemPointerAttributeNumber, Var::varattno, Var::varlevelsup, Var::varno, and Var::vartype.

Referenced by ec_member_matches_ctid(), IsTidEqualAnyClause(), and IsTidEqualClause().

54 {
55  /* The vartype check is strictly paranoia */
57  var->vartype == TIDOID &&
58  var->varno == rel->relid &&
59  var->varlevelsup == 0)
60  return true;
61  return false;
62 }
Index varlevelsup
Definition: primnodes.h:177
AttrNumber varattno
Definition: primnodes.h:172
Oid vartype
Definition: primnodes.h:174
Index relid
Definition: pathnodes.h:669
Index varno
Definition: primnodes.h:170
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21

◆ IsCurrentOfClause()

static bool IsCurrentOfClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 165 of file tidpath.c.

References RestrictInfo::clause, CurrentOfExpr::cvarno, IsA, and RelOptInfo::relid.

Referenced by TidQualFromRestrictInfo().

166 {
167  CurrentOfExpr *node;
168 
169  /* Must be a CurrentOfExpr */
170  if (!(rinfo->clause && IsA(rinfo->clause, CurrentOfExpr)))
171  return false;
172  node = (CurrentOfExpr *) rinfo->clause;
173 
174  /* If it references this rel, we're good */
175  if (node->cvarno == rel->relid)
176  return true;
177 
178  return false;
179 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Index relid
Definition: pathnodes.h:669
Expr * clause
Definition: pathnodes.h:1943

◆ IsTidEqualAnyClause()

static bool IsTidEqualAnyClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 126 of file tidpath.c.

References ScalarArrayOpExpr::args, Assert, bms_is_member(), RestrictInfo::clause, contain_volatile_functions(), IsA, IsCTIDVar(), linitial, list_length(), lsecond, ScalarArrayOpExpr::opno, pull_varnos(), RelOptInfo::relid, and ScalarArrayOpExpr::useOr.

Referenced by TidQualFromRestrictInfo().

127 {
128  ScalarArrayOpExpr *node;
129  Node *arg1,
130  *arg2;
131 
132  /* Must be a ScalarArrayOpExpr */
133  if (!(rinfo->clause && IsA(rinfo->clause, ScalarArrayOpExpr)))
134  return false;
135  node = (ScalarArrayOpExpr *) rinfo->clause;
136 
137  /* Operator must be tideq */
138  if (node->opno != TIDEqualOperator)
139  return false;
140  if (!node->useOr)
141  return false;
142  Assert(list_length(node->args) == 2);
143  arg1 = linitial(node->args);
144  arg2 = lsecond(node->args);
145 
146  /* CTID must be first argument */
147  if (arg1 && IsA(arg1, Var) &&
148  IsCTIDVar((Var *) arg1, rel))
149  {
150  /* The other argument must be a pseudoconstant */
151  if (bms_is_member(rel->relid, pull_varnos(arg2)) ||
153  return false;
154 
155  return true; /* success */
156  }
157 
158  return false;
159 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: nodes.h:525
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:724
Definition: primnodes.h:167
#define lsecond(l)
Definition: pg_list.h:200
#define linitial(l)
Definition: pg_list.h:195
Relids pull_varnos(Node *node)
Definition: var.c:95
Index relid
Definition: pathnodes.h:669
Expr * clause
Definition: pathnodes.h:1943
static bool IsCTIDVar(Var *var, RelOptInfo *rel)
Definition: tidpath.c:53
#define Assert(condition)
Definition: c.h:732
static int list_length(const List *l)
Definition: pg_list.h:169
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ IsTidEqualClause()

static bool IsTidEqualClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 73 of file tidpath.c.

References OpExpr::args, Assert, bms_is_member(), RestrictInfo::clause, contain_volatile_functions(), is_opclause(), IsA, IsCTIDVar(), RestrictInfo::left_relids, linitial, list_length(), lsecond, OpExpr::opno, RelOptInfo::relid, and RestrictInfo::right_relids.

Referenced by BuildParameterizedTidPaths(), and TidQualFromRestrictInfo().

74 {
75  OpExpr *node;
76  Node *arg1,
77  *arg2,
78  *other;
79  Relids other_relids;
80 
81  /* Must be an OpExpr */
82  if (!is_opclause(rinfo->clause))
83  return false;
84  node = (OpExpr *) rinfo->clause;
85 
86  /* Operator must be tideq */
87  if (node->opno != TIDEqualOperator)
88  return false;
89  Assert(list_length(node->args) == 2);
90  arg1 = linitial(node->args);
91  arg2 = lsecond(node->args);
92 
93  /* Look for CTID as either argument */
94  other = NULL;
95  other_relids = NULL;
96  if (arg1 && IsA(arg1, Var) &&
97  IsCTIDVar((Var *) arg1, rel))
98  {
99  other = arg2;
100  other_relids = rinfo->right_relids;
101  }
102  if (!other && arg2 && IsA(arg2, Var) &&
103  IsCTIDVar((Var *) arg2, rel))
104  {
105  other = arg1;
106  other_relids = rinfo->left_relids;
107  }
108  if (!other)
109  return false;
110 
111  /* The other argument must be a pseudoconstant */
112  if (bms_is_member(rel->relid, other_relids) ||
114  return false;
115 
116  return true; /* success */
117 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Definition: nodes.h:525
Relids left_relids
Definition: pathnodes.h:1970
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:724
Definition: primnodes.h:167
#define lsecond(l)
Definition: pg_list.h:200
#define linitial(l)
Definition: pg_list.h:195
Index relid
Definition: pathnodes.h:669
Expr * clause
Definition: pathnodes.h:1943
static bool IsCTIDVar(Var *var, RelOptInfo *rel)
Definition: tidpath.c:53
Relids right_relids
Definition: pathnodes.h:1971
#define Assert(condition)
Definition: c.h:732
static int list_length(const List *l)
Definition: pg_list.h:169
Oid opno
Definition: primnodes.h:502
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:63
List * args
Definition: primnodes.h:508
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ TidQualFromRestrictInfo()

static List* TidQualFromRestrictInfo ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 193 of file tidpath.c.

References IsCurrentOfClause(), IsTidEqualAnyClause(), IsTidEqualClause(), list_make1, NIL, RestrictInfo::pseudoconstant, and restriction_is_securely_promotable().

Referenced by TidQualFromRestrictInfoList().

194 {
195  /*
196  * We may ignore pseudoconstant clauses (they can't contain Vars, so could
197  * not match anyway).
198  */
199  if (rinfo->pseudoconstant)
200  return NIL;
201 
202  /*
203  * If clause must wait till after some lower-security-level restriction
204  * clause, reject it.
205  */
206  if (!restriction_is_securely_promotable(rinfo, rel))
207  return NIL;
208 
209  /*
210  * Check all base cases. If we get a match, return the clause.
211  */
212  if (IsTidEqualClause(rinfo, rel) ||
213  IsTidEqualAnyClause(rinfo, rel) ||
214  IsCurrentOfClause(rinfo, rel))
215  return list_make1(rinfo);
216 
217  return NIL;
218 }
#define NIL
Definition: pg_list.h:65
static bool IsTidEqualAnyClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:126
bool pseudoconstant
Definition: pathnodes.h:1951
static bool IsCurrentOfClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:165
#define list_make1(x1)
Definition: pg_list.h:227
static bool IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:73
bool restriction_is_securely_promotable(RestrictInfo *restrictinfo, RelOptInfo *rel)
Definition: restrictinfo.c:376

◆ TidQualFromRestrictInfoList()

static List* TidQualFromRestrictInfoList ( List rlist,
RelOptInfo rel 
)
static

Definition at line 230 of file tidpath.c.

References Assert, castNode, is_andclause(), lfirst, lfirst_node, list_concat(), NIL, RestrictInfo::orclause, restriction_is_or_clause(), and TidQualFromRestrictInfo().

Referenced by create_tidscan_paths().

231 {
232  List *rlst = NIL;
233  ListCell *l;
234 
235  foreach(l, rlist)
236  {
238 
239  if (restriction_is_or_clause(rinfo))
240  {
241  ListCell *j;
242 
243  /*
244  * We must be able to extract a CTID condition from every
245  * sub-clause of an OR, or we can't use it.
246  */
247  foreach(j, ((BoolExpr *) rinfo->orclause)->args)
248  {
249  Node *orarg = (Node *) lfirst(j);
250  List *sublist;
251 
252  /* OR arguments should be ANDs or sub-RestrictInfos */
253  if (is_andclause(orarg))
254  {
255  List *andargs = ((BoolExpr *) orarg)->args;
256 
257  /* Recurse in case there are sub-ORs */
258  sublist = TidQualFromRestrictInfoList(andargs, rel);
259  }
260  else
261  {
262  RestrictInfo *rinfo = castNode(RestrictInfo, orarg);
263 
265  sublist = TidQualFromRestrictInfo(rinfo, rel);
266  }
267 
268  /*
269  * If nothing found in this arm, we can't do anything with
270  * this OR clause.
271  */
272  if (sublist == NIL)
273  {
274  rlst = NIL; /* forget anything we had */
275  break; /* out of loop over OR args */
276  }
277 
278  /*
279  * OK, continue constructing implicitly-OR'ed result list.
280  */
281  rlst = list_concat(rlst, sublist);
282  }
283  }
284  else
285  {
286  /* Not an OR clause, so handle base cases */
287  rlst = TidQualFromRestrictInfo(rinfo, rel);
288  }
289 
290  /*
291  * Stop as soon as we find any usable CTID condition. In theory we
292  * could get CTID equality conditions from different AND'ed clauses,
293  * in which case we could try to pick the most efficient one. In
294  * practice, such usage seems very unlikely, so we don't bother; we
295  * just exit as soon as we find the first candidate.
296  */
297  if (rlst)
298  break;
299  }
300 
301  return rlst;
302 }
#define NIL
Definition: pg_list.h:65
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Expr * orclause
Definition: pathnodes.h:1974
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:94
Definition: nodes.h:525
List * list_concat(List *list1, const List *list2)
Definition: list.c:516
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:361
#define lfirst_node(type, lc)
Definition: pg_list.h:193
static List * TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:193
static List * TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
Definition: tidpath.c:230
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
Definition: pg_list.h:50