PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
indxpath.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/stratnum.h"
#include "access/sysattr.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/selfuncs.h"
#include "utils/syscache.h"
Include dependency graph for indxpath.c:

Go to the source code of this file.

Data Structures

struct  IndexClauseSet
 
struct  PathClauseUsage
 
struct  ec_member_matches_arg
 
struct  OrArgIndexMatch
 

Macros

#define IndexCollMatchesExprColl(idxcollation, exprcollation)    ((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
 

Enumerations

enum  ScanTypeControl { ST_INDEXSCAN , ST_BITMAPSCAN , ST_ANYSCAN }
 

Functions

static void consider_index_join_clauses (PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *rclauseset, IndexClauseSet *jclauseset, IndexClauseSet *eclauseset, List **bitindexpaths)
 
static void consider_index_join_outer_rels (PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *rclauseset, IndexClauseSet *jclauseset, IndexClauseSet *eclauseset, List **bitindexpaths, List *indexjoinclauses, int considered_clauses, List **considered_relids)
 
static void get_join_index_paths (PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *rclauseset, IndexClauseSet *jclauseset, IndexClauseSet *eclauseset, List **bitindexpaths, Relids relids, List **considered_relids)
 
static bool eclass_already_used (EquivalenceClass *parent_ec, Relids oldrelids, List *indexjoinclauses)
 
static void get_index_paths (PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *clauses, List **bitindexpaths)
 
static Listbuild_index_paths (PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *clauses, bool useful_predicate, ScanTypeControl scantype, bool *skip_nonnative_saop)
 
static Listbuild_paths_for_OR (PlannerInfo *root, RelOptInfo *rel, List *clauses, List *other_clauses)
 
static Listgenerate_bitmap_or_paths (PlannerInfo *root, RelOptInfo *rel, List *clauses, List *other_clauses)
 
static Pathchoose_bitmap_and (PlannerInfo *root, RelOptInfo *rel, List *paths)
 
static int path_usage_comparator (const void *a, const void *b)
 
static Cost bitmap_scan_cost_est (PlannerInfo *root, RelOptInfo *rel, Path *ipath)
 
static Cost bitmap_and_cost_est (PlannerInfo *root, RelOptInfo *rel, List *paths)
 
static PathClauseUsageclassify_index_clause_usage (Path *path, List **clauselist)
 
static void find_indexpath_quals (Path *bitmapqual, List **quals, List **preds)
 
static int find_list_position (Node *node, List **nodelist)
 
static bool check_index_only (RelOptInfo *rel, IndexOptInfo *index)
 
static double get_loop_count (PlannerInfo *root, Index cur_relid, Relids outer_relids)
 
static double adjust_rowcount_for_semijoins (PlannerInfo *root, Index cur_relid, Index outer_relid, double rowcount)
 
static double approximate_joinrel_size (PlannerInfo *root, Relids relids)
 
static void match_restriction_clauses_to_index (PlannerInfo *root, IndexOptInfo *index, IndexClauseSet *clauseset)
 
static void match_join_clauses_to_index (PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *clauseset, List **joinorclauses)
 
static void match_eclass_clauses_to_index (PlannerInfo *root, IndexOptInfo *index, IndexClauseSet *clauseset)
 
static void match_clauses_to_index (PlannerInfo *root, List *clauses, IndexOptInfo *index, IndexClauseSet *clauseset)
 
static void match_clause_to_index (PlannerInfo *root, RestrictInfo *rinfo, IndexOptInfo *index, IndexClauseSet *clauseset)
 
