PostgreSQL Source Code git master
indxpath.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/stratnum.h"
#include "access/sysattr.h"
#include "access/transam.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/lsyscache.h"
#include "utils/selfuncs.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)
 
static bool contain_strippable_phv_walker (Node *node, void *context)
 
static Nodestrip_phvs_in_index_operand_mutator (Node *node, void *context)
 
void create_index_paths (PlannerInfo *root, RelOptInfo *rel)
 
static int or_arg_index_match_cmp (const void *a, const void *b)
 
static int or_arg_index_match_cmp_group (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 **extra_clauses)
 
bool indexcol_is_bool_constant_for_query (PlannerInfo *root, IndexOptInfo *index, int indexcol)
 
bool match_index_to_operand (Node *operand, int indexcol, IndexOptInfo *index)
 
Nodestrip_phvs_in_index_operand (Node *operand)
 
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 42 of file indxpath.c.

Enumeration Type Documentation

◆ ScanTypeControl

Enumerator
ST_INDEXSCAN 
ST_BITMAPSCAN 
ST_ANYSCAN 

Definition at line 46 of file indxpath.c.

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

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 2381 of file indxpath.c.

2385{
2386 ListCell *lc;
2387
2388 foreach(lc, root->join_info_list)
2389 {
2390 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
2391
2392 if (sjinfo->jointype == JOIN_SEMI &&
2393 bms_is_member(cur_relid, sjinfo->syn_lefthand) &&
2394 bms_is_member(outer_relid, sjinfo->syn_righthand))
2395 {
2396 /* Estimate number of unique-ified rows */
2397 double nraw;
2398 double nunique;
2399
2401 nunique = estimate_num_groups(root,
2402 sjinfo->semi_rhs_exprs,
2403 nraw,
2404 NULL,
2405 NULL);
2406 if (rowcount > nunique)
2407 rowcount = nunique;
2408 }
2409 }
2410 return rowcount;
2411}
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:2425
@ JOIN_SEMI
Definition: nodes.h:317
#define lfirst(lc)
Definition: pg_list.h:172
tree ctl root
Definition: radixtree.h:1857
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3771
Relids syn_lefthand
Definition: pathnodes.h:3119
List * semi_rhs_exprs
Definition: pathnodes.h:3132
JoinType jointype
Definition: pathnodes.h:3121
Relids syn_righthand
Definition: pathnodes.h:3120

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 2425 of file indxpath.c.

2426{
2427 double rowcount = 1.0;
2428 int relid;
2429
2430 relid = -1;
2431 while ((relid = bms_next_member(relids, relid)) >= 0)
2432 {
2433 RelOptInfo *rel;
2434
2435 /* Paranoia: ignore bogus relid indexes */
2436 if (relid >= root->simple_rel_array_size)
2437 continue;
2438 rel = root->simple_rel_array[relid];
2439 if (rel == NULL)
2440 continue;
2441 Assert(rel->relid == relid); /* sanity check on array */
2442
2443 /* Relation could be proven empty, if so ignore */
2444 if (IS_DUMMY_REL(rel))
2445 continue;
2446
2447 /* Otherwise, rel's rows estimate should be valid by now */
2448 Assert(rel->rows > 0);
2449
2450 /* Accumulate product */
2451 rowcount *= rel->rows;
2452 }
2453 return rowcount;
2454}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1305
Assert(PointerIsAligned(start, uint64))
#define IS_DUMMY_REL(r)
Definition: pathnodes.h:2194
Index relid
Definition: pathnodes.h:973
Cardinality rows
Definition: pathnodes.h:933

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 2059 of file indxpath.c.

2060{
2061 BitmapAndPath *apath;
2062
2063 /*
2064 * Might as well build a real BitmapAndPath here, as the work is slightly
2065 * too complicated to be worth repeating just to save one palloc.
2066 */
2067 apath = create_bitmap_and_path(root, rel, paths);
2068
2069 return bitmap_scan_cost_est(root, rel, (Path *) apath);
2070}
static Cost bitmap_scan_cost_est(PlannerInfo *root, RelOptInfo *rel, Path *ipath)
Definition: indxpath.c:2025
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 2025 of file indxpath.c.

2026{
2027 BitmapHeapPath bpath;
2028
2029 /* Set up a dummy BitmapHeapPath */
2030 bpath.path.type = T_BitmapHeapPath;
2031 bpath.path.pathtype = T_BitmapHeapScan;
2032 bpath.path.parent = rel;
2033 bpath.path.pathtarget = rel->reltarget;
2034 bpath.path.param_info = ipath->param_info;
2035 bpath.path.pathkeys = NIL;
2036 bpath.bitmapqual = ipath;
2037
2038 /*
2039 * Check the cost of temporary path without considering parallelism.
2040 * Parallel bitmap heap path will be considered at later stage.
2041 */
2042 bpath.path.parallel_workers = 0;
2043
2044 /* Now we can do cost_bitmap_heap_scan */
2045 cost_bitmap_heap_scan(&bpath.path, root, rel,
2046 bpath.path.param_info,
2047 ipath,
2049 PATH_REQ_OUTER(ipath)));
2050
2051 return bpath.path.total_cost;
2052}
void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, Path *bitmapqual, double loop_count)
Definition: costsize.c:997
static double get_loop_count(PlannerInfo *root, Index cur_relid, Relids outer_relids)
Definition: indxpath.c:2328
#define PATH_REQ_OUTER(path)
Definition: pathnodes.h:1917
#define NIL
Definition: pg_list.h:68
Path * bitmapqual
Definition: pathnodes.h:2033
List * pathkeys
Definition: pathnodes.h:1913
NodeTag pathtype
Definition: pathnodes.h:1873
int parallel_workers
Definition: pathnodes.h:1904
Cost total_cost
Definition: pathnodes.h:1910
struct PathTarget * reltarget
Definition: pathnodes.h:949

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 812 of file indxpath.c.

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

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 1094 of file indxpath.c.

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

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 2229 of file indxpath.c.

