summaryrefslogtreecommitdiff
path: root/src/backend/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access')
-rw-r--r--src/backend/access/gin/gininsert.c11
-rw-r--r--src/backend/access/gist/gist.c6
-rw-r--r--src/backend/access/hash/hash.c6
-rw-r--r--src/backend/access/heap/tuptoaster.c6
-rw-r--r--src/backend/access/index/indexam.c6
-rw-r--r--src/backend/access/nbtree/nbtinsert.c113
-rw-r--r--src/backend/access/nbtree/nbtree.c9
7 files changed, 120 insertions, 37 deletions
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 2adaed43d48..d175a5a99e6 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.22 2009/06/11 14:48:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.23 2009/07/29 20:56:17 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -415,12 +415,11 @@ gininsert(PG_FUNCTION_ARGS)
#ifdef NOT_USED
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- bool checkUnique = PG_GETARG_BOOL(5);
+ IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
#endif
GinState ginstate;
MemoryContext oldCtx;
MemoryContext insertCtx;
- uint32 res = 0;
int i;
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
@@ -440,7 +439,7 @@ gininsert(PG_FUNCTION_ARGS)
memset(&collector, 0, sizeof(GinTupleCollector));
for (i = 0; i < ginstate.origTupdesc->natts; i++)
if (!isnull[i])
- res += ginHeapTupleFastCollect(index, &ginstate, &collector,
+ ginHeapTupleFastCollect(index, &ginstate, &collector,
(OffsetNumber) (i + 1), values[i], ht_ctid);
ginHeapTupleFastInsert(index, &ginstate, &collector);
@@ -449,7 +448,7 @@ gininsert(PG_FUNCTION_ARGS)
{
for (i = 0; i < ginstate.origTupdesc->natts; i++)
if (!isnull[i])
- res += ginHeapTupleInsert(index, &ginstate,
+ ginHeapTupleInsert(index, &ginstate,
(OffsetNumber) (i + 1), values[i], ht_ctid);
}
@@ -457,5 +456,5 @@ gininsert(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldCtx);
MemoryContextDelete(insertCtx);
- PG_RETURN_BOOL(res > 0);
+ PG_RETURN_BOOL(false);
}
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 2742969c6af..ef6febef85c 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.156 2009/01/01 17:23:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.157 2009/07/29 20:56:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -225,7 +225,7 @@ gistinsert(PG_FUNCTION_ARGS)
#ifdef NOT_USED
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- bool checkUnique = PG_GETARG_BOOL(5);
+ IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
#endif
IndexTuple itup;
GISTSTATE giststate;
@@ -248,7 +248,7 @@ gistinsert(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldCtx);
MemoryContextDelete(insertCtx);
- PG_RETURN_BOOL(true);
+ PG_RETURN_BOOL(false);
}
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 49b6594f1eb..35056838364 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.112 2009/06/11 14:48:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.113 2009/07/29 20:56:18 tgl Exp $
*
* NOTES
* This file contains only the public interface routines.
@@ -165,7 +165,7 @@ hashinsert(PG_FUNCTION_ARGS)
#ifdef NOT_USED
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- bool checkUnique = PG_GETARG_BOOL(5);
+ IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
#endif
IndexTuple itup;
@@ -192,7 +192,7 @@ hashinsert(PG_FUNCTION_ARGS)
pfree(itup);
- PG_RETURN_BOOL(true);
+ PG_RETURN_BOOL(false);
}
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 781bfd2e486..2fbf8f43bbd 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.94 2009/07/22 01:21:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.95 2009/07/29 20:56:18 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1229,7 +1229,9 @@ toast_save_datum(Relation rel, Datum value, int options)
*/
index_insert(toastidx, t_values, t_isnull,
&(toasttup->t_self),
- toastrel, toastidx->rd_index->indisunique);
+ toastrel,
+ toastidx->rd_index->indisunique ?
+ UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
/*
* Free memory
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 32623965c78..f4ffeccd328 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.114 2009/06/11 14:48:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.115 2009/07/29 20:56:18 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
@@ -185,7 +185,7 @@ index_insert(Relation indexRelation,
bool *isnull,
ItemPointer heap_t_ctid,
Relation heapRelation,
- bool check_uniqueness)
+ IndexUniqueCheck checkUnique)
{
FmgrInfo *procedure;
@@ -201,7 +201,7 @@ index_insert(Relation indexRelation,
PointerGetDatum(isnull),
PointerGetDatum(heap_t_ctid),
PointerGetDatum(heapRelation),
- BoolGetDatum(check_uniqueness)));
+ Int32GetDatum((int32) checkUnique)));
}
/*
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index a06faa20203..f0137182249 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.170 2009/06/11 14:48:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.171 2009/07/29 20:56:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,8 +49,9 @@ typedef struct
static Buffer _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
static TransactionId _bt_check_unique(Relation rel, IndexTuple itup,
- Relation heapRel, Buffer buf, OffsetNumber ioffset,
- ScanKey itup_scankey);
+ Relation heapRel, Buffer buf, OffsetNumber offset,
+ ScanKey itup_scankey,
+ IndexUniqueCheck checkUnique, bool *is_unique);
static void _bt_findinsertloc(Relation rel,
Buffer *bufptr,
OffsetNumber *offsetptr,
@@ -85,11 +86,24 @@ static void _bt_vacuum_one_page(Relation rel, Buffer buffer);
*
* This routine is called by the public interface routines, btbuild
* and btinsert. By here, itup is filled in, including the TID.
+ *
+ * If checkUnique is UNIQUE_CHECK_NO or UNIQUE_CHECK_PARTIAL, this
+ * will allow duplicates. Otherwise (UNIQUE_CHECK_YES or
+ * UNIQUE_CHECK_EXISTING) it will throw error for a duplicate.
+ * For UNIQUE_CHECK_EXISTING we merely run the duplicate check, and
+ * don't actually insert.
+ *
+ * The result value is only significant for UNIQUE_CHECK_PARTIAL:
+ * it must be TRUE if the entry is known unique, else FALSE.
+ * (In the current implementation we'll also return TRUE after a
+ * successful UNIQUE_CHECK_YES or UNIQUE_CHECK_EXISTING call, but
+ * that's just a coding artifact.)
*/
-void
+bool
_bt_doinsert(Relation rel, IndexTuple itup,
- bool index_is_unique, Relation heapRel)
+ IndexUniqueCheck checkUnique, Relation heapRel)
{
+ bool is_unique = false;
int natts = rel->rd_rel->relnatts;
ScanKey itup_scankey;
BTStack stack;
@@ -134,13 +148,18 @@ top:
*
* If we must wait for another xact, we release the lock while waiting,
* and then must start over completely.
+ *
+ * For a partial uniqueness check, we don't wait for the other xact.
+ * Just let the tuple in and return false for possibly non-unique,
+ * or true for definitely unique.
*/
- if (index_is_unique)
+ if (checkUnique != UNIQUE_CHECK_NO)
{
TransactionId xwait;
offset = _bt_binsrch(rel, buf, natts, itup_scankey, false);
- xwait = _bt_check_unique(rel, itup, heapRel, buf, offset, itup_scankey);
+ xwait = _bt_check_unique(rel, itup, heapRel, buf, offset, itup_scankey,
+ checkUnique, &is_unique);
if (TransactionIdIsValid(xwait))
{
@@ -153,13 +172,23 @@ top:
}
}
- /* do the insertion */
- _bt_findinsertloc(rel, &buf, &offset, natts, itup_scankey, itup);
- _bt_insertonpg(rel, buf, stack, itup, offset, false);
+ if (checkUnique != UNIQUE_CHECK_EXISTING)
+ {
+ /* do the insertion */
+ _bt_findinsertloc(rel, &buf, &offset, natts, itup_scankey, itup);
+ _bt_insertonpg(rel, buf, stack, itup, offset, false);
+ }
+ else
+ {
+ /* just release the buffer */
+ _bt_relbuf(rel, buf);
+ }
/* be tidy */
_bt_freestack(stack);
_bt_freeskey(itup_scankey);
+
+ return is_unique;
}
/*
@@ -172,10 +201,16 @@ top:
* Returns InvalidTransactionId if there is no conflict, else an xact ID
* we must wait for to see if it commits a conflicting tuple. If an actual
* conflict is detected, no return --- just ereport().
+ *
+ * However, if checkUnique == UNIQUE_CHECK_PARTIAL, we always return
+ * InvalidTransactionId because we don't want to wait. In this case we
+ * set *is_unique to false if there is a potential conflict, and the
+ * core code must redo the uniqueness check later.
*/
static TransactionId
_bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
- Buffer buf, OffsetNumber offset, ScanKey itup_scankey)
+ Buffer buf, OffsetNumber offset, ScanKey itup_scankey,
+ IndexUniqueCheck checkUnique, bool *is_unique)
{
TupleDesc itupdesc = RelationGetDescr(rel);
int natts = rel->rd_rel->relnatts;
@@ -184,6 +219,10 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
Page page;
BTPageOpaque opaque;
Buffer nbuf = InvalidBuffer;
+ bool found = false;
+
+ /* Assume unique until we find a duplicate */
+ *is_unique = true;
InitDirtySnapshot(SnapshotDirty);
@@ -241,21 +280,48 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
htid = curitup->t_tid;
/*
+ * If we are doing a recheck, we expect to find the tuple we
+ * are rechecking. It's not a duplicate, but we have to keep
+ * scanning.
+ */
+ if (checkUnique == UNIQUE_CHECK_EXISTING &&
+ ItemPointerCompare(&htid, &itup->t_tid) == 0)
+ {
+ found = true;
+ }
+
+ /*
* We check the whole HOT-chain to see if there is any tuple
* that satisfies SnapshotDirty. This is necessary because we
* have just a single index entry for the entire chain.
*/
- if (heap_hot_search(&htid, heapRel, &SnapshotDirty, &all_dead))
+ else if (heap_hot_search(&htid, heapRel, &SnapshotDirty,
+ &all_dead))
{
- /* it is a duplicate */
- TransactionId xwait =
- (TransactionIdIsValid(SnapshotDirty.xmin)) ?
- SnapshotDirty.xmin : SnapshotDirty.xmax;
+ TransactionId xwait;
+
+ /*
+ * It is a duplicate. If we are only doing a partial
+ * check, then don't bother checking if the tuple is
+ * being updated in another transaction. Just return
+ * the fact that it is a potential conflict and leave
+ * the full check till later.
+ */
+ if (checkUnique == UNIQUE_CHECK_PARTIAL)
+ {
+ if (nbuf != InvalidBuffer)
+ _bt_relbuf(rel, nbuf);
+ *is_unique = false;
+ return InvalidTransactionId;
+ }
/*
* If this tuple is being updated by other transaction
* then we have to wait for its commit/abort.
*/
+ xwait = (TransactionIdIsValid(SnapshotDirty.xmin)) ?
+ SnapshotDirty.xmin : SnapshotDirty.xmax;
+
if (TransactionIdIsValid(xwait))
{
if (nbuf != InvalidBuffer)
@@ -295,6 +361,9 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
break;
}
+ /*
+ * This is a definite conflict.
+ */
ereport(ERROR,
(errcode(ERRCODE_UNIQUE_VIOLATION),
errmsg("duplicate key value violates unique constraint \"%s\"",
@@ -349,6 +418,18 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
}
}
+ /*
+ * If we are doing a recheck then we should have found the tuple we
+ * are checking. Otherwise there's something very wrong --- probably,
+ * the index is on a non-immutable expression.
+ */
+ if (checkUnique == UNIQUE_CHECK_EXISTING && !found)
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("failed to re-find tuple within index \"%s\"",
+ RelationGetRelationName(rel)),
+ errhint("This may be because of a non-immutable index expression.")));
+
if (nbuf != InvalidBuffer)
_bt_relbuf(rel, nbuf);
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 2b76e7cd453..87a8a225dbf 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.171 2009/06/11 14:48:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.172 2009/07/29 20:56:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -217,18 +217,19 @@ btinsert(PG_FUNCTION_ARGS)
bool *isnull = (bool *) PG_GETARG_POINTER(2);
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
- bool checkUnique = PG_GETARG_BOOL(5);
+ IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
+ bool result;
IndexTuple itup;
/* generate an index tuple */
itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
itup->t_tid = *ht_ctid;
- _bt_doinsert(rel, itup, checkUnique, heapRel);
+ result = _bt_doinsert(rel, itup, checkUnique, heapRel);
pfree(itup);
- PG_RETURN_BOOL(true);
+ PG_RETURN_BOOL(result);
}
/*