static IndexClausematch_clause_to_indexcol (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static bool IsBooleanOpfamily (Oid opfamily)
 
static IndexClausematch_boolean_index_clause (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static IndexClausematch_opclause_to_indexcol (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static IndexClausematch_funcclause_to_indexcol (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static IndexClauseget_index_clause_from_support (PlannerInfo *root, RestrictInfo *rinfo, Oid funcid, int indexarg, int indexcol, IndexOptInfo *index)
 
static IndexClausematch_saopclause_to_indexcol (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static IndexClausematch_rowcompare_to_indexcol (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static IndexClausematch_orclause_to_indexcol (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
 
static IndexClauseexpand_indexqual_rowcompare (PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index, Oid expr_op, bool var_on_left)
 
static void match_pathkeys_to_index (IndexOptInfo *index, List *pathkeys, List **orderby_clauses_p, List **clause_columns_p)
 
static Exprmatch_clause_to_ordering_op (IndexOptInfo *index, int indexcol, Expr *clause, Oid pk_opfamily)
 
static bool ec_member_matches_indexcol (PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
 
void create_index_paths (PlannerInfo *root, RelOptInfo *rel)
 
static int or_arg_index_match_cmp (const void *a, const void *b)
 
static Listgroup_similar_or_args (PlannerInfo *root, RelOptInfo *rel, RestrictInfo *rinfo)
 
static Listmake_bitmap_paths_for_or_group (PlannerInfo *root, RelOptInfo *rel, RestrictInfo *ri, List *other_clauses)
 
void check_index_predicates (PlannerInfo *root, RelOptInfo *rel)
 
bool relation_has_unique_index_for (PlannerInfo *root, RelOptInfo *rel, List *restrictlist, List *exprlist, List *oprlist)
 
bool indexcol_is_bool_constant_for_query (PlannerInfo *root, IndexOptInfo *index, int indexcol)
 
bool match_index_to_operand (Node *operand, int indexcol, IndexOptInfo *index)
 
bool is_pseudo_constant_for_index (PlannerInfo *root, Node *expr, IndexOptInfo *index)
 

Macro Definition Documentation

◆ IndexCollMatchesExprColl

#define IndexCollMatchesExprColl (   idxcollation,
  exprcollation 
)     ((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))

Definition at line 43 of file indxpath.c.

Enumeration Type Documentation

◆ ScanTypeControl

Enumerator
ST_INDEXSCAN 
ST_BITMAPSCAN 
ST_ANYSCAN 

Definition at line 47 of file indxpath.c.

48 {
49  ST_INDEXSCAN, /* must support amgettuple */
50  ST_BITMAPSCAN, /* must support amgetbitmap */
51  ST_ANYSCAN, /* either is okay */
ScanTypeControl
Definition: indxpath.c:48
@ ST_ANYSCAN
Definition: indxpath.c:51
@ ST_BITMAPSCAN
Definition: indxpath.c:50
@ ST_INDEXSCAN
Definition: indxpath.c:49

Function Documentation

◆ adjust_rowcount_for_semijoins()

static double adjust_rowcount_for_semijoins ( PlannerInfo root,
Index  cur_relid,
Index  outer_relid,
double  rowcount 
)
static

Definition at line 2315 of file indxpath.c.

2319 {
2320  ListCell *lc;
2321 
2322  foreach(lc, root->join_info_list)
2323  {
2324  SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
2325 
2326  if (sjinfo->jointype == JOIN_SEMI &&
2327  bms_is_member(cur_relid, sjinfo->syn_lefthand) &&
2328  bms_is_member(outer_relid, sjinfo->syn_righthand))
2329  {
2330  /* Estimate number of unique-ified rows */
2331  double nraw;
2332  double nunique;
2333 
2334  nraw = approximate_joinrel_size(root, sjinfo->syn_righthand);
2335  nunique = estimate_num_groups(root,
2336  sjinfo->semi_rhs_exprs,
2337  nraw,
2338  NULL,
2339  NULL);
2340  if (rowcount > nunique)
2341  rowcount = nunique;
2342  }
2343  }
2344  return rowcount;
2345 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
static double approximate_joinrel_size(PlannerInfo *root, Relids relids)
Definition: indxpath.c:2359
@ JOIN_SEMI
Definition: nodes.h:307
#define lfirst(lc)
Definition: pg_list.h:172
tree ctl root
Definition: radixtree.h:1886
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3420
Relids syn_lefthand
Definition: pathnodes.h:2906
List * semi_rhs_exprs
Definition: pathnodes.h:2919
JoinType jointype
Definition: pathnodes.h:2908
Relids syn_righthand
Definition: pathnodes.h:2907

References approximate_joinrel_size(), bms_is_member(), estimate_num_groups(), JOIN_SEMI, SpecialJoinInfo::jointype, lfirst, root, SpecialJoinInfo::semi_rhs_exprs, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.

Referenced by get_loop_count().

◆ approximate_joinrel_size()

static double approximate_joinrel_size ( PlannerInfo root,
Relids  relids 
)
static

Definition at line 2359 of file indxpath.c.

2360 {
2361  double rowcount = 1.0;
2362  int relid;
2363 
2364  relid = -1;
2365  while ((relid = bms_next_member(relids, relid)) >= 0)
2366  {
2367  RelOptInfo *rel;
2368 
2369  /* Paranoia: ignore bogus relid indexes */
2370  if (relid >= root->simple_rel_array_size)
2371  continue;
2372  rel = root->simple_rel_array[relid];
2373  if (rel == NULL)
2374  continue;
2375  Assert(rel->relid == relid); /* sanity check on array */
2376 
2377  /* Relation could be proven empty, if so ignore */
2378  if (IS_DUMMY_REL(rel))
2379  continue;
2380 
2381  /* Otherwise, rel's rows estimate should be valid by now */
2382  Assert(rel->rows > 0);
2383 
2384  /* Accumulate product */
2385  rowcount *= rel->rows;
2386  }
2387  return rowcount;
2388 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define Assert(condition)
Definition: c.h:863
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:1956
Index relid
Definition: pathnodes.h:918
Cardinality rows
Definition: pathnodes.h:877

References Assert, bms_next_member(), IS_DUMMY_REL, RelOptInfo::relid, root, and RelOptInfo::rows.

Referenced by adjust_rowcount_for_semijoins().

◆ bitmap_and_cost_est()

static Cost bitmap_and_cost_est ( PlannerInfo root,
RelOptInfo rel,
List paths 
)
static

Definition at line 1993 of file indxpath.c.

1994 {
1995  BitmapAndPath *apath;
1996 
1997  /*
1998  * Might as well build a real BitmapAndPath here, as the work is slightly
1999  * too complicated to be worth repeating just to save one palloc.
2000  */
2001  apath = create_bitmap_and_path(root, rel, paths);
2002 
2003  return bitmap_scan_cost_est(root, rel, (Path *) apath);
2004 }
static Cost bitmap_scan_cost_est(PlannerInfo *root, RelOptInfo *rel, Path *ipath)
Definition: indxpath.c:1959
BitmapAndPath * create_bitmap_and_path(PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
Definition: pathnode.c:1131

References bitmap_scan_cost_est(), create_bitmap_and_path(), and root.

Referenced by choose_bitmap_and().

◆ bitmap_scan_cost_est()

static Cost bitmap_scan_cost_est ( PlannerInfo root,
RelOptInfo rel,
Path ipath 
)
static

Definition at line 1959 of file indxpath.c.

1960 {
1961  BitmapHeapPath bpath;
1962 
1963  /* Set up a dummy BitmapHeapPath */
1964  bpath.path.type = T_BitmapHeapPath;
1965  bpath.path.pathtype = T_BitmapHeapScan;
1966  bpath.path.parent = rel;
1967  bpath.path.pathtarget = rel->reltarget;
1968  bpath.path.param_info = ipath->param_info;
1969  bpath.path.pathkeys = NIL;
1970  bpath.bitmapqual = ipath;
1971 
1972  /*
1973  * Check the cost of temporary path without considering parallelism.
1974  * Parallel bitmap heap path will be considered at later stage.
1975  */
1976  bpath.path.parallel_workers = 0;
1977 
1978  /* Now we can do cost_bitmap_heap_scan */
1979  cost_bitmap_heap_scan(&bpath.path, root, rel,
1980  bpath.path.param_info,
1981  ipath,
1982  get_loop_count(root, rel->relid,
1983  PATH_REQ_OUTER(ipath)));
1984 
1985  return bpath.path.total_cost;
1986 }
void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, Path *bitmapqual, double loop_count)
Definition: costsize.c:1023
static double get_loop_count(PlannerInfo *root, Index cur_relid, Relids outer_relids)
Definition: indxpath.c:2262
#define PATH_REQ_OUTER(path)
Definition: pathnodes.h:1679
#define NIL
Definition: pg_list.h:68
Path * bitmapqual
Definition: pathnodes.h:1795
List * pathkeys
Definition: pathnodes.h:1675
NodeTag pathtype
Definition: pathnodes.h:1635
int parallel_workers
Definition: pathnodes.h:1666
Cost total_cost
Definition: pathnodes.h:1672
struct PathTarget * reltarget
Definition: pathnodes.h:893

References BitmapHeapPath::bitmapqual, cost_bitmap_heap_scan(), get_loop_count(), NIL, Path::parallel_workers, BitmapHeapPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, RelOptInfo::relid, RelOptInfo::reltarget, root, and Path::total_cost.

Referenced by bitmap_and_cost_est(), and choose_bitmap_and().

◆ build_index_paths()

static List * build_index_paths ( PlannerInfo root,
RelOptInfo rel,
IndexOptInfo index,
IndexClauseSet clauses,
bool  useful_predicate,
ScanTypeControl  scantype,
bool skip_nonnative_saop 
)
static

Definition at line 811 of file indxpath.c.

816 {
817  List *result = NIL;
818  IndexPath *ipath;
819  List *index_clauses;
820  Relids outer_relids;
821  double loop_count;
822  List *orderbyclauses;
823  List *orderbyclausecols;
824  List *index_pathkeys;
825  List *useful_pathkeys;
826  bool pathkeys_possibly_useful;
827  bool index_is_ordered;
828  bool index_only_scan;
829  int indexcol;
830 
831  Assert(skip_nonnative_saop != NULL || scantype == ST_BITMAPSCAN);
832 
833  /*
834  * Check that index supports the desired scan type(s)
835  */
836  switch (scantype)
837  {
838  case ST_INDEXSCAN:
839  if (!index->amhasgettuple)
840  return NIL;
841  break;
842  case ST_BITMAPSCAN:
843  if (!index->amhasgetbitmap)
844  return NIL;
845  break;
846  case ST_ANYSCAN:
847  /* either or both are OK */
848  break;
849  }
850 
851  /*
852  * 1. Combine the per-column IndexClause lists into an overall list.
853  *
854  * In the resulting list, clauses are ordered by index key, so that the
855  * column numbers form a nondecreasing sequence. (This order is depended
856  * on by btree and possibly other places.) The list can be empty, if the
857  * index AM allows that.
858  *
859  * We also build a Relids set showing which outer rels are required by the
860  * selected clauses. Any lateral_relids are included in that, but not
861  * otherwise accounted for.
862  */
863  index_clauses = NIL;
864  outer_relids = bms_copy(rel->lateral_relids);
865  for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
866  {
867  ListCell *lc;
868 
869  foreach(lc, clauses->indexclauses[indexcol])
870  {
871  IndexClause *iclause = (IndexClause *) lfirst(lc);
872  RestrictInfo *rinfo = iclause->rinfo;
873 
874  if (skip_nonnative_saop && !index->amsearcharray &&
875  IsA(rinfo->clause, ScalarArrayOpExpr))
876  {
877  /*
878  * Caller asked us to generate IndexPaths that omit any
879  * ScalarArrayOpExpr clauses when the underlying index AM
880  * lacks native support.
881  *
882  * We must omit this clause (and tell caller about it).
883  */
884  *skip_nonnative_saop = true;
885  continue;
886  }
887 
888  /* OK to include this clause */
889  index_clauses = lappend(index_clauses, iclause);
890  outer_relids = bms_add_members(outer_relids,
891  rinfo->clause_relids);
892  }
893 
894  /*
895  * If no clauses match the first index column, check for amoptionalkey
896  * restriction. We can't generate a scan over an index with
897  * amoptionalkey = false unless there's at least one index clause.
898  * (When working on columns after the first, this test cannot fail. It
899  * is always okay for columns after the first to not have any
900  * clauses.)
901  */
902  if (index_clauses == NIL && !index->amoptionalkey)
903  return NIL;
904  }
905 
906  /* We do not want the index's rel itself listed in outer_relids */
907  outer_relids = bms_del_member(outer_relids, rel->relid);
908 
909  /* Compute loop_count for cost estimation purposes */
910  loop_count = get_loop_count(root, rel->relid, outer_relids);
911 
912  /*
913  * 2. Compute pathkeys describing index's ordering, if any, then see how
914  * many of them are actually useful for this query. This is not relevant
915  * if we are only trying to build bitmap indexscans.
916  */
917  pathkeys_possibly_useful = (scantype != ST_BITMAPSCAN &&
918  has_useful_pathkeys(root, rel));
919  index_is_ordered = (index->sortopfamily != NULL);
920  if (index_is_ordered && pathkeys_possibly_useful)
921  {
922  index_pathkeys = build_index_pathkeys(root, index,
924  useful_pathkeys = truncate_useless_pathkeys(root, rel,
925  index_pathkeys);
926  orderbyclauses = NIL;
927  orderbyclausecols = NIL;
928  }
929  else if (index->amcanorderbyop && pathkeys_possibly_useful)
930  {
931  /*
932  * See if we can generate ordering operators for query_pathkeys or at
933  * least some prefix thereof. Matching to just a prefix of the
934  * query_pathkeys will allow an incremental sort to be considered on
935  * the index's partially sorted results.
936  */
937  match_pathkeys_to_index(index, root->query_pathkeys,
938  &orderbyclauses,
939  &orderbyclausecols);
940  if (list_length(root->query_pathkeys) == list_length(orderbyclauses))
941  useful_pathkeys = root->query_pathkeys;
942  else
943  useful_pathkeys = list_copy_head(root->query_pathkeys,
944  list_length(orderbyclauses));
945  }
946  else
947  {
948  useful_pathkeys = NIL;
949  orderbyclauses = NIL;
950  orderbyclausecols = NIL;
951  }
952 
953  /*
954  * 3. Check if an index-only scan is possible. If we're not building
955  * plain indexscans, this isn't relevant since bitmap scans don't support
956  * index data retrieval anyway.
957  */
958  index_only_scan = (scantype != ST_BITMAPSCAN &&
959  check_index_only(rel, index));
960 
961  /*
962  * 4. Generate an indexscan path if there are relevant restriction clauses
963  * in the current clauses, OR the index ordering is potentially useful for
964  * later merging or final output ordering, OR the index has a useful
965  * predicate, OR an index-only scan is possible.
966  */
967  if (index_clauses != NIL || useful_pathkeys != NIL || useful_predicate ||
968  index_only_scan)
969  {
970  ipath = create_index_path(root, index,
971  index_clauses,
972  orderbyclauses,
973  orderbyclausecols,
974  useful_pathkeys,
976  index_only_scan,
977  outer_relids,
978  loop_count,
979  false);
980  result = lappend(result, ipath);
981 
982  /*
983  * If appropriate, consider parallel index scan. We don't allow
984  * parallel index scan for bitmap index scans.
985  */
986  if (index->amcanparallel &&
987  rel->consider_parallel && outer_relids == NULL &&
988  scantype != ST_BITMAPSCAN)
989  {
990  ipath = create_index_path(root, index,
991  index_clauses,
992  orderbyclauses,
993  orderbyclausecols,
994  useful_pathkeys,
996  index_only_scan,
997  outer_relids,
998  loop_count,
999  true);
1000 
1001  /*
1002  * if, after costing the path, we find that it's not worth using
1003  * parallel workers, just free it.
1004  */
1005  if (ipath->path.parallel_workers > 0)
1006  add_partial_path(rel, (Path *) ipath);
1007  else
1008  pfree(ipath);
1009  }
1010  }
1011 
1012  /*
1013  * 5. If the index is ordered, a backwards scan might be interesting.
1014  */
1015  if (index_is_ordered && pathkeys_possibly_useful)
1016  {
1017  index_pathkeys = build_index_pathkeys(root, index,
1019  useful_pathkeys = truncate_useless_pathkeys(root, rel,
1020  index_pathkeys);
1021  if (useful_pathkeys != NIL)
1022  {
1023  ipath = create_index_path(root, index,
1024  index_clauses,
1025  NIL,
1026  NIL,
1027  useful_pathkeys,
1029  index_only_scan,
1030  outer_relids,
1031  loop_count,
1032  false);
1033  result = lappend(result, ipath);
1034 
1035  /* If appropriate, consider parallel index scan */
1036  if (index->amcanparallel &&
1037  rel->consider_parallel && outer_relids == NULL &&
1038  scantype != ST_BITMAPSCAN)
1039  {
1040  ipath = create_index_path(root, index,
1041  index_clauses,
1042  NIL,
1043  NIL,
1044  useful_pathkeys,
1046  index_only_scan,
1047  outer_relids,
1048  loop_count,
1049  true);
1050 
1051  /*
1052  * if, after costing the path, we find that it's not worth
1053  * using parallel workers, just free it.
1054  */
1055  if (ipath->path.parallel_workers > 0)
1056  add_partial_path(rel, (Path *) ipath);
1057  else
1058  pfree(ipath);
1059  }
1060  }
1061  }
1062 
1063  return result;
1064 }
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
static bool check_index_only(RelOptInfo *rel, IndexOptInfo *index)
Definition: indxpath.c:2163
static void match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys, List **orderby_clauses_p, List **clause_columns_p)
Definition: indxpath.c:3722
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_copy_head(const List *oldlist, int len)
Definition: list.c:1593
void pfree(void *pointer)
Definition: mcxt.c:1521
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
Definition: pathkeys.c:2277
List * truncate_useless_pathkeys(PlannerInfo *root, RelOptInfo *rel, List *pathkeys)
Definition: pathkeys.c:2231
List * build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index, ScanDirection scandir)
Definition: pathkeys.c:740
IndexPath * create_index_path(PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
Definition: pathnode.c:1049
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:795
static int list_length(const List *l)
Definition: pg_list.h:152
@ BackwardScanDirection
Definition: sdir.h:26
@ ForwardScanDirection
Definition: sdir.h:28
List * indexclauses[INDEX_MAX_KEYS]
Definition: indxpath.c:59
struct RestrictInfo * rinfo
Definition: pathnodes.h:1768
Path path
Definition: pathnodes.h:1719
Definition: pg_list.h:54
bool consider_parallel
Definition: pathnodes.h:887
Relids lateral_relids
Definition: pathnodes.h:913
Expr * clause
Definition: pathnodes.h:2574
Definition: type.h:95

References add_partial_path(), Assert, BackwardScanDirection, bms_add_members(), bms_copy(), bms_del_member(), build_index_pathkeys(), check_index_only(), RestrictInfo::clause, RelOptInfo::consider_parallel, create_index_path(), ForwardScanDirection, get_loop_count(), has_useful_pathkeys(), IndexClauseSet::indexclauses, IsA, lappend(), RelOptInfo::lateral_relids, lfirst, list_copy_head(), list_length(), match_pathkeys_to_index(), NIL, Path::parallel_workers, IndexPath::path, pfree(), RelOptInfo::relid, IndexClause::rinfo, root, ST_ANYSCAN, ST_BITMAPSCAN, ST_INDEXSCAN, and truncate_useless_pathkeys().

Referenced by build_paths_for_OR(), and get_index_paths().

◆ build_paths_for_OR()

static List * build_paths_for_OR ( PlannerInfo root,
RelOptInfo rel,
List clauses,
List other_clauses 
)
static

Definition at line 1093 of file indxpath.c.

1095 {
1096  List *result = NIL;
1097  List *all_clauses = NIL; /* not computed till needed */
1098  ListCell *lc;
1099 
1100  foreach(lc, rel->indexlist)
1101  {
1103  IndexClauseSet clauseset;
1104  List *indexpaths;
1105  bool useful_predicate;
1106 
1107  /* Ignore index if it doesn't support bitmap scans */
1108  if (!index->amhasgetbitmap)
1109  continue;
1110 
1111  /*
1112  * Ignore partial indexes that do not match the query. If a partial
1113  * index is marked predOK then we know it's OK. Otherwise, we have to
1114  * test whether the added clauses are sufficient to imply the
1115  * predicate. If so, we can use the index in the current context.
1116  *
1117  * We set useful_predicate to true iff the predicate was proven using
1118  * the current set of clauses. This is needed to prevent matching a
1119  * predOK index to an arm of an OR, which would be a legal but
1120  * pointlessly inefficient plan. (A better plan will be generated by
1121  * just scanning the predOK index alone, no OR.)
1122  */
1123  useful_predicate = false;
1124  if (index->indpred != NIL)
1125  {
1126  if (index->predOK)
1127  {
1128  /* Usable, but don't set useful_predicate */
1129  }
1130  else
1131  {
1132  /* Form all_clauses if not done already */
1133  if (all_clauses == NIL)
1134  all_clauses = list_concat_copy(clauses, other_clauses);
1135 
1136  if (!predicate_implied_by(index->indpred, all_clauses, false))
1137  continue; /* can't use it at all */
1138 
1139  if (!predicate_implied_by(index->indpred, other_clauses, false))
1140  useful_predicate = true;
1141  }
1142  }
1143 
1144  /*
1145  * Identify the restriction clauses that can match the index.
1146  */
1147  MemSet(&clauseset, 0, sizeof(clauseset));
1148  match_clauses_to_index(root, clauses, index, &clauseset);
1149 
1150  /*
1151  * If no matches so far, and the index predicate isn't useful, we
1152  * don't want it.
1153  */
1154  if (!clauseset.nonempty && !useful_predicate)
1155  continue;
1156 
1157  /*
1158  * Add "other" restriction clauses to the clauseset.
1159  */
1160  match_clauses_to_index(root, other_clauses, index, &clauseset);
1161 
1162  /*
1163  * Construct paths if possible.
1164  */
1165  indexpaths = build_index_paths(root, rel,
1166  index, &clauseset,
1167  useful_predicate,
1168  ST_BITMAPSCAN,
1169  NULL);
1170  result = list_concat(result, indexpaths);
1171  }
1172 
1173  return result;
1174 }
#define MemSet(start, val, len)
Definition: c.h:1025
static List * build_index_paths(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *clauses, bool useful_predicate, ScanTypeControl scantype, bool *skip_nonnative_saop)
Definition: indxpath.c:811
static void match_clauses_to_index(PlannerInfo *root, List *clauses, IndexOptInfo *index, IndexClauseSet *clauseset)
Definition: indxpath.c:2484
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
bool predicate_implied_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:152
bool nonempty
Definition: indxpath.c:57
List * indexlist
Definition: pathnodes.h:944

References build_index_paths(), RelOptInfo::indexlist, lfirst, list_concat(), list_concat_copy(), match_clauses_to_index(), MemSet, NIL, IndexClauseSet::nonempty, predicate_implied_by(), root, and ST_BITMAPSCAN.

Referenced by generate_bitmap_or_paths(), and make_bitmap_paths_for_or_group().

◆ check_index_only()

static bool check_index_only ( RelOptInfo rel,
IndexOptInfo index 
)
static

Definition at line 2163 of file indxpath.c.

2164 {
2165  bool result;
2166  Bitmapset *attrs_used = NULL;
2167  Bitmapset *index_canreturn_attrs = NULL;
2168  ListCell *lc;
2169  int i;
2170 
2171  /* Index-only scans must be enabled */
2172  if (!enable_indexonlyscan)
2173  return false;
2174 
2175  /*
2176  * Check that all needed attributes of the relation are available from the
2177  * index.
2178  */
2179 
2180  /*
2181  * First, identify all the attributes needed for joins or final output.
2182  * Note: we must look at rel's targetlist, not the attr_needed data,
2183  * because attr_needed isn't computed for inheritance child rels.
2184  */
2185  pull_varattnos((Node *) rel->reltarget->exprs, rel->relid, &attrs_used);
2186 
2187  /*
2188  * Add all the attributes used by restriction clauses; but consider only
2189  * those clauses not implied by the index predicate, since ones that are
2190  * so implied don't need to be checked explicitly in the plan.
2191  *
2192  * Note: attributes used only in index quals would not be needed at
2193  * runtime either, if we are certain that the index is not lossy. However
2194  * it'd be complicated to account for that accurately, and it doesn't
2195  * matter in most cases, since we'd conclude that such attributes are
2196  * available from the index anyway.
2197  */
2198  foreach(lc, index->indrestrictinfo)
2199  {
2200  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2201 
2202  pull_varattnos((Node *) rinfo->clause, rel->relid, &attrs_used);
2203  }
2204 
2205  /*
2206  * Construct a bitmapset of columns that the index can return back in an
2207  * index-only scan.
2208  */
2209  for (i = 0; i < index->ncolumns; i++)
2210  {
2211  int attno = index->indexkeys[i];
2212 
2213  /*
2214  * For the moment, we just ignore index expressions. It might be nice
2215  * to do something with them, later.
2216  */
2217  if (attno == 0)
2218  continue;
2219 
2220  if (index->canreturn[i])
2221  index_canreturn_attrs =
2222  bms_add_member(index_canreturn_attrs,
2224  }
2225 
2226  /* Do we have all the necessary attributes? */
2227  result = bms_is_subset(attrs_used, index_canreturn_attrs);
2228 
2229  bms_free(attrs_used);
2230  bms_free(index_canreturn_attrs);
2231 
2232  return result;
2233 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
bool enable_indexonlyscan
Definition: costsize.c:147
int i
Definition: isn.c:72
Definition: nodes.h:129
List * exprs
Definition: pathnodes.h:1542
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296

References bms_add_member(), bms_free(), bms_is_subset(), RestrictInfo::clause, enable_indexonlyscan, PathTarget::exprs, FirstLowInvalidHeapAttributeNumber, i, lfirst, pull_varattnos(), RelOptInfo::relid, and RelOptInfo::reltarget.

Referenced by build_index_paths().

◆ check_index_predicates()

void check_index_predicates ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 3946 of file indxpath.c.

3947 {
3948  List *clauselist;
3949  bool have_partial;
3950  bool is_target_rel;
3951  Relids otherrels;
3952  ListCell *lc;
3953 
3954  /* Indexes are available only on base or "other" member relations. */
3955  Assert(IS_SIMPLE_REL(rel));
3956 
3957  /*
3958  * Initialize the indrestrictinfo lists to be identical to
3959  * baserestrictinfo, and check whether there are any partial indexes. If
3960  * not, this is all we need to do.
3961  */
3962  have_partial = false;
3963  foreach(lc, rel->indexlist)
3964  {
3966 
3967  index->indrestrictinfo = rel->baserestrictinfo;
3968  if (index->indpred)
3969  have_partial = true;
3970  }
3971  if (!have_partial)
3972  return;
3973 
3974  /*
3975  * Construct a list of clauses that we can assume true for the purpose of
3976  * proving the index(es) usable. Restriction clauses for the rel are
3977  * always usable, and so are any join clauses that are "movable to" this
3978  * rel. Also, we can consider any EC-derivable join clauses (which must
3979  * be "movable to" this rel, by definition).
3980  */
3981  clauselist = list_copy(rel->baserestrictinfo);
3982 
3983  /* Scan the rel's join clauses */
3984  foreach(lc, rel->joininfo)
3985  {
3986  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
3987 
3988  /* Check if clause can be moved to this rel */
3989  if (!join_clause_is_movable_to(rinfo, rel))
3990  continue;
3991 
3992  clauselist = lappend(clauselist, rinfo);
3993  }
3994 
3995  /*
3996  * Add on any equivalence-derivable join clauses. Computing the correct
3997  * relid sets for generate_join_implied_equalities is slightly tricky
3998  * because the rel could be a child rel rather than a true baserel, and in
3999  * that case we must subtract its parents' relid(s) from all_query_rels.
4000  * Additionally, we mustn't consider clauses that are only computable
4001  * after outer joins that can null the rel.
4002  */
4003  if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
4004  otherrels = bms_difference(root->all_query_rels,
4005  find_childrel_parents(root, rel));
4006  else
4007  otherrels = bms_difference(root->all_query_rels, rel->relids);
4008  otherrels = bms_del_members(otherrels, rel->nulling_relids);
4009 
4010  if (!bms_is_empty(otherrels))
4011  clauselist =
4012  list_concat(clauselist,
4014  bms_union(rel->relids,
4015  otherrels),
4016  otherrels,
4017  rel,
4018  NULL));
4019 
4020  /*
4021  * Normally we remove quals that are implied by a partial index's
4022  * predicate from indrestrictinfo, indicating that they need not be
4023  * checked explicitly by an indexscan plan using this index. However, if
4024  * the rel is a target relation of UPDATE/DELETE/MERGE/SELECT FOR UPDATE,
4025  * we cannot remove such quals from the plan, because they need to be in
4026  * the plan so that they will be properly rechecked by EvalPlanQual
4027  * testing. Some day we might want to remove such quals from the main
4028  * plan anyway and pass them through to EvalPlanQual via a side channel;
4029  * but for now, we just don't remove implied quals at all for target
4030  * relations.
4031  */
4032  is_target_rel = (bms_is_member(rel->relid, root->all_result_relids) ||
4033  get_plan_rowmark(root->rowMarks, rel->relid) != NULL);
4034 
4035  /*
4036  * Now try to prove each index predicate true, and compute the
4037  * indrestrictinfo lists for partial indexes. Note that we compute the
4038  * indrestrictinfo list even for non-predOK indexes; this might seem
4039  * wasteful, but we may be able to use such indexes in OR clauses, cf
4040  * generate_bitmap_or_paths().
4041  */
4042  foreach(lc, rel->indexlist)
4043  {
4045  ListCell *lcr;
4046 
4047  if (index->indpred == NIL)
4048  continue; /* ignore non-partial indexes here */
4049 
4050  if (!index->predOK) /* don't repeat work if already proven OK */
4051  index->predOK = predicate_implied_by(index->indpred, clauselist,
4052  false);
4053 
4054  /* If rel is an update target, leave indrestrictinfo as set above */
4055  if (is_target_rel)
4056  continue;
4057 
4058  /* Else compute indrestrictinfo as the non-implied quals */
4059  index->indrestrictinfo = NIL;
4060  foreach(lcr, rel->baserestrictinfo)
4061  {
4062  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcr);
4063 
4064  /* predicate_implied_by() assumes first arg is immutable */
4065  if (contain_mutable_functions((Node *) rinfo->clause) ||
4067  index->indpred, false))
4068  index->indrestrictinfo = lappend(index->indrestrictinfo, rinfo);
4069  }
4070  }
4071 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:346
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161
#define bms_is_empty(a)
Definition: bitmapset.h:118
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:370
List * generate_join_implied_equalities(PlannerInfo *root, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
Definition: equivclass.c:1385
List * list_copy(const List *oldlist)
Definition: list.c:1573
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:839
@ RELOPT_OTHER_MEMBER_REL
Definition: pathnodes.h:829
#define list_make1(x1)
Definition: pg_list.h:212
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:509
Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel)
Definition: relnode.c:1509
bool join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel)
Definition: restrictinfo.c:575
List * baserestrictinfo
Definition: pathnodes.h:985
List * joininfo
Definition: pathnodes.h:991
Relids relids
Definition: pathnodes.h:871
RelOptKind reloptkind
Definition: pathnodes.h:865
Relids nulling_relids
Definition: pathnodes.h:938

References Assert, RelOptInfo::baserestrictinfo, bms_del_members(), bms_difference(), bms_is_empty, bms_is_member(), bms_union(), RestrictInfo::clause, contain_mutable_functions(), find_childrel_parents(), generate_join_implied_equalities(), get_plan_rowmark(), RelOptInfo::indexlist, IS_SIMPLE_REL, join_clause_is_movable_to(), RelOptInfo::joininfo, lappend(), lfirst, list_concat(), list_copy(), list_make1, NIL, RelOptInfo::nulling_relids, predicate_implied_by(), RelOptInfo::relid, RelOptInfo::relids, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, and root.

Referenced by set_plain_rel_size(), and set_tablesample_rel_size().

◆ choose_bitmap_and()

static Path * choose_bitmap_and ( PlannerInfo root,
RelOptInfo rel,
List paths 
)
static

Definition at line 1720 of file indxpath.c.

1721 {
1722  int npaths = list_length(paths);
1723  PathClauseUsage **pathinfoarray;
1724  PathClauseUsage *pathinfo;
1725  List *clauselist;
1726  List *bestpaths = NIL;
1727  Cost bestcost = 0;
1728  int i,
1729  j;
1730  ListCell *l;
1731 
1732  Assert(npaths > 0); /* else caller error */
1733  if (npaths == 1)
1734  return (Path *) linitial(paths); /* easy case */
1735 
1736  /*
1737  * In theory we should consider every nonempty subset of the given paths.
1738  * In practice that seems like overkill, given the crude nature of the
1739  * estimates, not to mention the possible effects of higher-level AND and
1740  * OR clauses. Moreover, it's completely impractical if there are a large
1741  * number of paths, since the work would grow as O(2^N).
1742  *
1743  * As a heuristic, we first check for paths using exactly the same sets of
1744  * WHERE clauses + index predicate conditions, and reject all but the
1745  * cheapest-to-scan in any such group. This primarily gets rid of indexes
1746  * that include the interesting columns but also irrelevant columns. (In
1747  * situations where the DBA has gone overboard on creating variant
1748  * indexes, this can make for a very large reduction in the number of
1749  * paths considered further.)
1750  *
1751  * We then sort the surviving paths with the cheapest-to-scan first, and
1752  * for each path, consider using that path alone as the basis for a bitmap
1753  * scan. Then we consider bitmap AND scans formed from that path plus
1754  * each subsequent (higher-cost) path, adding on a subsequent path if it
1755  * results in a reduction in the estimated total scan cost. This means we
1756  * consider about O(N^2) rather than O(2^N) path combinations, which is
1757  * quite tolerable, especially given than N is usually reasonably small
1758  * because of the prefiltering step. The cheapest of these is returned.
1759  *
1760  * We will only consider AND combinations in which no two indexes use the
1761  * same WHERE clause. This is a bit of a kluge: it's needed because
1762  * costsize.c and clausesel.c aren't very smart about redundant clauses.
1763  * They will usually double-count the redundant clauses, producing a
1764  * too-small selectivity that makes a redundant AND step look like it
1765  * reduces the total cost. Perhaps someday that code will be smarter and
1766  * we can remove this limitation. (But note that this also defends
1767  * against flat-out duplicate input paths, which can happen because
1768  * match_join_clauses_to_index will find the same OR join clauses that
1769  * extract_restriction_or_clauses has pulled OR restriction clauses out
1770  * of.)
1771  *
1772  * For the same reason, we reject AND combinations in which an index
1773  * predicate clause duplicates another clause. Here we find it necessary
1774  * to be even stricter: we'll reject a partial index if any of its
1775  * predicate clauses are implied by the set of WHERE clauses and predicate
1776  * clauses used so far. This covers cases such as a condition "x = 42"
1777  * used with a plain index, followed by a clauseless scan of a partial
1778  * index "WHERE x >= 40 AND x < 50". The partial index has been accepted
1779  * only because "x = 42" was present, and so allowing it would partially
1780  * double-count selectivity. (We could use predicate_implied_by on
1781  * regular qual clauses too, to have a more intelligent, but much more
1782  * expensive, check for redundancy --- but in most cases simple equality
1783  * seems to suffice.)
1784  */
1785 
1786  /*
1787  * Extract clause usage info and detect any paths that use exactly the
1788  * same set of clauses; keep only the cheapest-to-scan of any such groups.
1789  * The surviving paths are put into an array for qsort'ing.
1790  */
1791  pathinfoarray = (PathClauseUsage **)
1792  palloc(npaths * sizeof(PathClauseUsage *));
1793  clauselist = NIL;
1794  npaths = 0;
1795  foreach(l, paths)
1796  {
1797  Path *ipath = (Path *) lfirst(l);
1798 
1799  pathinfo = classify_index_clause_usage(ipath, &clauselist);
1800 
1801  /* If it's unclassifiable, treat it as distinct from all others */
1802  if (pathinfo->unclassifiable)
1803  {
1804  pathinfoarray[npaths++] = pathinfo;
1805  continue;
1806  }
1807 
1808  for (i = 0; i < npaths; i++)
1809  {
1810  if (!pathinfoarray[i]->unclassifiable &&
1811  bms_equal(pathinfo->clauseids, pathinfoarray[i]->clauseids))
1812  break;
1813  }
1814  if (i < npaths)
1815  {
1816  /* duplicate clauseids, keep the cheaper one */
1817  Cost ncost;
1818  Cost ocost;
1819  Selectivity nselec;
1820  Selectivity oselec;
1821 
1822  cost_bitmap_tree_node(pathinfo->path, &ncost, &nselec);
1823  cost_bitmap_tree_node(pathinfoarray[i]->path, &ocost, &oselec);
1824  if (ncost < ocost)
1825  pathinfoarray[i] = pathinfo;
1826  }
1827  else
1828  {
1829  /* not duplicate clauseids, add to array */
1830  pathinfoarray[npaths++] = pathinfo;
1831  }
1832  }
1833 
1834  /* If only one surviving path, we're done */
1835  if (npaths == 1)
1836  return pathinfoarray[0]->path;
1837 
1838  /* Sort the surviving paths by index access cost */
1839  qsort(pathinfoarray, npaths, sizeof(PathClauseUsage *),
1841 
1842  /*
1843  * For each surviving index, consider it as an "AND group leader", and see
1844  * whether adding on any of the later indexes results in an AND path with
1845  * cheaper total cost than before. Then take the cheapest AND group.
1846  *
1847  * Note: paths that are either clauseless or unclassifiable will have
1848  * empty clauseids, so that they will not be rejected by the clauseids
1849  * filter here, nor will they cause later paths to be rejected by it.
1850  */
1851  for (i = 0; i < npaths; i++)
1852  {
1853  Cost costsofar;
1854  List *qualsofar;
1855  Bitmapset *clauseidsofar;
1856 
1857  pathinfo = pathinfoarray[i];
1858  paths = list_make1(pathinfo->path);
1859  costsofar = bitmap_scan_cost_est(root, rel, pathinfo->path);
1860  qualsofar = list_concat_copy(pathinfo->quals, pathinfo->preds);
1861  clauseidsofar = bms_copy(pathinfo->clauseids);
1862 
1863  for (j = i + 1; j < npaths; j++)
1864  {
1865  Cost newcost;
1866 
1867  pathinfo = pathinfoarray[j];
1868  /* Check for redundancy */
1869  if (bms_overlap(pathinfo->clauseids, clauseidsofar))
1870  continue; /* consider it redundant */
1871  if (pathinfo->preds)
1872  {
1873  bool redundant = false;
1874 
1875  /* we check each predicate clause separately */
1876  foreach(l, pathinfo->preds)
1877  {
1878  Node *np = (Node *) lfirst(l);
1879 
1880  if (predicate_implied_by(list_make1(np), qualsofar, false))
1881  {
1882  redundant = true;
1883  break; /* out of inner foreach loop */
1884  }
1885  }
1886  if (redundant)
1887  continue;
1888  }
1889  /* tentatively add new path to paths, so we can estimate cost */
1890  paths = lappend(paths, pathinfo->path);
1891  newcost = bitmap_and_cost_est(root, rel, paths);
1892  if (newcost < costsofar)
1893  {
1894  /* keep new path in paths, update subsidiary variables */
1895  costsofar = newcost;
1896  qualsofar = list_concat(qualsofar, pathinfo->quals);
1897  qualsofar = list_concat(qualsofar, pathinfo->preds);
1898  clauseidsofar = bms_add_members(clauseidsofar,
1899  pathinfo->clauseids);
1900  }
1901  else
1902  {
1903  /* reject new path, remove it from paths list */
1904  paths = list_truncate(paths, list_length(paths) - 1);
1905  }
1906  }
1907 
1908  /* Keep the cheapest AND-group (or singleton) */
1909  if (i == 0 || costsofar < bestcost)
1910  {
1911  bestpaths = paths;
1912  bestcost = costsofar;
1913  }
1914 
1915  /* some easy cleanup (we don't try real hard though) */
1916  list_free(qualsofar);
1917  }
1918 
1919  if (list_length(bestpaths) == 1)
1920  return (Path *) linitial(bestpaths); /* no need for AND */
1921  return (Path *) create_bitmap_and_path(root, rel, bestpaths);
1922 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
Definition: costsize.c:1122
static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
Definition: indxpath.c:1993
static PathClauseUsage * classify_index_clause_usage(Path *path, List **clauselist)
Definition: indxpath.c:2022
static int path_usage_comparator(const void *a, const void *b)
Definition: indxpath.c:1926
int j
Definition: isn.c:73
List * list_truncate(List *list, int new_size)
Definition: list.c:631
void list_free(List *list)
Definition: list.c:1546
void * palloc(Size size)
Definition: mcxt.c:1317
double Cost
Definition: nodes.h:251
double Selectivity
Definition: nodes.h:250
#define linitial(l)
Definition: pg_list.h:178
#define qsort(a, b, c, d)
Definition: port.h:447
List * quals
Definition: indxpath.c:66
List * preds
Definition: indxpath.c:67
Bitmapset * clauseids
Definition: indxpath.c:68
bool unclassifiable
Definition: indxpath.c:69
Path * path
Definition: indxpath.c:65

References Assert, bitmap_and_cost_est(), bitmap_scan_cost_est(), bms_add_members(), bms_copy(), bms_equal(), bms_overlap(), classify_index_clause_usage(), PathClauseUsage::clauseids, cost_bitmap_tree_node(), create_bitmap_and_path(), i, j, lappend(), lfirst, linitial, list_concat(), list_concat_copy(), list_free(), list_length(), list_make1, list_truncate(), NIL, palloc(), PathClauseUsage::path, path_usage_comparator(), predicate_implied_by(), PathClauseUsage::preds, qsort, PathClauseUsage::quals, root, and PathClauseUsage::unclassifiable.

Referenced by create_index_paths(), generate_bitmap_or_paths(), and make_bitmap_paths_for_or_group().

◆ classify_index_clause_usage()

static PathClauseUsage * classify_index_clause_usage ( Path path,
List **  clauselist 
)
static

Definition at line 2022 of file indxpath.c.

2023 {
2024  PathClauseUsage *result;
2025  Bitmapset *clauseids;
2026  ListCell *lc;
2027 
2028  result = (PathClauseUsage *) palloc(sizeof(PathClauseUsage));
2029  result->path = path;
2030 
2031  /* Recursively find the quals and preds used by the path */
2032  result->quals = NIL;
2033  result->preds = NIL;
2034  find_indexpath_quals(path, &result->quals, &result->preds);
2035 
2036  /*
2037  * Some machine-generated queries have outlandish numbers of qual clauses.
2038  * To avoid getting into O(N^2) behavior even in this preliminary
2039  * classification step, we want to limit the number of entries we can
2040  * accumulate in *clauselist. Treat any path with more than 100 quals +
2041  * preds as unclassifiable, which will cause calling code to consider it
2042  * distinct from all other paths.
2043  */
2044  if (list_length(result->quals) + list_length(result->preds) > 100)
2045  {
2046  result->clauseids = NULL;
2047  result->unclassifiable = true;
2048  return result;
2049  }
2050 
2051  /* Build up a bitmapset representing the quals and preds */
2052  clauseids = NULL;
2053  foreach(lc, result->quals)
2054  {
2055  Node *node = (Node *) lfirst(lc);
2056 
2057  clauseids = bms_add_member(clauseids,
2058  find_list_position(node, clauselist));
2059  }
2060  foreach(lc, result->preds)
2061  {
2062  Node *node = (Node *) lfirst(lc);
2063 
2064  clauseids = bms_add_member(clauseids,
2065  find_list_position(node, clauselist));
2066  }
2067  result->clauseids = clauseids;
2068  result->unclassifiable = false;
2069 
2070  return result;
2071 }
static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds)
Definition: indxpath.c:2090
static int find_list_position(Node *node, List **nodelist)
Definition: indxpath.c:2137

References bms_add_member(), PathClauseUsage::clauseids, find_indexpath_quals(), find_list_position(), lfirst, list_length(), NIL, palloc(), PathClauseUsage::path, PathClauseUsage::preds, PathClauseUsage::quals, and PathClauseUsage::unclassifiable.

Referenced by choose_bitmap_and().

◆ consider_index_join_clauses()

static void consider_index_join_clauses ( PlannerInfo root,
RelOptInfo rel,
IndexOptInfo index,
IndexClauseSet rclauseset,
IndexClauseSet jclauseset,
IndexClauseSet eclauseset,
List **  bitindexpaths 
)
static

Definition at line 438 of file indxpath.c.

444 {
445  int considered_clauses = 0;
446  List *considered_relids = NIL;
447  int indexcol;
448 
449  /*
450  * The strategy here is to identify every potentially useful set of outer
451  * rels that can provide indexable join clauses. For each such set,
452  * select all the join clauses available from those outer rels, add on all
453  * the indexable restriction clauses, and generate plain and/or bitmap
454  * index paths for that set of clauses. This is based on the assumption
455  * that it's always better to apply a clause as an indexqual than as a
456  * filter (qpqual); which is where an available clause would end up being
457  * applied if we omit it from the indexquals.
458  *
459  * This looks expensive, but in most practical cases there won't be very
460  * many distinct sets of outer rels to consider. As a safety valve when
461  * that's not true, we use a heuristic: limit the number of outer rel sets
462  * considered to a multiple of the number of clauses considered. (We'll
463  * always consider using each individual join clause, though.)
464  *
465  * For simplicity in selecting relevant clauses, we represent each set of
466  * outer rels as a maximum set of clause_relids --- that is, the indexed
467  * relation itself is also included in the relids set. considered_relids
468  * lists all relids sets we've already tried.
469  */
470  for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
471  {
472  /* Consider each applicable simple join clause */
473  considered_clauses += list_length(jclauseset->indexclauses[indexcol]);
475  rclauseset, jclauseset, eclauseset,
476  bitindexpaths,
477  jclauseset->indexclauses[indexcol],
478  considered_clauses,
479  &considered_relids);
480  /* Consider each applicable eclass join clause */
481  considered_clauses += list_length(eclauseset->indexclauses[indexcol]);
483  rclauseset, jclauseset, eclauseset,
484  bitindexpaths,
485  eclauseset->indexclauses[indexcol],
486  considered_clauses,
487  &considered_relids);
488  }
489 }
static void consider_index_join_outer_rels(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *rclauseset, IndexClauseSet *jclauseset, IndexClauseSet *eclauseset, List **bitindexpaths, List *indexjoinclauses, int considered_clauses, List **considered_relids)
Definition: indxpath.c:504

References consider_index_join_outer_rels(), IndexClauseSet::indexclauses, list_length(), NIL, and root.

Referenced by create_index_paths().

◆ consider_index_join_outer_rels()

static void consider_index_join_outer_rels ( PlannerInfo root,
RelOptInfo rel,
IndexOptInfo index,
IndexClauseSet rclauseset,
IndexClauseSet jclauseset,
IndexClauseSet eclauseset,
List **  bitindexpaths,
List indexjoinclauses,
int  considered_clauses,
List **  considered_relids 
)
static

Definition at line 504 of file indxpath.c.

513 {
514  ListCell *lc;
515 
516  /* Examine relids of each joinclause in the given list */
517  foreach(lc, indexjoinclauses)
518  {
519  IndexClause *iclause = (IndexClause *) lfirst(lc);
520  Relids clause_relids = iclause->rinfo->clause_relids;
521  EquivalenceClass *parent_ec = iclause->rinfo->parent_ec;
522  int num_considered_relids;
523 
524  /* If we already tried its relids set, no need to do so again */
525  if (list_member(*considered_relids, clause_relids))
526  continue;
527 
528  /*
529  * Generate the union of this clause's relids set with each
530  * previously-tried set. This ensures we try this clause along with
531  * every interesting subset of previous clauses. However, to avoid
532  * exponential growth of planning time when there are many clauses,
533  * limit the number of relid sets accepted to 10 * considered_clauses.
534  *
535  * Note: get_join_index_paths appends entries to *considered_relids,
536  * but we do not need to visit such newly-added entries within this
537  * loop, so we don't use foreach() here. No real harm would be done
538  * if we did visit them, since the subset check would reject them; but
539  * it would waste some cycles.
540  */
541  num_considered_relids = list_length(*considered_relids);
542  for (int pos = 0; pos < num_considered_relids; pos++)
543  {
544  Relids oldrelids = (Relids) list_nth(*considered_relids, pos);
545 
546  /*
547  * If either is a subset of the other, no new set is possible.
548  * This isn't a complete test for redundancy, but it's easy and
549  * cheap. get_join_index_paths will check more carefully if we
550  * already generated the same relids set.
551  */
552  if (bms_subset_compare(clause_relids, oldrelids) != BMS_DIFFERENT)
553  continue;
554 
555  /*
556  * If this clause was derived from an equivalence class, the
557  * clause list may contain other clauses derived from the same
558  * eclass. We should not consider that combining this clause with
559  * one of those clauses generates a usefully different
560  * parameterization; so skip if any clause derived from the same
561  * eclass would already have been included when using oldrelids.
562  */
563  if (parent_ec &&
564  eclass_already_used(parent_ec, oldrelids,
565  indexjoinclauses))
566  continue;
567 
568  /*
569  * If the number of relid sets considered exceeds our heuristic
570  * limit, stop considering combinations of clauses. We'll still
571  * consider the current clause alone, though (below this loop).
572  */
573  if (list_length(*considered_relids) >= 10 * considered_clauses)
574  break;
575 
576  /* OK, try the union set */
578  rclauseset, jclauseset, eclauseset,
579  bitindexpaths,
580  bms_union(clause_relids, oldrelids),
581  considered_relids);
582  }
583 
584  /* Also try this set of relids by itself */
586  rclauseset, jclauseset, eclauseset,
587  bitindexpaths,
588  clause_relids,
589  considered_relids);
590  }
591 }
BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:445
@ BMS_DIFFERENT
Definition: bitmapset.h:65
static void get_join_index_paths(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *rclauseset, IndexClauseSet *jclauseset, IndexClauseSet *eclauseset, List **bitindexpaths, Relids relids, List **considered_relids)
Definition: indxpath.c:607
static bool eclass_already_used(EquivalenceClass *parent_ec, Relids oldrelids, List *indexjoinclauses)
Definition: indxpath.c:685
bool list_member(const List *list, const void *datum)
Definition: list.c:661
Bitmapset * Relids
Definition: pathnodes.h:30
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299

References BMS_DIFFERENT, bms_subset_compare(), bms_union(), eclass_already_used(), get_join_index_paths(), lfirst, list_length(), list_member(), list_nth(), IndexClause::rinfo, and root.

Referenced by consider_index_join_clauses().

◆ create_index_paths()

void create_index_paths ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 241 of file indxpath.c.

242 {
243  List *indexpaths;
244  List *bitindexpaths;
245  List *bitjoinpaths;
246  List *joinorclauses;
247  IndexClauseSet rclauseset;
248  IndexClauseSet jclauseset;
249  IndexClauseSet eclauseset;
250  ListCell *lc;
251 
252  /* Skip the whole mess if no indexes */
253  if (rel->indexlist == NIL)
254  return;
255 
256  /* Bitmap paths are collected and then dealt with at the end */
257  bitindexpaths = bitjoinpaths = joinorclauses = NIL;
258 
259  /* Examine each index in turn */
260  foreach(lc, rel->indexlist)
261  {
263 
264  /* Protect limited-size array in IndexClauseSets */
265  Assert(index->nkeycolumns <= INDEX_MAX_KEYS);
266 
267  /*
268  * Ignore partial indexes that do not match the query.
269  * (generate_bitmap_or_paths() might be able to do something with
270  * them, but that's of no concern here.)
271  */
272  if (index->indpred != NIL && !index->predOK)
273  continue;
274 
275  /*
276  * Identify the restriction clauses that can match the index.
277  */
278  MemSet(&rclauseset, 0, sizeof(rclauseset));
280 
281  /*
282  * Build index paths from the restriction clauses. These will be
283  * non-parameterized paths. Plain paths go directly to add_path(),
284  * bitmap paths are added to bitindexpaths to be handled below.
285  */
286  get_index_paths(root, rel, index, &rclauseset,
287  &bitindexpaths);
288 
289  /*
290  * Identify the join clauses that can match the index. For the moment
291  * we keep them separate from the restriction clauses. Note that this
292  * step finds only "loose" join clauses that have not been merged into
293  * EquivalenceClasses. Also, collect join OR clauses for later.
294  */
295  MemSet(&jclauseset, 0, sizeof(jclauseset));
297  &jclauseset, &joinorclauses);
298 
299  /*
300  * Look for EquivalenceClasses that can generate joinclauses matching
301  * the index.
302  */
303  MemSet(&eclauseset, 0, sizeof(eclauseset));
305  &eclauseset);
306 
307  /*
308  * If we found any plain or eclass join clauses, build parameterized
309  * index paths using them.
310  */
311  if (jclauseset.nonempty || eclauseset.nonempty)
313  &rclauseset,
314  &jclauseset,
315  &eclauseset,
316  &bitjoinpaths);
317  }
318 
319  /*
320  * Generate BitmapOrPaths for any suitable OR-clauses present in the
321  * restriction list. Add these to bitindexpaths.
322  */
323  indexpaths = generate_bitmap_or_paths(root, rel,
324  rel->baserestrictinfo, NIL);
325  bitindexpaths = list_concat(bitindexpaths, indexpaths);
326 
327  /*
328  * Likewise, generate BitmapOrPaths for any suitable OR-clauses present in
329  * the joinclause list. Add these to bitjoinpaths.
330  */
331  indexpaths = generate_bitmap_or_paths(root, rel,
332  joinorclauses, rel->baserestrictinfo);
333  bitjoinpaths = list_concat(bitjoinpaths, indexpaths);
334 
335  /*
336  * If we found anything usable, generate a BitmapHeapPath for the most
337  * promising combination of restriction bitmap index paths. Note there
338  * will be only one such path no matter how many indexes exist. This
339  * should be sufficient since there's basically only one figure of merit
340  * (total cost) for such a path.
341  */
342  if (bitindexpaths != NIL)
343  {
344  Path *bitmapqual;
345  BitmapHeapPath *bpath;
346 
347  bitmapqual = choose_bitmap_and(root, rel, bitindexpaths);
348  bpath = create_bitmap_heap_path(root, rel, bitmapqual,
349  rel->lateral_relids, 1.0, 0);
350  add_path(rel, (Path *) bpath);
351 
352  /* create a partial bitmap heap path */
353  if (rel->consider_parallel && rel->lateral_relids == NULL)
354  create_partial_bitmap_paths(root, rel, bitmapqual);
355  }
356 
357  /*
358  * Likewise, if we found anything usable, generate BitmapHeapPaths for the
359  * most promising combinations of join bitmap index paths. Our strategy
360  * is to generate one such path for each distinct parameterization seen
361  * among the available bitmap index paths. This may look pretty
362  * expensive, but usually there won't be very many distinct
363  * parameterizations. (This logic is quite similar to that in
364  * consider_index_join_clauses, but we're working with whole paths not
365  * individual clauses.)
366  */
367  if (bitjoinpaths != NIL)
368  {
369  List *all_path_outers;
370 
371  /* Identify each distinct parameterization seen in bitjoinpaths */
372  all_path_outers = NIL;
373  foreach(lc, bitjoinpaths)
374  {
375  Path *path = (Path *) lfirst(lc);
376  Relids required_outer = PATH_REQ_OUTER(path);
377 
378  all_path_outers = list_append_unique(all_path_outers,
379  required_outer);
380  }
381 
382  /* Now, for each distinct parameterization set ... */
383  foreach(lc, all_path_outers)
384  {
385  Relids max_outers = (Relids) lfirst(lc);
386  List *this_path_set;
387  Path *bitmapqual;
388  Relids required_outer;
389  double loop_count;
390  BitmapHeapPath *bpath;
391  ListCell *lcp;
392 
393  /* Identify all the bitmap join paths needing no more than that */
394  this_path_set = NIL;
395  foreach(lcp, bitjoinpaths)
396  {
397  Path *path = (Path *) lfirst(lcp);
398 
399  if (bms_is_subset(PATH_REQ_OUTER(path), max_outers))
400  this_path_set = lappend(this_path_set, path);
401  }
402 
403  /*
404  * Add in restriction bitmap paths, since they can be used
405  * together with any join paths.
406  */
407  this_path_set = list_concat(this_path_set, bitindexpaths);
408 
409  /* Select best AND combination for this parameterization */
410  bitmapqual = choose_bitmap_and(root, rel, this_path_set);
411 
412  /* And push that path into the mix */
413  required_outer = PATH_REQ_OUTER(bitmapqual);
414  loop_count = get_loop_count(root, rel->relid, required_outer);
415  bpath = create_bitmap_heap_path(root, rel, bitmapqual,
416  required_outer, loop_count, 0);
417  add_path(rel, (Path *) bpath);
418  }
419  }
420 }
void create_partial_bitmap_paths(PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual)
Definition: allpaths.c:4178
static Path * choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
Definition: indxpath.c:1720
static void match_join_clauses_to_index(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *clauseset, List **joinorclauses)
Definition: indxpath.c:2416
static void match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index, IndexClauseSet *clauseset)
Definition: indxpath.c:2446
static void get_index_paths(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *clauses, List **bitindexpaths)
Definition: indxpath.c:717
static void consider_index_join_clauses(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, IndexClauseSet *rclauseset, IndexClauseSet *jclauseset, IndexClauseSet *eclauseset, List **bitindexpaths)
Definition: indxpath.c:438
static void match_restriction_clauses_to_index(PlannerInfo *root, IndexOptInfo *index, IndexClauseSet *clauseset)
Definition: indxpath.c:2401
static List * generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel, List *clauses, List *other_clauses)
Definition: indxpath.c:1564
List * list_append_unique(List *list, void *datum)
Definition: list.c:1343
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:461
BitmapHeapPath * create_bitmap_heap_path(PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
Definition: pathnode.c:1098
#define INDEX_MAX_KEYS

References add_path(), Assert, RelOptInfo::baserestrictinfo, bms_is_subset(), choose_bitmap_and(), consider_index_join_clauses(), RelOptInfo::consider_parallel, create_bitmap_heap_path(), create_partial_bitmap_paths(), generate_bitmap_or_paths(), get_index_paths(), get_loop_count(), INDEX_MAX_KEYS, RelOptInfo::indexlist, lappend(), RelOptInfo::lateral_relids, lfirst, list_append_unique(), list_concat(), match_eclass_clauses_to_index(), match_join_clauses_to_index(), match_restriction_clauses_to_index(), MemSet, NIL, IndexClauseSet::nonempty, PATH_REQ_OUTER, RelOptInfo::relid, and root.

Referenced by set_plain_rel_pathlist().

◆ ec_member_matches_indexcol()

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

Definition at line 4084 of file indxpath.c.

4087 {
4088  IndexOptInfo *index = ((ec_member_matches_arg *) arg)->index;
4089  int indexcol = ((ec_member_matches_arg *) arg)->indexcol;
4090  Oid curFamily;
4091  Oid curCollation;
4092 
4093  Assert(indexcol < index->nkeycolumns);
4094 
4095  curFamily = index->opfamily[indexcol];
4096  curCollation = index->indexcollations[indexcol];
4097 
4098  /*
4099  * If it's a btree index, we can reject it if its opfamily isn't
4100  * compatible with the EC, since no clause generated from the EC could be
4101  * used with the index. For non-btree indexes, we can't easily tell
4102  * whether clauses generated from the EC could be used with the index, so
4103  * don't check the opfamily. This might mean we return "true" for a
4104  * useless EC, so we have to recheck the results of
4105  * generate_implied_equalities_for_column; see
4106  * match_eclass_clauses_to_index.
4107  */
4108  if (index->relam == BTREE_AM_OID &&
4109  !list_member_oid(ec->ec_opfamilies, curFamily))
4110  return false;
4111 
4112  /* We insist on collation match for all index types, though */
4113  if (!IndexCollMatchesExprColl(curCollation, ec->ec_collation))
4114  return false;
4115 
4116  return match_index_to_operand((Node *) em->em_expr, indexcol, index);
4117 }
#define IndexCollMatchesExprColl(idxcollation, exprcollation)
Definition: indxpath.c:43
bool match_index_to_operand(Node *operand, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:4367
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
void * arg
unsigned int Oid
Definition: postgres_ext.h:31
List * ec_opfamilies
Definition: pathnodes.h:1392

References arg, Assert, EquivalenceClass::ec_collation, EquivalenceClass::ec_opfamilies, EquivalenceMember::em_expr, IndexCollMatchesExprColl, list_member_oid(), and match_index_to_operand().

Referenced by match_eclass_clauses_to_index().

◆ eclass_already_used()

static bool eclass_already_used ( EquivalenceClass parent_ec,
Relids  oldrelids,
List indexjoinclauses 
)
static

Definition at line 685 of file indxpath.c.

687 {
688  ListCell *lc;
689 
690  foreach(lc, indexjoinclauses)
691  {
692  IndexClause *iclause = (IndexClause *) lfirst(lc);
693  RestrictInfo *rinfo = iclause->rinfo;
694 
695  if (rinfo->parent_ec == parent_ec &&
696  bms_is_subset(rinfo->clause_relids, oldrelids))
697  return true;
698  }
699  return false;
700 }

References bms_is_subset(), lfirst, and IndexClause::rinfo.

Referenced by consider_index_join_outer_rels().

◆ expand_indexqual_rowcompare()

static IndexClause * expand_indexqual_rowcompare ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index,
Oid  expr_op,
bool  var_on_left 
)
static

Definition at line 3500 of file indxpath.c.

3506 {
3507  IndexClause *iclause = makeNode(IndexClause);
3508  RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
3509  int op_strategy;
3510  Oid op_lefttype;
3511  Oid op_righttype;
3512  int matching_cols;
3513  List *expr_ops;
3514  List *opfamilies;
3515  List *lefttypes;
3516  List *righttypes;
3517  List *new_ops;
3518  List *var_args;
3519  List *non_var_args;
3520 
3521  iclause->rinfo = rinfo;
3522  iclause->indexcol = indexcol;
3523 
3524  if (var_on_left)
3525  {
3526  var_args = clause->largs;
3527  non_var_args = clause->rargs;
3528  }
3529  else
3530  {
3531  var_args = clause->rargs;
3532  non_var_args = clause->largs;
3533  }
3534 
3535  get_op_opfamily_properties(expr_op, index->opfamily[indexcol], false,
3536  &op_strategy,
3537  &op_lefttype,
3538  &op_righttype);
3539 
3540  /* Initialize returned list of which index columns are used */
3541  iclause->indexcols = list_make1_int(indexcol);
3542 
3543  /* Build lists of ops, opfamilies and operator datatypes in case needed */
3544  expr_ops = list_make1_oid(expr_op);
3545  opfamilies = list_make1_oid(index->opfamily[indexcol]);
3546  lefttypes = list_make1_oid(op_lefttype);
3547  righttypes = list_make1_oid(op_righttype);
3548 
3549  /*
3550  * See how many of the remaining columns match some index column in the
3551  * same way. As in match_clause_to_indexcol(), the "other" side of any
3552  * potential index condition is OK as long as it doesn't use Vars from the
3553  * indexed relation.
3554  */
3555  matching_cols = 1;
3556 
3557  while (matching_cols < list_length(var_args))
3558  {
3559  Node *varop = (Node *) list_nth(var_args, matching_cols);
3560  Node *constop = (Node *) list_nth(non_var_args, matching_cols);
3561  int i;
3562 
3563  expr_op = list_nth_oid(clause->opnos, matching_cols);
3564  if (!var_on_left)
3565  {
3566  /* indexkey is on right, so commute the operator */
3567  expr_op = get_commutator(expr_op);
3568  if (expr_op == InvalidOid)
3569  break; /* operator is not usable */
3570  }
3571  if (bms_is_member(index->rel->relid, pull_varnos(root, constop)))
3572  break; /* no good, Var on wrong side */
3573  if (contain_volatile_functions(constop))
3574  break; /* no good, volatile comparison value */
3575 
3576  /*
3577  * The Var side can match any key column of the index.
3578  */
3579  for (i = 0; i < index->nkeycolumns; i++)
3580  {
3581  if (match_index_to_operand(varop, i, index) &&
3582  get_op_opfamily_strategy(expr_op,
3583  index->opfamily[i]) == op_strategy &&
3584  IndexCollMatchesExprColl(index->indexcollations[i],
3585  list_nth_oid(clause->inputcollids,
3586  matching_cols)))
3587  break;
3588  }
3589  if (i >= index->nkeycolumns)
3590  break; /* no match found */
3591 
3592  /* Add column number to returned list */
3593  iclause->indexcols = lappend_int(iclause->indexcols, i);
3594 
3595  /* Add operator info to lists */
3596  get_op_opfamily_properties(expr_op, index->opfamily[i], false,
3597  &op_strategy,
3598  &op_lefttype,
3599  &op_righttype);
3600  expr_ops = lappend_oid(expr_ops, expr_op);
3601  opfamilies = lappend_oid(opfamilies, index->opfamily[i]);
3602  lefttypes = lappend_oid(lefttypes, op_lefttype);
3603  righttypes = lappend_oid(righttypes, op_righttype);
3604 
3605  /* This column matches, keep scanning */
3606  matching_cols++;
3607  }
3608 
3609  /* Result is non-lossy if all columns are usable as index quals */
3610  iclause->lossy = (matching_cols != list_length(clause->opnos));
3611 
3612  /*
3613  * We can use rinfo->clause as-is if we have var on left and it's all
3614  * usable as index quals.
3615  */
3616  if (var_on_left && !iclause->lossy)
3617  iclause->indexquals = list_make1(rinfo);
3618  else
3619  {
3620  /*
3621  * We have to generate a modified rowcompare (possibly just one
3622  * OpExpr). The painful part of this is changing < to <= or > to >=,
3623  * so deal with that first.
3624  */
3625  if (!iclause->lossy)
3626  {
3627  /* very easy, just use the commuted operators */
3628  new_ops = expr_ops;
3629  }
3630  else if (op_strategy == BTLessEqualStrategyNumber ||
3631  op_strategy == BTGreaterEqualStrategyNumber)
3632  {
3633  /* easy, just use the same (possibly commuted) operators */
3634  new_ops = list_truncate(expr_ops, matching_cols);
3635  }
3636  else
3637  {
3638  ListCell *opfamilies_cell;
3639  ListCell *lefttypes_cell;
3640  ListCell *righttypes_cell;
3641 
3642  if (op_strategy == BTLessStrategyNumber)
3643  op_strategy = BTLessEqualStrategyNumber;
3644  else if (op_strategy == BTGreaterStrategyNumber)
3645  op_strategy = BTGreaterEqualStrategyNumber;
3646  else
3647  elog(ERROR, "unexpected strategy number %d", op_strategy);
3648  new_ops = NIL;
3649  forthree(opfamilies_cell, opfamilies,
3650  lefttypes_cell, lefttypes,
3651  righttypes_cell, righttypes)
3652  {
3653  Oid opfam = lfirst_oid(opfamilies_cell);
3654  Oid lefttype = lfirst_oid(lefttypes_cell);
3655  Oid righttype = lfirst_oid(righttypes_cell);
3656 
3657  expr_op = get_opfamily_member(opfam, lefttype, righttype,
3658  op_strategy);
3659  if (!OidIsValid(expr_op)) /* should not happen */
3660  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
3661  op_strategy, lefttype, righttype, opfam);
3662  new_ops = lappend_oid(new_ops, expr_op);
3663  }
3664  }
3665 
3666  /* If we have more than one matching col, create a subset rowcompare */
3667  if (matching_cols > 1)
3668  {
3670 
3671  rc->rctype = (RowCompareType) op_strategy;
3672  rc->opnos = new_ops;
3673  rc->opfamilies = list_copy_head(clause->opfamilies,
3674  matching_cols);
3675  rc->inputcollids = list_copy_head(clause->inputcollids,
3676  matching_cols);
3677  rc->largs = list_copy_head(var_args, matching_cols);
3678  rc->rargs = list_copy_head(non_var_args, matching_cols);
3680  (Expr *) rc));
3681  }
3682  else
3683  {
3684  Expr *op;
3685 
3686  /* We don't report an index column list in this case */
3687  iclause->indexcols = NIL;
3688 
3689  op = make_opclause(linitial_oid(new_ops), BOOLOID, false,
3690  copyObject(linitial(var_args)),
3691  copyObject(linitial(non_var_args)),
3692  InvalidOid,
3693  linitial_oid(clause->inputcollids));
3695  }
3696  }
3697 
3698  return iclause;
3699 }
#define OidIsValid(objectId)
Definition: c.h:780
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:136
int get_op_opfamily_strategy(Oid opno, Oid opfamily)
Definition: lsyscache.c:83
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
Oid get_commutator(Oid opno)
Definition: lsyscache.c:1509
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: makefuncs.c:651
#define copyObject(obj)
Definition: nodes.h:224
#define makeNode(_type_)
Definition: nodes.h:155
static Oid list_nth_oid(const List *list, int n)
Definition: pg_list.h:321
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:563
#define list_make1_int(x1)
Definition: pg_list.h:227
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define InvalidOid
Definition: postgres_ext.h:36
RowCompareType
Definition: primnodes.h:1453
#define make_simple_restrictinfo(root, clause)
Definition: restrictinfo.h:21
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
AttrNumber indexcol
Definition: pathnodes.h:1771
List * indexcols
Definition: pathnodes.h:1772
List * indexquals
Definition: pathnodes.h:1769
RowCompareType rctype
Definition: primnodes.h:1468
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:113

