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 bool RestrictInfoIsTidQual (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 415 of file tidpath.c.

416 {
417  ListCell *l;
418 
419  foreach(l, clauses)
420  {
422  List *tidquals;
423  Relids required_outer;
424 
425  /*
426  * Validate whether each clause is actually usable; we must check this
427  * even when examining clauses generated from an EquivalenceClass,
428  * since they might not satisfy the restriction on not having Vars of
429  * our rel on the other side, or somebody might've built an operator
430  * class that accepts type "tid" but has other operators in it.
431  *
432  * We currently consider only TidEqual join clauses. In principle we
433  * might find a suitable ScalarArrayOpExpr in the rel's joininfo list,
434  * but it seems unlikely to be worth expending the cycles to check.
435  * And we definitely won't find a CurrentOfExpr here. Hence, we don't
436  * use RestrictInfoIsTidQual; but this must match that function
437  * otherwise.
438  */
439  if (rinfo->pseudoconstant ||
440  !restriction_is_securely_promotable(rinfo, rel) ||
441  !IsTidEqualClause(rinfo, rel))
442  continue;
443 
444  /*
445  * Check if clause can be moved to this rel; this is probably
446  * redundant when considering EC-derived clauses, but we must check it
447  * for "loose" join clauses.
448  */
449  if (!join_clause_is_movable_to(rinfo, rel))
450  continue;
451 
452  /* OK, make list of clauses for this path */
453  tidquals = list_make1(rinfo);
454 
455  /* Compute required outer rels for this path */
456  required_outer = bms_union(rinfo->required_relids, rel->lateral_relids);
457  required_outer = bms_del_member(required_outer, rel->relid);
458 
459  add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
460  required_outer));
461  }
462 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
TidPath * create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
Definition: pathnode.c:1179
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:420
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define list_make1(x1)
Definition: pg_list.h:212
tree ctl root
Definition: radixtree.h:1884
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:908
Relids lateral_relids
Definition: pathnodes.h:903
Relids required_relids
Definition: pathnodes.h:2584
static bool IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:130

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, restriction_is_securely_promotable(), and root.

Referenced by create_tidscan_paths().

◆ create_tidscan_paths()

void create_tidscan_paths ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 487 of file tidpath.c.

