Skip to content

Commit 9fbb3ed

Browse files
committed
Don't trust deferred-unique indexes for join removal.
The uniqueness condition might fail to hold intra-transaction, and assuming it does can give incorrect query results. Per report from Marti Raudsepp, though this is not his proposed patch. Back-patch to 9.0, where both these features were introduced. In the released branches, add the new IndexOptInfo field to the end of the struct, to try to minimize ABI breakage for third-party code that may be examining that struct.
1 parent 015cda4 commit 9fbb3ed

File tree

5 files changed

+16
-4
lines changed

5 files changed

+16
-4
lines changed

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,7 @@ _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
16161616
WRITE_NODE_FIELD(indpred);
16171617
WRITE_BOOL_FIELD(predOK);
16181618
WRITE_BOOL_FIELD(unique);
1619+
WRITE_BOOL_FIELD(immediate);
16191620
WRITE_BOOL_FIELD(hypothetical);
16201621
}
16211622

src/backend/optimizer/path/indxpath.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,10 +1948,11 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
19481948
int c;
19491949

19501950
/*
1951-
* If the index is not unique or if it's a partial index that doesn't
1952-
* match the query, it's useless here.
1951+
* If the index is not unique, or not immediately enforced, or if it's
1952+
* a partial index that doesn't match the query, it's useless here.
19531953
*/
1954-
if (!ind->unique || (ind->indpred != NIL && !ind->predOK))
1954+
if (!ind->unique || !ind->immediate ||
1955+
(ind->indpred != NIL && !ind->predOK))
19551956
continue;
19561957

19571958
/*

src/backend/optimizer/util/plancat.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
275275
ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
276276
info->predOK = false; /* set later in indxpath.c */
277277
info->unique = index->indisunique;
278+
info->immediate = index->indimmediate;
278279
info->hypothetical = false;
279280

280281
/*
@@ -876,6 +877,11 @@ join_selectivity(PlannerInfo *root,
876877
* Detect whether there is a unique index on the specified attribute
877878
* of the specified relation, thus allowing us to conclude that all
878879
* the (non-null) values of the attribute are distinct.
880+
*
881+
* This function does not check the index's indimmediate property, which
882+
* means that uniqueness may transiently fail to hold intra-transaction.
883+
* That's appropriate when we are making statistical estimates, but beware
884+
* of using this for any correctness proofs.
879885
*/
880886
bool
881887
has_unique_index(RelOptInfo *rel, AttrNumber attno)

src/backend/utils/adt/selfuncs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4102,7 +4102,9 @@ get_join_variables(PlannerInfo *root, List *args, SpecialJoinInfo *sjinfo,
41024102
* commonly the same as the exposed type of the variable argument,
41034103
* but can be different in binary-compatible-type cases.
41044104
* isunique: TRUE if we were able to match the var to a unique index,
4105-
* implying its values are unique for this query.
4105+
* implying its values are unique for this query. (Caution: this
4106+
* should be trusted for statistical purposes only, since we do not
4107+
* check indimmediate.)
41064108
*
41074109
* Caller is responsible for doing ReleaseVariableStats() before exiting.
41084110
*/

src/include/nodes/relation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ typedef struct IndexOptInfo
473473
bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
474474
/* added in 9.0.4: */
475475
bool hypothetical; /* true if index doesn't really exist */
476+
/* added in 9.0.6: */
477+
bool immediate; /* is uniqueness enforced immediately? */
476478
} IndexOptInfo;
477479

478480

0 commit comments

Comments
 (0)