References bms_is_member(), BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, RestrictInfo::clause, contain_volatile_functions(), copyObject, elog, ERROR, forthree, get_commutator(), get_op_opfamily_properties(), get_op_opfamily_strategy(), get_opfamily_member(), i, if(), IndexClause::indexcol, IndexCollMatchesExprColl, IndexClause::indexcols, IndexClause::indexquals, InvalidOid, lappend_int(), lappend_oid(), RowCompareExpr::largs, lfirst_oid, linitial, linitial_oid, list_copy_head(), list_length(), list_make1, list_make1_int, list_make1_oid, list_nth(), list_nth_oid(), list_truncate(), IndexClause::lossy, make_opclause(), make_simple_restrictinfo, makeNode, match_index_to_operand(), NIL, OidIsValid, pull_varnos(), RowCompareExpr::rargs, RowCompareExpr::rctype, IndexClause::rinfo, and root.

Referenced by match_rowcompare_to_indexcol().

◆ find_indexpath_quals()

static void find_indexpath_quals ( Path bitmapqual,
List **  quals,
List **  preds 
)
static

Definition at line 2090 of file indxpath.c.

2091 {
2092  if (IsA(bitmapqual, BitmapAndPath))
2093  {
2094  BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
2095  ListCell *l;
2096 
2097  foreach(l, apath->bitmapquals)
2098  {
2099  find_indexpath_quals((Path *) lfirst(l), quals, preds);
2100  }
2101  }
2102  else if (IsA(bitmapqual, BitmapOrPath))
2103  {
2104  BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
2105  ListCell *l;
2106 
2107  foreach(l, opath->bitmapquals)
2108  {
2109  find_indexpath_quals((Path *) lfirst(l), quals, preds);
2110  }
2111  }
2112  else if (IsA(bitmapqual, IndexPath))
2113  {
2114  IndexPath *ipath = (IndexPath *) bitmapqual;
2115  ListCell *l;
2116 
2117  foreach(l, ipath->indexclauses)
2118  {
2119  IndexClause *iclause = (IndexClause *) lfirst(l);
2120 
2121  *quals = lappend(*quals, iclause->rinfo->clause);
2122  }
2123  *preds = list_concat(*preds, ipath->indexinfo->indpred);
2124  }
2125  else
2126  elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
2127 }
#define nodeTag(nodeptr)
Definition: nodes.h:133
List * bitmapquals
Definition: pathnodes.h:1807
List * bitmapquals
Definition: pathnodes.h:1820
List * indpred
Definition: pathnodes.h:1174
List * indexclauses
Definition: pathnodes.h:1721
IndexOptInfo * indexinfo
Definition: pathnodes.h:1720