2230{
2231 bool result;
2232 Bitmapset *attrs_used = NULL;
2233 Bitmapset *index_canreturn_attrs = NULL;
2234 ListCell *lc;
2235 int i;
2236
2237 /* Index-only scans must be enabled */
2239 return false;
2240
2241 /*
2242 * Check that all needed attributes of the relation are available from the
2243 * index.
2244 */
2245
2246 /*
2247 * First, identify all the attributes needed for joins or final output.
2248 * Note: we must look at rel's targetlist, not the attr_needed data,
2249 * because attr_needed isn't computed for inheritance child rels.
2250 */
2251 pull_varattnos((Node *) rel->reltarget->exprs, rel->relid, &attrs_used);
2252
2253 /*
2254 * Add all the attributes used by restriction clauses; but consider only
2255 * those clauses not implied by the index predicate, since ones that are
2256 * so implied don't need to be checked explicitly in the plan.
2257 *
2258 * Note: attributes used only in index quals would not be needed at
2259 * runtime either, if we are certain that the index is not lossy. However
2260 * it'd be complicated to account for that accurately, and it doesn't
2261 * matter in most cases, since we'd conclude that such attributes are
2262 * available from the index anyway.
2263 */
2264 foreach(lc, index->indrestrictinfo)
2265 {
2266 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2267
2268 pull_varattnos((Node *) rinfo->clause, rel->relid, &attrs_used);
2269 }
2270
2271 /*
2272 * Construct a bitmapset of columns that the index can return back in an
2273 * index-only scan.
2274 */
2275 for (i = 0; i < index->ncolumns; i++)
2276 {
2277 int attno = index->indexkeys[i];
2278
2279 /*
2280 * For the moment, we just ignore index expressions. It might be nice
2281 * to do something with them, later.
2282 */
2283 if (attno == 0)
2284 continue;
2285
2286 if (index->canreturn[i])
2287 index_canreturn_attrs =
2288 bms_add_member(index_canreturn_attrs,
2290 }
2291
2292 /* Do we have all the necessary attributes? */
2293 result = bms_is_subset(attrs_used, index_canreturn_attrs);
2294
2295 bms_free(attrs_used);
2296 bms_free(index_canreturn_attrs);
2297
2298 return result;
2299}
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:814
bool enable_indexonlyscan
Definition: costsize.c:147
int i
Definition: isn.c:77
Definition: nodes.h:135
List * exprs
Definition: pathnodes.h:1780
#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 3943 of file indxpath.c.

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

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 1787 of file indxpath.c.

1788{
1789 int npaths = list_length(paths);
1790 PathClauseUsage **pathinfoarray;
1791 PathClauseUsage *pathinfo;
1792 List *clauselist;
1793 List *bestpaths = NIL;
1794 Cost bestcost = 0;
1795 int i,
1796 j;
1797 ListCell *l;
1798
1799 Assert(npaths > 0); /* else caller error */
1800 if (npaths == 1)
1801 return (Path *) linitial(paths); /* easy case */
1802
1803 /*
1804 * In theory we should consider every nonempty subset of the given paths.
1805 * In practice that seems like overkill, given the crude nature of the
1806 * estimates, not to mention the possible effects of higher-level AND and
1807 * OR clauses. Moreover, it's completely impractical if there are a large
1808 * number of paths, since the work would grow as O(2^N).
1809 *
1810 * As a heuristic, we first check for paths using exactly the same sets of
1811 * WHERE clauses + index predicate conditions, and reject all but the
1812 * cheapest-to-scan in any such group. This primarily gets rid of indexes
1813 * that include the interesting columns but also irrelevant columns. (In
1814 * situations where the DBA has gone overboard on creating variant
1815 * indexes, this can make for a very large reduction in the number of
1816 * paths considered further.)
1817 *
1818 * We then sort the surviving paths with the cheapest-to-scan first, and
1819 * for each path, consider using that path alone as the basis for a bitmap
1820 * scan. Then we consider bitmap AND scans formed from that path plus
1821 * each subsequent (higher-cost) path, adding on a subsequent path if it
1822 * results in a reduction in the estimated total scan cost. This means we
1823 * consider about O(N^2) rather than O(2^N) path combinations, which is
1824 * quite tolerable, especially given than N is usually reasonably small
1825 * because of the prefiltering step. The cheapest of these is returned.
1826 *
1827 * We will only consider AND combinations in which no two indexes use the
1828 * same WHERE clause. This is a bit of a kluge: it's needed because
1829 * costsize.c and clausesel.c aren't very smart about redundant clauses.
1830 * They will usually double-count the redundant clauses, producing a
1831 * too-small selectivity that makes a redundant AND step look like it
1832 * reduces the total cost. Perhaps someday that code will be smarter and
1833 * we can remove this limitation. (But note that this also defends
1834 * against flat-out duplicate input paths, which can happen because
1835 * match_join_clauses_to_index will find the same OR join clauses that
1836 * extract_restriction_or_clauses has pulled OR restriction clauses out
1837 * of.)
1838 *
1839 * For the same reason, we reject AND combinations in which an index
1840 * predicate clause duplicates another clause. Here we find it necessary
1841 * to be even stricter: we'll reject a partial index if any of its
1842 * predicate clauses are implied by the set of WHERE clauses and predicate
1843 * clauses used so far. This covers cases such as a condition "x = 42"
1844 * used with a plain index, followed by a clauseless scan of a partial
1845 * index "WHERE x >= 40 AND x < 50". The partial index has been accepted
1846 * only because "x = 42" was present, and so allowing it would partially
1847 * double-count selectivity. (We could use predicate_implied_by on
1848 * regular qual clauses too, to have a more intelligent, but much more
1849 * expensive, check for redundancy --- but in most cases simple equality
1850 * seems to suffice.)
1851 */
1852
1853 /*
1854 * Extract clause usage info and detect any paths that use exactly the
1855 * same set of clauses; keep only the cheapest-to-scan of any such groups.
1856 * The surviving paths are put into an array for qsort'ing.
1857 */
1858 pathinfoarray = palloc_array(PathClauseUsage *, npaths);
1859 clauselist = NIL;
1860 npaths = 0;
1861 foreach(l, paths)
1862 {
1863 Path *ipath = (Path *) lfirst(l);
1864
1865 pathinfo = classify_index_clause_usage(ipath, &clauselist);
1866
1867 /* If it's unclassifiable, treat it as distinct from all others */
1868 if (pathinfo->unclassifiable)
1869 {
1870 pathinfoarray[npaths++] = pathinfo;
1871 continue;
1872 }
1873
1874 for (i = 0; i < npaths; i++)
1875 {
1876 if (!pathinfoarray[i]->unclassifiable &&
1877 bms_equal(pathinfo->clauseids, pathinfoarray[i]->clauseids))
1878 break;
1879 }
1880 if (i < npaths)
1881 {
1882 /* duplicate clauseids, keep the cheaper one */
1883 Cost ncost;
1884 Cost ocost;
1885 Selectivity nselec;
1886 Selectivity oselec;
1887
1888 cost_bitmap_tree_node(pathinfo->path, &ncost, &nselec);
1889 cost_bitmap_tree_node(pathinfoarray[i]->path, &ocost, &oselec);
1890 if (ncost < ocost)
1891 pathinfoarray[i] = pathinfo;
1892 }
1893 else
1894 {
1895 /* not duplicate clauseids, add to array */
1896 pathinfoarray[npaths++] = pathinfo;
1897 }
1898 }
1899
1900 /* If only one surviving path, we're done */
1901 if (npaths == 1)
1902 return pathinfoarray[0]->path;
1903
1904 /* Sort the surviving paths by index access cost */
1905 qsort(pathinfoarray, npaths, sizeof(PathClauseUsage *),
1907
1908 /*
1909 * For each surviving index, consider it as an "AND group leader", and see
1910 * whether adding on any of the later indexes results in an AND path with
1911 * cheaper total cost than before. Then take the cheapest AND group.
1912 *
1913 * Note: paths that are either clauseless or unclassifiable will have
1914 * empty clauseids, so that they will not be rejected by the clauseids
1915 * filter here, nor will they cause later paths to be rejected by it.
1916 */
1917 for (i = 0; i < npaths; i++)
1918 {
1919 Cost costsofar;
1920 List *qualsofar;
1921 Bitmapset *clauseidsofar;
1922
1923 pathinfo = pathinfoarray[i];
1924 paths = list_make1(pathinfo->path);
1925 costsofar = bitmap_scan_cost_est(root, rel, pathinfo->path);
1926 qualsofar = list_concat_copy(pathinfo->quals, pathinfo->preds);
1927 clauseidsofar = bms_copy(pathinfo->clauseids);
1928
1929 for (j = i + 1; j < npaths; j++)
1930 {
1931 Cost newcost;
1932
1933 pathinfo = pathinfoarray[j];
1934 /* Check for redundancy */
1935 if (bms_overlap(pathinfo->clauseids, clauseidsofar))
1936 continue; /* consider it redundant */
1937 if (pathinfo->preds)
1938 {
1939 bool redundant = false;
1940
1941 /* we check each predicate clause separately */
1942 foreach(l, pathinfo->preds)
1943 {
1944 Node *np = (Node *) lfirst(l);
1945
1946 if (predicate_implied_by(list_make1(np), qualsofar, false))
1947 {
1948 redundant = true;
1949 break; /* out of inner foreach loop */
1950 }
1951 }
1952 if (redundant)
1953 continue;
1954 }
1955 /* tentatively add new path to paths, so we can estimate cost */
1956 paths = lappend(paths, pathinfo->path);
1957 newcost = bitmap_and_cost_est(root, rel, paths);
1958 if (newcost < costsofar)
1959 {
1960 /* keep new path in paths, update subsidiary variables */
1961 costsofar = newcost;
1962 qualsofar = list_concat(qualsofar, pathinfo->quals);
1963 qualsofar = list_concat(qualsofar, pathinfo->preds);
1964 clauseidsofar = bms_add_members(clauseidsofar,
1965 pathinfo->clauseids);
1966 }
1967 else
1968 {
1969 /* reject new path, remove it from paths list */
1970 paths = list_truncate(paths, list_length(paths) - 1);
1971 }
1972 }
1973
1974 /* Keep the cheapest AND-group (or singleton) */
1975 if (i == 0 || costsofar < bestcost)
1976 {
1977 bestpaths = paths;
1978 bestcost = costsofar;
1979 }
1980
1981 /* some easy cleanup (we don't try real hard though) */
1982 list_free(qualsofar);
1983 }
1984
1985 if (list_length(bestpaths) == 1)
1986 return (Path *) linitial(bestpaths); /* no need for AND */
1987 return (Path *) create_bitmap_and_path(root, rel, bestpaths);
1988}
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:581
void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
Definition: costsize.c:1096
#define palloc_array(type, count)
Definition: fe_memutils.h:76
static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
Definition: indxpath.c:2059
static PathClauseUsage * classify_index_clause_usage(Path *path, List **clauselist)
Definition: indxpath.c:2088
static int path_usage_comparator(const void *a, const void *b)
Definition: indxpath.c:1992
int j
Definition: isn.c:78
void list_free(List *list)
Definition: list.c:1546
List * list_truncate(List *list, int new_size)
Definition: list.c:631
double Cost
Definition: nodes.h:261
double Selectivity
Definition: nodes.h:260
#define linitial(l)
Definition: pg_list.h:178
#define qsort(a, b, c, d)
Definition: port.h:495
List * quals
Definition: indxpath.c:65
List * preds
Definition: indxpath.c:66
Bitmapset * clauseids
Definition: indxpath.c:67
bool unclassifiable
Definition: indxpath.c:68
Path * path
Definition: indxpath.c:64

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_array, 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 2088 of file indxpath.c.

2089{
2090 PathClauseUsage *result;
2091 Bitmapset *clauseids;
2092 ListCell *lc;
2093
2095 result->path = path;
2096
2097 /* Recursively find the quals and preds used by the path */
2098 result->quals = NIL;
2099 result->preds = NIL;
2100 find_indexpath_quals(path, &result->quals, &result->preds);
2101
2102 /*
2103 * Some machine-generated queries have outlandish numbers of qual clauses.
2104 * To avoid getting into O(N^2) behavior even in this preliminary
2105 * classification step, we want to limit the number of entries we can
2106 * accumulate in *clauselist. Treat any path with more than 100 quals +
2107 * preds as unclassifiable, which will cause calling code to consider it
2108 * distinct from all other paths.
2109 */
2110 if (list_length(result->quals) + list_length(result->preds) > 100)
2111 {
2112 result->clauseids = NULL;
2113 result->unclassifiable = true;
2114 return result;
2115 }
2116
2117 /* Build up a bitmapset representing the quals and preds */
2118 clauseids = NULL;
2119 foreach(lc, result->quals)
2120 {
2121 Node *node = (Node *) lfirst(lc);
2122
2123 clauseids = bms_add_member(clauseids,
2124 find_list_position(node, clauselist));
2125 }
2126 foreach(lc, result->preds)
2127 {
2128 Node *node = (Node *) lfirst(lc);
2129
2130 clauseids = bms_add_member(clauseids,
2131 find_list_position(node, clauselist));
2132 }
2133 result->clauseids = clauseids;
2134 result->unclassifiable = false;
2135
2136 return result;
2137}
#define palloc_object(type)
Definition: fe_memutils.h:74
static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds)
Definition: indxpath.c:2156
static int find_list_position(Node *node, List **nodelist)
Definition: indxpath.c:2203

References bms_add_member(), PathClauseUsage::clauseids, find_indexpath_quals(), find_list_position(), lfirst, list_length(), NIL, palloc_object, 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 439 of file indxpath.c.

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

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 505 of file indxpath.c.

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

◆ contain_strippable_phv_walker()

static bool contain_strippable_phv_walker ( Node node,
void *  context 
)
static

Definition at line 4469 of file indxpath.c.

4470{
4471 if (node == NULL)
4472 return false;
4473
4474 if (IsA(node, PlaceHolderVar))
4475 {
4476 PlaceHolderVar *phv = (PlaceHolderVar *) node;
4477
4478 if (bms_is_empty(phv->phnullingrels))
4479 return true;
4480 }
4481
4483 context);
4484}
static bool contain_strippable_phv_walker(Node *node, void *context)
Definition: indxpath.c:4469
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
Relids phnullingrels
Definition: pathnodes.h:3019

