]> granicus.if.org Git - postgresql/commitdiff
Don't trust deferred-unique indexes for join removal.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 23 Oct 2011 04:43:39 +0000 (00:43 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 23 Oct 2011 04:43:39 +0000 (00:43 -0400)
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.

src/backend/nodes/outfuncs.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/util/plancat.c
src/backend/utils/adt/selfuncs.c
src/include/nodes/relation.h

index 98a02b27ddfd7e05e89f4ece181ced5aa60b3f83..f7d39edf6fd24961f88dd92383ea87151b97acc2 100644 (file)
@@ -1770,6 +1770,7 @@ _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
        WRITE_NODE_FIELD(indextlist);
        WRITE_BOOL_FIELD(predOK);
        WRITE_BOOL_FIELD(unique);
+       WRITE_BOOL_FIELD(immediate);
        WRITE_BOOL_FIELD(hypothetical);
 }
 
index 940efb38b668dac8a8e773f996efcda5267ca6c1..77df5a24ea24d67abc4b0b087960aacf76cb012d 100644 (file)
@@ -2277,10 +2277,11 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
                int                     c;
 
                /*
-                * If the index is not unique or if it's a partial index that doesn't
-                * match the query, it's useless here.
+                * If the index is not unique, or not immediately enforced, or if it's
+                * a partial index that doesn't match the query, it's useless here.
                 */
-               if (!ind->unique || (ind->indpred != NIL && !ind->predOK))
+               if (!ind->unique || !ind->immediate ||
+                       (ind->indpred != NIL && !ind->predOK))
                        continue;
 
                /*
index bb8095224247694b0630ea6ea7947e980dbc45f5..de629e93c9adf6f925a49010dae2d82c2ca97181 100644 (file)
@@ -324,6 +324,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 
                        info->predOK = false;           /* set later in indxpath.c */
                        info->unique = index->indisunique;
+                       info->immediate = index->indimmediate;
                        info->hypothetical = false;
 
                        /*
@@ -1076,6 +1077,11 @@ join_selectivity(PlannerInfo *root,
  * Detect whether there is a unique index on the specified attribute
  * of the specified relation, thus allowing us to conclude that all
  * the (non-null) values of the attribute are distinct.
+ *
+ * This function does not check the index's indimmediate property, which
+ * means that uniqueness may transiently fail to hold intra-transaction.
+ * That's appropriate when we are making statistical estimates, but beware
+ * of using this for any correctness proofs.
  */
 bool
 has_unique_index(RelOptInfo *rel, AttrNumber attno)
index 96946281dabe1d0f2db82878d536043733b4a4ff..f05cc4f87ee51647ffe3a10fb55c33aecb7c9959 100644 (file)
@@ -4129,7 +4129,9 @@ get_join_variables(PlannerInfo *root, List *args, SpecialJoinInfo *sjinfo,
  *             commonly the same as the exposed type of the variable argument,
  *             but can be different in binary-compatible-type cases.
  *     isunique: TRUE if we were able to match the var to a unique index,
- *             implying its values are unique for this query.
+ *             implying its values are unique for this query.  (Caution: this
+ *             should be trusted for statistical purposes only, since we do not
+ *             check indimmediate.)
  *
  * Caller is responsible for doing ReleaseVariableStats() before exiting.
  */
index 2925d7e76598d50a9bb0cdf9a4ede12338a849c4..ede97571e06ab1fd6dd5bbd7bad9b482899d52e7 100644 (file)
@@ -488,6 +488,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            hypothetical;   /* true if index doesn't really exist */
        bool            amcanorderbyop; /* does AM support order by operator result? */
        bool            amcanreturn;    /* can AM return IndexTuples? */