References BitmapAndPath::bitmapquals, BitmapOrPath::bitmapquals, RestrictInfo::clause, elog, ERROR, IndexPath::indexclauses, IndexPath::indexinfo, IndexOptInfo::indpred, IsA, lappend(), lfirst, list_concat(), nodeTag, and IndexClause::rinfo.

Referenced by classify_index_clause_usage().

◆ find_list_position()

static int find_list_position ( Node node,
List **  nodelist 
)
static

Definition at line 2137 of file indxpath.c.

2138 {
2139  int i;
2140  ListCell *lc;
2141 
2142  i = 0;
2143  foreach(lc, *nodelist)
2144  {
2145  Node *oldnode = (Node *) lfirst(lc);
2146 
2147  if (equal(node, oldnode))
2148  return i;
2149  i++;
2150  }
2151 
2152  *nodelist = lappend(*nodelist, node);
2153 
2154  return i;
2155 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223

References equal(), i, lappend(), and lfirst.

Referenced by classify_index_clause_usage().

◆ generate_bitmap_or_paths()

static List * generate_bitmap_or_paths ( PlannerInfo root,
RelOptInfo rel,
List clauses,
List other_clauses 
)
static

Definition at line 1564 of file indxpath.c.

1566 {
1567  List *result = NIL;
1568  List *all_clauses;
1569  ListCell *lc;
1570 
1571  /*
1572  * We can use both the current and other clauses as context for
1573  * build_paths_for_OR; no need to remove ORs from the lists.
1574  */
1575  all_clauses = list_concat_copy(clauses, other_clauses);
1576 
1577  foreach(lc, clauses)
1578  {
1579  RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
1580  List *pathlist;
1581  Path *bitmapqual;
1582  ListCell *j;
1583  List *groupedArgs;
1584  List *inner_other_clauses = NIL;
1585 
1586  /* Ignore RestrictInfos that aren't ORs */
1587  if (!restriction_is_or_clause(rinfo))
1588  continue;
1589 
1590  /*
1591  * We must be able to match at least one index to each of the arms of
1592  * the OR, else we can't use it.
1593  */
1594  pathlist = NIL;
1595 
1596  /*
1597  * Group the similar OR-clause arguments into dedicated RestrictInfos,
1598  * because each of those RestrictInfos has a chance to match the index
1599  * as a whole.
1600  */
1601  groupedArgs = group_similar_or_args(root, rel, rinfo);
1602 
1603  if (groupedArgs != ((BoolExpr *) rinfo->orclause)->args)
1604  {
1605  /*
1606  * Some parts of the rinfo were probably grouped. In this case,
1607  * we have a set of sub-rinfos that together are an exact
1608  * duplicate of rinfo. Thus, we need to remove the rinfo from
1609  * other clauses. match_clauses_to_index detects duplicated
1610  * iclauses by comparing pointers to original rinfos that would be
1611  * different. So, we must delete rinfo to avoid de-facto
1612  * duplicated clauses in the index clauses list.
1613  */
1614  inner_other_clauses = list_delete(list_copy(all_clauses), rinfo);
1615  }
1616 
1617  foreach(j, groupedArgs)
1618  {
1619  Node *orarg = (Node *) lfirst(j);
1620  List *indlist;
1621 
1622  /* OR arguments should be ANDs or sub-RestrictInfos */
1623  if (is_andclause(orarg))
1624  {
1625  List *andargs = ((BoolExpr *) orarg)->args;
1626 
1627  indlist = build_paths_for_OR(root, rel,
1628  andargs,
1629  all_clauses);
1630 
1631  /* Recurse in case there are sub-ORs */
1632  indlist = list_concat(indlist,
1634  andargs,
1635  all_clauses));
1636  }
1638  {
1639  RestrictInfo *ri = castNode(RestrictInfo, orarg);
1640 
1641  /*
1642  * Generate bitmap paths for the group of similar OR-clause
1643  * arguments.
1644  */
1646  rel, ri,
1647  inner_other_clauses);
1648 
1649  if (indlist == NIL)
1650  {
1651  pathlist = NIL;
1652  break;
1653  }
1654  else
1655  {
1656  pathlist = list_concat(pathlist, indlist);
1657  continue;
1658  }
1659  }
1660  else
1661  {
1662  RestrictInfo *ri = castNode(RestrictInfo, orarg);
1663  List *orargs;
1664 
1665  orargs = list_make1(ri);
1666 
1667  indlist = build_paths_for_OR(root, rel,
1668  orargs,
1669  all_clauses);
1670  }
1671 
1672  /*
1673  * If nothing matched this arm, we can't do anything with this OR
1674  * clause.
1675  */
1676  if (indlist == NIL)
1677  {
1678  pathlist = NIL;
1679  break;
1680  }
1681 
1682  /*
1683  * OK, pick the most promising AND combination, and add it to
1684  * pathlist.
1685  */
1686  bitmapqual = choose_bitmap_and(root, rel, indlist);
1687  pathlist = lappend(pathlist, bitmapqual);
1688  }
1689 
1690  if (inner_other_clauses != NIL)
1691  list_free(inner_other_clauses);
1692 
1693  /*
1694  * If we have a match for every arm, then turn them into a
1695  * BitmapOrPath, and add to result list.
1696  */
1697  if (pathlist != NIL)
1698  {
1699  bitmapqual = (Path *) create_bitmap_or_path(root, rel, pathlist);
1700  result = lappend(result, bitmapqual);
1701  }
1702  }
1703 
1704  return result;
1705 }
static List * group_similar_or_args(PlannerInfo *root, RelOptInfo *rel, RestrictInfo *rinfo)
Definition: indxpath.c:1247
static List * make_bitmap_paths_for_or_group(PlannerInfo *root, RelOptInfo *rel, RestrictInfo *ri, List *other_clauses)
Definition: indxpath.c:1483
static List * build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel, List *clauses, List *other_clauses)
Definition: indxpath.c:1093
List * list_delete(List *list, void *datum)
Definition: list.c:853
static bool is_andclause(const void *clause)
Definition: nodeFuncs.h:107
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
BitmapOrPath * create_bitmap_or_path(PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
Definition: pathnode.c:1183
#define lfirst_node(type, lc)
Definition: pg_list.h:176
bool restriction_is_or_clause(RestrictInfo *restrictinfo)
Definition: restrictinfo.c:407

References build_paths_for_OR(), castNode, choose_bitmap_and(), create_bitmap_or_path(), group_similar_or_args(), is_andclause(), j, lappend(), lfirst, lfirst_node, list_concat(), list_concat_copy(), list_copy(), list_delete(), list_free(), list_make1, make_bitmap_paths_for_or_group(), NIL, restriction_is_or_clause(), and root.

Referenced by create_index_paths().

◆ get_index_clause_from_support()

static IndexClause * get_index_clause_from_support ( PlannerInfo root,
RestrictInfo rinfo,
Oid  funcid,
int  indexarg,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 3001 of file indxpath.c.

3007 {
3008  Oid prosupport = get_func_support(funcid);
3010  List *sresult;
3011 
3012  if (!OidIsValid(prosupport))
3013  return NULL;
3014 
3015  req.type = T_SupportRequestIndexCondition;
3016  req.root = root;
3017  req.funcid = funcid;
3018  req.node = (Node *) rinfo->clause;
3019  req.indexarg = indexarg;
3020  req.index = index;
3021  req.indexcol = indexcol;
3022  req.opfamily = index->opfamily[indexcol];
3023  req.indexcollation = index->indexcollations[indexcol];
3024 
3025  req.lossy = true; /* default assumption */
3026 
3027  sresult = (List *)
3028  DatumGetPointer(OidFunctionCall1(prosupport,
3029  PointerGetDatum(&req)));
3030 
3031  if (sresult != NIL)
3032  {
3033  IndexClause *iclause = makeNode(IndexClause);
3034  List *indexquals = NIL;
3035  ListCell *lc;
3036 
3037  /*
3038  * The support function API says it should just give back bare
3039  * clauses, so here we must wrap each one in a RestrictInfo.
3040  */
3041  foreach(lc, sresult)
3042  {
3043  Expr *clause = (Expr *) lfirst(lc);
3044 
3045  indexquals = lappend(indexquals,
3046  make_simple_restrictinfo(root, clause));
3047  }
3048 
3049  iclause->rinfo = rinfo;
3050  iclause->indexquals = indexquals;
3051  iclause->lossy = req.lossy;
3052  iclause->indexcol = indexcol;
3053  iclause->indexcols = NIL;
3054 
3055  return iclause;
3056  }
3057 
3058  return NULL;
3059 }
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:679
RegProcedure get_func_support(Oid funcid)
Definition: lsyscache.c:1858
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
struct IndexOptInfo * index
Definition: supportnodes.h:232
struct PlannerInfo * root
Definition: supportnodes.h:228

References RestrictInfo::clause, DatumGetPointer(), SupportRequestIndexCondition::funcid, get_func_support(), SupportRequestIndexCondition::index, SupportRequestIndexCondition::indexarg, IndexClause::indexcol, SupportRequestIndexCondition::indexcol, SupportRequestIndexCondition::indexcollation, IndexClause::indexcols, IndexClause::indexquals, lappend(), lfirst, IndexClause::lossy, SupportRequestIndexCondition::lossy, make_simple_restrictinfo, makeNode, NIL, SupportRequestIndexCondition::node, OidFunctionCall1, OidIsValid, SupportRequestIndexCondition::opfamily, PointerGetDatum(), IndexClause::rinfo, root, SupportRequestIndexCondition::root, and SupportRequestIndexCondition::type.

Referenced by match_funcclause_to_indexcol(), and match_opclause_to_indexcol().

◆ get_index_paths()

static void get_index_paths ( PlannerInfo root,
RelOptInfo rel,
IndexOptInfo index,
IndexClauseSet clauses,
List **  bitindexpaths 
)
static

Definition at line 717 of file indxpath.c.

720 {
721  List *indexpaths;
722  bool skip_nonnative_saop = false;
723  ListCell *lc;
724 
725  /*
726  * Build simple index paths using the clauses. Allow ScalarArrayOpExpr
727  * clauses only if the index AM supports them natively.
728  */
729  indexpaths = build_index_paths(root, rel,
730  index, clauses,
731  index->predOK,
732  ST_ANYSCAN,
733  &skip_nonnative_saop);
734 
735  /*
736  * Submit all the ones that can form plain IndexScan plans to add_path. (A
737  * plain IndexPath can represent either a plain IndexScan or an
738  * IndexOnlyScan, but for our purposes here that distinction does not
739  * matter. However, some of the indexes might support only bitmap scans,
740  * and those we mustn't submit to add_path here.)
741  *
742  * Also, pick out the ones that are usable as bitmap scans. For that, we
743  * must discard indexes that don't support bitmap scans, and we also are
744  * only interested in paths that have some selectivity; we should discard
745  * anything that was generated solely for ordering purposes.
746  */
747  foreach(lc, indexpaths)
748  {
749  IndexPath *ipath = (IndexPath *) lfirst(lc);
750 
751  if (index->amhasgettuple)
752  add_path(rel, (Path *) ipath);
753 
754  if (index->amhasgetbitmap &&
755  (ipath->path.pathkeys == NIL ||
756  ipath->indexselectivity < 1.0))
757  *bitindexpaths = lappend(*bitindexpaths, ipath);
758  }
759 
760  /*
761  * If there were ScalarArrayOpExpr clauses that the index can't handle
762  * natively, generate bitmap scan paths relying on executor-managed
763  * ScalarArrayOpExpr.
764  */
765  if (skip_nonnative_saop)
766  {
767  indexpaths = build_index_paths(root, rel,
768  index, clauses,
769  false,
771  NULL);
772  *bitindexpaths = list_concat(*bitindexpaths, indexpaths);
773  }
774 }
Selectivity indexselectivity
Definition: pathnodes.h:1726

References add_path(), build_index_paths(), IndexPath::indexselectivity, lappend(), lfirst, list_concat(), NIL, IndexPath::path, Path::pathkeys, root, ST_ANYSCAN, and ST_BITMAPSCAN.

Referenced by create_index_paths(), and get_join_index_paths().

◆ get_join_index_paths()

static void get_join_index_paths ( PlannerInfo root,
RelOptInfo rel,
IndexOptInfo index,
IndexClauseSet rclauseset,
IndexClauseSet jclauseset,
IndexClauseSet eclauseset,
List **  bitindexpaths,
Relids  relids,
List **  considered_relids 
)
static

Definition at line 607 of file indxpath.c.

615 {
616  IndexClauseSet clauseset;
617  int indexcol;
618 
619  /* If we already considered this relids set, don't repeat the work */
620  if (list_member(*considered_relids, relids))
621  return;
622 
623  /* Identify indexclauses usable with this relids set */
624  MemSet(&clauseset, 0, sizeof(clauseset));
625 
626  for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
627  {
628  ListCell *lc;
629 
630  /* First find applicable simple join clauses */
631  foreach(lc, jclauseset->indexclauses[indexcol])
632  {
633  IndexClause *iclause = (IndexClause *) lfirst(lc);
634 
635  if (bms_is_subset(iclause->rinfo->clause_relids, relids))
636  clauseset.indexclauses[indexcol] =
637  lappend(clauseset.indexclauses[indexcol], iclause);
638  }
639 
640  /*
641  * Add applicable eclass join clauses. The clauses generated for each
642  * column are redundant (cf generate_implied_equalities_for_column),
643  * so we need at most one. This is the only exception to the general
644  * rule of using all available index clauses.
645  */
646  foreach(lc, eclauseset->indexclauses[indexcol])
647  {
648  IndexClause *iclause = (IndexClause *) lfirst(lc);
649 
650  if (bms_is_subset(iclause->rinfo->clause_relids, relids))
651  {
652  clauseset.indexclauses[indexcol] =
653  lappend(clauseset.indexclauses[indexcol], iclause);
654  break;
655  }
656  }
657 
658  /* Add restriction clauses */
659  clauseset.indexclauses[indexcol] =
660  list_concat(clauseset.indexclauses[indexcol],
661  rclauseset->indexclauses[indexcol]);
662 
663  if (clauseset.indexclauses[indexcol] != NIL)
664  clauseset.nonempty = true;
665  }
666 
667  /* We should have found something, else caller passed silly relids */
668  Assert(clauseset.nonempty);
669 
670  /* Build index path(s) using the collected set of clauses */
671  get_index_paths(root, rel, index, &clauseset, bitindexpaths);
672 
673  /*
674  * Remember we considered paths for this set of relids.
675  */
676  *considered_relids = lappend(*considered_relids, relids);
677 }

References Assert, bms_is_subset(), get_index_paths(), IndexClauseSet::indexclauses, lappend(), lfirst, list_concat(), list_member(), MemSet, NIL, IndexClauseSet::nonempty, IndexClause::rinfo, and root.

Referenced by consider_index_join_outer_rels().

◆ get_loop_count()

static double get_loop_count ( PlannerInfo root,
Index  cur_relid,
Relids  outer_relids 
)
static

Definition at line 2262 of file indxpath.c.

2263 {
2264  double result;
2265  int outer_relid;
2266 
2267  /* For a non-parameterized path, just return 1.0 quickly */
2268  if (outer_relids == NULL)
2269  return 1.0;
2270 
2271  result = 0.0;
2272  outer_relid = -1;
2273  while ((outer_relid = bms_next_member(outer_relids, outer_relid)) >= 0)
2274  {
2275  RelOptInfo *outer_rel;
2276  double rowcount;
2277 
2278  /* Paranoia: ignore bogus relid indexes */
2279  if (outer_relid >= root->simple_rel_array_size)
2280  continue;
2281  outer_rel = root->simple_rel_array[outer_relid];
2282  if (outer_rel == NULL)
2283  continue;
2284  Assert(outer_rel->relid == outer_relid); /* sanity check on array */
2285 
2286  /* Other relation could be proven empty, if so ignore */
2287  if (IS_DUMMY_REL(outer_rel))
2288  continue;
2289 
2290  /* Otherwise, rel's rows estimate should be valid by now */
2291  Assert(outer_rel->rows > 0);
2292 
2293  /* Check to see if rel is on the inside of any semijoins */
2295  cur_relid,
2296  outer_relid,
2297  outer_rel->rows);
2298 
2299  /* Remember smallest row count estimate among the outer rels */
2300  if (result == 0.0 || result > rowcount)
2301  result = rowcount;
2302  }
2303  /* Return 1.0 if we found no valid relations (shouldn't happen) */
2304  return (result > 0.0) ? result : 1.0;
2305 }
static double adjust_rowcount_for_semijoins(PlannerInfo *root, Index cur_relid, Index outer_relid, double rowcount)
Definition: indxpath.c:2315

References adjust_rowcount_for_semijoins(), Assert, bms_next_member(), IS_DUMMY_REL, RelOptInfo::relid, root, and RelOptInfo::rows.

Referenced by bitmap_scan_cost_est(), build_index_paths(), and create_index_paths().

◆ group_similar_or_args()

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

Definition at line 1247 of file indxpath.c.

1248 {
1249  int n;
1250  int i;
1251  int group_start;
1252  OrArgIndexMatch *matches;
1253  bool matched = false;
1254  ListCell *lc;
1255  ListCell *lc2;
1256  List *orargs;
1257  List *result = NIL;
1258 
1259  Assert(IsA(rinfo->orclause, BoolExpr));
1260  orargs = ((BoolExpr *) rinfo->orclause)->args;
1261  n = list_length(orargs);
1262 
1263  /*
1264  * To avoid N^2 behavior, take utility pass along the list of OR-clause
1265  * arguments. For each argument, fill the OrArgIndexMatch structure,
1266  * which will be used to sort these arguments at the next step.
1267  */
1268  i = -1;
1269  matches = (OrArgIndexMatch *) palloc(sizeof(OrArgIndexMatch) * n);
1270  foreach(lc, orargs)
1271  {
1272  Node *arg = lfirst(lc);
1273  RestrictInfo *argrinfo;
1274  OpExpr *clause;
1275  Oid opno;
1276  Node *leftop,
1277  *rightop;
1278  Node *nonConstExpr;
1279  int indexnum;
1280  int colnum;
1281 
1282  i++;
1283  matches[i].argindex = i;
1284  matches[i].indexnum = -1;
1285  matches[i].colnum = -1;
1286  matches[i].opno = InvalidOid;
1287  matches[i].inputcollid = InvalidOid;
1288 
1289  if (!IsA(arg, RestrictInfo))
1290  continue;
1291 
1292  argrinfo = castNode(RestrictInfo, arg);
1293 
1294  /* Only operator clauses can match */
1295  if (!IsA(argrinfo->clause, OpExpr))
1296  continue;
1297 
1298  clause = (OpExpr *) argrinfo->clause;
1299  opno = clause->opno;
1300 
1301  /* Only binary operators can match */
1302  if (list_length(clause->args) != 2)
1303  continue;
1304 
1305  /*
1306  * Ignore any RelabelType node above the operands. This is needed to
1307  * be able to apply indexscanning in binary-compatible-operator cases.
1308  * Note: we can assume there is at most one RelabelType node;
1309  * eval_const_expressions() will have simplified if more than one.
1310  */
1311  leftop = get_leftop(clause);
1312  if (IsA(leftop, RelabelType))
1313  leftop = (Node *) ((RelabelType *) leftop)->arg;
1314 
1315  rightop = get_rightop(clause);
1316  if (IsA(rightop, RelabelType))
1317  rightop = (Node *) ((RelabelType *) rightop)->arg;
1318 
1319  /*
1320  * Check for clauses of the form: (indexkey operator constant) or
1321  * (constant operator indexkey). But we don't know a particular index
1322  * yet. First check for a constant, which must be Const or Param.
1323  * That's cheaper than search for an index key among all indexes.
1324  */
1325  if (IsA(leftop, Const) || IsA(leftop, Param))
1326  {
1327  opno = get_commutator(opno);
1328 
1329  if (!OidIsValid(opno))
1330  {
1331  /* commutator doesn't exist, we can't reverse the order */
1332  continue;
1333  }
1334  nonConstExpr = rightop;
1335  }
1336  else if (IsA(rightop, Const) || IsA(rightop, Param))
1337  {
1338  nonConstExpr = leftop;
1339  }
1340  else
1341  {
1342  continue;
1343  }
1344 
1345  /*
1346  * Match non-constant part to the index key. It's possible that a
1347  * single non-constant part matches multiple index keys. It's OK, we
1348  * just stop with first matching index key. Given that this choice is
1349  * determined the same for every clause, we will group similar clauses
1350  * together anyway.
1351  */
1352  indexnum = 0;
1353  foreach(lc2, rel->indexlist)
1354  {
1355  IndexOptInfo *index = (IndexOptInfo *) lfirst(lc2);
1356 
1357  /* Ignore index if it doesn't support bitmap scans */
1358  if (!index->amhasgetbitmap)
1359  continue;
1360 
1361  for (colnum = 0; colnum < index->nkeycolumns; colnum++)
1362  {
1363  if (match_index_to_operand(nonConstExpr, colnum, index))
1364  {
1365  matches[i].indexnum = indexnum;
1366  matches[i].colnum = colnum;
1367  matches[i].opno = opno;
1368  matches[i].inputcollid = clause->inputcollid;
1369  matched = true;
1370  break;
1371  }
1372  }
1373 
1374  /*
1375  * Stop looping through the indexes, if we managed to match
1376  * nonConstExpr to any index column.
1377  */
1378  if (matches[i].indexnum >= 0)
1379  break;
1380  indexnum++;
1381  }
1382  }
1383 
1384  /*
1385  * Fast-path check: if no clause is matching to the index column, we can
1386  * just give up at this stage and return the clause list as-is.
1387  */
1388  if (!matched)
1389  {
1390  pfree(matches);
1391  return orargs;
1392  }
1393 
1394  /* Sort clauses to make similar clauses go together */
1395  qsort(matches, n, sizeof(OrArgIndexMatch), or_arg_index_match_cmp);
1396 
1397  /*
1398  * Group similar clauses into single sub-restrictinfo. Side effect: the
1399  * resulting list of restrictions will be sorted by indexnum and colnum.
1400  */
1401  group_start = 0;
1402  for (i = 1; i <= n; i++)
1403  {
1404  /* Check if it's a group boundary */
1405  if (group_start >= 0 &&
1406  (i == n ||
1407  matches[i].indexnum != matches[group_start].indexnum ||
1408  matches[i].colnum != matches[group_start].colnum ||
1409  matches[i].opno != matches[group_start].opno ||
1410  matches[i].inputcollid != matches[group_start].inputcollid ||
1411  matches[i].indexnum == -1))
1412  {
1413  /*
1414  * One clause in group: add it "as is" to the upper-level OR.
1415  */
1416  if (i - group_start == 1)
1417  {
1418  result = lappend(result,
1419  list_nth(orargs,
1420  matches[group_start].argindex));
1421  }
1422  else
1423  {
1424  /*
1425  * Two or more clauses in a group: create a nested OR.
1426  */
1427  List *args = NIL;
1428  List *rargs = NIL;
1429  RestrictInfo *subrinfo;
1430  int j;
1431 
1432  Assert(i - group_start >= 2);
1433 
1434  /* Construct the list of nested OR arguments */
1435  for (j = group_start; j < i; j++)
1436  {
1437  Node *arg = list_nth(orargs, matches[j].argindex);
1438 
1439  rargs = lappend(rargs, arg);
1440  if (IsA(arg, RestrictInfo))
1441  args = lappend(args, ((RestrictInfo *) arg)->clause);
1442  else
1443  args = lappend(args, arg);
1444  }
1445 
1446  /* Construct the nested OR and wrap it with RestrictInfo */
1447  subrinfo = make_plain_restrictinfo(root,
1449  make_orclause(rargs),
1450  rinfo->is_pushed_down,
1451  rinfo->has_clone,
1452  rinfo->is_clone,
1453  rinfo->pseudoconstant,
1454  rinfo->security_level,
1455  rinfo->required_relids,
1456  rinfo->incompatible_relids,
1457  rinfo->outer_relids);
1458  result = lappend(result, subrinfo);
1459  }
1460 
1461  group_start = i;
1462  }
1463  }
1464  pfree(matches);
1465  return result;
1466 }
static int or_arg_index_match_cmp(const void *a, const void *b)
Definition: indxpath.c:1199
Expr * make_orclause(List *orclauses)
Definition: makefuncs.c:693
static Node * get_rightop(const void *clause)
Definition: nodeFuncs.h:95
static Node * get_leftop(const void *clause)
Definition: nodeFuncs.h:83
RestrictInfo * make_plain_restrictinfo(PlannerInfo *root, Expr *clause, Expr *orclause, bool is_pushed_down, bool has_clone, bool is_clone, bool pseudoconstant, Index security_level, Relids required_relids, Relids incompatible_relids, Relids outer_relids)
Definition: restrictinfo.c:103
Oid opno
Definition: primnodes.h:818
List * args
Definition: primnodes.h:836
bool is_pushed_down
Definition: pathnodes.h:2577
Index security_level
Definition: pathnodes.h:2596
Relids required_relids
Definition: pathnodes.h:2605
Relids outer_relids
Definition: pathnodes.h:2611
Relids incompatible_relids
Definition: pathnodes.h:2608
bool has_clone
Definition: pathnodes.h:2586

References arg, OrArgIndexMatch::argindex, generate_unaccent_rules::args, OpExpr::args, Assert, castNode, RestrictInfo::clause, OrArgIndexMatch::colnum, get_commutator(), get_leftop(), get_rightop(), RestrictInfo::has_clone, i, if(), RestrictInfo::incompatible_relids, RelOptInfo::indexlist, OrArgIndexMatch::indexnum, OrArgIndexMatch::inputcollid, InvalidOid, RestrictInfo::is_clone, RestrictInfo::is_pushed_down, IsA, j, lappend(), lfirst, list_length(), list_nth(), make_orclause(), make_plain_restrictinfo(), match_index_to_operand(), NIL, OidIsValid, OrArgIndexMatch::opno, OpExpr::opno, or_arg_index_match_cmp(), RestrictInfo::outer_relids, palloc(), pfree(), qsort, RestrictInfo::required_relids, root, and RestrictInfo::security_level.

Referenced by generate_bitmap_or_paths().

◆ indexcol_is_bool_constant_for_query()

bool indexcol_is_bool_constant_for_query ( PlannerInfo root,
IndexOptInfo index,
int  indexcol 
)

Definition at line 4316 of file indxpath.c.

4319 {
4320  ListCell *lc;
4321 
4322  /* If the index isn't boolean, we can't possibly get a match */
4323  if (!IsBooleanOpfamily(index->opfamily[indexcol]))
4324  return false;
4325 
4326  /* Check each restriction clause for the index's rel */
4327  foreach(lc, index->rel->baserestrictinfo)
4328  {
4329  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
4330 
4331  /*
4332  * As in match_clause_to_indexcol, never match pseudoconstants to
4333  * indexes. (It might be semantically okay to do so here, but the
4334  * odds of getting a match are negligible, so don't waste the cycles.)
4335  */
4336  if (rinfo->pseudoconstant)
4337  continue;
4338 
4339  /* See if we can match the clause's expression to the index column */
4340  if (match_boolean_index_clause(root, rinfo, indexcol, index))
4341  return true;
4342  }
4343 
4344  return false;
4345 }
static bool IsBooleanOpfamily(Oid opfamily)
Definition: indxpath.c:2724
static IndexClause * match_boolean_index_clause(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:2749

References IsBooleanOpfamily(), lfirst, match_boolean_index_clause(), and root.

Referenced by build_index_pathkeys().

◆ is_pseudo_constant_for_index()

bool is_pseudo_constant_for_index ( PlannerInfo root,
Node expr,
IndexOptInfo index 
)

Definition at line 4453 of file indxpath.c.

4454 {
4455  /* pull_varnos is cheaper than volatility check, so do that first */
4456  if (bms_is_member(index->rel->relid, pull_varnos(root, expr)))
4457  return false; /* no good, contains Var of table */
4458  if (contain_volatile_functions(expr))
4459  return false; /* no good, volatile comparison value */
4460  return true;
4461 }

References bms_is_member(), contain_volatile_functions(), pull_varnos(), and root.

◆ IsBooleanOpfamily()

static bool IsBooleanOpfamily ( Oid  opfamily)
static

Definition at line 2724 of file indxpath.c.

2725 {
2726  if (opfamily < FirstNormalObjectId)
2727  return IsBuiltinBooleanOpfamily(opfamily);
2728  else
2729  return op_in_opfamily(BooleanEqualOperator, opfamily);
2730 }
bool op_in_opfamily(Oid opno, Oid opfamily)
Definition: lsyscache.c:66
#define FirstNormalObjectId
Definition: transam.h:197

References FirstNormalObjectId, and op_in_opfamily().

Referenced by indexcol_is_bool_constant_for_query(), and match_clause_to_indexcol().

◆ make_bitmap_paths_for_or_group()

static List* make_bitmap_paths_for_or_group ( PlannerInfo root,
RelOptInfo rel,
RestrictInfo ri,
List other_clauses 
)
static

Definition at line 1483 of file indxpath.c.

1485 {
1486  List *jointlist = NIL;
1487  List *splitlist = NIL;
1488  ListCell *lc;
1489  List *orargs;
1490  List *args = ((BoolExpr *) ri->orclause)->args;
1491  Cost jointcost = 0.0,
1492  splitcost = 0.0;
1493  Path *bitmapqual;
1494  List *indlist;
1495 
1496  /*
1497  * First, try to match the whole group to the one index.
1498  */
1499  orargs = list_make1(ri);
1500  indlist = build_paths_for_OR(root, rel,
1501  orargs,
1502  other_clauses);
1503  if (indlist != NIL)
1504  {
1505  bitmapqual = choose_bitmap_and(root, rel, indlist);
1506  jointcost = bitmapqual->total_cost;
1507  jointlist = list_make1(bitmapqual);
1508  }
1509 
1510  /*
1511  * If we manage to find a bitmap scan, which uses the group of OR-clause
1512  * arguments as a whole, we can skip matching OR-clause arguments
1513  * one-by-one as long as there are no other clauses, which can bring more
1514  * efficiency to one-by-one case.
1515  */
1516  if (jointlist != NIL && other_clauses == NIL)
1517  return jointlist;
1518 
1519  /*
1520  * Also try to match all containing clauses one-by-one.
1521  */
1522  foreach(lc, args)
1523  {
1524  orargs = list_make1(lfirst(lc));
1525 
1526  indlist = build_paths_for_OR(root, rel,
1527  orargs,
1528  other_clauses);
1529 
1530  if (indlist == NIL)
1531  {
1532  splitlist = NIL;
1533  break;
1534  }
1535 
1536  bitmapqual = choose_bitmap_and(root, rel, indlist);
1537  splitcost += bitmapqual->total_cost;
1538  splitlist = lappend(splitlist, bitmapqual);
1539  }
1540 
1541  /*
1542  * Pick the best option.
1543  */
1544  if (splitlist == NIL)
1545  return jointlist;
1546  else if (jointlist == NIL)
1547  return splitlist;
1548  else
1549  return (jointcost < splitcost) ? jointlist : splitlist;
1550 }

References generate_unaccent_rules::args, build_paths_for_OR(), choose_bitmap_and(), lappend(), lfirst, list_make1, NIL, root, and Path::total_cost.

Referenced by generate_bitmap_or_paths().

◆ match_boolean_index_clause()

static IndexClause * match_boolean_index_clause ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 2749 of file indxpath.c.

2753 {
2754  Node *clause = (Node *) rinfo->clause;
2755  Expr *op = NULL;
2756 
2757  /* Direct match? */
2758  if (match_index_to_operand(clause, indexcol, index))
2759  {
2760  /* convert to indexkey = TRUE */
2761  op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2762  (Expr *) clause,
2763  (Expr *) makeBoolConst(true, false),
2765  }
2766  /* NOT clause? */
2767  else if (is_notclause(clause))
2768  {
2769  Node *arg = (Node *) get_notclausearg((Expr *) clause);
2770 
2771  if (match_index_to_operand(arg, indexcol, index))
2772  {
2773  /* convert to indexkey = FALSE */
2774  op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2775  (Expr *) arg,
2776  (Expr *) makeBoolConst(false, false),
2778  }
2779  }
2780 
2781  /*
2782  * Since we only consider clauses at top level of WHERE, we can convert
2783  * indexkey IS TRUE and indexkey IS FALSE to index searches as well. The
2784  * different meaning for NULL isn't important.
2785  */
2786  else if (clause && IsA(clause, BooleanTest))
2787  {
2788  BooleanTest *btest = (BooleanTest *) clause;
2789  Node *arg = (Node *) btest->arg;
2790 
2791  if (btest->booltesttype == IS_TRUE &&
2792  match_index_to_operand(arg, indexcol, index))
2793  {
2794  /* convert to indexkey = TRUE */
2795  op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2796  (Expr *) arg,
2797  (Expr *) makeBoolConst(true, false),
2799  }
2800  else if (btest->booltesttype == IS_FALSE &&
2801  match_index_to_operand(arg, indexcol, index))
2802  {
2803  /* convert to indexkey = FALSE */
2804  op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2805  (Expr *) arg,
2806  (Expr *) makeBoolConst(false, false),
2808  }
2809  }
2810 
2811  /*
2812  * If we successfully made an operator clause from the given qual, we must
2813  * wrap it in an IndexClause. It's not lossy.
2814  */
2815  if (op)
2816  {
2817  IndexClause *iclause = makeNode(IndexClause);
2818 
2819  iclause->rinfo = rinfo;
2821  iclause->lossy = false;
2822  iclause->indexcol = indexcol;
2823  iclause->indexcols = NIL;
2824  return iclause;
2825  }
2826 
2827  return NULL;
2828 }
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:359
static Expr * get_notclausearg(const void *notclause)
Definition: nodeFuncs.h:134
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:125
@ IS_TRUE
Definition: primnodes.h:1976
@ IS_FALSE
Definition: primnodes.h:1976
BoolTestType booltesttype
Definition: primnodes.h:1983
Expr * arg
Definition: primnodes.h:1982

References arg, BooleanTest::arg, BooleanTest::booltesttype, RestrictInfo::clause, get_notclausearg(), if(), IndexClause::indexcol, IndexClause::indexcols, IndexClause::indexquals, InvalidOid, IS_FALSE, is_notclause(), IS_TRUE, IsA, list_make1, IndexClause::lossy, make_opclause(), make_simple_restrictinfo, makeBoolConst(), makeNode, match_index_to_operand(), NIL, IndexClause::rinfo, and root.

Referenced by indexcol_is_bool_constant_for_query(), and match_clause_to_indexcol().

◆ match_clause_to_index()

static void match_clause_to_index ( PlannerInfo root,
RestrictInfo rinfo,
IndexOptInfo index,
IndexClauseSet clauseset 
)
static

Definition at line 2517 of file indxpath.c.

2521 {
2522  int indexcol;
2523 
2524  /*
2525  * Never match pseudoconstants to indexes. (Normally a match could not
2526  * happen anyway, since a pseudoconstant clause couldn't contain a Var,
2527  * but what if someone builds an expression index on a constant? It's not
2528  * totally unreasonable to do so with a partial index, either.)
2529  */
2530  if (rinfo->pseudoconstant)
2531  return;
2532 
2533  /*
2534  * If clause can't be used as an indexqual because it must wait till after
2535  * some lower-security-level restriction clause, reject it.
2536  */
2537  if (!restriction_is_securely_promotable(rinfo, index->rel))
2538  return;
2539 
2540  /* OK, check each index key column for a match */
2541  for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
2542  {
2543  IndexClause *iclause;
2544  ListCell *lc;
2545 
2546  /* Ignore duplicates */
2547  foreach(lc, clauseset->indexclauses[indexcol])
2548  {
2549  iclause = (IndexClause *) lfirst(lc);
2550 
2551  if (iclause->rinfo == rinfo)
2552  return;
2553  }
2554 
2555  /* OK, try to match the clause to the index column */
2556  iclause = match_clause_to_indexcol(root,
2557  rinfo,
2558  indexcol,
2559  index);
2560  if (iclause)
2561  {
2562  /* Success, so record it */
2563  clauseset->indexclauses[indexcol] =
2564  lappend(clauseset->indexclauses[indexcol], iclause);
2565  clauseset->nonempty = true;
2566  return;
2567  }
2568  }
2569 }
static IndexClause * match_clause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:2643
bool restriction_is_securely_promotable(RestrictInfo *restrictinfo, RelOptInfo *rel)
Definition: restrictinfo.c:422

References IndexClauseSet::indexclauses, lappend(), lfirst, match_clause_to_indexcol(), IndexClauseSet::nonempty, restriction_is_securely_promotable(), IndexClause::rinfo, and root.

Referenced by match_clauses_to_index(), and match_join_clauses_to_index().

◆ match_clause_to_indexcol()

static IndexClause * match_clause_to_indexcol ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 2643 of file indxpath.c.

2647 {
2648  IndexClause *iclause;
2649  Expr *clause = rinfo->clause;
2650  Oid opfamily;
2651 
2652  Assert(indexcol < index->nkeycolumns);
2653 
2654  /*
2655  * Historically this code has coped with NULL clauses. That's probably
2656  * not possible anymore, but we might as well continue to cope.
2657  */
2658  if (clause == NULL)
2659  return NULL;
2660 
2661  /* First check for boolean-index cases. */
2662  opfamily = index->opfamily[indexcol];
2663  if (IsBooleanOpfamily(opfamily))
2664  {
2665  iclause = match_boolean_index_clause(root, rinfo, indexcol, index);
2666  if (iclause)
2667  return iclause;
2668  }
2669 
2670  /*
2671  * Clause must be an opclause, funcclause, ScalarArrayOpExpr,
2672  * RowCompareExpr, or OR-clause that could be converted to SAOP. Or, if
2673  * the index supports it, we can handle IS NULL/NOT NULL clauses.
2674  */
2675  if (IsA(clause, OpExpr))
2676  {
2677  return match_opclause_to_indexcol(root, rinfo, indexcol, index);
2678  }
2679  else if (IsA(clause, FuncExpr))
2680  {
2681  return match_funcclause_to_indexcol(root, rinfo, indexcol, index);
2682  }
2683  else if (IsA(clause, ScalarArrayOpExpr))
2684  {
2685  return match_saopclause_to_indexcol(root, rinfo, indexcol, index);
2686  }
2687  else if (IsA(clause, RowCompareExpr))
2688  {
2689  return match_rowcompare_to_indexcol(root, rinfo, indexcol, index);
2690  }
2691  else if (restriction_is_or_clause(rinfo))
2692  {
2693  return match_orclause_to_indexcol(root, rinfo, indexcol, index);
2694  }
2695  else if (index->amsearchnulls && IsA(clause, NullTest))
2696  {
2697  NullTest *nt = (NullTest *) clause;
2698 
2699  if (!nt->argisrow &&
2700  match_index_to_operand((Node *) nt->arg, indexcol, index))
2701  {
2702  iclause = makeNode(IndexClause);
2703  iclause->rinfo = rinfo;
2704  iclause->indexquals = list_make1(rinfo);
2705  iclause->lossy = false;
2706  iclause->indexcol = indexcol;
2707  iclause->indexcols = NIL;
2708  return iclause;
2709  }
2710  }
2711 
2712  return NULL;
2713 }
static IndexClause * match_saopclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3067
static IndexClause * match_orclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3229
static IndexClause * match_opclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:2836
static IndexClause * match_rowcompare_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3135
static IndexClause * match_funcclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:2955
Expr * arg
Definition: primnodes.h:1958

References NullTest::arg, Assert, RestrictInfo::clause, IndexClause::indexcol, IndexClause::indexcols, IndexClause::indexquals, IsA, IsBooleanOpfamily(), list_make1, IndexClause::lossy, makeNode, match_boolean_index_clause(), match_funcclause_to_indexcol(), match_index_to_operand(), match_opclause_to_indexcol(), match_orclause_to_indexcol(), match_rowcompare_to_indexcol(), match_saopclause_to_indexcol(), NIL, restriction_is_or_clause(), IndexClause::rinfo, and root.

Referenced by match_clause_to_index().

◆ match_clause_to_ordering_op()

static Expr * match_clause_to_ordering_op ( IndexOptInfo index,
int  indexcol,
Expr clause,
Oid  pk_opfamily 
)
static

Definition at line 3832 of file indxpath.c.

3836 {
3837  Oid opfamily;
3838  Oid idxcollation;
3839  Node *leftop,
3840  *rightop;
3841  Oid expr_op;
3842  Oid expr_coll;
3843  Oid sortfamily;
3844  bool commuted;
3845 
3846  Assert(indexcol < index->nkeycolumns);
3847 
3848  opfamily = index->opfamily[indexcol];
3849  idxcollation = index->indexcollations[indexcol];
3850 
3851  /*
3852  * Clause must be a binary opclause.
3853  */
3854  if (!is_opclause(clause))
3855  return NULL;
3856  leftop = get_leftop(clause);
3857  rightop = get_rightop(clause);
3858  if (!leftop || !rightop)
3859  return NULL;
3860  expr_op = ((OpExpr *) clause)->opno;
3861  expr_coll = ((OpExpr *) clause)->inputcollid;
3862 
3863  /*
3864  * We can forget the whole thing right away if wrong collation.
3865  */
3866  if (!IndexCollMatchesExprColl(idxcollation, expr_coll))
3867  return NULL;
3868 
3869  /*
3870  * Check for clauses of the form: (indexkey operator constant) or
3871  * (constant operator indexkey).
3872  */
3873  if (match_index_to_operand(leftop, indexcol, index) &&
3874  !contain_var_clause(rightop) &&
3875  !contain_volatile_functions(rightop))
3876  {
3877  commuted = false;
3878  }
3879  else if (match_index_to_operand(rightop, indexcol, index) &&
3880  !contain_var_clause(leftop) &&
3881  !contain_volatile_functions(leftop))
3882  {
3883  /* Might match, but we need a commuted operator */
3884  expr_op = get_commutator(expr_op);
3885  if (expr_op == InvalidOid)
3886  return NULL;
3887  commuted = true;
3888  }
3889  else
3890  return NULL;
3891 
3892  /*
3893  * Is the (commuted) operator an ordering operator for the opfamily? And
3894  * if so, does it yield the right sorting semantics?
3895  */
3896  sortfamily = get_op_opfamily_sortfamily(expr_op, opfamily);
3897  if (sortfamily != pk_opfamily)
3898  return NULL;
3899 
3900  /* We have a match. Return clause or a commuted version thereof. */
3901  if (commuted)
3902  {
3903  OpExpr *newclause = makeNode(OpExpr);
3904 
3905  /* flat-copy all the fields of clause */
3906  memcpy(newclause, clause, sizeof(OpExpr));
3907 
3908  /* commute it */
3909  newclause->opno = expr_op;
3910  newclause->opfuncid = InvalidOid;
3911  newclause->args = list_make2(rightop, leftop);
3912 
3913  clause = (Expr *) newclause;
3914  }
3915 
3916  return clause;
3917 }
Oid get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
Definition: lsyscache.c:108
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:76
#define list_make2(x1, x2)
Definition: pg_list.h:214
bool contain_var_clause(Node *node)
Definition: var.c:408

References OpExpr::args, Assert, contain_var_clause(), contain_volatile_functions(), get_commutator(), get_leftop(), get_op_opfamily_sortfamily(), get_rightop(), IndexCollMatchesExprColl, InvalidOid, is_opclause(), list_make2, makeNode, match_index_to_operand(), and OpExpr::opno.

Referenced by match_pathkeys_to_index().

◆ match_clauses_to_index()

static void match_clauses_to_index ( PlannerInfo root,
List clauses,
IndexOptInfo index,
IndexClauseSet clauseset 
)
static

Definition at line 2484 of file indxpath.c.

2488 {
2489  ListCell *lc;
2490 
2491  foreach(lc, clauses)
2492  {
2493  RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
2494 
2495  match_clause_to_index(root, rinfo, index, clauseset);
2496  }
2497 }
static void match_clause_to_index(PlannerInfo *root, RestrictInfo *rinfo, IndexOptInfo *index, IndexClauseSet *clauseset)
Definition: indxpath.c:2517

References lfirst_node, match_clause_to_index(), and root.

Referenced by build_paths_for_OR(), match_eclass_clauses_to_index(), and match_restriction_clauses_to_index().

◆ match_eclass_clauses_to_index()

static void match_eclass_clauses_to_index ( PlannerInfo root,
IndexOptInfo index,
IndexClauseSet clauseset 
)
static

Definition at line 2446 of file indxpath.c.

2448 {
2449  int indexcol;
2450 
2451  /* No work if rel is not in any such ECs */
2452  if (!index->rel->has_eclass_joins)
2453  return;
2454 
2455  for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
2456  {
2458  List *clauses;
2459 
2460  /* Generate clauses, skipping any that join to lateral_referencers */
2461  arg.index = index;
2462  arg.indexcol = indexcol;
2464  index->rel,
2466  (void *) &arg,
2467  index->rel->lateral_referencers);
2468 
2469  /*
2470  * We have to check whether the results actually do match the index,
2471  * since for non-btree indexes the EC's equality operators might not
2472  * be in the index opclass (cf ec_member_matches_indexcol).
2473  */
2474  match_clauses_to_index(root, clauses, index, clauseset);
2475  }
2476 }
List * generate_implied_equalities_for_column(PlannerInfo *root, RelOptInfo *rel, ec_matches_callback_type callback, void *callback_arg, Relids prohibited_rels)
Definition: equivclass.c:3014
static bool ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
Definition: indxpath.c:4084

References arg, ec_member_matches_indexcol(), generate_implied_equalities_for_column(), match_clauses_to_index(), and root.

Referenced by create_index_paths().

◆ match_funcclause_to_indexcol()

static IndexClause * match_funcclause_to_indexcol ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 2955 of file indxpath.c.

2959 {
2960  FuncExpr *clause = (FuncExpr *) rinfo->clause;
2961  int indexarg;
2962  ListCell *lc;
2963 
2964  /*
2965  * We have no built-in intelligence about function clauses, but if there's
2966  * a planner support function, it might be able to do something. But, to
2967  * cut down on wasted planning cycles, only call the support function if
2968  * at least one argument matches the target index column.
2969  *
2970  * Note that we don't insist on the other arguments being pseudoconstants;
2971  * the support function has to check that. This is to allow cases where
2972  * only some of the other arguments need to be included in the indexqual.
2973  */
2974  indexarg = 0;
2975  foreach(lc, clause->args)
2976  {
2977  Node *op = (Node *) lfirst(lc);
2978 
2979  if (match_index_to_operand(op, indexcol, index))
2980  {
2982  rinfo,
2983  clause->funcid,
2984  indexarg,
2985  indexcol,
2986  index);
2987  }
2988 
2989  indexarg++;
2990  }
2991 
2992  return NULL;
2993 }
static IndexClause * get_index_clause_from_support(PlannerInfo *root, RestrictInfo *rinfo, Oid funcid, int indexarg, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3001
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768

References FuncExpr::args, RestrictInfo::clause, FuncExpr::funcid, get_index_clause_from_support(), lfirst, match_index_to_operand(), and root.

Referenced by match_clause_to_indexcol().

◆ match_index_to_operand()

bool match_index_to_operand ( Node operand,
int  indexcol,
IndexOptInfo index 
)

Definition at line 4367 of file indxpath.c.

4370 {
4371  int indkey;
4372 
4373  /*
4374  * Ignore any RelabelType node above the operand. This is needed to be
4375  * able to apply indexscanning in binary-compatible-operator cases. Note:
4376  * we can assume there is at most one RelabelType node;
4377  * eval_const_expressions() will have simplified if more than one.
4378  */
4379  if (operand && IsA(operand, RelabelType))
4380  operand = (Node *) ((RelabelType *) operand)->arg;
4381 
4382  indkey = index->indexkeys[indexcol];
4383  if (indkey != 0)
4384  {
4385  /*
4386  * Simple index column; operand must be a matching Var.
4387  */
4388  if (operand && IsA(operand, Var) &&
4389  index->rel->relid == ((Var *) operand)->varno &&
4390  indkey == ((Var *) operand)->varattno &&
4391  ((Var *) operand)->varnullingrels == NULL)
4392  return true;
4393  }
4394  else
4395  {
4396  /*
4397  * Index expression; find the correct expression. (This search could
4398  * be avoided, at the cost of complicating all the callers of this
4399  * routine; doesn't seem worth it.)
4400  */
4401  ListCell *indexpr_item;
4402  int i;
4403  Node *indexkey;
4404 
4405  indexpr_item = list_head(index->indexprs);
4406  for (i = 0; i < indexcol; i++)
4407  {
4408  if (index->indexkeys[i] == 0)
4409  {
4410  if (indexpr_item == NULL)
4411  elog(ERROR, "wrong number of index expressions");
4412  indexpr_item = lnext(index->indexprs, indexpr_item);
4413  }
4414  }
4415  if (indexpr_item == NULL)
4416  elog(ERROR, "wrong number of index expressions");
4417  indexkey = (Node *) lfirst(indexpr_item);
4418 
4419  /*
4420  * Does it match the operand? Again, strip any relabeling.
4421  */
4422  if (indexkey && IsA(indexkey, RelabelType))
4423  indexkey = (Node *) ((RelabelType *) indexkey)->arg;
4424 
4425  if (equal(indexkey, operand))
4426  return true;
4427  }
4428 
4429  return false;
4430 }
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
Definition: primnodes.h:248

References arg, elog, equal(), ERROR, i, IsA, lfirst, list_head(), and lnext().

Referenced by ec_member_matches_indexcol(), expand_indexqual_rowcompare(), get_actual_variable_range(), group_similar_or_args(), match_boolean_index_clause(), match_clause_to_indexcol(), match_clause_to_ordering_op(), match_funcclause_to_indexcol(), match_opclause_to_indexcol(), match_orclause_to_indexcol(), match_rowcompare_to_indexcol(), match_saopclause_to_indexcol(), and relation_has_unique_index_for().

◆ match_join_clauses_to_index()

static void match_join_clauses_to_index ( PlannerInfo root,
RelOptInfo rel,
IndexOptInfo index,
IndexClauseSet clauseset,
List **  joinorclauses 
)
static

Definition at line 2416 of file indxpath.c.

2420 {
2421  ListCell *lc;
2422 
2423  /* Scan the rel's join clauses */
2424  foreach(lc, rel->joininfo)
2425  {
2426  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2427 
2428  /* Check if clause can be moved to this rel */
2429  if (!join_clause_is_movable_to(rinfo, rel))
2430  continue;
2431 
2432  /* Potentially usable, so see if it matches the index or is an OR */
2433  if (restriction_is_or_clause(rinfo))
2434  *joinorclauses = lappend(*joinorclauses, rinfo);
2435  else
2436  match_clause_to_index(root, rinfo, index, clauseset);
2437  }
2438 }

References join_clause_is_movable_to(), RelOptInfo::joininfo, lappend(), lfirst, match_clause_to_index(), restriction_is_or_clause(), and root.

Referenced by create_index_paths().

◆ match_opclause_to_indexcol()

static IndexClause * match_opclause_to_indexcol ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 2836 of file indxpath.c.

2840 {
2841  IndexClause *iclause;
2842  OpExpr *clause = (OpExpr *) rinfo->clause;
2843  Node *leftop,
2844  *rightop;
2845  Oid expr_op;
2846  Oid expr_coll;
2847  Index index_relid;
2848  Oid opfamily;
2849  Oid idxcollation;
2850 
2851  /*
2852  * Only binary operators need apply. (In theory, a planner support
2853  * function could do something with a unary operator, but it seems
2854  * unlikely to be worth the cycles to check.)
2855  */
2856  if (list_length(clause->args) != 2)
2857  return NULL;
2858 
2859  leftop = (Node *) linitial(clause->args);
2860  rightop = (Node *) lsecond(clause->args);
2861  expr_op = clause->opno;
2862  expr_coll = clause->inputcollid;
2863 
2864  index_relid = index->rel->relid;
2865  opfamily = index->opfamily[indexcol];
2866  idxcollation = index->indexcollations[indexcol];
2867 
2868  /*
2869  * Check for clauses of the form: (indexkey operator constant) or
2870  * (constant operator indexkey). See match_clause_to_indexcol's notes
2871  * about const-ness.
2872  *
2873  * Note that we don't ask the support function about clauses that don't
2874  * have one of these forms. Again, in principle it might be possible to
2875  * do something, but it seems unlikely to be worth the cycles to check.
2876  */
2877  if (match_index_to_operand(leftop, indexcol, index) &&
2878  !bms_is_member(index_relid, rinfo->right_relids) &&
2879  !contain_volatile_functions(rightop))
2880  {
2881  if (IndexCollMatchesExprColl(idxcollation, expr_coll) &&
2882  op_in_opfamily(expr_op, opfamily))
2883  {
2884  iclause = makeNode(IndexClause);
2885  iclause->rinfo = rinfo;
2886  iclause->indexquals = list_make1(rinfo);
2887  iclause->lossy = false;
2888  iclause->indexcol = indexcol;
2889  iclause->indexcols = NIL;
2890  return iclause;
2891  }
2892 
2893  /*
2894  * If we didn't find a member of the index's opfamily, try the support
2895  * function for the operator's underlying function.
2896  */
2897  set_opfuncid(clause); /* make sure we have opfuncid */
2899  rinfo,
2900  clause->opfuncid,
2901  0, /* indexarg on left */
2902  indexcol,
2903  index);
2904  }
2905 
2906  if (match_index_to_operand(rightop, indexcol, index) &&
2907  !bms_is_member(index_relid, rinfo->left_relids) &&
2908  !contain_volatile_functions(leftop))
2909  {
2910  if (IndexCollMatchesExprColl(idxcollation, expr_coll))
2911  {
2912  Oid comm_op = get_commutator(expr_op);
2913 
2914  if (OidIsValid(comm_op) &&
2915  op_in_opfamily(comm_op, opfamily))
2916  {
2917  RestrictInfo *commrinfo;
2918 
2919  /* Build a commuted OpExpr and RestrictInfo */
2920  commrinfo = commute_restrictinfo(rinfo, comm_op);
2921 
2922  /* Make an IndexClause showing that as a derived qual */
2923  iclause = makeNode(IndexClause);
2924  iclause->rinfo = rinfo;
2925  iclause->indexquals = list_make1(commrinfo);
2926  iclause->lossy = false;
2927  iclause->indexcol = indexcol;
2928  iclause->indexcols = NIL;
2929  return iclause;
2930  }
2931  }
2932 
2933  /*
2934  * If we didn't find a member of the index's opfamily, try the support
2935  * function for the operator's underlying function.
2936  */
2937  set_opfuncid(clause); /* make sure we have opfuncid */
2939  rinfo,
2940  clause->opfuncid,
2941  1, /* indexarg on right */
2942  indexcol,
2943  index);
2944  }
2945 
2946  return NULL;
2947 }
unsigned int Index
Definition: c.h:619
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1861
#define lsecond(l)
Definition: pg_list.h:183
RestrictInfo * commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
Definition: restrictinfo.c:350