References bms_is_empty, contain_strippable_phv_walker(), expression_tree_walker, IsA, and PlaceHolderVar::phnullingrels.

Referenced by contain_strippable_phv_walker(), and strip_phvs_in_index_operand().

◆ create_index_paths()

void create_index_paths ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 242 of file indxpath.c.

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

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

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 686 of file indxpath.c.

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

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 3496 of file indxpath.c.

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

References bms_is_member(), BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, RestrictInfo::clause, RowCompareExpr::cmptype, 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, 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 2156 of file indxpath.c.

2157{
2158 if (IsA(bitmapqual, BitmapAndPath))
2159 {
2160 BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
2161 ListCell *l;
2162
2163 foreach(l, apath->bitmapquals)
2164 {
2165 find_indexpath_quals((Path *) lfirst(l), quals, preds);
2166 }
2167 }
2168 else if (IsA(bitmapqual, BitmapOrPath))
2169 {
2170 BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
2171 ListCell *l;
2172
2173 foreach(l, opath->bitmapquals)
2174 {
2175 find_indexpath_quals((Path *) lfirst(l), quals, preds);
2176 }
2177 }
2178 else if (IsA(bitmapqual, IndexPath))
2179 {
2180 IndexPath *ipath = (IndexPath *) bitmapqual;
2181 ListCell *l;
2182
2183 foreach(l, ipath->indexclauses)
2184 {
2185 IndexClause *iclause = (IndexClause *) lfirst(l);
2186
2187 *quals = lappend(*quals, iclause->rinfo->clause);
2188 }
2189 *preds = list_concat(*preds, ipath->indexinfo->indpred);
2190 }
2191 else
2192 elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
2193}
#define nodeTag(nodeptr)
Definition: nodes.h:139
List * bitmapquals
Definition: pathnodes.h:2045
List * bitmapquals
Definition: pathnodes.h:2058
List * indpred
Definition: pathnodes.h:1311
List * indexclauses
Definition: pathnodes.h:1959
IndexOptInfo * indexinfo
Definition: pathnodes.h:1958

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

Referenced by classify_index_clause_usage(), and find_indexpath_quals().

◆ find_list_position()

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

Definition at line 2203 of file indxpath.c.

2204{
2205 int i;
2206 ListCell *lc;
2207
2208 i = 0;
2209 foreach(lc, *nodelist)
2210 {
2211 Node *oldnode = (Node *) lfirst(lc);
2212
2213 if (equal(node, oldnode))
2214 return i;
2215 i++;
2216 }
2217
2218 *nodelist = lappend(*nodelist, node);
2219
2220 return i;
2221}
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 1631 of file indxpath.c.

1633{
1634 List *result = NIL;
1635 List *all_clauses;
1636 ListCell *lc;
1637
1638 /*
1639 * We can use both the current and other clauses as context for
1640 * build_paths_for_OR; no need to remove ORs from the lists.
1641 */
1642 all_clauses = list_concat_copy(clauses, other_clauses);
1643
1644 foreach(lc, clauses)
1645 {
1647 List *pathlist;
1648 Path *bitmapqual;
1649 ListCell *j;
1650 List *groupedArgs;
1651 List *inner_other_clauses = NIL;
1652
1653 /* Ignore RestrictInfos that aren't ORs */
1654 if (!restriction_is_or_clause(rinfo))
1655 continue;
1656
1657 /*
1658 * We must be able to match at least one index to each of the arms of
1659 * the OR, else we can't use it.
1660 */
1661 pathlist = NIL;
1662
1663 /*
1664 * Group the similar OR-clause arguments into dedicated RestrictInfos,
1665 * because each of those RestrictInfos has a chance to match the index
1666 * as a whole.
1667 */
1668 groupedArgs = group_similar_or_args(root, rel, rinfo);
1669
1670 if (groupedArgs != ((BoolExpr *) rinfo->orclause)->args)
1671 {
1672 /*
1673 * Some parts of the rinfo were probably grouped. In this case,
1674 * we have a set of sub-rinfos that together are an exact
1675 * duplicate of rinfo. Thus, we need to remove the rinfo from
1676 * other clauses. match_clauses_to_index detects duplicated
1677 * iclauses by comparing pointers to original rinfos that would be
1678 * different. So, we must delete rinfo to avoid de-facto
1679 * duplicated clauses in the index clauses list.
1680 */
1681 inner_other_clauses = list_delete(list_copy(all_clauses), rinfo);
1682 }
1683
1684 foreach(j, groupedArgs)
1685 {
1686 Node *orarg = (Node *) lfirst(j);
1687 List *indlist;
1688
1689 /* OR arguments should be ANDs or sub-RestrictInfos */
1690 if (is_andclause(orarg))
1691 {
1692 List *andargs = ((BoolExpr *) orarg)->args;
1693
1694 indlist = build_paths_for_OR(root, rel,
1695 andargs,
1696 all_clauses);
1697
1698 /* Recurse in case there are sub-ORs */
1699 indlist = list_concat(indlist,
1701 andargs,
1702 all_clauses));
1703 }
1705 {
1706 RestrictInfo *ri = castNode(RestrictInfo, orarg);
1707
1708 /*
1709 * Generate bitmap paths for the group of similar OR-clause
1710 * arguments.
1711 */
1713 rel, ri,
1714 inner_other_clauses);
1715
1716 if (indlist == NIL)
1717 {
1718 pathlist = NIL;
1719 break;
1720 }
1721 else
1722 {
1723 pathlist = list_concat(pathlist, indlist);
1724 continue;
1725 }
1726 }
1727 else
1728 {
1729 RestrictInfo *ri = castNode(RestrictInfo, orarg);
1730 List *orargs;
1731
1732 orargs = list_make1(ri);
1733
1734 indlist = build_paths_for_OR(root, rel,
1735 orargs,
1736 all_clauses);
1737 }
1738
1739 /*
1740 * If nothing matched this arm, we can't do anything with this OR
1741 * clause.
1742 */
1743 if (indlist == NIL)
1744 {
1745 pathlist = NIL;
1746 break;
1747 }
1748
1749 /*
1750 * OK, pick the most promising AND combination, and add it to
1751 * pathlist.
1752 */
1753 bitmapqual = choose_bitmap_and(root, rel, indlist);
1754 pathlist = lappend(pathlist, bitmapqual);
1755 }
1756
1757 if (inner_other_clauses != NIL)
1758 list_free(inner_other_clauses);
1759
1760 /*
1761 * If we have a match for every arm, then turn them into a
1762 * BitmapOrPath, and add to result list.
1763 */
1764 if (pathlist != NIL)
1765 {
1766 bitmapqual = (Path *) create_bitmap_or_path(root, rel, pathlist);
1767 result = lappend(result, bitmapqual);
1768 }
1769 }
1770
1771 return result;
1772}
static List * build_paths_for_OR(PlannerInfo *root, RelOptInfo *rel, List *clauses, List *other_clauses)
Definition: indxpath.c:1094
static List * group_similar_or_args(PlannerInfo *root, RelOptInfo *rel, RestrictInfo *rinfo)
Definition: indxpath.c:1273
static List * make_bitmap_paths_for_or_group(PlannerInfo *root, RelOptInfo *rel, RestrictInfo *ri, List *other_clauses)
Definition: indxpath.c:1550
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:182
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(), generate_bitmap_or_paths(), 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(), and generate_bitmap_or_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 3070 of file indxpath.c.

