mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Create new routines systable_beginscan_ordered, systable_getnext_ordered,
systable_endscan_ordered that have API similar to systable_beginscan etc (in particular, the passed-in scankeys have heap not index attnums), but guarantee ordered output, unlike the existing functions. For the moment these are just very thin wrappers around index_beginscan/index_getnext/etc. Someday they might need to get smarter; but for now this is just a code refactoring exercise to reduce the number of direct callers of index_getnext, in preparation for changing that function's API. In passing, remove index_getnext_indexitem, which has been dead code for quite some time, and will have even less use than that in the presence of run-time-lossy indexes.
This commit is contained in:
parent
00832809a0
commit
ec498cdcbb
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.85 2008/03/26 21:10:37 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.86 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -1184,7 +1184,9 @@ toast_save_datum(Relation rel, Datum value,
|
|||||||
toast_pointer.va_extsize = data_todo;
|
toast_pointer.va_extsize = data_todo;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, toastidx);
|
toast_pointer.va_valueid = GetNewOidWithIndex(toastrel,
|
||||||
|
RelationGetRelid(toastidx),
|
||||||
|
(AttrNumber) 1);
|
||||||
toast_pointer.va_toastrelid = rel->rd_rel->reltoastrelid;
|
toast_pointer.va_toastrelid = rel->rd_rel->reltoastrelid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1273,7 +1275,7 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
Relation toastrel;
|
Relation toastrel;
|
||||||
Relation toastidx;
|
Relation toastidx;
|
||||||
ScanKeyData toastkey;
|
ScanKeyData toastkey;
|
||||||
IndexScanDesc toastscan;
|
SysScanDesc toastscan;
|
||||||
HeapTuple toasttup;
|
HeapTuple toasttup;
|
||||||
|
|
||||||
if (!VARATT_IS_EXTERNAL(attr))
|
if (!VARATT_IS_EXTERNAL(attr))
|
||||||
@ -1289,8 +1291,7 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
|
toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup a scan key to fetch from the index by va_valueid (we don't
|
* Setup a scan key to find chunks with matching va_valueid
|
||||||
* particularly care whether we see them in sequence or not)
|
|
||||||
*/
|
*/
|
||||||
ScanKeyInit(&toastkey,
|
ScanKeyInit(&toastkey,
|
||||||
(AttrNumber) 1,
|
(AttrNumber) 1,
|
||||||
@ -1298,11 +1299,13 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
ObjectIdGetDatum(toast_pointer.va_valueid));
|
ObjectIdGetDatum(toast_pointer.va_valueid));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the chunks by index
|
* Find all the chunks. (We don't actually care whether we see them in
|
||||||
|
* sequence or not, but since we've already locked the index we might
|
||||||
|
* as well use systable_beginscan_ordered.)
|
||||||
*/
|
*/
|
||||||
toastscan = index_beginscan(toastrel, toastidx,
|
toastscan = systable_beginscan_ordered(toastrel, toastidx,
|
||||||
SnapshotToast, 1, &toastkey);
|
SnapshotToast, 1, &toastkey);
|
||||||
while ((toasttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Have a chunk, delete it
|
* Have a chunk, delete it
|
||||||
@ -1313,7 +1316,7 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
/*
|
/*
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
*/
|
*/
|
||||||
index_endscan(toastscan);
|
systable_endscan_ordered(toastscan);
|
||||||
index_close(toastidx, RowExclusiveLock);
|
index_close(toastidx, RowExclusiveLock);
|
||||||
heap_close(toastrel, RowExclusiveLock);
|
heap_close(toastrel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
@ -1332,7 +1335,7 @@ toast_fetch_datum(struct varlena * attr)
|
|||||||
Relation toastrel;
|
Relation toastrel;
|
||||||
Relation toastidx;
|
Relation toastidx;
|
||||||
ScanKeyData toastkey;
|
ScanKeyData toastkey;
|
||||||
IndexScanDesc toastscan;
|
SysScanDesc toastscan;
|
||||||
HeapTuple ttup;
|
HeapTuple ttup;
|
||||||
TupleDesc toasttupDesc;
|
TupleDesc toasttupDesc;
|
||||||
struct varlena *result;
|
struct varlena *result;
|
||||||
@ -1383,9 +1386,9 @@ toast_fetch_datum(struct varlena * attr)
|
|||||||
*/
|
*/
|
||||||
nextidx = 0;
|
nextidx = 0;
|
||||||
|
|
||||||
toastscan = index_beginscan(toastrel, toastidx,
|
toastscan = systable_beginscan_ordered(toastrel, toastidx,
|
||||||
SnapshotToast, 1, &toastkey);
|
SnapshotToast, 1, &toastkey);
|
||||||
while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Have a chunk, extract the sequence number and the data
|
* Have a chunk, extract the sequence number and the data
|
||||||
@ -1464,7 +1467,7 @@ toast_fetch_datum(struct varlena * attr)
|
|||||||
/*
|
/*
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
*/
|
*/
|
||||||
index_endscan(toastscan);
|
systable_endscan_ordered(toastscan);
|
||||||
index_close(toastidx, AccessShareLock);
|
index_close(toastidx, AccessShareLock);
|
||||||
heap_close(toastrel, AccessShareLock);
|
heap_close(toastrel, AccessShareLock);
|
||||||
|
|
||||||
@ -1485,7 +1488,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
|
|||||||
Relation toastidx;
|
Relation toastidx;
|
||||||
ScanKeyData toastkey[3];
|
ScanKeyData toastkey[3];
|
||||||
int nscankeys;
|
int nscankeys;
|
||||||
IndexScanDesc toastscan;
|
SysScanDesc toastscan;
|
||||||
HeapTuple ttup;
|
HeapTuple ttup;
|
||||||
TupleDesc toasttupDesc;
|
TupleDesc toasttupDesc;
|
||||||
struct varlena *result;
|
struct varlena *result;
|
||||||
@ -1592,9 +1595,9 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
|
|||||||
* The index is on (valueid, chunkidx) so they will come in order
|
* The index is on (valueid, chunkidx) so they will come in order
|
||||||
*/
|
*/
|
||||||
nextidx = startchunk;
|
nextidx = startchunk;
|
||||||
toastscan = index_beginscan(toastrel, toastidx,
|
toastscan = systable_beginscan_ordered(toastrel, toastidx,
|
||||||
SnapshotToast, nscankeys, toastkey);
|
SnapshotToast, nscankeys, toastkey);
|
||||||
while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Have a chunk, extract the sequence number and the data
|
* Have a chunk, extract the sequence number and the data
|
||||||
@ -1681,7 +1684,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
|
|||||||
/*
|
/*
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
*/
|
*/
|
||||||
index_endscan(toastscan);
|
systable_endscan_ordered(toastscan);
|
||||||
index_close(toastidx, AccessShareLock);
|
index_close(toastidx, AccessShareLock);
|
||||||
heap_close(toastrel, AccessShareLock);
|
heap_close(toastrel, AccessShareLock);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.66 2008/04/10 22:25:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.67 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* many of the old access method routines have been turned into
|
* many of the old access method routines have been turned into
|
||||||
@ -258,3 +258,87 @@ systable_endscan(SysScanDesc sysscan)
|
|||||||
|
|
||||||
pfree(sysscan);
|
pfree(sysscan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* systable_beginscan_ordered --- set up for ordered catalog scan
|
||||||
|
*
|
||||||
|
* These routines have essentially the same API as systable_beginscan etc,
|
||||||
|
* except that they guarantee to return multiple matching tuples in
|
||||||
|
* index order. Also, for largely historical reasons, the index to use
|
||||||
|
* is opened and locked by the caller, not here.
|
||||||
|
*
|
||||||
|
* Currently we do not support non-index-based scans here. (In principle
|
||||||
|
* we could do a heapscan and sort, but the uses are in places that
|
||||||
|
* probably don't need to still work with corrupted catalog indexes.)
|
||||||
|
* For the moment, therefore, these functions are merely the thinnest of
|
||||||
|
* wrappers around index_beginscan/index_getnext. The main reason for their
|
||||||
|
* existence is to centralize possible future support of lossy operators
|
||||||
|
* in catalog scans.
|
||||||
|
*/
|
||||||
|
SysScanDesc
|
||||||
|
systable_beginscan_ordered(Relation heapRelation,
|
||||||
|
Relation indexRelation,
|
||||||
|
Snapshot snapshot,
|
||||||
|
int nkeys, ScanKey key)
|
||||||
|
{
|
||||||
|
SysScanDesc sysscan;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* REINDEX can probably be a hard error here ... */
|
||||||
|
if (ReindexIsProcessingIndex(RelationGetRelid(indexRelation)))
|
||||||
|
elog(ERROR, "cannot do ordered scan on index \"%s\", because it is the current REINDEX target",
|
||||||
|
RelationGetRelationName(indexRelation));
|
||||||
|
/* ... but we only throw a warning about violating IgnoreSystemIndexes */
|
||||||
|
if (IgnoreSystemIndexes)
|
||||||
|
elog(WARNING, "using index \"%s\" despite IgnoreSystemIndexes",
|
||||||
|
RelationGetRelationName(indexRelation));
|
||||||
|
|
||||||
|
sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
|
||||||
|
|
||||||
|
sysscan->heap_rel = heapRelation;
|
||||||
|
sysscan->irel = indexRelation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change attribute numbers to be index column numbers.
|
||||||
|
*
|
||||||
|
* This code could be generalized to search for the index key numbers
|
||||||
|
* to substitute, but for now there's no need.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < nkeys; i++)
|
||||||
|
{
|
||||||
|
Assert(key[i].sk_attno == indexRelation->rd_index->indkey.values[i]);
|
||||||
|
key[i].sk_attno = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sysscan->iscan = index_beginscan(heapRelation, indexRelation,
|
||||||
|
snapshot, nkeys, key);
|
||||||
|
sysscan->scan = NULL;
|
||||||
|
|
||||||
|
return sysscan;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* systable_getnext_ordered --- get next tuple in an ordered catalog scan
|
||||||
|
*/
|
||||||
|
HeapTuple
|
||||||
|
systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
|
||||||
|
{
|
||||||
|
HeapTuple htup;
|
||||||
|
|
||||||
|
Assert(sysscan->irel);
|
||||||
|
htup = index_getnext(sysscan->iscan, direction);
|
||||||
|
|
||||||
|
return htup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* systable_endscan_ordered --- close scan, release resources
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
systable_endscan_ordered(SysScanDesc sysscan)
|
||||||
|
{
|
||||||
|
Assert(sysscan->irel);
|
||||||
|
index_endscan(sysscan->iscan);
|
||||||
|
pfree(sysscan);
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.105 2008/04/10 22:25:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.106 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* index_open - open an index relation by relation OID
|
* index_open - open an index relation by relation OID
|
||||||
@ -206,12 +206,7 @@ index_insert(Relation indexRelation,
|
|||||||
/*
|
/*
|
||||||
* index_beginscan - start a scan of an index with amgettuple
|
* index_beginscan - start a scan of an index with amgettuple
|
||||||
*
|
*
|
||||||
* Note: heapRelation may be NULL if there is no intention of calling
|
* Caller must be holding suitable locks on the heap and the index.
|
||||||
* index_getnext on this scan; index_getnext_indexitem will not use the
|
|
||||||
* heapRelation link (nor the snapshot). However, the caller had better
|
|
||||||
* be holding some kind of lock on the heap relation in any case, to ensure
|
|
||||||
* no one deletes it (or the index) out from under us. Caller must also
|
|
||||||
* be holding a lock on the index.
|
|
||||||
*/
|
*/
|
||||||
IndexScanDesc
|
IndexScanDesc
|
||||||
index_beginscan(Relation heapRelation,
|
index_beginscan(Relation heapRelation,
|
||||||
@ -634,45 +629,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
|||||||
return NULL; /* failure exit */
|
return NULL; /* failure exit */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* index_getnext_indexitem - get the next index tuple from a scan
|
|
||||||
*
|
|
||||||
* Finds the next index tuple satisfying the scan keys. Note that the
|
|
||||||
* corresponding heap tuple is not accessed, and thus no time qual (snapshot)
|
|
||||||
* check is done, other than the index AM's internal check for killed tuples
|
|
||||||
* (which most callers of this routine will probably want to suppress by
|
|
||||||
* setting scan->ignore_killed_tuples = false).
|
|
||||||
*
|
|
||||||
* On success (TRUE return), the heap TID of the found index entry is in
|
|
||||||
* scan->xs_ctup.t_self. scan->xs_cbuf is untouched.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
index_getnext_indexitem(IndexScanDesc scan,
|
|
||||||
ScanDirection direction)
|
|
||||||
{
|
|
||||||
FmgrInfo *procedure;
|
|
||||||
bool found;
|
|
||||||
|
|
||||||
SCAN_CHECKS;
|
|
||||||
GET_SCAN_PROCEDURE(amgettuple);
|
|
||||||
|
|
||||||
/* just make sure this is false... */
|
|
||||||
scan->kill_prior_tuple = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* have the am's gettuple proc do all the work.
|
|
||||||
*/
|
|
||||||
found = DatumGetBool(FunctionCall2(procedure,
|
|
||||||
PointerGetDatum(scan),
|
|
||||||
Int32GetDatum(direction)));
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
pgstat_count_index_tuples(scan->indexRelation, 1);
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* index_getbitmap - get all tuples at once from an index scan
|
* index_getbitmap - get all tuples at once from an index scan
|
||||||
*
|
*
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.74 2008/03/26 16:20:46 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.75 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -312,9 +312,7 @@ IsSharedRelation(Oid relationId)
|
|||||||
Oid
|
Oid
|
||||||
GetNewOid(Relation relation)
|
GetNewOid(Relation relation)
|
||||||
{
|
{
|
||||||
Oid newOid;
|
|
||||||
Oid oidIndex;
|
Oid oidIndex;
|
||||||
Relation indexrel;
|
|
||||||
|
|
||||||
/* If relation doesn't have OIDs at all, caller is confused */
|
/* If relation doesn't have OIDs at all, caller is confused */
|
||||||
Assert(relation->rd_rel->relhasoids);
|
Assert(relation->rd_rel->relhasoids);
|
||||||
@ -342,11 +340,7 @@ GetNewOid(Relation relation)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, use the index to find a nonconflicting OID */
|
/* Otherwise, use the index to find a nonconflicting OID */
|
||||||
indexrel = index_open(oidIndex, AccessShareLock);
|
return GetNewOidWithIndex(relation, oidIndex, ObjectIdAttributeNumber);
|
||||||
newOid = GetNewOidWithIndex(relation, indexrel);
|
|
||||||
index_close(indexrel, AccessShareLock);
|
|
||||||
|
|
||||||
return newOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -357,16 +351,17 @@ GetNewOid(Relation relation)
|
|||||||
* an index that will not be recognized by RelationGetOidIndex: TOAST tables
|
* an index that will not be recognized by RelationGetOidIndex: TOAST tables
|
||||||
* and pg_largeobject have indexes that are usable, but have multiple columns
|
* and pg_largeobject have indexes that are usable, but have multiple columns
|
||||||
* and are on ordinary columns rather than a true OID column. This code
|
* and are on ordinary columns rather than a true OID column. This code
|
||||||
* will work anyway, so long as the OID is the index's first column.
|
* will work anyway, so long as the OID is the index's first column. The
|
||||||
|
* caller must pass in the actual heap attnum of the OID column, however.
|
||||||
*
|
*
|
||||||
* Caller must have a suitable lock on the relation.
|
* Caller must have a suitable lock on the relation.
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
GetNewOidWithIndex(Relation relation, Relation indexrel)
|
GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
|
||||||
{
|
{
|
||||||
Oid newOid;
|
Oid newOid;
|
||||||
SnapshotData SnapshotDirty;
|
SnapshotData SnapshotDirty;
|
||||||
IndexScanDesc scan;
|
SysScanDesc scan;
|
||||||
ScanKeyData key;
|
ScanKeyData key;
|
||||||
bool collides;
|
bool collides;
|
||||||
|
|
||||||
@ -380,17 +375,17 @@ GetNewOidWithIndex(Relation relation, Relation indexrel)
|
|||||||
newOid = GetNewObjectId();
|
newOid = GetNewObjectId();
|
||||||
|
|
||||||
ScanKeyInit(&key,
|
ScanKeyInit(&key,
|
||||||
(AttrNumber) 1,
|
oidcolumn,
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
ObjectIdGetDatum(newOid));
|
ObjectIdGetDatum(newOid));
|
||||||
|
|
||||||
/* see notes above about using SnapshotDirty */
|
/* see notes above about using SnapshotDirty */
|
||||||
scan = index_beginscan(relation, indexrel,
|
scan = systable_beginscan(relation, indexId, true,
|
||||||
&SnapshotDirty, 1, &key);
|
&SnapshotDirty, 1, &key);
|
||||||
|
|
||||||
collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));
|
collides = HeapTupleIsValid(systable_getnext(scan));
|
||||||
|
|
||||||
index_endscan(scan);
|
systable_endscan(scan);
|
||||||
} while (collides);
|
} while (collides);
|
||||||
|
|
||||||
return newOid;
|
return newOid;
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.131 2008/03/26 21:10:38 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.132 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -201,7 +201,8 @@ inv_create(Oid lobjId)
|
|||||||
{
|
{
|
||||||
open_lo_relation();
|
open_lo_relation();
|
||||||
|
|
||||||
lobjId = GetNewOidWithIndex(lo_heap_r, lo_index_r);
|
lobjId = GetNewOidWithIndex(lo_heap_r, LargeObjectLOidPNIndexId,
|
||||||
|
Anum_pg_largeobject_loid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -311,7 +312,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
uint32 lastbyte = 0;
|
uint32 lastbyte = 0;
|
||||||
ScanKeyData skey[1];
|
ScanKeyData skey[1];
|
||||||
IndexScanDesc sd;
|
SysScanDesc sd;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
Assert(PointerIsValid(obj_desc));
|
Assert(PointerIsValid(obj_desc));
|
||||||
@ -323,8 +324,8 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
|||||||
BTEqualStrategyNumber, F_OIDEQ,
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
ObjectIdGetDatum(obj_desc->id));
|
ObjectIdGetDatum(obj_desc->id));
|
||||||
|
|
||||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
|
||||||
obj_desc->snapshot, 1, skey);
|
obj_desc->snapshot, 1, skey);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Because the pg_largeobject index is on both loid and pageno, but we
|
* Because the pg_largeobject index is on both loid and pageno, but we
|
||||||
@ -332,7 +333,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
|||||||
* large object in reverse pageno order. So, it's sufficient to examine
|
* large object in reverse pageno order. So, it's sufficient to examine
|
||||||
* the first valid tuple (== last valid page).
|
* the first valid tuple (== last valid page).
|
||||||
*/
|
*/
|
||||||
while ((tuple = index_getnext(sd, BackwardScanDirection)) != NULL)
|
while ((tuple = systable_getnext_ordered(sd, BackwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
Form_pg_largeobject data;
|
Form_pg_largeobject data;
|
||||||
bytea *datafield;
|
bytea *datafield;
|
||||||
@ -356,7 +357,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
index_endscan(sd);
|
systable_endscan_ordered(sd);
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -415,7 +416,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||||||
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
||||||
uint32 pageoff;
|
uint32 pageoff;
|
||||||
ScanKeyData skey[2];
|
ScanKeyData skey[2];
|
||||||
IndexScanDesc sd;
|
SysScanDesc sd;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
Assert(PointerIsValid(obj_desc));
|
Assert(PointerIsValid(obj_desc));
|
||||||
@ -436,10 +437,10 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||||||
BTGreaterEqualStrategyNumber, F_INT4GE,
|
BTGreaterEqualStrategyNumber, F_INT4GE,
|
||||||
Int32GetDatum(pageno));
|
Int32GetDatum(pageno));
|
||||||
|
|
||||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
|
||||||
obj_desc->snapshot, 2, skey);
|
obj_desc->snapshot, 2, skey);
|
||||||
|
|
||||||
while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
while ((tuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
Form_pg_largeobject data;
|
Form_pg_largeobject data;
|
||||||
bytea *datafield;
|
bytea *datafield;
|
||||||
@ -450,7 +451,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||||||
data = (Form_pg_largeobject) GETSTRUCT(tuple);
|
data = (Form_pg_largeobject) GETSTRUCT(tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume the indexscan will deliver pages in order. However,
|
* We expect the indexscan will deliver pages in order. However,
|
||||||
* there may be missing pages if the LO contains unwritten "holes". We
|
* there may be missing pages if the LO contains unwritten "holes". We
|
||||||
* want missing sections to read out as zeroes.
|
* want missing sections to read out as zeroes.
|
||||||
*/
|
*/
|
||||||
@ -495,7 +496,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
index_endscan(sd);
|
systable_endscan_ordered(sd);
|
||||||
|
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
@ -509,7 +510,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
|
|||||||
int len;
|
int len;
|
||||||
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
|
||||||
ScanKeyData skey[2];
|
ScanKeyData skey[2];
|
||||||
IndexScanDesc sd;
|
SysScanDesc sd;
|
||||||
HeapTuple oldtuple;
|
HeapTuple oldtuple;
|
||||||
Form_pg_largeobject olddata;
|
Form_pg_largeobject olddata;
|
||||||
bool neednextpage;
|
bool neednextpage;
|
||||||
@ -555,8 +556,8 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
|
|||||||
BTGreaterEqualStrategyNumber, F_INT4GE,
|
BTGreaterEqualStrategyNumber, F_INT4GE,
|
||||||
Int32GetDatum(pageno));
|
Int32GetDatum(pageno));
|
||||||
|
|
||||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
|
||||||
obj_desc->snapshot, 2, skey);
|
obj_desc->snapshot, 2, skey);
|
||||||
|
|
||||||
oldtuple = NULL;
|
oldtuple = NULL;
|
||||||
olddata = NULL;
|
olddata = NULL;
|
||||||
@ -565,12 +566,12 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
|
|||||||
while (nwritten < nbytes)
|
while (nwritten < nbytes)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If possible, get next pre-existing page of the LO. We assume the
|
* If possible, get next pre-existing page of the LO. We expect the
|
||||||
* indexscan will deliver these in order --- but there may be holes.
|
* indexscan will deliver these in order --- but there may be holes.
|
||||||
*/
|
*/
|
||||||
if (neednextpage)
|
if (neednextpage)
|
||||||
{
|
{
|
||||||
if ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
if (HeapTupleHasNulls(oldtuple)) /* paranoia */
|
if (HeapTupleHasNulls(oldtuple)) /* paranoia */
|
||||||
elog(ERROR, "null field found in pg_largeobject");
|
elog(ERROR, "null field found in pg_largeobject");
|
||||||
@ -685,7 +686,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
|
|||||||
pageno++;
|
pageno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
index_endscan(sd);
|
systable_endscan_ordered(sd);
|
||||||
|
|
||||||
CatalogCloseIndexes(indstate);
|
CatalogCloseIndexes(indstate);
|
||||||
|
|
||||||
@ -704,7 +705,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
|
|||||||
int32 pageno = (int32) (len / LOBLKSIZE);
|
int32 pageno = (int32) (len / LOBLKSIZE);
|
||||||
int off;
|
int off;
|
||||||
ScanKeyData skey[2];
|
ScanKeyData skey[2];
|
||||||
IndexScanDesc sd;
|
SysScanDesc sd;
|
||||||
HeapTuple oldtuple;
|
HeapTuple oldtuple;
|
||||||
Form_pg_largeobject olddata;
|
Form_pg_largeobject olddata;
|
||||||
struct
|
struct
|
||||||
@ -743,15 +744,15 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
|
|||||||
BTGreaterEqualStrategyNumber, F_INT4GE,
|
BTGreaterEqualStrategyNumber, F_INT4GE,
|
||||||
Int32GetDatum(pageno));
|
Int32GetDatum(pageno));
|
||||||
|
|
||||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
|
||||||
obj_desc->snapshot, 2, skey);
|
obj_desc->snapshot, 2, skey);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If possible, get the page the truncation point is in. The truncation
|
* If possible, get the page the truncation point is in. The truncation
|
||||||
* point may be beyond the end of the LO or in a hole.
|
* point may be beyond the end of the LO or in a hole.
|
||||||
*/
|
*/
|
||||||
olddata = NULL;
|
olddata = NULL;
|
||||||
if ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
if (HeapTupleHasNulls(oldtuple)) /* paranoia */
|
if (HeapTupleHasNulls(oldtuple)) /* paranoia */
|
||||||
elog(ERROR, "null field found in pg_largeobject");
|
elog(ERROR, "null field found in pg_largeobject");
|
||||||
@ -846,12 +847,12 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
|
|||||||
/*
|
/*
|
||||||
* Delete any pages after the truncation point
|
* Delete any pages after the truncation point
|
||||||
*/
|
*/
|
||||||
while ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
simple_heap_delete(lo_heap_r, &oldtuple->t_self);
|
simple_heap_delete(lo_heap_r, &oldtuple->t_self);
|
||||||
}
|
}
|
||||||
|
|
||||||
index_endscan(sd);
|
systable_endscan_ordered(sd);
|
||||||
|
|
||||||
CatalogCloseIndexes(indstate);
|
CatalogCloseIndexes(indstate);
|
||||||
|
|
||||||
|
11
src/backend/utils/cache/ts_cache.c
vendored
11
src/backend/utils/cache/ts_cache.c
vendored
@ -20,7 +20,7 @@
|
|||||||
* Copyright (c) 2006-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2006-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.6 2008/03/26 21:10:39 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.7 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -419,7 +419,7 @@ lookup_ts_config_cache(Oid cfgId)
|
|||||||
Relation maprel;
|
Relation maprel;
|
||||||
Relation mapidx;
|
Relation mapidx;
|
||||||
ScanKeyData mapskey;
|
ScanKeyData mapskey;
|
||||||
IndexScanDesc mapscan;
|
SysScanDesc mapscan;
|
||||||
HeapTuple maptup;
|
HeapTuple maptup;
|
||||||
ListDictionary maplists[MAXTOKENTYPE + 1];
|
ListDictionary maplists[MAXTOKENTYPE + 1];
|
||||||
Oid mapdicts[MAXDICTSPERTT];
|
Oid mapdicts[MAXDICTSPERTT];
|
||||||
@ -488,9 +488,10 @@ lookup_ts_config_cache(Oid cfgId)
|
|||||||
|
|
||||||
maprel = heap_open(TSConfigMapRelationId, AccessShareLock);
|
maprel = heap_open(TSConfigMapRelationId, AccessShareLock);
|
||||||
mapidx = index_open(TSConfigMapIndexId, AccessShareLock);
|
mapidx = index_open(TSConfigMapIndexId, AccessShareLock);
|
||||||
mapscan = index_beginscan(maprel, mapidx, SnapshotNow, 1, &mapskey);
|
mapscan = systable_beginscan_ordered(maprel, mapidx,
|
||||||
|
SnapshotNow, 1, &mapskey);
|
||||||
|
|
||||||
while ((maptup = index_getnext(mapscan, ForwardScanDirection)) != NULL)
|
while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
|
Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
|
||||||
int toktype = cfgmap->maptokentype;
|
int toktype = cfgmap->maptokentype;
|
||||||
@ -524,7 +525,7 @@ lookup_ts_config_cache(Oid cfgId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index_endscan(mapscan);
|
systable_endscan_ordered(mapscan);
|
||||||
index_close(mapidx, AccessShareLock);
|
index_close(mapidx, AccessShareLock);
|
||||||
heap_close(maprel, AccessShareLock);
|
heap_close(maprel, AccessShareLock);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/genam.h,v 1.70 2008/04/10 22:25:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/access/genam.h,v 1.71 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -108,8 +108,6 @@ extern void index_endscan(IndexScanDesc scan);
|
|||||||
extern void index_markpos(IndexScanDesc scan);
|
extern void index_markpos(IndexScanDesc scan);
|
||||||
extern void index_restrpos(IndexScanDesc scan);
|
extern void index_restrpos(IndexScanDesc scan);
|
||||||
extern HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction);
|
extern HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction);
|
||||||
extern bool index_getnext_indexitem(IndexScanDesc scan,
|
|
||||||
ScanDirection direction);
|
|
||||||
extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);
|
extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);
|
||||||
|
|
||||||
extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
|
extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
|
||||||
@ -140,5 +138,12 @@ extern SysScanDesc systable_beginscan(Relation heapRelation,
|
|||||||
int nkeys, ScanKey key);
|
int nkeys, ScanKey key);
|
||||||
extern HeapTuple systable_getnext(SysScanDesc sysscan);
|
extern HeapTuple systable_getnext(SysScanDesc sysscan);
|
||||||
extern void systable_endscan(SysScanDesc sysscan);
|
extern void systable_endscan(SysScanDesc sysscan);
|
||||||
|
extern SysScanDesc systable_beginscan_ordered(Relation heapRelation,
|
||||||
|
Relation indexRelation,
|
||||||
|
Snapshot snapshot,
|
||||||
|
int nkeys, ScanKey key);
|
||||||
|
extern HeapTuple systable_getnext_ordered(SysScanDesc sysscan,
|
||||||
|
ScanDirection direction);
|
||||||
|
extern void systable_endscan_ordered(SysScanDesc sysscan);
|
||||||
|
|
||||||
#endif /* GENAM_H */
|
#endif /* GENAM_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.62 2008/04/10 22:25:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.63 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -76,14 +76,12 @@ typedef struct IndexScanDescData
|
|||||||
/* index access method's private state */
|
/* index access method's private state */
|
||||||
void *opaque; /* access-method-specific info */
|
void *opaque; /* access-method-specific info */
|
||||||
|
|
||||||
/*
|
/* xs_ctup/xs_cbuf are valid after a successful index_getnext */
|
||||||
* xs_ctup/xs_cbuf are valid after a successful index_getnext. After
|
|
||||||
* index_getnext_indexitem, xs_ctup.t_self contains the heap tuple TID
|
|
||||||
* from the index entry, but its other fields are not valid.
|
|
||||||
*/
|
|
||||||
HeapTupleData xs_ctup; /* current heap tuple, if any */
|
HeapTupleData xs_ctup; /* current heap tuple, if any */
|
||||||
Buffer xs_cbuf; /* current heap buffer in scan, if any */
|
Buffer xs_cbuf; /* current heap buffer in scan, if any */
|
||||||
/* NB: if xs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
|
/* NB: if xs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
|
||||||
|
|
||||||
|
/* state data for traversing HOT chains in index_getnext */
|
||||||
TransactionId xs_prev_xmax; /* previous HOT chain member's XMAX, if any */
|
TransactionId xs_prev_xmax; /* previous HOT chain member's XMAX, if any */
|
||||||
OffsetNumber xs_next_hot; /* next member of HOT chain, if any */
|
OffsetNumber xs_next_hot; /* next member of HOT chain, if any */
|
||||||
bool xs_hot_dead; /* T if all members of HOT chain are dead */
|
bool xs_hot_dead; /* T if all members of HOT chain are dead */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.38 2008/01/01 19:45:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.39 2008/04/12 23:14:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -34,7 +34,8 @@ extern bool IsReservedName(const char *name);
|
|||||||
extern bool IsSharedRelation(Oid relationId);
|
extern bool IsSharedRelation(Oid relationId);
|
||||||
|
|
||||||
extern Oid GetNewOid(Relation relation);
|
extern Oid GetNewOid(Relation relation);
|
||||||
extern Oid GetNewOidWithIndex(Relation relation, Relation indexrel);
|
extern Oid GetNewOidWithIndex(Relation relation, Oid indexId,
|
||||||
|
AttrNumber oidcolumn);
|
||||||
extern Oid GetNewRelFileNode(Oid reltablespace, bool relisshared,
|
extern Oid GetNewRelFileNode(Oid reltablespace, bool relisshared,
|
||||||
Relation pg_class);
|
Relation pg_class);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user