References OpExpr::args, bms_is_member(), RestrictInfo::clause, commute_restrictinfo(), contain_volatile_functions(), get_commutator(), get_index_clause_from_support(), if(), IndexClause::indexcol, IndexCollMatchesExprColl, IndexClause::indexcols, IndexClause::indexquals, linitial, list_length(), list_make1, IndexClause::lossy, lsecond, makeNode, match_index_to_operand(), NIL, OidIsValid, op_in_opfamily(), OpExpr::opno, IndexClause::rinfo, root, and set_opfuncid().

Referenced by match_clause_to_indexcol().

◆ match_orclause_to_indexcol()

static IndexClause * match_orclause_to_indexcol ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 3229 of file indxpath.c.

3233 {
3234  ListCell *lc;
3235  BoolExpr *orclause = (BoolExpr *) rinfo->orclause;
3236  Node *indexExpr = NULL;
3237  List *consts = NIL;
3238  Node *arrayNode = NULL;
3239  ScalarArrayOpExpr *saopexpr = NULL;
3240  Oid matchOpno = InvalidOid;
3241  IndexClause *iclause;
3242  Oid consttype = InvalidOid;
3243  Oid arraytype = InvalidOid;
3244  Oid inputcollid = InvalidOid;
3245  bool firstTime = true;
3246  bool haveParam = false;
3247 
3248  Assert(IsA(orclause, BoolExpr));
3249  Assert(orclause->boolop == OR_EXPR);
3250 
3251  /*
3252  * Try to convert a list of OR-clauses to a single SAOP expression. Each
3253  * OR entry must be in the form: (indexkey operator constant) or (constant
3254  * operator indexkey). Operators of all the entries must match. Constant
3255  * might be either Const or Param. To be effective, give up on the first
3256  * non-matching entry. Exit is implemented as a break from the loop,
3257  * which is catched afterwards.
3258  */
3259  foreach(lc, orclause->args)
3260  {
3261  RestrictInfo *subRinfo;
3262  OpExpr *subClause;
3263  Oid opno;
3264  Node *leftop,
3265  *rightop;
3266  Node *constExpr;
3267 
3268  if (!IsA(lfirst(lc), RestrictInfo))
3269  break;
3270 
3271  subRinfo = (RestrictInfo *) lfirst(lc);
3272 
3273  /* Only operator clauses can match */
3274  if (!IsA(subRinfo->clause, OpExpr))
3275  break;
3276 
3277  subClause = (OpExpr *) subRinfo->clause;
3278  opno = subClause->opno;
3279 
3280  /* Only binary operators can match */
3281  if (list_length(subClause->args) != 2)
3282  break;
3283 
3284  /*
3285  * The parameters below must match between sub-rinfo and its parent as
3286  * make_restrictinfo() fills them with the same values, and further
3287  * modifications are also the same for the whole subtree. However,
3288  * still make a sanity check.
3289  */
3290  Assert(subRinfo->is_pushed_down == rinfo->is_pushed_down);
3291  Assert(subRinfo->is_clone == rinfo->is_clone);
3292  Assert(subRinfo->security_level == rinfo->security_level);
3294  Assert(bms_equal(subRinfo->outer_relids, rinfo->outer_relids));
3295 
3296  /*
3297  * Also, check that required_relids in sub-rinfo is subset of parent's
3298  * required_relids.
3299  */
3301 
3302  /* Only the operator returning a boolean suit the transformation. */
3303  if (get_op_rettype(opno) != BOOLOID)
3304  break;
3305 
3306  /*
3307  * Check for clauses of the form: (indexkey operator constant) or
3308  * (constant operator indexkey). Determine indexkey side first, check
3309  * the constant later.
3310  */
3311  leftop = (Node *) linitial(subClause->args);
3312  rightop = (Node *) lsecond(subClause->args);
3313  if (match_index_to_operand(leftop, indexcol, index))
3314  {
3315  indexExpr = leftop;
3316  constExpr = rightop;
3317  }
3318  else if (match_index_to_operand(rightop, indexcol, index))
3319  {
3320  opno = get_commutator(opno);
3321  if (!OidIsValid(opno))
3322  {
3323  /* commutator doesn't exist, we can't reverse the order */
3324  break;
3325  }
3326  indexExpr = rightop;
3327  constExpr = leftop;
3328  }
3329  else
3330  {
3331  break;
3332  }
3333 
3334  /*
3335  * Ignore any RelabelType node above the operands. This is needed to
3336  * be able to apply indexscanning in binary-compatible-operator cases.
3337  * Note: we can assume there is at most one RelabelType node;
3338  * eval_const_expressions() will have simplified if more than one.
3339  */
3340  if (IsA(constExpr, RelabelType))
3341  constExpr = (Node *) ((RelabelType *) constExpr)->arg;
3342  if (IsA(indexExpr, RelabelType))
3343  indexExpr = (Node *) ((RelabelType *) indexExpr)->arg;
3344 
3345  /* We allow constant to be Const or Param */
3346  if (!IsA(constExpr, Const) && !IsA(constExpr, Param))
3347  break;
3348 
3349  /* Forbid transformation for composite types, records. */
3350  if (type_is_rowtype(exprType(constExpr)) ||
3351  type_is_rowtype(exprType(indexExpr)))
3352  break;
3353 
3354  /*
3355  * Save information about the operator, type, and collation for the
3356  * first matching qual. Then, check that subsequent quals match the
3357  * first.
3358  */
3359  if (firstTime)
3360  {
3361  matchOpno = opno;
3362  consttype = exprType(constExpr);
3363  arraytype = get_array_type(consttype);
3364  inputcollid = subClause->inputcollid;
3365 
3366  /*
3367  * Check that the operator is presented in the opfamily and that
3368  * the expression collation matches the index collation. Also,
3369  * there must be an array type to construct an array later.
3370  */
3371  if (!IndexCollMatchesExprColl(index->indexcollations[indexcol], inputcollid) ||
3372  !op_in_opfamily(matchOpno, index->opfamily[indexcol]) ||
3373  !OidIsValid(arraytype))
3374  break;
3375  firstTime = false;
3376  }
3377  else
3378  {
3379  if (opno != matchOpno ||
3380  inputcollid != subClause->inputcollid ||
3381  consttype != exprType(constExpr))
3382  break;
3383  }
3384 
3385  if (IsA(constExpr, Param))
3386  haveParam = true;
3387  consts = lappend(consts, constExpr);
3388  }
3389 
3390  /*
3391  * Catch the break from the loop above. Normally, a foreach() loop ends
3392  * up with a NULL list cell. A non-NULL list cell indicates a break from
3393  * the foreach() loop. Free the consts list and return NULL then.
3394  */
3395  if (lc != NULL)
3396  {
3397  list_free(consts);
3398  return NULL;
3399  }
3400 
3401  /*
3402  * Assemble an array from the list of constants. It seems more profitable
3403  * to build a const array. But in the presence of parameters, we don't
3404  * have a specific value here and must employ an ArrayExpr instead.
3405  */
3406  if (haveParam)
3407  {
3408  ArrayExpr *arrayExpr = makeNode(ArrayExpr);
3409 
3410  /* array_collid will be set by parse_collate.c */
3411  arrayExpr->element_typeid = consttype;
3412  arrayExpr->array_typeid = arraytype;
3413  arrayExpr->multidims = false;
3414  arrayExpr->elements = consts;
3415  arrayExpr->location = -1;
3416 
3417  arrayNode = (Node *) arrayExpr;
3418  }
3419  else
3420  {
3421  int16 typlen;
3422  bool typbyval;
3423  char typalign;
3424  Datum *elems;
3425  int i = 0;
3426  ArrayType *arrayConst;
3427 
3428  get_typlenbyvalalign(consttype, &typlen, &typbyval, &typalign);
3429 
3430  elems = (Datum *) palloc(sizeof(Datum) * list_length(consts));
3431  foreach_node(Const, value, consts)
3432  {
3433  Assert(!value->constisnull);
3434 
3435  elems[i++] = value->constvalue;
3436  }
3437 
3438  arrayConst = construct_array(elems, i, consttype,
3439  typlen, typbyval, typalign);
3440  arrayNode = (Node *) makeConst(arraytype, -1, inputcollid,
3441  -1, PointerGetDatum(arrayConst),
3442  false, false);
3443 
3444  pfree(elems);
3445  list_free(consts);
3446  }
3447 
3448  /* Build the SAOP expression node */
3449  saopexpr = makeNode(ScalarArrayOpExpr);
3450  saopexpr->opno = matchOpno;
3451  saopexpr->opfuncid = get_opcode(matchOpno);
3452  saopexpr->hashfuncid = InvalidOid;
3453  saopexpr->negfuncid = InvalidOid;
3454  saopexpr->useOr = true;
3455  saopexpr->inputcollid = inputcollid;
3456  saopexpr->args = list_make2(indexExpr, arrayNode);
3457  saopexpr->location = -1;
3458 
3459  /*
3460  * Finally, build an IndexClause based on the SAOP node. Use
3461  * make_simple_restrictinfo() to get RestrictInfo with clean selectivity
3462  * estimations, because they may differ from the estimation made for an OR
3463  * clause. Although it is not a lossy expression, keep the original rinfo
3464  * in iclause->rinfo as prescribed.
3465  */
3466  iclause = makeNode(IndexClause);
3467  iclause->rinfo = rinfo;
3468  iclause->indexquals = list_make1(make_simple_restrictinfo(root,
3469  &saopexpr->xpr));
3470  iclause->lossy = false;
3471  iclause->indexcol = indexcol;
3472  iclause->indexcols = NIL;
3473  return iclause;
3474 }
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3361
signed short int16
Definition: c.h:507
static struct @160 value
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2271
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1333
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2787
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
char typalign
Definition: pg_type.h:176
uintptr_t Datum
Definition: postgres.h:64
@ OR_EXPR
Definition: primnodes.h:931
ParseLoc location
Definition: primnodes.h:1384
List * elements
Definition: primnodes.h:1380
BoolExprType boolop
Definition: primnodes.h:939
List * args
Definition: primnodes.h:940

