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 IsBinaryTidClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static bool IsTidEqualClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static bool IsTidRangeClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static bool IsTidEqualAnyClause (PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
 
static bool IsCurrentOfClause (RestrictInfo *rinfo, RelOptInfo *rel)
 
static ListTidQualFromRestrictInfo (PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
 
static ListTidQualFromRestrictInfoList (PlannerInfo *root, List *rlist, RelOptInfo *rel)
 
static ListTidRangeQualFromRestrictInfoList (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 388 of file tidpath.c.

389 {
390  ListCell *l;
391 
392  foreach(l, clauses)
393  {
395  List *tidquals;
396  Relids required_outer;
397 
398  /*
399  * Validate whether each clause is actually usable; we must check this
400  * even when examining clauses generated from an EquivalenceClass,
401  * since they might not satisfy the restriction on not having Vars of
402  * our rel on the other side, or somebody might've built an operator
403  * class that accepts type "tid" but has other operators in it.
404  *
405  * We currently consider only TidEqual join clauses. In principle we
406  * might find a suitable ScalarArrayOpExpr in the rel's joininfo list,
407  * but it seems unlikely to be worth expending the cycles to check.
408  * And we definitely won't find a CurrentOfExpr here. Hence, we don't
409  * use TidQualFromRestrictInfo; but this must match that function
410  * otherwise.
411  */
412  if (rinfo->pseudoconstant ||
413  !restriction_is_securely_promotable(rinfo, rel) ||
414  !IsTidEqualClause(rinfo, rel))
415  continue;
416 
417  /*
418  * Check if clause can be moved to this rel; this is probably
419  * redundant when considering EC-derived clauses, but we must check it
420  * for "loose" join clauses.
421  */
422  if (!join_clause_is_movable_to(rinfo, rel))
423  continue;
424 
425  /* OK, make list of clauses for this path */
426  tidquals = list_make1(rinfo);
427 
428  /* Compute required outer rels for this path */
429  required_outer = bms_union(rinfo->required_relids, rel->lateral_relids);
430  required_outer = bms_del_member(required_outer, rel->relid);
431 
432  add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
433  required_outer));
434  }
435 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:211
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:793
TidPath * create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
Definition: pathnode.c:1181
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define list_make1(x1)
Definition: pg_list.h:212
bool restriction_is_securely_promotable(RestrictInfo *restrictinfo, RelOptInfo *rel)
Definition: restrictinfo.c:431
bool join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
Definition: restrictinfo.c:584
Definition: pg_list.h:54
Index relid
Definition: pathnodes.h:903
Relids lateral_relids
Definition: pathnodes.h:898
Relids required_relids
Definition: pathnodes.h:2560
static bool IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:131

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

Referenced by create_tidscan_paths().

◆ create_tidscan_paths()

void create_tidscan_paths ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 460 of file tidpath.c.

461 {
462  List *tidquals;
463  List *tidrangequals;
464 
465  /*
466  * If any suitable quals exist in the rel's baserestrict list, generate a
467  * plain (unparameterized) TidPath with them.
468  */
469  tidquals = TidQualFromRestrictInfoList(root, rel->baserestrictinfo, rel);
470 
471  if (tidquals != NIL)
472  {
473  /*
474  * This path uses no join clauses, but it could still have required
475  * parameterization due to LATERAL refs in its tlist.
476  */
477  Relids required_outer = rel->lateral_relids;
478 
479  add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
480  required_outer));
481  }
482 
483  /*
484  * If there are range quals in the baserestrict list, generate a
485  * TidRangePath.
486  */
488  rel);
489 
490  if (tidrangequals != NIL)
491  {
492  /*
493  * This path uses no join clauses, but it could still have required
494  * parameterization due to LATERAL refs in its tlist.
495  */
496  Relids required_outer = rel->lateral_relids;
497 
498  add_path(rel, (Path *) create_tidrangescan_path(root, rel,
499  tidrangequals,
500  required_outer));
501  }
502 
503  /*
504  * Try to generate parameterized TidPaths using equality clauses extracted
505  * from EquivalenceClasses. (This is important since simple "t1.ctid =
506  * t2.ctid" clauses will turn into ECs.)
507  */
508  if (rel->has_eclass_joins)
509  {
510  List *clauses;
511 
512  /* Generate clauses, skipping any that join to lateral_referencers */
514  rel,
516  NULL,
517  rel->lateral_referencers);
518 
519  /* Generate a path for each usable join clause */
520  BuildParameterizedTidPaths(root, rel, clauses);
521  }
522 
523  /*
524  * Also consider parameterized TidPaths using "loose" join quals. Quals
525  * of the form "t1.ctid = t2.ctid" would turn into these if they are outer
526  * join quals, for example.
527  */
528  BuildParameterizedTidPaths(root, rel, rel->joininfo);
529 }
List * generate_implied_equalities_for_column(PlannerInfo *root, RelOptInfo *rel, ec_matches_callback_type callback, void *callback_arg, Relids prohibited_rels)
Definition: equivclass.c:2884
TidRangePath * create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer)
Definition: pathnode.c:1210
#define NIL
Definition: pg_list.h:68
List * baserestrictinfo
Definition: pathnodes.h:964
List * joininfo
Definition: pathnodes.h:970
Relids lateral_referencers
Definition: pathnodes.h:921
bool has_eclass_joins
Definition: pathnodes.h:972
static void BuildParameterizedTidPaths(PlannerInfo *root, RelOptInfo *rel, List *clauses)
Definition: tidpath.c:388
static List * TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel)
Definition: tidpath.c:277
static List * TidRangeQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
Definition: tidpath.c:360
static bool ec_member_matches_ctid(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
Definition: tidpath.c:443

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

Referenced by set_plain_rel_pathlist().

◆ ec_member_matches_ctid()

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

Definition at line 443 of file tidpath.c.

446 {
447  if (em->em_expr && IsA(em->em_expr, Var) &&
448  IsCTIDVar((Var *) em->em_expr, rel))
449  return true;
450  return false;
451 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
Definition: primnodes.h:234
static bool IsCTIDVar(Var *var, RelOptInfo *rel)
Definition: tidpath.c:56

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

Referenced by create_tidscan_paths().

◆ IsBinaryTidClause()

static bool IsBinaryTidClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 77 of file tidpath.c.

78 {
79  OpExpr *node;
80  Node *arg1,
81  *arg2,
82  *other;
83  Relids other_relids;
84 
85  /* Must be an OpExpr */
86  if (!is_opclause(rinfo->clause))
87  return false;
88  node = (OpExpr *) rinfo->clause;
89 
90  /* OpExpr must have two arguments */
91  if (list_length(node->args) != 2)
92  return false;
93  arg1 = linitial(node->args);
94  arg2 = lsecond(node->args);
95 
96  /* Look for CTID as either argument */
97  other = NULL;
98  other_relids = NULL;
99  if (arg1 && IsA(arg1, Var) &&
100  IsCTIDVar((Var *) arg1, rel))
101  {
102  other = arg2;
103  other_relids = rinfo->right_relids;
104  }
105  if (!other && arg2 && IsA(arg2, Var) &&
106  IsCTIDVar((Var *) arg2, rel))
107  {
108  other = arg1;
109  other_relids = rinfo->left_relids;
110  }
111  if (!other)
112  return false;
113 
114  /* The other argument must be a pseudoconstant */
115  if (bms_is_member(rel->relid, other_relids) ||
117  return false;
118 
119  return true; /* success */
120 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:460
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:521
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:74
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
Definition: nodes.h:129
List * args
Definition: primnodes.h:771
Expr * clause
Definition: pathnodes.h:2529

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

Referenced by IsTidEqualClause(), and IsTidRangeClause().

◆ IsCTIDVar()

static bool IsCTIDVar ( Var var,
RelOptInfo rel 
)
inlinestatic

Definition at line 56 of file tidpath.c.

57 {
58  /* The vartype check is strictly paranoia */
60  var->vartype == TIDOID &&
61  var->varno == rel->relid &&
62  var->varnullingrels == NULL &&
63  var->varlevelsup == 0)
64  return true;
65  return false;
66 }
AttrNumber varattno
Definition: primnodes.h:246
int varno
Definition: primnodes.h:241
Index varlevelsup
Definition: primnodes.h:266
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21

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

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

◆ IsCurrentOfClause()

static bool IsCurrentOfClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 212 of file tidpath.c.

213 {
214  CurrentOfExpr *node;
215 
216  /* Must be a CurrentOfExpr */
217  if (!(rinfo->clause && IsA(rinfo->clause, CurrentOfExpr)))
218  return false;
219  node = (CurrentOfExpr *) rinfo->clause;
220 
221  /* If it references this rel, we're good */
222  if (node->cvarno == rel->relid)
223  return true;
224 
225  return false;
226 }

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

Referenced by TidQualFromRestrictInfo().

◆ IsTidEqualAnyClause()

static bool IsTidEqualAnyClause ( PlannerInfo root,
RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 173 of file tidpath.c.

174 {
175  ScalarArrayOpExpr *node;
176  Node *arg1,
177  *arg2;
178 
179  /* Must be a ScalarArrayOpExpr */
180  if (!(rinfo->clause && IsA(rinfo->clause, ScalarArrayOpExpr)))
181  return false;
182  node = (ScalarArrayOpExpr *) rinfo->clause;
183 
184  /* Operator must be tideq */
185  if (node->opno != TIDEqualOperator)
186  return false;
187  if (!node->useOr)
188  return false;
189  Assert(list_length(node->args) == 2);
190  arg1 = linitial(node->args);
191  arg2 = lsecond(node->args);
192 
193  /* CTID must be first argument */
194  if (arg1 && IsA(arg1, Var) &&
195  IsCTIDVar((Var *) arg1, rel))
196  {
197  /* The other argument must be a pseudoconstant */
198  if (bms_is_member(rel->relid, pull_varnos(root, arg2)) ||
200  return false;
201 
202  return true; /* success */
203  }
204 
205  return false;
206 }
Assert(fmt[strlen(fmt) - 1] !='\n')
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108

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

Referenced by TidQualFromRestrictInfo().

◆ IsTidEqualClause()

static bool IsTidEqualClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 131 of file tidpath.c.

132 {
133  if (!IsBinaryTidClause(rinfo, rel))
134  return false;
135 
136  if (((OpExpr *) rinfo->clause)->opno == TIDEqualOperator)
137  return true;
138 
139  return false;
140 }
static bool IsBinaryTidClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:77

References RestrictInfo::clause, and IsBinaryTidClause().

Referenced by BuildParameterizedTidPaths(), and TidQualFromRestrictInfo().

◆ IsTidRangeClause()

static bool IsTidRangeClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 151 of file tidpath.c.

152 {
153  Oid opno;
154 
155  if (!IsBinaryTidClause(rinfo, rel))
156  return false;
157  opno = ((OpExpr *) rinfo->clause)->opno;
158 
159  if (opno == TIDLessOperator || opno == TIDLessEqOperator ||
160  opno == TIDGreaterOperator || opno == TIDGreaterEqOperator)
161  return true;
162 
163  return false;
164 }
unsigned int Oid
Definition: postgres_ext.h:31

References RestrictInfo::clause, and IsBinaryTidClause().

Referenced by TidRangeQualFromRestrictInfoList().

◆ TidQualFromRestrictInfo()

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

Definition at line 240 of file tidpath.c.

241 {
242  /*
243  * We may ignore pseudoconstant clauses (they can't contain Vars, so could
244  * not match anyway).
245  */
246  if (rinfo->pseudoconstant)
247  return NIL;
248 
249  /*
250  * If clause must wait till after some lower-security-level restriction
251  * clause, reject it.
252  */
253  if (!restriction_is_securely_promotable(rinfo, rel))
254  return NIL;
255 
256  /*
257  * Check all base cases. If we get a match, return the clause.
258  */
259  if (IsTidEqualClause(rinfo, rel) ||
260  IsTidEqualAnyClause(root, rinfo, rel) ||
261  IsCurrentOfClause(rinfo, rel))
262  return list_make1(rinfo);
263 
264  return NIL;
265 }
static bool IsCurrentOfClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:212
static bool IsTidEqualAnyClause(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:173

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

Referenced by TidQualFromRestrictInfoList().

◆ TidQualFromRestrictInfoList()

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

Definition at line 277 of file tidpath.c.

278 {
279  List *rlst = NIL;
280  ListCell *l;
281 
282  foreach(l, rlist)
283  {
285 
286  if (restriction_is_or_clause(rinfo))
287  {
288  ListCell *j;
289 
290  /*
291  * We must be able to extract a CTID condition from every
292  * sub-clause of an OR, or we can't use it.
293  */
294  foreach(j, ((BoolExpr *) rinfo->orclause)->args)
295  {
296  Node *orarg = (Node *) lfirst(j);
297  List *sublist;
298 
299  /* OR arguments should be ANDs or sub-RestrictInfos */
300  if (is_andclause(orarg))
301  {
302  List *andargs = ((BoolExpr *) orarg)->args;
303 
304  /* Recurse in case there are sub-ORs */
305  sublist = TidQualFromRestrictInfoList(root, andargs, rel);
306  }
307  else
308  {
309  RestrictInfo *ri = castNode(RestrictInfo, orarg);
310 
312  sublist = TidQualFromRestrictInfo(root, ri, rel);
313  }
314 
315  /*
316  * If nothing found in this arm, we can't do anything with
317  * this OR clause.
318  */
319  if (sublist == NIL)
320  {
321  rlst = NIL; /* forget anything we had */
322  break; /* out of loop over OR args */
323  }
324 
325  /*
326  * OK, continue constructing implicitly-OR'ed result list.
327  */
328  rlst = list_concat(rlst, sublist);
329  }
330  }
331  else
332  {
333  /* Not an OR clause, so handle base cases */
334  rlst = TidQualFromRestrictInfo(root, rinfo, rel);
335  }
336 
337  /*
338  * Stop as soon as we find any usable CTID condition. In theory we
339  * could get CTID equality conditions from different AND'ed clauses,
340  * in which case we could try to pick the most efficient one. In
341  * practice, such usage seems very unlikely, so we don't bother; we
342  * just exit as soon as we find the first candidate.
343  */
344  if (rlst)
345  break;
346  }
347 
348  return rlst;
349 }
int j
Definition: isn.c:74
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:105
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
#define lfirst(lc)
Definition: pg_list.h:172
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:416
static List * TidQualFromRestrictInfo(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:240

References Assert(), castNode, is_andclause(), j, lfirst, lfirst_node, list_concat(), NIL, restriction_is_or_clause(), and TidQualFromRestrictInfo().

Referenced by create_tidscan_paths().

◆ TidRangeQualFromRestrictInfoList()

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

Definition at line 360 of file tidpath.c.

361 {
362  List *rlst = NIL;
363  ListCell *l;
364 
365  if ((rel->amflags & AMFLAG_HAS_TID_RANGE) == 0)
366  return NIL;
367 
368  foreach(l, rlist)
369  {
371 
372  if (IsTidRangeClause(rinfo, rel))
373  rlst = lappend(rlst, rinfo);
374  }
375 
376  return rlst;
377 }
List * lappend(List *list, void *datum)
Definition: list.c:338
#define AMFLAG_HAS_TID_RANGE
Definition: pathnodes.h:808
uint32 amflags
Definition: pathnodes.h:937
static bool IsTidRangeClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:151

References AMFLAG_HAS_TID_RANGE, RelOptInfo::amflags, IsTidRangeClause(), lappend(), lfirst_node, and NIL.

Referenced by create_tidscan_paths().