3076{
3077 Oid prosupport = get_func_support(funcid);
3079 List *sresult;
3080
3081 if (!OidIsValid(prosupport))
3082 return NULL;
3083
3084 req.type = T_SupportRequestIndexCondition;
3085 req.root = root;
3086 req.funcid = funcid;
3087 req.node = (Node *) rinfo->clause;
3088 req.indexarg = indexarg;
3089 req.index = index;
3090 req.indexcol = indexcol;
3091 req.opfamily = index->opfamily[indexcol];
3092 req.indexcollation = index->indexcollations[indexcol];
3093
3094 req.lossy = true; /* default assumption */
3095
3096 sresult = (List *)
3098 PointerGetDatum(&req)));
3099
3100 if (sresult != NIL)
3101 {
3102 IndexClause *iclause = makeNode(IndexClause);
3103 List *indexquals = NIL;
3104 ListCell *lc;
3105
3106 /*
3107 * The support function API says it should just give back bare
3108 * clauses, so here we must wrap each one in a RestrictInfo.
3109 */
3110 foreach(lc, sresult)
3111 {
3112 Expr *clause = (Expr *) lfirst(lc);
3113
3114 indexquals = lappend(indexquals,
3116 }
3117
3118 iclause->rinfo = rinfo;
3119 iclause->indexquals = indexquals;
3120 iclause->lossy = req.lossy;
3121 iclause->indexcol = indexcol;
3122 iclause->indexcols = NIL;
3123
3124 return iclause;
3125 }
3126
3127 return NULL;
3128}
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:722
RegProcedure get_func_support(Oid funcid)
Definition: lsyscache.c:2008
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:352
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:342

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 718 of file indxpath.c.

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

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 608 of file indxpath.c.

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

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 2328 of file indxpath.c.

2329{
2330 double result;
2331 int outer_relid;
2332
2333 /* For a non-parameterized path, just return 1.0 quickly */
2334 if (outer_relids == NULL)
2335 return 1.0;
2336
2337 result = 0.0;
2338 outer_relid = -1;
2339 while ((outer_relid = bms_next_member(outer_relids, outer_relid)) >= 0)
2340 {
2341 RelOptInfo *outer_rel;
2342 double rowcount;
2343
2344 /* Paranoia: ignore bogus relid indexes */
2345 if (outer_relid >= root->simple_rel_array_size)
2346 continue;
2347 outer_rel = root->simple_rel_array[outer_relid];
2348 if (outer_rel == NULL)
2349 continue;
2350 Assert(outer_rel->relid == outer_relid); /* sanity check on array */
2351
2352 /* Other relation could be proven empty, if so ignore */
2353 if (IS_DUMMY_REL(outer_rel))
2354 continue;
2355
2356 /* Otherwise, rel's rows estimate should be valid by now */
2357 Assert(outer_rel->rows > 0);
2358
2359 /* Check to see if rel is on the inside of any semijoins */
2361 cur_relid,
2362 outer_relid,
2363 outer_rel->rows);
2364
2365 /* Remember smallest row count estimate among the outer rels */
2366 if (result == 0.0 || result > rowcount)
2367 result = rowcount;
2368 }
2369 /* Return 1.0 if we found no valid relations (shouldn't happen) */
2370 return (result > 0.0) ? result : 1.0;
2371}
static double adjust_rowcount_for_semijoins(PlannerInfo *root, Index cur_relid, Index outer_relid, double rowcount)
Definition: indxpath.c:2381

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 1273 of file indxpath.c.