References arg, OpExpr::args, BoolExpr::args, Assert, bms_equal(), bms_is_subset(), BoolExpr::boolop, RestrictInfo::clause, construct_array(), ArrayExpr::elements, exprType(), foreach_node, get_array_type(), get_commutator(), get_op_rettype(), get_opcode(), get_typlenbyvalalign(), i, if(), RestrictInfo::incompatible_relids, IndexCollMatchesExprColl, InvalidOid, RestrictInfo::is_clone, RestrictInfo::is_pushed_down, IsA, lappend(), lfirst, linitial, list_free(), list_length(), list_make1, list_make2, ArrayExpr::location, lsecond, make_simple_restrictinfo, makeConst(), makeNode, match_index_to_operand(), NIL, OidIsValid, op_in_opfamily(), OpExpr::opno, OR_EXPR, RestrictInfo::outer_relids, palloc(), pfree(), PointerGetDatum(), RestrictInfo::required_relids, root, RestrictInfo::security_level, typalign, type_is_rowtype(), and value.

Referenced by match_clause_to_indexcol().

◆ match_pathkeys_to_index()

static void match_pathkeys_to_index ( IndexOptInfo index,
List pathkeys,
List **  orderby_clauses_p,
List **  clause_columns_p 
)
static

Definition at line 3722 of file indxpath.c.