488 {
489  List *tidquals;
490  List *tidrangequals;
491 
492  /*
493  * If any suitable quals exist in the rel's baserestrict list, generate a
494  * plain (unparameterized) TidPath with them.
495  */
496  tidquals = TidQualFromRestrictInfoList(root, rel->baserestrictinfo, rel);
497 
498  if (tidquals != NIL)
499  {
500  /*
501  * This path uses no join clauses, but it could still have required
502  * parameterization due to LATERAL refs in its tlist.
503  */
504  Relids required_outer = rel->lateral_relids;
505 
506  add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
507  required_outer));
508  }
509 
510  /*
511  * If there are range quals in the baserestrict list, generate a
512  * TidRangePath.
513  */
515  rel);
516 
517  if (tidrangequals != NIL)
518  {
519  /*
520  * This path uses no join clauses, but it could still have required
521  * parameterization due to LATERAL refs in its tlist.
522  */
523  Relids required_outer = rel->lateral_relids;
524 
526  tidrangequals,
527  required_outer));
528  }
529 
530  /*
531  * Try to generate parameterized TidPaths using equality clauses extracted
532  * from EquivalenceClasses. (This is important since simple "t1.ctid =
533  * t2.ctid" clauses will turn into ECs.)
534  */
535  if (rel->has_eclass_joins)
536  {
537  List *clauses;
538 
539  /* Generate clauses, skipping any that join to lateral_referencers */
541  rel,
543  NULL,
544  rel->lateral_referencers);
545 
546  /* Generate a path for each usable join clause */
547  BuildParameterizedTidPaths(root, rel, clauses);
548  }
549 
550  /*
551  * Also consider parameterized TidPaths using "loose" join quals. Quals
552  * of the form "t1.ctid = t2.ctid" would turn into these if they are outer
553  * join quals, for example.
554  */
556 }
List * generate_implied_equalities_for_column(PlannerInfo *root, RelOptInfo *rel, ec_matches_callback_type callback, void *callback_arg, Relids prohibited_rels)
Definition: equivclass.c:2971
TidRangePath * create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer)
Definition: pathnode.c:1208
#define NIL
Definition: pg_list.h:68
List * baserestrictinfo
Definition: pathnodes.h:975
List * joininfo
Definition: pathnodes.h:981
Relids lateral_referencers
Definition: pathnodes.h:932
bool has_eclass_joins
Definition: pathnodes.h:983
static void BuildParameterizedTidPaths(PlannerInfo *root, RelOptInfo *rel, List *clauses)
Definition: tidpath.c:415
static List * TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel)
Definition: tidpath.c:280
static List * TidRangeQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
Definition: tidpath.c:387
static bool ec_member_matches_ctid(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
Definition: tidpath.c:470

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, root, 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 470 of file tidpath.c.

473 {
474  if (em->em_expr && IsA(em->em_expr, Var) &&
475  IsCTIDVar((Var *) em->em_expr, rel))
476  return true;
477  return false;
478 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
Definition: primnodes.h:248
static bool IsCTIDVar(Var *var, RelOptInfo *rel)
Definition: tidpath.c:55

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

Referenced by create_tidscan_paths().

◆ IsBinaryTidClause()

static bool IsBinaryTidClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 76 of file tidpath.c.

77 {
78  OpExpr *node;
79  Node *arg1,
80  *arg2,
81  *other;
82  Relids other_relids;
83 
84  /* Must be an OpExpr */
85  if (!is_opclause(rinfo->clause))
86  return false;
87  node = (OpExpr *) rinfo->clause;
88 
89  /* OpExpr must have two arguments */
90  if (list_length(node->args) != 2)
91  return false;
92  arg1 = linitial(node->args);
93  arg2 = lsecond(node->args);
94 
95  /* Look for CTID as either argument */
96  other = NULL;
97  other_relids = NULL;
98  if (arg1 && IsA(arg1, Var) &&
99  IsCTIDVar((Var *) arg1, rel))
100  {
101  other = arg2;
102  other_relids = rinfo->right_relids;
103  }
104  if (!other && arg2 && IsA(arg2, Var) &&
105  IsCTIDVar((Var *) arg2, rel))
106  {
107  other = arg1;
108  other_relids = rinfo->left_relids;
109  }
110  if (!other)
111  return false;
112 
113  /* The other argument must be a pseudoconstant */
114  if (bms_is_member(rel->relid, other_relids) ||
116  return false;
117 
118  return true; /* success */
119 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
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:836
Expr * clause
Definition: pathnodes.h:2553

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 55 of file tidpath.c.

56 {
57  /* The vartype check is strictly paranoia */
59  var->vartype == TIDOID &&
60  var->varno == rel->relid &&
61  var->varnullingrels == NULL &&
62  var->varlevelsup == 0)
63  return true;
64  return false;
65 }
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
#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 211 of file tidpath.c.

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

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

Referenced by RestrictInfoIsTidQual(), and TidQualFromRestrictInfoList().

◆ IsTidEqualAnyClause()

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

Definition at line 172 of file tidpath.c.

173 {
174  ScalarArrayOpExpr *node;
175  Node *arg1,
176  *arg2;
177 
178  /* Must be a ScalarArrayOpExpr */
179  if (!(rinfo->clause && IsA(rinfo->clause, ScalarArrayOpExpr)))
180  return false;
181  node = (ScalarArrayOpExpr *) rinfo->clause;
182 
183  /* Operator must be tideq */
184  if (node->opno != TIDEqualOperator)
185  return false;
186  if (!node->useOr)
187  return false;
188  Assert(list_length(node->args) == 2);
189  arg1 = linitial(node->args);
190  arg2 = lsecond(node->args);
191 
192  /* CTID must be first argument */
193  if (arg1 && IsA(arg1, Var) &&
194  IsCTIDVar((Var *) arg1, rel))
195  {
196  /* The other argument must be a pseudoconstant */
197  if (bms_is_member(rel->relid, pull_varnos(root, arg2)) ||
199  return false;
200 
201  return true; /* success */
202  }
203 
204  return false;
205 }
#define Assert(condition)
Definition: c.h:858
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, root, and ScalarArrayOpExpr::useOr.

Referenced by RestrictInfoIsTidQual().

◆ IsTidEqualClause()

static bool IsTidEqualClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 130 of file tidpath.c.

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

References RestrictInfo::clause, and IsBinaryTidClause().

Referenced by BuildParameterizedTidPaths(), and RestrictInfoIsTidQual().

◆ IsTidRangeClause()

static bool IsTidRangeClause ( RestrictInfo rinfo,
RelOptInfo rel 
)
static

Definition at line 150 of file tidpath.c.

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

References RestrictInfo::clause, and IsBinaryTidClause().

Referenced by TidRangeQualFromRestrictInfoList().

◆ RestrictInfoIsTidQual()

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

Definition at line 234 of file tidpath.c.

235 {
236  /*
237  * We may ignore pseudoconstant clauses (they can't contain Vars, so could
238  * not match anyway).
239  */
240  if (rinfo->pseudoconstant)
241  return false;
242 
243  /*
244  * If clause must wait till after some lower-security-level restriction
245  * clause, reject it.
246  */
247  if (!restriction_is_securely_promotable(rinfo, rel))
248  return false;
249 
250  /*
251  * Check all base cases.
252  */
253  if (IsTidEqualClause(rinfo, rel) ||
254  IsTidEqualAnyClause(root, rinfo, rel) ||
255  IsCurrentOfClause(rinfo, rel))
256  return true;
257 
258  return false;
259 }
static bool IsCurrentOfClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:211
static bool IsTidEqualAnyClause(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:172

References IsCurrentOfClause(), IsTidEqualAnyClause(), IsTidEqualClause(), restriction_is_securely_promotable(), and root.

Referenced by TidQualFromRestrictInfoList().

◆ TidQualFromRestrictInfoList()

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

Definition at line 280 of file tidpath.c.

281 {
282  RestrictInfo *tidclause = NULL; /* best simple CTID qual so far */
283  List *orlist = NIL; /* best OR'ed CTID qual so far */
284  ListCell *l;
285 
286  foreach(l, rlist)
287  {
289 
290  if (restriction_is_or_clause(rinfo))
291  {
292  List *rlst = NIL;
293  ListCell *j;
294 
295  /*
296  * We must be able to extract a CTID condition from every
297  * sub-clause of an OR, or we can't use it.
298  */
299  foreach(j, ((BoolExpr *) rinfo->orclause)->args)
300  {
301  Node *orarg = (Node *) lfirst(j);
302  List *sublist;
303 
304  /* OR arguments should be ANDs or sub-RestrictInfos */
305  if (is_andclause(orarg))
306  {
307  List *andargs = ((BoolExpr *) orarg)->args;
308 
309  /* Recurse in case there are sub-ORs */
310  sublist = TidQualFromRestrictInfoList(root, andargs, rel);
311  }
312  else
313  {
314  RestrictInfo *ri = castNode(RestrictInfo, orarg);
315 
317  if (RestrictInfoIsTidQual(root, ri, rel))
318  sublist = list_make1(ri);
319  else
320  sublist = NIL;
321  }
322 
323  /*
324  * If nothing found in this arm, we can't do anything with
325  * this OR clause.
326  */
327  if (sublist == NIL)
328  {
329  rlst = NIL; /* forget anything we had */
330  break; /* out of loop over OR args */
331  }
332 
333  /*
334  * OK, continue constructing implicitly-OR'ed result list.
335  */
336  rlst = list_concat(rlst, sublist);
337  }
338 
339  if (rlst)
340  {
341  /*
342  * Accept the OR'ed list if it's the first one, or if it's
343  * shorter than the previous one.
344  */
345  if (orlist == NIL || list_length(rlst) < list_length(orlist))
346  orlist = rlst;
347  }
348  }
349  else
350  {
351  /* Not an OR clause, so handle base cases */
352  if (RestrictInfoIsTidQual(root, rinfo, rel))
353  {
354  /* We can stop immediately if it's a CurrentOfExpr */
355  if (IsCurrentOfClause(rinfo, rel))
356  return list_make1(rinfo);
357 
358  /*
359  * Otherwise, remember the first non-OR CTID qual. We could
360  * try to apply some preference order if there's more than
361  * one, but such usage seems very unlikely, so don't bother.
362  */
363  if (tidclause == NULL)
364  tidclause = rinfo;
365  }
366  }
367  }
368 
369  /*
370  * Prefer any singleton CTID qual to an OR'ed list. Again, it seems
371  * unlikely to be worth thinking harder than that.
372  */
373  if (tidclause)
374  return list_make1(tidclause);
375  return orlist;
376 }
int j
Definition: isn.c:74
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:105
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#define lfirst(lc)
Definition: pg_list.h:172
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:416
static bool RestrictInfoIsTidQual(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:234

References Assert, castNode, is_andclause(), IsCurrentOfClause(), j, lfirst, lfirst_node, list_concat(), list_length(), list_make1, NIL, RestrictInfoIsTidQual(), restriction_is_or_clause(), and root.

Referenced by create_tidscan_paths().

◆ TidRangeQualFromRestrictInfoList()

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

Definition at line 387 of file tidpath.c.

388 {
389  List *rlst = NIL;
390  ListCell *l;
391 
392  if ((rel->amflags & AMFLAG_HAS_TID_RANGE) == 0)
393  return NIL;
394 
395  foreach(l, rlist)
396  {
398 
399  if (IsTidRangeClause(rinfo, rel))
400  rlst = lappend(rlst, rinfo);
401  }
402 
403  return rlst;
404 }
List * lappend(List *list, void *datum)
Definition: list.c:339
#define AMFLAG_HAS_TID_RANGE
Definition: pathnodes.h:813
uint32 amflags
Definition: pathnodes.h:948
static bool IsTidRangeClause(RestrictInfo *rinfo, RelOptInfo *rel)
Definition: tidpath.c:150

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

Referenced by create_tidscan_paths().