1274{
1275 int n;
1276 int i;
1277 int group_start;
1278 OrArgIndexMatch *matches;
1279 bool matched = false;
1280 ListCell *lc;
1281 ListCell *lc2;
1282 List *orargs;
1283 List *result = NIL;
1284 Index relid = rel->relid;
1285
1286 Assert(IsA(rinfo->orclause, BoolExpr));
1287 orargs = ((BoolExpr *) rinfo->orclause)->args;
1288 n = list_length(orargs);
1289
1290 /*
1291 * To avoid N^2 behavior, take utility pass along the list of OR-clause
1292 * arguments. For each argument, fill the OrArgIndexMatch structure,
1293 * which will be used to sort these arguments at the next step.
1294 */
1295 i = -1;
1296 matches = palloc_array(OrArgIndexMatch, n);
1297 foreach(lc, orargs)
1298 {
1299 Node *arg = lfirst(lc);
1300 RestrictInfo *argrinfo;
1301 OpExpr *clause;
1302 Oid opno;
1303 Node *leftop,
1304 *rightop;
1305 Node *nonConstExpr;
1306 int indexnum;
1307 int colnum;
1308
1309 i++;
1310 matches[i].argindex = i;
1311 matches[i].groupindex = i;
1312 matches[i].indexnum = -1;
1313 matches[i].colnum = -1;
1314 matches[i].opno = InvalidOid;
1315 matches[i].inputcollid = InvalidOid;
1316
1317 if (!IsA(arg, RestrictInfo))
1318 continue;
1319
1320 argrinfo = castNode(RestrictInfo, arg);
1321
1322 /* Only operator clauses can match */
1323 if (!IsA(argrinfo->clause, OpExpr))
1324 continue;
1325
1326 clause = (OpExpr *) argrinfo->clause;
1327 opno = clause->opno;
1328
1329 /* Only binary operators can match */
1330 if (list_length(clause->args) != 2)
1331 continue;
1332
1333 /*
1334 * Ignore any RelabelType node above the operands. This is needed to
1335 * be able to apply indexscanning in binary-compatible-operator cases.
1336 * Note: we can assume there is at most one RelabelType node;
1337 * eval_const_expressions() will have simplified if more than one.
1338 */
1339 leftop = get_leftop(clause);
1340 if (IsA(leftop, RelabelType))
1341 leftop = (Node *) ((RelabelType *) leftop)->arg;
1342
1343 rightop = get_rightop(clause);
1344 if (IsA(rightop, RelabelType))
1345 rightop = (Node *) ((RelabelType *) rightop)->arg;
1346
1347 /*
1348 * Check for clauses of the form: (indexkey operator constant) or
1349 * (constant operator indexkey). But we don't know a particular index
1350 * yet. Therefore, we try to distinguish the potential index key and
1351 * constant first, then search for a matching index key among all
1352 * indexes.
1353 */
1354 if (bms_is_member(relid, argrinfo->right_relids) &&
1355 !bms_is_member(relid, argrinfo->left_relids) &&
1357 {
1358 opno = get_commutator(opno);
1359
1360 if (!OidIsValid(opno))
1361 {
1362 /* commutator doesn't exist, we can't reverse the order */
1363 continue;
1364 }
1365 nonConstExpr = rightop;
1366 }
1367 else if (bms_is_member(relid, argrinfo->left_relids) &&
1368 !bms_is_member(relid, argrinfo->right_relids) &&
1370 {
1371 nonConstExpr = leftop;
1372 }
1373 else
1374 {
1375 continue;
1376 }
1377
1378 /*
1379 * Match non-constant part to the index key. It's possible that a
1380 * single non-constant part matches multiple index keys. It's OK, we
1381 * just stop with first matching index key. Given that this choice is
1382 * determined the same for every clause, we will group similar clauses
1383 * together anyway.
1384 */
1385 indexnum = 0;
1386 foreach(lc2, rel->indexlist)
1387 {
1389
1390 /*
1391 * Ignore index if it doesn't support bitmap scans or SAOP
1392 * clauses.
1393 */
1394 if (!index->amhasgetbitmap || !index->amsearcharray)
1395 continue;
1396
1397 for (colnum = 0; colnum < index->nkeycolumns; colnum++)
1398 {
1399 if (match_index_to_operand(nonConstExpr, colnum, index))
1400 {
1401 matches[i].indexnum = indexnum;
1402 matches[i].colnum = colnum;
1403 matches[i].opno = opno;
1404 matches[i].inputcollid = clause->inputcollid;
1405 matched = true;
1406 break;
1407 }
1408 }
1409
1410 /*
1411 * Stop looping through the indexes, if we managed to match
1412 * nonConstExpr to any index column.
1413 */
1414 if (matches[i].indexnum >= 0)
1415 break;
1416 indexnum++;
1417 }
1418 }
1419
1420 /*
1421 * Fast-path check: if no clause is matching to the index column, we can
1422 * just give up at this stage and return the clause list as-is.
1423 */
1424 if (!matched)
1425 {
1426 pfree(matches);
1427 return orargs;
1428 }
1429
1430 /*
1431 * Sort clauses to make similar clauses go together. But at the same
1432 * time, we would like to change the order of clauses as little as
1433 * possible. To do so, we reorder each group of similar clauses so that
1434 * the first item of the group stays in place, and all the other items are
1435 * moved after it. So, if there are no similar clauses, the order of
1436 * clauses stays the same. When there are some groups, required
1437 * reordering happens while the rest of the clauses remain in their
1438 * places. That is achieved by assigning a 'groupindex' to each clause:
1439 * the number of the first item in the group in the original clause list.
1440 */
1441 qsort(matches, n, sizeof(OrArgIndexMatch), or_arg_index_match_cmp);
1442
1443 /* Assign groupindex to the sorted clauses */
1444 for (i = 1; i < n; i++)
1445 {
1446 /*
1447 * When two clauses are similar and should belong to the same group,
1448 * copy the 'groupindex' from the previous clause. Given we are
1449 * considering clauses in direct order, all the clauses would have a
1450 * 'groupindex' equal to the 'groupindex' of the first clause in the
1451 * group.
1452 */
1453 if (matches[i].indexnum == matches[i - 1].indexnum &&
1454 matches[i].colnum == matches[i - 1].colnum &&
1455 matches[i].opno == matches[i - 1].opno &&
1456 matches[i].inputcollid == matches[i - 1].inputcollid &&
1457 matches[i].indexnum != -1)
1458 matches[i].groupindex = matches[i - 1].groupindex;
1459 }
1460
1461 /* Re-sort clauses first by groupindex then by argindex */
1463
1464 /*
1465 * Group similar clauses into single sub-restrictinfo. Side effect: the
1466 * resulting list of restrictions will be sorted by indexnum and colnum.
1467 */
1468 group_start = 0;
1469 for (i = 1; i <= n; i++)
1470 {
1471 /* Check if it's a group boundary */
1472 if (group_start >= 0 &&
1473 (i == n ||
1474 matches[i].indexnum != matches[group_start].indexnum ||
1475 matches[i].colnum != matches[group_start].colnum ||
1476 matches[i].opno != matches[group_start].opno ||
1477 matches[i].inputcollid != matches[group_start].inputcollid ||
1478 matches[i].indexnum == -1))
1479 {
1480 /*
1481 * One clause in group: add it "as is" to the upper-level OR.
1482 */
1483 if (i - group_start == 1)
1484 {
1485 result = lappend(result,
1486 list_nth(orargs,
1487 matches[group_start].argindex));
1488 }
1489 else
1490 {
1491 /*
1492 * Two or more clauses in a group: create a nested OR.
1493 */
1494 List *args = NIL;
1495 List *rargs = NIL;
1496 RestrictInfo *subrinfo;
1497 int j;
1498
1499 Assert(i - group_start >= 2);
1500
1501 /* Construct the list of nested OR arguments */
1502 for (j = group_start; j < i; j++)
1503 {
1504 Node *arg = list_nth(orargs, matches[j].argindex);
1505
1506 rargs = lappend(rargs, arg);
1507 if (IsA(arg, RestrictInfo))
1508 args = lappend(args, ((RestrictInfo *) arg)->clause);
1509 else
1510 args = lappend(args, arg);
1511 }
1512
1513 /* Construct the nested OR and wrap it with RestrictInfo */
1514 subrinfo = make_plain_restrictinfo(root,
1516 make_orclause(rargs),
1517 rinfo->is_pushed_down,
1518 rinfo->has_clone,
1519 rinfo->is_clone,
1520 rinfo->pseudoconstant,
1521 rinfo->security_level,
1522 rinfo->required_relids,
1523 rinfo->incompatible_relids,
1524 rinfo->outer_relids);
1525 result = lappend(result, subrinfo);
1526 }
1527
1528 group_start = i;
1529 }
1530 }
1531 pfree(matches);
1532 return result;
1533}
unsigned int Index
Definition: c.h:634
static int or_arg_index_match_cmp(const void *a, const void *b)
Definition: indxpath.c:1202
static int or_arg_index_match_cmp_group(const void *a, const void *b)
Definition: indxpath.c:1240
Expr * make_orclause(List *orclauses)
Definition: makefuncs.c:743
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:850
List * args
Definition: primnodes.h:868
bool is_pushed_down
Definition: pathnodes.h:2795
Index security_level
Definition: pathnodes.h:2814
Relids required_relids
Definition: pathnodes.h:2823
Relids outer_relids
Definition: pathnodes.h:2829
Relids incompatible_relids
Definition: pathnodes.h:2826
bool has_clone
Definition: pathnodes.h:2804

References arg, OrArgIndexMatch::argindex, generate_unaccent_rules::args, OpExpr::args, Assert(), bms_is_member(), castNode, RestrictInfo::clause, OrArgIndexMatch::colnum, contain_volatile_functions(), get_commutator(), get_leftop(), get_rightop(), OrArgIndexMatch::groupindex, 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(), or_arg_index_match_cmp_group(), RestrictInfo::outer_relids, palloc_array, pfree(), qsort, RelOptInfo::relid, 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 4305 of file indxpath.c.

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

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 4539 of file indxpath.c.

4540{
4541 /* pull_varnos is cheaper than volatility check, so do that first */
4542 if (bms_is_member(index->rel->relid, pull_varnos(root, expr)))
4543 return false; /* no good, contains Var of table */
4545 return false; /* no good, volatile comparison value */
4546 return true;
4547}

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

◆ IsBooleanOpfamily()

static bool IsBooleanOpfamily ( Oid  opfamily)
static

Definition at line 2793 of file indxpath.c.

2794{
2795 if (opfamily < FirstNormalObjectId)
2796 return IsBuiltinBooleanOpfamily(opfamily);
2797 else
2798 return op_in_opfamily(BooleanEqualOperator, opfamily);
2799}
bool op_in_opfamily(Oid opno, Oid opfamily)
Definition: lsyscache.c:68
#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 1550 of file indxpath.c.

1552{
1553 List *jointlist = NIL;
1554 List *splitlist = NIL;
1555 ListCell *lc;
1556 List *orargs;
1557 List *args = ((BoolExpr *) ri->orclause)->args;
1558 Cost jointcost = 0.0,
1559 splitcost = 0.0;
1560 Path *bitmapqual;
1561 List *indlist;
1562
1563 /*
1564 * First, try to match the whole group to the one index.
1565 */
1566 orargs = list_make1(ri);
1567 indlist = build_paths_for_OR(root, rel,
1568 orargs,
1569 other_clauses);
1570 if (indlist != NIL)
1571 {
1572 bitmapqual = choose_bitmap_and(root, rel, indlist);
1573 jointcost = bitmapqual->total_cost;
1574 jointlist = list_make1(bitmapqual);
1575 }
1576
1577 /*
1578 * If we manage to find a bitmap scan, which uses the group of OR-clause
1579 * arguments as a whole, we can skip matching OR-clause arguments
1580 * one-by-one as long as there are no other clauses, which can bring more
1581 * efficiency to one-by-one case.
1582 */
1583 if (jointlist != NIL && other_clauses == NIL)
1584 return jointlist;
1585
1586 /*
1587 * Also try to match all containing clauses one-by-one.
1588 */
1589 foreach(lc, args)
1590 {
1591 orargs = list_make1(lfirst(lc));
1592
1593 indlist = build_paths_for_OR(root, rel,
1594 orargs,
1595 other_clauses);
1596
1597 if (indlist == NIL)
1598 {
1599 splitlist = NIL;
1600 break;
1601 }
1602
1603 bitmapqual = choose_bitmap_and(root, rel, indlist);
1604 splitcost += bitmapqual->total_cost;
1605 splitlist = lappend(splitlist, bitmapqual);
1606 }
1607
1608 /*
1609 * Pick the best option.
1610 */
1611 if (splitlist == NIL)
1612 return jointlist;
1613 else if (jointlist == NIL)
1614 return splitlist;
1615 else
1616 return (jointcost < splitcost) ? jointlist : splitlist;
1617}

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 2818 of file indxpath.c.

2822{
2823 Node *clause = (Node *) rinfo->clause;
2824 Expr *op = NULL;
2825
2826 /* Direct match? */
2827 if (match_index_to_operand(clause, indexcol, index))
2828 {
2829 /* convert to indexkey = TRUE */
2830 op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2831 (Expr *) clause,
2832 (Expr *) makeBoolConst(true, false),
2834 }
2835 /* NOT clause? */
2836 else if (is_notclause(clause))
2837 {
2838 Node *arg = (Node *) get_notclausearg((Expr *) clause);
2839
2840 if (match_index_to_operand(arg, indexcol, index))
2841 {
2842 /* convert to indexkey = FALSE */
2843 op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2844 (Expr *) arg,
2845 (Expr *) makeBoolConst(false, false),
2847 }
2848 }
2849
2850 /*
2851 * Since we only consider clauses at top level of WHERE, we can convert
2852 * indexkey IS TRUE and indexkey IS FALSE to index searches as well. The
2853 * different meaning for NULL isn't important.
2854 */
2855 else if (clause && IsA(clause, BooleanTest))
2856 {
2857 BooleanTest *btest = (BooleanTest *) clause;
2858 Node *arg = (Node *) btest->arg;
2859
2860 if (btest->booltesttype == IS_TRUE &&
2861 match_index_to_operand(arg, indexcol, index))
2862 {
2863 /* convert to indexkey = TRUE */
2864 op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2865 (Expr *) arg,
2866 (Expr *) makeBoolConst(true, false),
2868 }
2869 else if (btest->booltesttype == IS_FALSE &&
2870 match_index_to_operand(arg, indexcol, index))
2871 {
2872 /* convert to indexkey = FALSE */
2873 op = make_opclause(BooleanEqualOperator, BOOLOID, false,
2874 (Expr *) arg,
2875 (Expr *) makeBoolConst(false, false),
2877 }
2878 }
2879
2880 /*
2881 * If we successfully made an operator clause from the given qual, we must
2882 * wrap it in an IndexClause. It's not lossy.
2883 */
2884 if (op)
2885 {
2886 IndexClause *iclause = makeNode(IndexClause);
2887
2888 iclause->rinfo = rinfo;
2890 iclause->lossy = false;
2891 iclause->indexcol = indexcol;
2892 iclause->indexcols = NIL;
2893 return iclause;
2894 }
2895
2896 return NULL;
2897}
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:408
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:125
static Expr * get_notclausearg(const void *notclause)
Definition: nodeFuncs.h:134
@ IS_TRUE
Definition: primnodes.h:2001
@ IS_FALSE
Definition: primnodes.h:2001
BoolTestType booltesttype
Definition: primnodes.h:2008
Expr * arg
Definition: primnodes.h:2007

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 2588 of file indxpath.c.

2592{
2593 int indexcol;
2594
2595 /*
2596 * Never match pseudoconstants to indexes. (Normally a match could not
2597 * happen anyway, since a pseudoconstant clause couldn't contain a Var,
2598 * but what if someone builds an expression index on a constant? It's not
2599 * totally unreasonable to do so with a partial index, either.)
2600 */
2601 if (rinfo->pseudoconstant)
2602 return;
2603
2604 /*
2605 * If clause can't be used as an indexqual because it must wait till after
2606 * some lower-security-level restriction clause, reject it.
2607 */
2608 if (!restriction_is_securely_promotable(rinfo, index->rel))
2609 return;
2610
2611 /* OK, check each index key column for a match */
2612 for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
2613 {
2614 IndexClause *iclause;
2615 ListCell *lc;
2616
2617 /* Ignore duplicates */
2618 foreach(lc, clauseset->indexclauses[indexcol])
2619 {
2620 iclause = (IndexClause *) lfirst(lc);
2621
2622 if (iclause->rinfo == rinfo)
2623 return;
2624 }
2625
2626 /* OK, try to match the clause to the index column */
2628 rinfo,
2629 indexcol,
2630 index);
2631 if (iclause)
2632 {
2633 /* Success, so record it */
2634 clauseset->indexclauses[indexcol] =
2635 lappend(clauseset->indexclauses[indexcol], iclause);
2636 clauseset->nonempty = true;
2637 return;
2638 }
2639 }
2640}
static IndexClause * match_clause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:2712
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 2712 of file indxpath.c.

2716{
2717 IndexClause *iclause;
2718 Expr *clause = rinfo->clause;
2719 Oid opfamily;
2720
2721 Assert(indexcol < index->nkeycolumns);
2722
2723 /*
2724 * Historically this code has coped with NULL clauses. That's probably
2725 * not possible anymore, but we might as well continue to cope.
2726 */
2727 if (clause == NULL)
2728 return NULL;
2729
2730 /* First check for boolean-index cases. */
2731 opfamily = index->opfamily[indexcol];
2732 if (IsBooleanOpfamily(opfamily))
2733 {
2734 iclause = match_boolean_index_clause(root, rinfo, indexcol, index);
2735 if (iclause)
2736 return iclause;
2737 }
2738
2739 /*
2740 * Clause must be an opclause, funcclause, ScalarArrayOpExpr,
2741 * RowCompareExpr, or OR-clause that could be converted to SAOP. Or, if
2742 * the index supports it, we can handle IS NULL/NOT NULL clauses.
2743 */
2744 if (IsA(clause, OpExpr))
2745 {
2746 return match_opclause_to_indexcol(root, rinfo, indexcol, index);
2747 }
2748 else if (IsA(clause, FuncExpr))
2749 {
2750 return match_funcclause_to_indexcol(root, rinfo, indexcol, index);
2751 }
2752 else if (IsA(clause, ScalarArrayOpExpr))
2753 {
2754 return match_saopclause_to_indexcol(root, rinfo, indexcol, index);
2755 }
2756 else if (IsA(clause, RowCompareExpr))
2757 {
2758 return match_rowcompare_to_indexcol(root, rinfo, indexcol, index);
2759 }
2760 else if (restriction_is_or_clause(rinfo))
2761 {
2762 return match_orclause_to_indexcol(root, rinfo, indexcol, index);
2763 }
2764 else if (index->amsearchnulls && IsA(clause, NullTest))
2765 {
2766 NullTest *nt = (NullTest *) clause;
2767
2768 if (!nt->argisrow &&
2769 match_index_to_operand((Node *) nt->arg, indexcol, index))
2770 {
2771 iclause = makeNode(IndexClause);
2772 iclause->rinfo = rinfo;
2773 iclause->indexquals = list_make1(rinfo);
2774 iclause->lossy = false;
2775 iclause->indexcol = indexcol;
2776 iclause->indexcols = NIL;
2777 return iclause;
2778 }
2779 }
2780
2781 return NULL;
2782}
static IndexClause * match_saopclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3136
static IndexClause * match_orclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3298
static IndexClause * match_opclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:2905
static IndexClause * match_rowcompare_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3204
static IndexClause * match_funcclause_to_indexcol(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3024
Expr * arg
Definition: primnodes.h:1983

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 3829 of file indxpath.c.

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

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 2555 of file indxpath.c.

2559{
2560 ListCell *lc;
2561
2562 foreach(lc, clauses)
2563 {
2565
2566 match_clause_to_index(root, rinfo, index, clauseset);
2567 }
2568}
static void match_clause_to_index(PlannerInfo *root, RestrictInfo *rinfo, IndexOptInfo *index, IndexClauseSet *clauseset)
Definition: indxpath.c:2588

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 2517 of file indxpath.c.

2519{
2520 int indexcol;
2521
2522 /* No work if rel is not in any such ECs */
2523 if (!index->rel->has_eclass_joins)
2524 return;
2525
2526 for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
2527 {
2529 List *clauses;
2530
2531 /* Generate clauses, skipping any that join to lateral_referencers */
2532 arg.index = index;
2533 arg.indexcol = indexcol;
2535 index->rel,
2537 &arg,
2538 index->rel->lateral_referencers);
2539
2540 /*
2541 * We have to check whether the results actually do match the index,
2542 * since for non-btree indexes the EC's equality operators might not
2543 * be in the index opclass (cf ec_member_matches_indexcol).
2544 */
2545 match_clauses_to_index(root, clauses, index, clauseset);
2546 }
2547}
List * generate_implied_equalities_for_column(PlannerInfo *root, RelOptInfo *rel, ec_matches_callback_type callback, void *callback_arg, Relids prohibited_rels)
Definition: equivclass.c:3239
static bool ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg)
Definition: indxpath.c:4091

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 3024 of file indxpath.c.

3028{
3029 FuncExpr *clause = (FuncExpr *) rinfo->clause;
3030 int indexarg;
3031 ListCell *lc;
3032
3033 /*
3034 * We have no built-in intelligence about function clauses, but if there's
3035 * a planner support function, it might be able to do something. But, to
3036 * cut down on wasted planning cycles, only call the support function if
3037 * at least one argument matches the target index column.
3038 *
3039 * Note that we don't insist on the other arguments being pseudoconstants;
3040 * the support function has to check that. This is to allow cases where
3041 * only some of the other arguments need to be included in the indexqual.
3042 */
3043 indexarg = 0;
3044 foreach(lc, clause->args)
3045 {
3046 Node *op = (Node *) lfirst(lc);
3047
3048 if (match_index_to_operand(op, indexcol, index))
3049 {
3051 rinfo,
3052 clause->funcid,
3053 indexarg,
3054 indexcol,
3055 index);
3056 }
3057
3058 indexarg++;
3059 }
3060
3061 return NULL;
3062}
static IndexClause * get_index_clause_from_support(PlannerInfo *root, RestrictInfo *rinfo, Oid funcid, int indexarg, int indexcol, IndexOptInfo *index)
Definition: indxpath.c:3070
Oid funcid
Definition: primnodes.h:782
List * args
Definition: primnodes.h:800

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 4356 of file indxpath.c.