3725 {
3726  ListCell *lc1;
3727 
3728  *orderby_clauses_p = NIL; /* set default results */
3729  *clause_columns_p = NIL;
3730 
3731  /* Only indexes with the amcanorderbyop property are interesting here */
3732  if (!index->amcanorderbyop)
3733  return;
3734 
3735  foreach(lc1, pathkeys)
3736  {
3737  PathKey *pathkey = (PathKey *) lfirst(lc1);
3738  bool found = false;
3739  ListCell *lc2;
3740 
3741 
3742  /* Pathkey must request default sort order for the target opfamily */
3743  if (pathkey->pk_strategy != BTLessStrategyNumber ||
3744  pathkey->pk_nulls_first)
3745  return;
3746 
3747  /* If eclass is volatile, no hope of using an indexscan */
3748  if (pathkey->pk_eclass->ec_has_volatile)
3749  return;
3750 
3751  /*
3752  * Try to match eclass member expression(s) to index. Note that child
3753  * EC members are considered, but only when they belong to the target
3754  * relation. (Unlike regular members, the same expression could be a
3755  * child member of more than one EC. Therefore, the same index could
3756  * be considered to match more than one pathkey list, which is OK
3757  * here. See also get_eclass_for_sort_expr.)
3758  */
3759  foreach(lc2, pathkey->pk_eclass->ec_members)
3760  {
3761  EquivalenceMember *member = (EquivalenceMember *) lfirst(lc2);
3762  int indexcol;
3763 
3764  /* No possibility of match if it references other relations */
3765  if (!bms_equal(member->em_relids, index->rel->relids))
3766  continue;
3767 
3768  /*
3769  * We allow any column of the index to match each pathkey; they
3770  * don't have to match left-to-right as you might expect. This is
3771  * correct for GiST, and it doesn't matter for SP-GiST because
3772  * that doesn't handle multiple columns anyway, and no other
3773  * existing AMs support amcanorderbyop. We might need different
3774  * logic in future for other implementations.
3775  */
3776  for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
3777  {
3778  Expr *expr;
3779 
3781  indexcol,
3782  member->em_expr,
3783  pathkey->pk_opfamily);
3784  if (expr)
3785  {
3786  *orderby_clauses_p = lappend(*orderby_clauses_p, expr);
3787  *clause_columns_p = lappend_int(*clause_columns_p, indexcol);
3788  found = true;
3789  break;
3790  }
3791  }
3792 
3793  if (found) /* don't want to look at remaining members */
3794  break;
3795  }
3796 
3797  /*
3798  * Return the matches found so far when this pathkey couldn't be
3799  * matched to the index.
3800  */
3801  if (!found)
3802  return;
3803  }
3804 }
static Expr * match_clause_to_ordering_op(IndexOptInfo *index, int indexcol, Expr *clause, Oid pk_opfamily)
Definition: indxpath.c:3832
bool pk_nulls_first
Definition: pathnodes.h:1480
int pk_strategy
Definition: pathnodes.h:1479
Oid pk_opfamily
Definition: pathnodes.h:1478

