diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 4c7505e..450da18 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1788,6 +1788,7 @@ _outIndexOptInfo(StringInfo str, const IndexOptInfo *node) WRITE_BOOL_FIELD(predOK); WRITE_BOOL_FIELD(unique); WRITE_BOOL_FIELD(immediate); + WRITE_BOOL_FIELD(allnotnull); WRITE_BOOL_FIELD(hypothetical); /* we don't bother with fields copied from the pg_am entry */ } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 606734a..118eb25 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -950,8 +950,18 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel, index_is_ordered = (index->sortopfamily != NULL); if (index_is_ordered && pathkeys_possibly_useful) { + bool pathkeys_are_extensible; + index_pathkeys = build_index_pathkeys(root, index, ForwardScanDirection); + pathkeys_are_extensible = (index->unique && + index->immediate && + index->allnotnull && + index_pathkeys != NIL && + pathkeys_contained_in(index_pathkeys, + root->query_pathkeys)); + if (pathkeys_are_extensible) + index_pathkeys = extend_index_pathkeys(root, rel); useful_pathkeys = truncate_useless_pathkeys(root, rel, index_pathkeys); orderbyclauses = NIL; diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 9c8ede6..0df5d46 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -1525,3 +1525,40 @@ has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel) return true; /* might be able to use them for ordering */ return false; /* definitely useless */ } + +/* + * extend_index_pathkeys + * Build the extended pathkey list from query_pathkeys. + */ +List * +extend_index_pathkeys(PlannerInfo *root, RelOptInfo *rel) +{ + List *pathkeys = NIL; + ListCell *lc1; + + foreach(lc1, root->query_pathkeys) + { + PathKey *pathkey = (PathKey *) lfirst(lc1); + bool found = false; + ListCell *lc2; + + foreach(lc2, pathkey->pk_eclass->ec_members) + { + EquivalenceMember *member = (EquivalenceMember *) lfirst(lc2); + + if (!bms_equal(member->em_relids, rel->relids)) + continue; + else + { + pathkeys = lappend(pathkeys, pathkey); + found = true; + break; + } + } + + if (!found) + break; + } + + return pathkeys; +} diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 954666c..d45de8f 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -333,6 +333,26 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, info->immediate = index->indimmediate; info->hypothetical = false; + info->allnotnull = true; + for (i = 0; i < ncolumns; i++) + { + int attrno = info->indexkeys[i]; + + if (attrno == 0) + { + info->allnotnull = false; + break; + } + else if (attrno > 0) + { + if (!relation->rd_att->attrs[attrno - 1]->attnotnull) + { + info->allnotnull = false; + break; + } + } + } + /* * Estimate the index size. If it's not a partial index, we lock * the number-of-tuples estimate to equal the parent table; if it diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 6d7b594..a198d2e 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -524,6 +524,7 @@ typedef struct IndexOptInfo bool predOK; /* true if predicate matches query */ bool unique; /* true if a unique index */ bool immediate; /* is uniqueness enforced immediately? */ + bool allnotnull; /* true if index's keys are all not null */ bool hypothetical; /* true if index doesn't really exist */ bool canreturn; /* can index return IndexTuples? */ bool amcanorderbyop; /* does AM support order by operator result? */ diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 999adaa..d62827c 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -196,5 +196,6 @@ extern List *truncate_useless_pathkeys(PlannerInfo *root, RelOptInfo *rel, List *pathkeys); extern bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel); +extern List *extend_index_pathkeys(PlannerInfo *root, RelOptInfo *rel); #endif /* PATHS_H */ diff --git a/src/test/isolation/expected/drop-index-concurrently-1.out b/src/test/isolation/expected/drop-index-concurrently-1.out index 75dff56..ab96fa0 100644 --- a/src/test/isolation/expected/drop-index-concurrently-1.out +++ b/src/test/isolation/expected/drop-index-concurrently-1.out @@ -19,10 +19,8 @@ Sort step explains: EXPLAIN (COSTS OFF) EXECUTE getrow_seq; QUERY PLAN -Sort - Sort Key: id, data - -> Seq Scan on test_dc - Filter: ((data)::text = '34'::text) +Index Scan using test_dc_pkey on test_dc + Filter: ((data)::text = '34'::text) step select2: SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; id data