4359{
4360 int indkey;
4361
4362 /*
4363 * Ignore any PlaceHolderVar node contained in the operand. This is
4364 * needed to be able to apply indexscanning in cases where the operand (or
4365 * a subtree) has been wrapped in PlaceHolderVars to enforce separate
4366 * identity or as a result of outer joins.
4367 */
4368 operand = strip_phvs_in_index_operand(operand);
4369
4370 /*
4371 * Ignore any RelabelType node above the operand. This is needed to be
4372 * able to apply indexscanning in binary-compatible-operator cases.
4373 *
4374 * Note: we must handle nested RelabelType nodes here. While
4375 * eval_const_expressions() will have simplified them to at most one
4376 * layer, our prior stripping of PlaceHolderVars may have brought separate
4377 * RelabelTypes into adjacency.
4378 */
4379 while (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}
Node * strip_phvs_in_index_operand(Node *operand)
Definition: indxpath.c:4451
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:262

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

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 2483 of file indxpath.c.

2487{
2488 ListCell *lc;
2489
2490 /* Scan the rel's join clauses */
2491 foreach(lc, rel->joininfo)
2492 {
2493 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2494
2495 /* Check if clause can be moved to this rel */
2496 if (!join_clause_is_movable_to(rinfo, rel))
2497 continue;
2498
2499 /*
2500 * Potentially usable, so see if it matches the index or is an OR. Use
2501 * list_append_unique_ptr() here to avoid possible duplicates when
2502 * processing the same clauses with different indexes.
2503 */
2504 if (restriction_is_or_clause(rinfo))
2505 *joinorclauses = list_append_unique_ptr(*joinorclauses, rinfo);
2506
2507 match_clause_to_index(root, rinfo, index, clauseset);
2508 }
2509}
List * list_append_unique_ptr(List *list, void *datum)
Definition: list.c:1356

References join_clause_is_movable_to(), RelOptInfo::joininfo, lfirst, list_append_unique_ptr(), 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 2905 of file indxpath.c.

2909{
2910 IndexClause *iclause;
2911 OpExpr *clause = (OpExpr *) rinfo->clause;
2912 Node *leftop,
2913 *rightop;
2914 Oid expr_op;
2915 Oid expr_coll;
2916 Index index_relid;
2917 Oid opfamily;
2918 Oid idxcollation;
2919
2920 /*
2921 * Only binary operators need apply. (In theory, a planner support
2922 * function could do something with a unary operator, but it seems
2923 * unlikely to be worth the cycles to check.)
2924 */
2925 if (list_length(clause->args) != 2)
2926 return NULL;
2927
2928 leftop = (Node *) linitial(clause->args);
2929 rightop = (Node *) lsecond(clause->args);
2930 expr_op = clause->opno;
2931 expr_coll = clause->inputcollid;
2932
2933 index_relid = index->rel->relid;
2934 opfamily = index->opfamily[indexcol];
2935 idxcollation = index->indexcollations[indexcol];
2936
2937 /*
2938 * Check for clauses of the form: (indexkey operator constant) or
2939 * (constant operator indexkey). See match_clause_to_indexcol's notes
2940 * about const-ness.
2941 *
2942 * Note that we don't ask the support function about clauses that don't
2943 * have one of these forms. Again, in principle it might be possible to
2944 * do something, but it seems unlikely to be worth the cycles to check.
2945 */
2946 if (match_index_to_operand(leftop, indexcol, index) &&
2947 !bms_is_member(index_relid, rinfo->right_relids) &&
2949 {
2950 if (IndexCollMatchesExprColl(idxcollation, expr_coll) &&
2951 op_in_opfamily(expr_op, opfamily))
2952 {
2953 iclause = makeNode(IndexClause);
2954 iclause->rinfo = rinfo;
2955 iclause->indexquals = list_make1(rinfo);
2956 iclause->lossy = false;
2957 iclause->indexcol = indexcol;
2958 iclause->indexcols = NIL;
2959 return iclause;
2960 }
2961
2962 /*
2963 * If we didn't find a member of the index's opfamily, try the support
2964 * function for the operator's underlying function.
2965 */
2966 set_opfuncid(clause); /* make sure we have opfuncid */
2968 rinfo,
2969 clause->opfuncid,
2970 0, /* indexarg on left */
2971 indexcol,
2972 index);
2973 }
2974
2975 if (match_index_to_operand(rightop, indexcol, index) &&
2976 !bms_is_member(index_relid, rinfo->left_relids) &&
2978 {
2979 if (IndexCollMatchesExprColl(idxcollation, expr_coll))
2980 {
2981 Oid comm_op = get_commutator(expr_op);
2982
2983 if (OidIsValid(comm_op) &&
2984 op_in_opfamily(comm_op, opfamily))
2985 {
2986 RestrictInfo *commrinfo;
2987
2988 /* Build a commuted OpExpr and RestrictInfo */
2989 commrinfo = commute_restrictinfo(rinfo, comm_op);
2990
2991 /* Make an IndexClause showing that as a derived qual */
2992 iclause = makeNode(IndexClause);
2993 iclause->rinfo = rinfo;
2994 iclause->indexquals = list_make1(commrinfo);
2995 iclause->lossy = false;
2996 iclause->indexcol = indexcol;
2997 iclause->indexcols = NIL;
2998 return iclause;
2999 }
3000 }
3001
3002 /*
3003 * If we didn't find a member of the index's opfamily, try the support
3004 * function for the operator's underlying function.
3005 */
3006 set_opfuncid(clause); /* make sure we have opfuncid */
3008 rinfo,
3009 clause->opfuncid,
3010 1, /* indexarg on right */
3011 indexcol,
3012 index);
3013 }
3014
3015 return NULL;
3016}
void set_opfuncid(OpExpr *opexpr)
Definition: nodeFuncs.c:1871
#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 3298 of file indxpath.c.

3302{
3303 BoolExpr *orclause = (BoolExpr *) rinfo->orclause;
3304 List *consts = NIL;
3305 Node *indexExpr = NULL;
3306 Oid matchOpno = InvalidOid;
3307 Oid consttype = InvalidOid;
3308 Oid arraytype = InvalidOid;
3309 Oid inputcollid = InvalidOid;
3310 bool firstTime = true;
3311 bool haveNonConst = false;
3312 Index indexRelid = index->rel->relid;
3313 ScalarArrayOpExpr *saopexpr;
3314 IndexClause *iclause;
3315 ListCell *lc;
3316
3317 /* Forget it if index doesn't support SAOP clauses */
3318 if (!index->amsearcharray)
3319 return NULL;
3320
3321 /*
3322 * Try to convert a list of OR-clauses to a single SAOP expression. Each
3323 * OR entry must be in the form: (indexkey operator constant) or (constant
3324 * operator indexkey). Operators of all the entries must match. On
3325 * discovery of anything unsupported, we give up by breaking out of the
3326 * loop immediately and returning NULL.
3327 */
3328 foreach(lc, orclause->args)
3329 {
3330 RestrictInfo *subRinfo = (RestrictInfo *) lfirst(lc);
3331 OpExpr *subClause;
3332 Oid opno;
3333 Node *leftop,
3334 *rightop;
3335 Node *constExpr;
3336
3337 /* If it's not a RestrictInfo (i.e. it's a sub-AND), we can't use it */
3338 if (!IsA(subRinfo, RestrictInfo))
3339 break;
3340
3341 /* Only operator clauses can match */
3342 if (!IsA(subRinfo->clause, OpExpr))
3343 break;
3344
3345 subClause = (OpExpr *) subRinfo->clause;
3346 opno = subClause->opno;
3347
3348 /* Only binary operators can match */
3349 if (list_length(subClause->args) != 2)
3350 break;
3351
3352 /*
3353 * Check for clauses of the form: (indexkey operator constant) or
3354 * (constant operator indexkey). These tests should agree with
3355 * match_opclause_to_indexcol.
3356 */
3357 leftop = (Node *) linitial(subClause->args);
3358 rightop = (Node *) lsecond(subClause->args);
3359 if (match_index_to_operand(leftop, indexcol, index) &&
3360 !bms_is_member(indexRelid, subRinfo->right_relids) &&
3362 {
3363 indexExpr = leftop;
3364 constExpr = rightop;
3365 }
3366 else if (match_index_to_operand(rightop, indexcol, index) &&
3367 !bms_is_member(indexRelid, subRinfo->left_relids) &&
3369 {
3370 opno = get_commutator(opno);
3371 if (!OidIsValid(opno))
3372 {
3373 /* commutator doesn't exist, we can't reverse the order */
3374 break;
3375 }
3376 indexExpr = rightop;
3377 constExpr = leftop;
3378 }
3379 else
3380 {
3381 break;
3382 }
3383
3384 /*
3385 * Save information about the operator, type, and collation for the
3386 * first matching qual. Then, check that subsequent quals match the
3387 * first.
3388 */
3389 if (firstTime)
3390 {
3391 matchOpno = opno;
3392 consttype = exprType(constExpr);
3393 arraytype = get_array_type(consttype);
3394 inputcollid = subClause->inputcollid;
3395
3396 /*
3397 * Check that the operator is presented in the opfamily and that
3398 * the expression collation matches the index collation. Also,
3399 * there must be an array type to construct an array later.
3400 */
3401 if (!IndexCollMatchesExprColl(index->indexcollations[indexcol],
3402 inputcollid) ||
3403 !op_in_opfamily(matchOpno, index->opfamily[indexcol]) ||
3404 !OidIsValid(arraytype))
3405 break;
3406
3407 /*
3408 * Disallow if either type is RECORD, mainly because we can't be
3409 * positive that all the RHS expressions are the same record type.
3410 */
3411 if (consttype == RECORDOID || exprType(indexExpr) == RECORDOID)
3412 break;
3413
3414 firstTime = false;
3415 }
3416 else
3417 {
3418 if (matchOpno != opno ||
3419 inputcollid != subClause->inputcollid ||
3420 consttype != exprType(constExpr))
3421 break;
3422 }
3423
3424 /*
3425 * The righthand inputs don't necessarily have to be plain Consts, but
3426 * make_SAOP_expr needs to know if any are not.
3427 */
3428 if (!IsA(constExpr, Const))
3429 haveNonConst = true;
3430
3431 consts = lappend(consts, constExpr);
3432 }
3433
3434 /*
3435 * Handle failed conversion from breaking out of the loop because of an
3436 * unsupported qual. Also check that we have an indexExpr, just in case
3437 * the OR list was somehow empty (it shouldn't be). Return NULL to
3438 * indicate the conversion failed.
3439 */
3440 if (lc != NULL || indexExpr == NULL)
3441 {
3442 list_free(consts); /* might as well */
3443 return NULL;
3444 }
3445
3446 /*
3447 * Build the new SAOP node. We use the indexExpr from the last OR arm;
3448 * since all the arms passed match_index_to_operand, it shouldn't matter
3449 * which one we use. But using "inputcollid" twice is a bit of a cheat:
3450 * we might end up with an array Const node that is labeled with a
3451 * collation despite its elements being of a noncollatable type. But
3452 * nothing is likely to complain about that, so we don't bother being more
3453 * accurate.
3454 */
3455 saopexpr = make_SAOP_expr(matchOpno, indexExpr, consttype, inputcollid,
3456 inputcollid, consts, haveNonConst);
3457 Assert(saopexpr != NULL);
3458
3459 /*
3460 * Finally, build an IndexClause based on the SAOP node. It's not lossy.
3461 */
3462 iclause = makeNode(IndexClause);
3463 iclause->rinfo = rinfo;
3464 iclause->indexquals = list_make1(make_simple_restrictinfo(root,
3465 (Expr *) saopexpr));
3466 iclause->lossy = false;
3467 iclause->indexcol = indexcol;
3468 iclause->indexcols = NIL;
3469 return iclause;
3470}
ScalarArrayOpExpr * make_SAOP_expr(Oid oper, Node *leftexpr, Oid coltype, Oid arraycollid, Oid inputcollid, List *exprs, bool haveNonConst)
Definition: clauses.c:5835
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2937
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
List * args
Definition: primnodes.h:972

References OpExpr::args, BoolExpr::args, Assert(), bms_is_member(), RestrictInfo::clause, contain_volatile_functions(), exprType(), get_array_type(), get_commutator(), if(), IndexCollMatchesExprColl, InvalidOid, IsA, lappend(), lfirst, linitial, list_free(), list_length(), list_make1, lsecond, make_SAOP_expr(), make_simple_restrictinfo, makeNode, match_index_to_operand(), NIL, OidIsValid, op_in_opfamily(), OpExpr::opno, and root.

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 3718 of file indxpath.c.

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

References bms_equal(), COMPARE_LT, eclass_member_iterator_next(), EquivalenceMember::em_expr, EquivalenceMember::em_relids, lappend(), lappend_int(), lfirst, match_clause_to_ordering_op(), NIL, PathKey::pk_cmptype, PathKey::pk_nulls_first, PathKey::pk_opfamily, and setup_eclass_member_iterator().

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 2467 of file indxpath.c.

2470{
2471 /* We can ignore clauses that are implied by the index predicate */
2472 match_clauses_to_index(root, index->indrestrictinfo, index, clauseset);
2473}

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 3204 of file indxpath.c.

3208{
3209 RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
3210 Index index_relid;
3211 Oid opfamily;
3212 Oid idxcollation;
3213 Node *leftop,
3214 *rightop;
3215 bool var_on_left;
3216 Oid expr_op;
3217 Oid expr_coll;
3218
3219 /* Forget it if we're not dealing with a btree index */
3220 if (index->relam != BTREE_AM_OID)
3221 return NULL;
3222
3223 index_relid = index->rel->relid;
3224 opfamily = index->opfamily[indexcol];
3225 idxcollation = index->indexcollations[indexcol];
3226
3227 /*
3228 * We could do the matching on the basis of insisting that the opfamily
3229 * shown in the RowCompareExpr be the same as the index column's opfamily,
3230 * but that could fail in the presence of reverse-sort opfamilies: it'd be
3231 * a matter of chance whether RowCompareExpr had picked the forward or
3232 * reverse-sort family. So look only at the operator, and match if it is
3233 * a member of the index's opfamily (after commutation, if the indexkey is
3234 * on the right). We'll worry later about whether any additional
3235 * operators are matchable to the index.
3236 */
3237 leftop = (Node *) linitial(clause->largs);
3238 rightop = (Node *) linitial(clause->rargs);
3239 expr_op = linitial_oid(clause->opnos);
3240 expr_coll = linitial_oid(clause->inputcollids);
3241
3242 /* Collations must match, if relevant */
3243 if (!IndexCollMatchesExprColl(idxcollation, expr_coll))
3244 return NULL;
3245
3246 /*
3247 * These syntactic tests are the same as in match_opclause_to_indexcol()
3248 */
3249 if (match_index_to_operand(leftop, indexcol, index) &&
3250 !bms_is_member(index_relid, pull_varnos(root, rightop)) &&
3252 {
3253 /* OK, indexkey is on left */
3254 var_on_left = true;
3255 }
3256 else if (match_index_to_operand(rightop, indexcol, index) &&
3257 !bms_is_member(index_relid, pull_varnos(root, leftop)) &&
3259 {
3260 /* indexkey is on right, so commute the operator */
3261 expr_op = get_commutator(expr_op);
3262 if (expr_op == InvalidOid)
3263 return NULL;
3264 var_on_left = false;
3265 }
3266 else
3267 return NULL;
3268
3269 /* We're good if the operator is the right type of opfamily member */
3270 switch (get_op_opfamily_strategy(expr_op, opfamily))
3271 {
3277 rinfo,
3278 indexcol,
3279 index,
3280 expr_op,
3281 var_on_left);
3282 }
3283
3284 return NULL;
3285}
static IndexClause * expand_indexqual_rowcompare(PlannerInfo *root, RestrictInfo *rinfo, int indexcol, IndexOptInfo *index, Oid expr_op, bool var_on_left)
Definition: indxpath.c:3496

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 3136 of file indxpath.c.

3140{
3141 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) rinfo->clause;
3142 Node *leftop,
3143 *rightop;
3144 Relids right_relids;
3145 Oid expr_op;
3146 Oid expr_coll;
3147 Index index_relid;
3148 Oid opfamily;
3149 Oid idxcollation;
3150
3151 /* We only accept ANY clauses, not ALL */
3152 if (!saop->useOr)
3153 return NULL;
3154 leftop = (Node *) linitial(saop->args);
3155 rightop = (Node *) lsecond(saop->args);
3156 right_relids = pull_varnos(root, rightop);
3157 expr_op = saop->opno;
3158 expr_coll = saop->inputcollid;
3159
3160 index_relid = index->rel->relid;
3161 opfamily = index->opfamily[indexcol];
3162 idxcollation = index->indexcollations[indexcol];
3163
3164 /*
3165 * We must have indexkey on the left and a pseudo-constant array argument.
3166 */
3167 if (match_index_to_operand(leftop, indexcol, index) &&
3168 !bms_is_member(index_relid, right_relids) &&
3170 {
3171 if (IndexCollMatchesExprColl(idxcollation, expr_coll) &&
3172 op_in_opfamily(expr_op, opfamily))
3173 {
3174 IndexClause *iclause = makeNode(IndexClause);
3175
3176 iclause->rinfo = rinfo;
3177 iclause->indexquals = list_make1(rinfo);
3178 iclause->lossy = false;
3179 iclause->indexcol = indexcol;
3180 iclause->indexcols = NIL;
3181 return iclause;
3182 }
3183
3184 /*
3185 * We do not currently ask support functions about ScalarArrayOpExprs,
3186 * though in principle we could.
3187 */
3188 }
3189
3190 return NULL;
3191}

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 1202 of file indxpath.c.

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

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

Referenced by group_similar_or_args().

◆ or_arg_index_match_cmp_group()

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

Definition at line 1240 of file indxpath.c.

1241{
1242 const OrArgIndexMatch *match_a = (const OrArgIndexMatch *) a;
1243 const OrArgIndexMatch *match_b = (const OrArgIndexMatch *) b;
1244
1245 if (match_a->groupindex < match_b->groupindex)
1246 return -1;
1247 else if (match_a->groupindex > match_b->groupindex)
1248 return 1;
1249
1250 if (match_a->argindex < match_b->argindex)
1251 return -1;
1252 else if (match_a->argindex > match_b->argindex)
1253 return 1;
1254
1255 return 0;
1256}

References a, OrArgIndexMatch::argindex, b, and OrArgIndexMatch::groupindex.

Referenced by group_similar_or_args().

◆ path_usage_comparator()

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

Definition at line 1992 of file indxpath.c.

1993{
1994 PathClauseUsage *pa = *(PathClauseUsage *const *) a;
1995 PathClauseUsage *pb = *(PathClauseUsage *const *) b;
1996 Cost acost;
1997 Cost bcost;
1998 Selectivity aselec;
1999 Selectivity bselec;
2000
2001 cost_bitmap_tree_node(pa->path, &acost, &aselec);
2002 cost_bitmap_tree_node(pb->path, &bcost, &bselec);
2003
2004 /*
2005 * If costs are the same, sort by selectivity.
2006 */
2007 if (acost < bcost)
2008 return -1;
2009 if (acost > bcost)
2010 return 1;
2011
2012 if (aselec < bselec)
2013 return -1;
2014 if (aselec > bselec)
2015 return 1;
2016
2017 return 0;
2018}

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 **  extra_clauses 
)

Definition at line 4147 of file indxpath.c.

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

References Assert(), RelOptInfo::baserestrictinfo, bms_is_empty, bms_membership(), BMS_SINGLETON, RestrictInfo::clause, get_leftop(), get_rightop(), RelOptInfo::indexlist, lappend(), lfirst, list_member_oid(), match_index_to_operand(), MemoryContextSwitchTo(), NIL, and root.

Referenced by rel_is_distinct_for().

◆ strip_phvs_in_index_operand()

Node * strip_phvs_in_index_operand ( Node operand)

Definition at line 4451 of file indxpath.c.

4452{
4453 /* Don't mutate/copy if no target PHVs exist */
4454 if (!contain_strippable_phv_walker(operand, NULL))
4455 return operand;
4456
4457 return strip_phvs_in_index_operand_mutator(operand, NULL);
4458}
static Node * strip_phvs_in_index_operand_mutator(Node *node, void *context)
Definition: indxpath.c:4494

References contain_strippable_phv_walker(), and strip_phvs_in_index_operand_mutator().

Referenced by fix_indexqual_operand(), and match_index_to_operand().

◆ strip_phvs_in_index_operand_mutator()

static Node * strip_phvs_in_index_operand_mutator ( Node node,
void *  context 
)
static

Definition at line 4494 of file indxpath.c.

4495{
4496 if (node == NULL)
4497 return NULL;
4498
4499 if (IsA(node, PlaceHolderVar))
4500 {
4501 PlaceHolderVar *phv = (PlaceHolderVar *) node;
4502
4503 /* If matches the criteria, strip it */
4504 if (bms_is_empty(phv->phnullingrels))
4505 {
4506 /* Recurse on its contained expression */
4507 return strip_phvs_in_index_operand_mutator((Node *) phv->phexpr,
4508 context);
4509 }
4510
4511 /* Otherwise, keep this PHV but check its contained expression */
4512 }
4513
4515 context);
4516}
#define expression_tree_mutator(n, m, c)
Definition: nodeFuncs.h:155

References bms_is_empty, expression_tree_mutator, IsA, PlaceHolderVar::phnullingrels, and strip_phvs_in_index_operand_mutator().

Referenced by strip_phvs_in_index_operand(), and strip_phvs_in_index_operand_mutator().