References bms_equal(), BTLessStrategyNumber, EquivalenceMember::em_expr, EquivalenceMember::em_relids, lappend(), lappend_int(), lfirst, match_clause_to_ordering_op(), NIL, PathKey::pk_nulls_first, PathKey::pk_opfamily, and PathKey::pk_strategy.

Referenced by build_index_paths().

◆ match_restriction_clauses_to_index()

static void match_restriction_clauses_to_index ( PlannerInfo root,
IndexOptInfo index,
IndexClauseSet clauseset 
)
static

Definition at line 2401 of file indxpath.c.

2404 {
2405  /* We can ignore clauses that are implied by the index predicate */
2406  match_clauses_to_index(root, index->indrestrictinfo, index, clauseset);
2407 }

References match_clauses_to_index(), and root.

Referenced by create_index_paths().

◆ match_rowcompare_to_indexcol()

static IndexClause * match_rowcompare_to_indexcol ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 3135 of file indxpath.c.

3139 {
3140  RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
3141  Index index_relid;
3142  Oid opfamily;
3143  Oid idxcollation;
3144  Node *leftop,
3145  *rightop;
3146  bool var_on_left;
3147  Oid expr_op;
3148  Oid expr_coll;
3149 
3150  /* Forget it if we're not dealing with a btree index */
3151  if (index->relam != BTREE_AM_OID)
3152  return NULL;
3153 
3154  index_relid = index->rel->relid;
3155  opfamily = index->opfamily[indexcol];
3156  idxcollation = index->indexcollations[indexcol];
3157 
3158  /*
3159  * We could do the matching on the basis of insisting that the opfamily
3160  * shown in the RowCompareExpr be the same as the index column's opfamily,
3161  * but that could fail in the presence of reverse-sort opfamilies: it'd be
3162  * a matter of chance whether RowCompareExpr had picked the forward or
3163  * reverse-sort family. So look only at the operator, and match if it is
3164  * a member of the index's opfamily (after commutation, if the indexkey is
3165  * on the right). We'll worry later about whether any additional
3166  * operators are matchable to the index.
3167  */
3168  leftop = (Node *) linitial(clause->largs);
3169  rightop = (Node *) linitial(clause->rargs);
3170  expr_op = linitial_oid(clause->opnos);
3171  expr_coll = linitial_oid(clause->inputcollids);
3172 
3173  /* Collations must match, if relevant */
3174  if (!IndexCollMatchesExprColl(idxcollation, expr_coll))
3175  return NULL;
3176 
3177  /*
3178  * These syntactic tests are the same as in match_opclause_to_indexcol()
3179  */
3180  if (match_index_to_operand(leftop, indexcol, index) &&
3181  !bms_is_member(index_relid, pull_varnos(root, rightop)) &&
3182  !contain_volatile_functions(rightop))
3183  {
3184  /* OK, indexkey is on left */
3185  var_on_left = true;
3186  }
3187  else if (match_index_to_operand(rightop, indexcol, index) &&
3188  !bms_is_member(index_relid, pull_varnos(root, leftop)) &&
3189  !contain_volatile_functions(leftop))
3190  {
3191  /* indexkey is on right, so commute the operator */
3192  expr_op = get_commutator(expr_op);
3193  if (expr_op == InvalidOid)
3194  return NULL;
3195  var_on_left = false;
3196  }
3197  else
3198  return NULL;
3199 
3200  /* We're good if the operator is the right type of opfamily member */
3201  switch (get_op_opfamily_strategy(expr_op, opfamily))
3202  {
3203  case BTLessStrategyNumber:
3208  rinfo,
3209  indexcol,
3210  index,
3211  expr_op,
3212  var_on_left);
3213  }
3214 
3215  return NULL;
3216 }
static IndexClause * expand_indexqual_rowcompare(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index, Oid expr_op, bool var_on_left)
Definition: indxpath.c:3500

References bms_is_member(), BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, RestrictInfo::clause, contain_volatile_functions(), expand_indexqual_rowcompare(), get_commutator(), get_op_opfamily_strategy(), if(), IndexCollMatchesExprColl, InvalidOid, RowCompareExpr::largs, linitial, linitial_oid, match_index_to_operand(), pull_varnos(), RowCompareExpr::rargs, and root.

Referenced by match_clause_to_indexcol().

◆ match_saopclause_to_indexcol()

static IndexClause * match_saopclause_to_indexcol ( PlannerInfo root,
RestrictInfo rinfo,
int  indexcol,
IndexOptInfo index 
)
static

Definition at line 3067 of file indxpath.c.

3071 {
3072  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) rinfo->clause;
3073  Node *leftop,
3074  *rightop;
3075  Relids right_relids;
3076  Oid expr_op;
3077  Oid expr_coll;
3078  Index index_relid;
3079  Oid opfamily;
3080  Oid idxcollation;
3081 
3082  /* We only accept ANY clauses, not ALL */
3083  if (!saop->useOr)
3084  return NULL;
3085  leftop = (Node *) linitial(saop->args);
3086  rightop = (Node *) lsecond(saop->args);
3087  right_relids = pull_varnos(root, rightop);
3088  expr_op = saop->opno;
3089  expr_coll = saop->inputcollid;
3090 
3091  index_relid = index->rel->relid;
3092  opfamily = index->opfamily[indexcol];
3093  idxcollation = index->indexcollations[indexcol];
3094 
3095  /*
3096  * We must have indexkey on the left and a pseudo-constant array argument.
3097  */
3098  if (match_index_to_operand(leftop, indexcol, index) &&
3099  !bms_is_member(index_relid, right_relids) &&
3100  !contain_volatile_functions(rightop))
3101  {
3102  if (IndexCollMatchesExprColl(idxcollation, expr_coll) &&
3103  op_in_opfamily(expr_op, opfamily))
3104  {
3105  IndexClause *iclause = makeNode(IndexClause);
3106 
3107  iclause->rinfo = rinfo;
3108  iclause->indexquals = list_make1(rinfo);
3109  iclause->lossy = false;
3110  iclause->indexcol = indexcol;
3111  iclause->indexcols = NIL;
3112  return iclause;
3113  }
3114 
3115  /*
3116  * We do not currently ask support functions about ScalarArrayOpExprs,
3117  * though in principle we could.
3118  */
3119  }
3120 
3121  return NULL;
3122 }

References ScalarArrayOpExpr::args, bms_is_member(), RestrictInfo::clause, contain_volatile_functions(), if(), IndexClause::indexcol, IndexCollMatchesExprColl, IndexClause::indexcols, IndexClause::indexquals, linitial, list_make1, IndexClause::lossy, lsecond, makeNode, match_index_to_operand(), NIL, op_in_opfamily(), ScalarArrayOpExpr::opno, pull_varnos(), IndexClause::rinfo, root, and ScalarArrayOpExpr::useOr.

Referenced by match_clause_to_indexcol().

◆ or_arg_index_match_cmp()

static int or_arg_index_match_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 1199 of file indxpath.c.

1200 {
1201  const OrArgIndexMatch *match_a = (const OrArgIndexMatch *) a;
1202  const OrArgIndexMatch *match_b = (const OrArgIndexMatch *) b;
1203 
1204  if (match_a->indexnum < match_b->indexnum)
1205  return -1;
1206  else if (match_a->indexnum > match_b->indexnum)
1207  return 1;
1208 
1209  if (match_a->colnum < match_b->colnum)
1210  return -1;
1211  else if (match_a->colnum > match_b->colnum)
1212  return 1;
1213 
1214  if (match_a->opno < match_b->opno)
1215  return -1;
1216  else if (match_a->opno > match_b->opno)
1217  return 1;
1218 
1219  if (match_a->inputcollid < match_b->inputcollid)
1220  return -1;
1221  else if (match_a->inputcollid > match_b->inputcollid)
1222  return 1;
1223 
1224  if (match_a->argindex < match_b->argindex)
1225  return -1;
1226  else if (match_a->argindex > match_b->argindex)
1227  return 1;
1228 
1229  return 0;
1230 }
int b
Definition: isn.c:69
int a
Definition: isn.c:68

References a, OrArgIndexMatch::argindex, b, OrArgIndexMatch::colnum, OrArgIndexMatch::indexnum, OrArgIndexMatch::inputcollid, and OrArgIndexMatch::opno.

Referenced by group_similar_or_args().

◆ path_usage_comparator()

static int path_usage_comparator ( const void *  a,
const void *  b 
)
static

Definition at line 1926 of file indxpath.c.

1927 {
1928  PathClauseUsage *pa = *(PathClauseUsage *const *) a;
1929  PathClauseUsage *pb = *(PathClauseUsage *const *) b;
1930  Cost acost;
1931  Cost bcost;
1932  Selectivity aselec;
1933  Selectivity bselec;
1934 
1935  cost_bitmap_tree_node(pa->path, &acost, &aselec);
1936  cost_bitmap_tree_node(pb->path, &bcost, &bselec);
1937 
1938  /*
1939  * If costs are the same, sort by selectivity.
1940  */
1941  if (acost < bcost)
1942  return -1;
1943  if (acost > bcost)
1944  return 1;
1945 
1946  if (aselec < bselec)
1947  return -1;
1948  if (aselec > bselec)
1949  return 1;
1950 
1951  return 0;
1952 }

References a, b, cost_bitmap_tree_node(), and PathClauseUsage::path.

Referenced by choose_bitmap_and().

◆ relation_has_unique_index_for()

bool relation_has_unique_index_for ( PlannerInfo root,
RelOptInfo rel,
List restrictlist,
List exprlist,
List oprlist 
)

Definition at line 4142 of file indxpath.c.

4145 {
4146  ListCell *ic;
4147 
4148  Assert(list_length(exprlist) == list_length(oprlist));
4149 
4150  /* Short-circuit if no indexes... */
4151  if (rel->indexlist == NIL)
4152  return false;
4153 
4154  /*
4155  * Examine the rel's restriction clauses for usable var = const clauses
4156  * that we can add to the restrictlist.
4157  */
4158  foreach(ic, rel->baserestrictinfo)
4159  {
4160  RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(ic);
4161 
4162  /*
4163  * Note: can_join won't be set for a restriction clause, but
4164  * mergeopfamilies will be if it has a mergejoinable operator and
4165  * doesn't contain volatile functions.
4166  */
4167  if (restrictinfo->mergeopfamilies == NIL)
4168  continue; /* not mergejoinable */
4169 
4170  /*
4171  * The clause certainly doesn't refer to anything but the given rel.
4172  * If either side is pseudoconstant then we can use it.
4173  */
4174  if (bms_is_empty(restrictinfo->left_relids))
4175  {
4176  /* righthand side is inner */
4177  restrictinfo->outer_is_left = true;
4178  }
4179  else if (bms_is_empty(restrictinfo->right_relids))
4180  {
4181  /* lefthand side is inner */
4182  restrictinfo->outer_is_left = false;
4183  }
4184  else
4185  continue;
4186 
4187  /* OK, add to list */
4188  restrictlist = lappend(restrictlist, restrictinfo);
4189  }
4190 
4191  /* Short-circuit the easy case */
4192  if (restrictlist == NIL && exprlist == NIL)
4193  return false;
4194 
4195  /* Examine each index of the relation ... */
4196  foreach(ic, rel->indexlist)
4197  {
4198  IndexOptInfo *ind = (IndexOptInfo *) lfirst(ic);
4199  int c;
4200 
4201  /*
4202  * If the index is not unique, or not immediately enforced, or if it's
4203  * a partial index, it's useless here. We're unable to make use of
4204  * predOK partial unique indexes due to the fact that
4205  * check_index_predicates() also makes use of join predicates to
4206  * determine if the partial index is usable. Here we need proofs that
4207  * hold true before any joins are evaluated.
4208  */
4209  if (!ind->unique || !ind->immediate || ind->indpred != NIL)
4210  continue;
4211 
4212  /*
4213  * Try to find each index column in the lists of conditions. This is
4214  * O(N^2) or worse, but we expect all the lists to be short.
4215  */
4216  for (c = 0; c < ind->nkeycolumns; c++)
4217  {
4218  bool matched = false;
4219  ListCell *lc;
4220  ListCell *lc2;
4221 
4222  foreach(lc, restrictlist)
4223  {
4224  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
4225  Node *rexpr;
4226 
4227  /*
4228  * The condition's equality operator must be a member of the
4229  * index opfamily, else it is not asserting the right kind of
4230  * equality behavior for this index. We check this first
4231  * since it's probably cheaper than match_index_to_operand().
4232  */
4233  if (!list_member_oid(rinfo->mergeopfamilies, ind->opfamily[c]))
4234  continue;
4235 
4236  /*
4237  * XXX at some point we may need to check collations here too.
4238  * For the moment we assume all collations reduce to the same
4239  * notion of equality.
4240  */
4241 
4242  /* OK, see if the condition operand matches the index key */
4243  if (rinfo->outer_is_left)
4244  rexpr = get_rightop(rinfo->clause);
4245  else
4246  rexpr = get_leftop(rinfo->clause);
4247 
4248  if (match_index_to_operand(rexpr, c, ind))
4249  {
4250  matched = true; /* column is unique */
4251  break;
4252  }
4253  }
4254 
4255  if (matched)
4256  continue;
4257 
4258  forboth(lc, exprlist, lc2, oprlist)
4259  {
4260  Node *expr = (Node *) lfirst(lc);
4261  Oid opr = lfirst_oid(lc2);
4262 
4263  /* See if the expression matches the index key */
4264  if (!match_index_to_operand(expr, c, ind))
4265  continue;
4266 
4267  /*
4268  * The equality operator must be a member of the index
4269  * opfamily, else it is not asserting the right kind of
4270  * equality behavior for this index. We assume the caller
4271  * determined it is an equality operator, so we don't need to
4272  * check any more tightly than this.
4273  */
4274  if (!op_in_opfamily(opr, ind->opfamily[c]))
4275  continue;
4276 
4277  /*
4278  * XXX at some point we may need to check collations here too.
4279  * For the moment we assume all collations reduce to the same
4280  * notion of equality.
4281  */
4282 
4283  matched = true; /* column is unique */
4284  break;
4285  }
4286 
4287  if (!matched)
4288  break; /* no match; this index doesn't help us */
4289  }
4290 
4291  /* Matched all key columns of this index? */
4292  if (c == ind->nkeycolumns)
4293  return true;
4294  }
4295 
4296  return false;
4297 }
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
char * c

References Assert, RelOptInfo::baserestrictinfo, bms_is_empty, RestrictInfo::clause, forboth, get_leftop(), get_rightop(), RelOptInfo::indexlist, lappend(), lfirst, lfirst_oid, list_length(), list_member_oid(), match_index_to_operand(), NIL, and op_in_opfamily().

Referenced by create_unique_path(), and rel_is_distinct_for().