-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.121 2006/03/10 19:10:46 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.122 2006/05/02 22:25:09 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
</row>
<row>
+ <entry><structfield>amstorage</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry></entry>
+ <entry>Can index storage data type differ from column data type?</entry>
+ </row>
+
+ <row>
<entry><structfield>amconcurrent</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
</row>
<row>
+ <entry><structfield>amclusterable</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry></entry>
+ <entry>Can an index of this type be CLUSTERed on?</entry>
+ </row>
+
+ <row>
<entry><structfield>aminsert</structfield></entry>
<entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
-<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.9 2006/03/10 19:10:48 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.10 2006/05/02 22:25:09 tgl Exp $ -->
<chapter id="indexam">
<title>Index Access Method Interface Definition</title>
<para>
<programlisting>
IndexBulkDeleteResult *
-ambulkdelete (Relation indexRelation,
+ambulkdelete (IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback,
void *callback_state);
</programlisting>
Delete tuple(s) from the index. This is a <quote>bulk delete</> operation
that is intended to be implemented by scanning the whole index and checking
each entry to see if it should be deleted.
- The passed-in <literal>callback</> function may be called, in the style
+ The passed-in <literal>callback</> function must be called, in the style
<literal>callback(<replaceable>TID</>, callback_state) returns bool</literal>,
to determine whether any particular index entry, as identified by its
referenced TID, is to be deleted. Must return either NULL or a palloc'd
struct containing statistics about the effects of the deletion operation.
+ It is OK to return NULL if no information needs to be passed on to
+ <function>amvacuumcleanup</>.
</para>
<para>
- If <literal>callback_state</> is NULL then no tuples are to be deleted.
- The index AM may choose to optimize this case (eg by not scanning the
- index) but it is still expected to deliver accurate statistics.
+ Because of limited <varname>maintenance_work_mem</>,
+ <function>ambulkdelete</> may need to be called more than once when many
+ tuples are to be deleted. The <literal>stats</> argument is the result
+ of the previous call for this index (it is NULL for the first call within a
+ <command>VACUUM</> operation). This allows the AM to accumulate statistics
+ across the whole operation. Typically, <function>ambulkdelete</> will
+ modify and return the same struct if the passed <literal>stats</> is not
+ null.
</para>
<para>
<programlisting>
IndexBulkDeleteResult *
-amvacuumcleanup (Relation indexRelation,
- IndexVacuumCleanupInfo *info,
+amvacuumcleanup (IndexVacuumInfo *info,
IndexBulkDeleteResult *stats);
</programlisting>
- Clean up after a <command>VACUUM</command> operation (one or more
- <function>ambulkdelete</> calls). An index access method does not have
- to provide this function (if so, the entry in <structname>pg_am</> must
- be zero). If it is provided, it is typically used for bulk cleanup
- such as reclaiming empty index pages. <literal>info</>
- provides some additional arguments such as a message level for statistical
- reports, and <literal>stats</> is whatever the last
- <function>ambulkdelete</> call returned. <function>amvacuumcleanup</>
- may replace or modify this struct before returning it. If the result
- is not NULL it must be a palloc'd struct. The statistics it contains
- will be reported by <command>VACUUM</> if <literal>VERBOSE</> is given.
+ Clean up after a <command>VACUUM</command> operation (zero or more
+ <function>ambulkdelete</> calls). This does not have to do anything
+ beyond returning index statistics, but it may perform bulk cleanup
+ such as reclaiming empty index pages. <literal>stats</> is whatever the
+ last <function>ambulkdelete</> call returned, or NULL if
+ <function>ambulkdelete</> was not called because no tuples needed to be
+ deleted. If the result is not NULL it must be a palloc'd struct.
+ The statistics it contains will be used to update <structname>pg_class</>,
+ and will be reported by <command>VACUUM</> if <literal>VERBOSE</> is given.
+ It is OK to return NULL if the index was not changed at all during the
+ <command>VACUUM</command> operation, but otherwise correct stats should
+ be returned.
</para>
<para>
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.1 2006/05/02 11:28:54 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.2 2006/05/02 22:25:10 tgl Exp $
*-------------------------------------------------------------------------
*/
Datum
ginbulkdelete(PG_FUNCTION_ARGS) {
- Relation index = (Relation) PG_GETARG_POINTER(0);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
- void *callback_state = (void *) PG_GETARG_POINTER(2);
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
+ IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
+ void *callback_state = (void *) PG_GETARG_POINTER(3);
+ Relation index = info->index;
BlockNumber blkno = GIN_ROOT_BLKNO;
GinVacuumState gvs;
Buffer buffer;
BlockNumber rootOfPostingTree[ BLCKSZ/ (sizeof(IndexTupleData)+sizeof(ItemId)) ];
uint32 nRoot;
+ /* first time through? */
+ if (stats == NULL)
+ stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ /* we'll re-count the tuples each time */
+ stats->num_index_tuples = 0;
+
gvs.index = index;
- gvs.result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ gvs.result = stats;
gvs.callback = callback;
gvs.callback_state = callback_state;
initGinState(&gvs.ginstate, index);
Datum
ginvacuumcleanup(PG_FUNCTION_ARGS) {
- Relation index = (Relation) PG_GETARG_POINTER(0);
- IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2);
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
+ Relation index = info->index;
bool needLock = !RELATION_IS_LOCAL(index);
BlockNumber npages,
blkno;
BlockNumber lastBlock = GIN_ROOT_BLKNO,
lastFilledBlock = GIN_ROOT_BLKNO;
+ /* Set up all-zero stats if ginbulkdelete wasn't called */
+ if (stats == NULL)
+ stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ /*
+ * XXX we always report the heap tuple count as the number of index
+ * entries. This is bogus if the index is partial, but it's real hard
+ * to tell how many distinct heap entries are referenced by a GIN index.
+ */
+ stats->num_index_tuples = info->num_heap_tuples;
if (info->vacuum_full) {
LockRelation(index, AccessExclusiveLock);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.18 2006/03/31 23:32:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.19 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Datum
gistvacuumcleanup(PG_FUNCTION_ARGS)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
- GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(2);
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);
+ Relation rel = info->index;
BlockNumber npages,
blkno;
BlockNumber nFreePages,
lastFilledBlock = GIST_ROOT_BLKNO;
bool needLock;
+ /* Set up all-zero stats if gistbulkdelete wasn't called */
+ if (stats == NULL)
+ {
+ stats = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
+ /* use heap's tuple count */
+ Assert(info->num_heap_tuples >= 0);
+ stats->std.num_index_tuples = info->num_heap_tuples;
+ /*
+ * XXX the above is wrong if index is partial. Would it be OK to
+ * just return NULL, or is there work we must do below?
+ */
+ }
+
/* gistVacuumUpdate may cause hard work */
if (info->vacuum_full)
{
if (info->vacuum_full)
UnlockRelation(rel, AccessExclusiveLock);
- /* if gistbulkdelete skipped the scan, use heap's tuple count */
- if (stats->std.num_index_tuples < 0)
- {
- Assert(info->num_heap_tuples >= 0);
- stats->std.num_index_tuples = info->num_heap_tuples;
- }
-
PG_RETURN_POINTER(stats);
}
Datum
gistbulkdelete(PG_FUNCTION_ARGS)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
- void *callback_state = (void *) PG_GETARG_POINTER(2);
- GistBulkDeleteResult *result;
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);
+ IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
+ void *callback_state = (void *) PG_GETARG_POINTER(3);
+ Relation rel = info->index;
GistBDItem *stack,
*ptr;
- bool needLock;
- result = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
+ /* first time through? */
+ if (stats == NULL)
+ stats = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
+ /* we'll re-count the tuples each time */
+ stats->std.num_index_tuples = 0;
- /*
- * We can skip the scan entirely if there's nothing to delete (indicated
- * by callback_state == NULL) and the index isn't partial. For a partial
- * index we must scan in order to derive a trustworthy tuple count.
- *
- * XXX as of PG 8.2 this is dead code because GIST indexes are always
- * effectively partial ... but keep it anyway in case our null-handling
- * gets fixed.
- */
- if (callback_state || vac_is_partial_index(rel))
- {
- stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
- stack->blkno = GIST_ROOT_BLKNO;
- }
- else
- {
- /* skip scan and set flag for gistvacuumcleanup */
- stack = NULL;
- result->std.num_index_tuples = -1;
- }
+ stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
+ stack->blkno = GIST_ROOT_BLKNO;
while (stack)
{
i--;
maxoff--;
ntodelete++;
- result->std.tuples_removed += 1;
+ stats->std.tuples_removed += 1;
Assert(maxoff == PageGetMaxOffsetNumber(page));
}
else
- result->std.num_index_tuples += 1;
+ stats->std.num_index_tuples += 1;
}
if (ntodelete)
stack->next = ptr;
if (GistTupleIsInvalid(idxtuple))
- result->needFullVacuum = true;
+ stats->needFullVacuum = true;
}
}
vacuum_delay_point();
}
- needLock = !RELATION_IS_LOCAL(rel);
-
- if (needLock)
- LockRelationForExtension(rel, ExclusiveLock);
- result->std.num_pages = RelationGetNumberOfBlocks(rel);
- if (needLock)
- UnlockRelationForExtension(rel, ExclusiveLock);
-
- PG_RETURN_POINTER(result);
+ PG_RETURN_POINTER(stats);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.88 2006/03/24 04:32:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.89 2006/05/02 22:25:10 tgl Exp $
*
* NOTES
* This file contains only the public interface routines.
Datum
hashbulkdelete(PG_FUNCTION_ARGS)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
- void *callback_state = (void *) PG_GETARG_POINTER(2);
- IndexBulkDeleteResult *result;
- BlockNumber num_pages;
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
+ IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
+ void *callback_state = (void *) PG_GETARG_POINTER(3);
+ Relation rel = info->index;
double tuples_removed;
double num_index_tuples;
double orig_ntuples;
cur_maxbucket = orig_maxbucket;
loop_top:
-
- /*
- * If we don't have anything to delete, skip the scan, and report the
- * number of tuples shown in the metapage. (Unlike btree and gist,
- * we can trust this number even for a partial index.)
- */
- if (!callback_state)
- {
- cur_bucket = cur_maxbucket + 1;
- num_index_tuples = local_metapage.hashm_ntuples;
- }
-
while (cur_bucket <= cur_maxbucket)
{
BlockNumber bucket_blkno;
_hash_wrtbuf(rel, metabuf);
/* return statistics */
- num_pages = RelationGetNumberOfBlocks(rel);
+ if (stats == NULL)
+ stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ stats->num_index_tuples = num_index_tuples;
+ stats->tuples_removed += tuples_removed;
+ /* hashvacuumcleanup will fill in num_pages */
+
+ PG_RETURN_POINTER(stats);
+}
- result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
- result->num_pages = num_pages;
- result->num_index_tuples = num_index_tuples;
- result->tuples_removed = tuples_removed;
+/*
+ * Post-VACUUM cleanup.
+ *
+ * Result: a palloc'd struct containing statistical info for VACUUM displays.
+ */
+Datum
+hashvacuumcleanup(PG_FUNCTION_ARGS)
+{
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
+ Relation rel = info->index;
+ BlockNumber num_pages;
+
+ /* If hashbulkdelete wasn't called, return NULL signifying no change */
+ if (stats == NULL)
+ PG_RETURN_POINTER(NULL);
+
+ /* update statistics */
+ num_pages = RelationGetNumberOfBlocks(rel);
+ stats->num_pages = num_pages;
- PG_RETURN_POINTER(result);
+ PG_RETURN_POINTER(stats);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.91 2006/03/05 15:58:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.92 2006/05/02 22:25:10 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
*
* callback routine tells whether a given main-heap tuple is
* to be deleted
- *
- * if callback_state is NULL then there are no tuples to be deleted;
- * index AM can choose to avoid work in this case, but must still
- * follow the protocol of returning statistical info.
*
* return value is an optional palloc'd struct of statistics
* ----------------
*/
IndexBulkDeleteResult *
-index_bulk_delete(Relation indexRelation,
+index_bulk_delete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback,
void *callback_state)
{
+ Relation indexRelation = info->index;
FmgrInfo *procedure;
IndexBulkDeleteResult *result;
GET_REL_PROCEDURE(ambulkdelete);
result = (IndexBulkDeleteResult *)
- DatumGetPointer(FunctionCall3(procedure,
- PointerGetDatum(indexRelation),
+ DatumGetPointer(FunctionCall4(procedure,
+ PointerGetDatum(info),
+ PointerGetDatum(stats),
PointerGetDatum((Pointer) callback),
PointerGetDatum(callback_state)));
* ----------------
*/
IndexBulkDeleteResult *
-index_vacuum_cleanup(Relation indexRelation,
- IndexVacuumCleanupInfo *info,
+index_vacuum_cleanup(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats)
{
+ Relation indexRelation = info->index;
FmgrInfo *procedure;
IndexBulkDeleteResult *result;
RELATION_CHECKS;
-
- /* It's okay for an index AM not to have a vacuumcleanup procedure */
- if (!RegProcedureIsValid(indexRelation->rd_am->amvacuumcleanup))
- return stats;
-
GET_REL_PROCEDURE(amvacuumcleanup);
result = (IndexBulkDeleteResult *)
- DatumGetPointer(FunctionCall3(procedure,
- PointerGetDatum(indexRelation),
- PointerGetDatum((Pointer) info),
- PointerGetDatum((Pointer) stats)));
+ DatumGetPointer(FunctionCall2(procedure,
+ PointerGetDatum(info),
+ PointerGetDatum(stats)));
return result;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.145 2006/04/25 22:46:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.146 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Datum
btbulkdelete(PG_FUNCTION_ARGS)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
- void *callback_state = (void *) PG_GETARG_POINTER(2);
- IndexBulkDeleteResult *result;
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
+ IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
+ void *callback_state = (void *) PG_GETARG_POINTER(3);
+ Relation rel = info->index;
double tuples_removed = 0;
OffsetNumber deletable[MaxOffsetNumber];
int ndeletable;
Buffer buf;
- BlockNumber num_pages;
/*
* The outer loop iterates over index leaf pages, the inner over items on
* further to its right, which the indexscan will have no pin on.) We can
* skip obtaining exclusive lock on empty pages though, since no indexscan
* could be stopped on those.
- *
- * We can skip the scan entirely if there's nothing to delete (indicated
- * by callback_state == NULL).
*/
- if (callback_state)
- buf = _bt_get_endpoint(rel, 0, false);
- else
- buf = InvalidBuffer;
+ buf = _bt_get_endpoint(rel, 0, false);
if (BufferIsValid(buf)) /* check for empty index */
{
}
/* return statistics */
- num_pages = RelationGetNumberOfBlocks(rel);
-
- result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
- result->num_pages = num_pages;
- /* btvacuumcleanup will fill in num_index_tuples */
- result->tuples_removed = tuples_removed;
+ if (stats == NULL)
+ stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ stats->tuples_removed += tuples_removed;
+ /* btvacuumcleanup will fill in num_pages and num_index_tuples */
- PG_RETURN_POINTER(result);
+ PG_RETURN_POINTER(stats);
}
/*
Datum
btvacuumcleanup(PG_FUNCTION_ARGS)
{
- Relation rel = (Relation) PG_GETARG_POINTER(0);
- IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2);
+ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
+ IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
+ Relation rel = info->index;
BlockNumber num_pages;
BlockNumber blkno;
BlockNumber *freePages;
MemoryContext oldcontext;
bool needLock;
- Assert(stats != NULL);
+ /* Set up all-zero stats if btbulkdelete wasn't called */
+ if (stats == NULL)
+ stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
/*
* First find out the number of pages in the index. We must acquire the
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.146 2006/05/02 15:45:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.147 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
errmsg("cannot cluster on partial index \"%s\"",
RelationGetRelationName(OldIndex))));
+ if (!OldIndex->rd_am->amclusterable)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot cluster on index \"%s\" because access method does not support clustering",
+ RelationGetRelationName(OldIndex))));
+
if (!OldIndex->rd_am->amindexnulls)
{
AttrNumber colno;
RelationGetRelationName(OldIndex))));
}
- if (!OldIndex->rd_am->amclusterable)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot cluster on index \"%s\" because access method does not support clustering",
- RelationGetRelationName(OldIndex))));
-
/*
* Disallow clustering system relations. This will definitely NOT work
* for shared relations (we have no way to update pg_class rows in other
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.44 2006/05/02 11:28:54 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.45 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
opclassoid; /* oid of opclass we create */
int numOperators, /* amstrategies value */
numProcs; /* amsupport value */
+ bool amstorage; /* amstorage flag */
List *operators; /* OpClassMember list for operators */
List *procedures; /* OpClassMember list for support procs */
ListCell *l;
Relation rel;
HeapTuple tup;
+ Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
char nulls[Natts_pg_opclass];
AclResult aclresult;
stmt->amname)));
amoid = HeapTupleGetOid(tup);
- numOperators = ((Form_pg_am) GETSTRUCT(tup))->amstrategies;
- numProcs = ((Form_pg_am) GETSTRUCT(tup))->amsupport;
+ pg_am = (Form_pg_am) GETSTRUCT(tup);
+ numOperators = pg_am->amstrategies;
+ numProcs = pg_am->amsupport;
+ amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
/* Just drop the spec if same as column datatype */
if (storageoid == typeoid)
storageoid = InvalidOid;
- else
- {
- /*
- * Currently, only GiST and GIN allows storagetype different from
- * datatype. This hardcoded test should be eliminated in favor of
- * adding another boolean column to pg_am ...
- */
- if (!(amoid == GIST_AM_OID || amoid == GIN_AM_OID))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("storage type may not be different from data type for access method \"%s\"",
- stmt->amname)));
- }
+ else if (!amstorage)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("storage type may not be different from data type for access method \"%s\"",
+ stmt->amname)));
}
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.327 2006/05/02 11:28:54 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.328 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
double num_tuples, int keep_tuples);
static void scan_index(Relation indrel, double num_tuples);
static bool tid_reaped(ItemPointer itemptr, void *state);
-static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
static void vac_update_fsm(Relation onerel, VacPageList fraged_pages,
BlockNumber rel_pages);
static VacPage copy_vac_page(VacPage vacpage);
}
/*
- * scan_index() -- scan one index relation to update statistic.
+ * scan_index() -- scan one index relation to update pg_class statistics.
*
* We use this when we have no deletions to do.
*/
scan_index(Relation indrel, double num_tuples)
{
IndexBulkDeleteResult *stats;
- IndexVacuumCleanupInfo vcinfo;
+ IndexVacuumInfo ivinfo;
PGRUsage ru0;
pg_rusage_init(&ru0);
- /*
- * Even though we're not planning to delete anything, we use the
- * ambulkdelete call, because (a) the scan happens within the index AM for
- * more speed, and (b) it may want to pass private statistics to the
- * amvacuumcleanup call.
- */
- stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
+ ivinfo.index = indrel;
+ ivinfo.vacuum_full = true;
+ ivinfo.message_level = elevel;
+ ivinfo.num_heap_tuples = num_tuples;
- /* Do post-VACUUM cleanup, even though we deleted nothing */
- vcinfo.vacuum_full = true;
- vcinfo.message_level = elevel;
- vcinfo.num_heap_tuples = num_tuples;
-
- stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
+ stats = index_vacuum_cleanup(&ivinfo, NULL);
if (!stats)
return;
/*
* Check for tuple count mismatch. If the index is partial, then it's OK
* for it to have fewer tuples than the heap; else we got trouble.
- *
- * XXX Hack. Since GIN stores every pointer to heap several times and
- * counting num_index_tuples during vacuum is very comlpex and slow
- * we just copy num_tuples to num_index_tuples as upper limit to avoid
- * WARNING and optimizer mistakes.
*/
- if ( indrel->rd_rel->relam == GIN_AM_OID )
- {
- stats->num_index_tuples = num_tuples;
- } else
if (stats->num_index_tuples != num_tuples)
{
if (stats->num_index_tuples > num_tuples ||
double num_tuples, int keep_tuples)
{
IndexBulkDeleteResult *stats;
- IndexVacuumCleanupInfo vcinfo;
+ IndexVacuumInfo ivinfo;
PGRUsage ru0;
pg_rusage_init(&ru0);
+ ivinfo.index = indrel;
+ ivinfo.vacuum_full = true;
+ ivinfo.message_level = elevel;
+ ivinfo.num_heap_tuples = num_tuples + keep_tuples;
+
/* Do bulk deletion */
- stats = index_bulk_delete(indrel, tid_reaped, (void *) vacpagelist);
+ stats = index_bulk_delete(&ivinfo, NULL, tid_reaped, (void *) vacpagelist);
/* Do post-VACUUM cleanup */
- vcinfo.vacuum_full = true;
- vcinfo.message_level = elevel;
- vcinfo.num_heap_tuples = num_tuples + keep_tuples;
-
- stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
+ stats = index_vacuum_cleanup(&ivinfo, stats);
if (!stats)
return;
/*
* Check for tuple count mismatch. If the index is partial, then it's OK
* for it to have fewer tuples than the heap; else we got trouble.
- *
- * XXX Hack. Since GIN stores every pointer to heap several times and
- * counting num_index_tuples during vacuum is very comlpex and slow
- * we just copy num_tuples to num_index_tuples as upper limit to avoid
- * WARNING and optimizer mistakes.
*/
- if ( indrel->rd_rel->relam == GIN_AM_OID )
- {
- stats->num_index_tuples = num_tuples;
- } else
if (stats->num_index_tuples != num_tuples + keep_tuples)
{
if (stats->num_index_tuples > num_tuples + keep_tuples ||
}
/*
- * Dummy version for scan_index.
- */
-static bool
-dummy_tid_reaped(ItemPointer itemptr, void *state)
-{
- return false;
-}
-
-/*
* Update the shared Free Space Map with the info we now have about
* free space in the relation, discarding any old info the map may have.
*/
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.69 2006/03/31 23:32:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.70 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
Relation *Irel, int nindexes);
static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
-static void lazy_scan_index(Relation indrel, LVRelStats *vacrelstats);
static void lazy_vacuum_index(Relation indrel,
- double *index_tups_vacuumed,
- BlockNumber *index_pages_removed,
- LVRelStats *vacrelstats);
+ IndexBulkDeleteResult **stats,
+ LVRelStats *vacrelstats);
+static void lazy_cleanup_index(Relation indrel,
+ IndexBulkDeleteResult *stats,
+ LVRelStats *vacrelstats);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int tupindex, LVRelStats *vacrelstats);
static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats);
static void lazy_record_free_space(LVRelStats *vacrelstats,
BlockNumber page, Size avail);
static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
-static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
static void lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats);
static int vac_cmp_itemptr(const void *left, const void *right);
static int vac_cmp_page_spaces(const void *left, const void *right);
tups_vacuumed,
nkeep,
nunused;
- double *index_tups_vacuumed;
- BlockNumber *index_pages_removed;
- bool did_vacuum_index = false;
+ IndexBulkDeleteResult **indstats;
int i;
PGRUsage ru0;
empty_pages = 0;
num_tuples = tups_vacuumed = nkeep = nunused = 0;
- /*
- * Because index vacuuming is done in multiple passes, we have to keep
- * track of the total number of rows and pages removed from each index.
- * index_tups_vacuumed[i] is the number removed so far from the i'th
- * index. (For partial indexes this could well be different from
- * tups_vacuumed.) Likewise for index_pages_removed[i].
- */
- index_tups_vacuumed = (double *) palloc0(nindexes * sizeof(double));
- index_pages_removed = (BlockNumber *) palloc0(nindexes * sizeof(BlockNumber));
+ indstats = (IndexBulkDeleteResult **)
+ palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
nblocks = RelationGetNumberOfBlocks(onerel);
vacrelstats->rel_pages = nblocks;
/* Remove index entries */
for (i = 0; i < nindexes; i++)
lazy_vacuum_index(Irel[i],
- &index_tups_vacuumed[i],
- &index_pages_removed[i],
+ &indstats[i],
vacrelstats);
- did_vacuum_index = true;
/* Remove tuples from heap */
lazy_vacuum_heap(onerel, vacrelstats);
/* Forget the now-vacuumed tuples, and press on */
/* Remove index entries */
for (i = 0; i < nindexes; i++)
lazy_vacuum_index(Irel[i],
- &index_tups_vacuumed[i],
- &index_pages_removed[i],
+ &indstats[i],
vacrelstats);
/* Remove tuples from heap */
lazy_vacuum_heap(onerel, vacrelstats);
}
- else if (!did_vacuum_index)
- {
- /* Must do post-vacuum cleanup and statistics update anyway */
- for (i = 0; i < nindexes; i++)
- lazy_scan_index(Irel[i], vacrelstats);
- }
+
+ /* Do post-vacuum cleanup and statistics update for each index */
+ for (i = 0; i < nindexes; i++)
+ lazy_cleanup_index(Irel[i], indstats[i], vacrelstats);
ereport(elevel,
(errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
}
/*
- * lazy_scan_index() -- scan one index relation to update pg_class statistic.
+ * lazy_vacuum_index() -- vacuum one index relation.
*
- * We use this when we have no deletions to do.
+ * Delete all the index entries pointing to tuples listed in
+ * vacrelstats->dead_tuples, and update running statistics.
*/
static void
-lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
+lazy_vacuum_index(Relation indrel,
+ IndexBulkDeleteResult **stats,
+ LVRelStats *vacrelstats)
{
- IndexBulkDeleteResult *stats;
- IndexVacuumCleanupInfo vcinfo;
+ IndexVacuumInfo ivinfo;
PGRUsage ru0;
pg_rusage_init(&ru0);
else
LockRelation(indrel, AccessExclusiveLock);
- /*
- * Even though we're not planning to delete anything, we use the
- * ambulkdelete call, because (a) the scan happens within the index AM for
- * more speed, and (b) it may want to pass private statistics to the
- * amvacuumcleanup call.
- */
- stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
-
- /* Do post-VACUUM cleanup, even though we deleted nothing */
- vcinfo.vacuum_full = false;
- vcinfo.message_level = elevel;
- vcinfo.num_heap_tuples = vacrelstats->rel_tuples;
+ ivinfo.index = indrel;
+ ivinfo.vacuum_full = false;
+ ivinfo.message_level = elevel;
+ /* We don't yet know rel_tuples, so pass -1 */
+ ivinfo.num_heap_tuples = -1;
- stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
+ /* Do bulk deletion */
+ *stats = index_bulk_delete(&ivinfo, *stats,
+ lazy_tid_reaped, (void *) vacrelstats);
/*
* Release lock acquired above.
else
UnlockRelation(indrel, AccessExclusiveLock);
- if (!stats)
- return;
-
- /* now update statistics in pg_class */
- vac_update_relstats(RelationGetRelid(indrel),
- stats->num_pages,
- stats->num_index_tuples,
- false);
-
ereport(elevel,
- (errmsg("index \"%s\" now contains %.0f row versions in %u pages",
+ (errmsg("scanned index \"%s\" to remove %d row versions",
RelationGetRelationName(indrel),
- stats->num_index_tuples,
- stats->num_pages),
- errdetail("%u index pages have been deleted, %u are currently reusable.\n"
- "%s.",
- stats->pages_deleted, stats->pages_free,
- pg_rusage_show(&ru0))));
-
- pfree(stats);
+ vacrelstats->num_dead_tuples),
+ errdetail("%s.", pg_rusage_show(&ru0))));
}
/*
- * lazy_vacuum_index() -- vacuum one index relation.
- *
- * Delete all the index entries pointing to tuples listed in
- * vacrelstats->dead_tuples.
- *
- * Increment *index_tups_vacuumed by the number of index entries
- * removed, and *index_pages_removed by the number of pages removed.
- *
- * Finally, we arrange to update the index relation's statistics in
- * pg_class.
+ * lazy_cleanup_index() -- do post-vacuum cleanup for one index relation.
*/
static void
-lazy_vacuum_index(Relation indrel,
- double *index_tups_vacuumed,
- BlockNumber *index_pages_removed,
- LVRelStats *vacrelstats)
+lazy_cleanup_index(Relation indrel,
+ IndexBulkDeleteResult *stats,
+ LVRelStats *vacrelstats)
{
- IndexBulkDeleteResult *stats;
- IndexVacuumCleanupInfo vcinfo;
+ IndexVacuumInfo ivinfo;
PGRUsage ru0;
pg_rusage_init(&ru0);
else
LockRelation(indrel, AccessExclusiveLock);
- /* Do bulk deletion */
- stats = index_bulk_delete(indrel, lazy_tid_reaped, (void *) vacrelstats);
-
- /* Do post-VACUUM cleanup */
- vcinfo.vacuum_full = false;
- vcinfo.message_level = elevel;
- /* We don't yet know rel_tuples, so pass -1 */
- /* index_bulk_delete can't have skipped scan anyway ... */
- vcinfo.num_heap_tuples = -1;
+ ivinfo.index = indrel;
+ ivinfo.vacuum_full = false;
+ ivinfo.message_level = elevel;
+ ivinfo.num_heap_tuples = vacrelstats->rel_tuples;
- stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
+ stats = index_vacuum_cleanup(&ivinfo, stats);
/*
* Release lock acquired above.
if (!stats)
return;
- /* accumulate total removed over multiple index-cleaning cycles */
- *index_tups_vacuumed += stats->tuples_removed;
- *index_pages_removed += stats->pages_removed;
-
/* now update statistics in pg_class */
vac_update_relstats(RelationGetRelid(indrel),
stats->num_pages,
}
/*
- * Dummy version for lazy_scan_index.
- */
-static bool
-dummy_tid_reaped(ItemPointer itemptr, void *state)
-{
- return false;
-}
-
-/*
* Update the shared Free Space Map with the info we now have about
* free space in the relation, discarding any old info the map may have.
*/
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.58 2006/03/05 15:58:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.59 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * Struct for statistics returned by bulk-delete operation
+ * Struct for input arguments passed to ambulkdelete and amvacuumcleanup
*
- * This is now also passed to the index AM's vacuum-cleanup operation,
- * if it has one, which can modify the results as needed. Note that
- * an index AM could choose to have bulk-delete return a larger struct
- * of which this is just the first field; this provides a way for bulk-delete
- * to communicate additional private data to vacuum-cleanup.
+ * Note that num_heap_tuples will not be valid during ambulkdelete,
+ * only amvacuumcleanup.
+ */
+typedef struct IndexVacuumInfo
+{
+ Relation index; /* the index being vacuumed */
+ bool vacuum_full; /* VACUUM FULL (we have exclusive lock) */
+ int message_level; /* ereport level for progress messages */
+ double num_heap_tuples; /* tuples remaining in heap */
+} IndexVacuumInfo;
+
+/*
+ * Struct for statistics returned by ambulkdelete and amvacuumcleanup
+ *
+ * This struct is normally allocated by the first ambulkdelete call and then
+ * passed along through subsequent ones until amvacuumcleanup; however,
+ * amvacuumcleanup must be prepared to allocate it in the case where no
+ * ambulkdelete calls were made (because no tuples needed deletion).
+ * Note that an index AM could choose to return a larger struct
+ * of which this is just the first field; this provides a way for ambulkdelete
+ * to communicate additional private data to amvacuumcleanup.
*
* Note: pages_removed is the amount by which the index physically shrank,
* if any (ie the change in its total size on disk). pages_deleted and
typedef struct IndexBulkDeleteResult
{
BlockNumber num_pages; /* pages remaining in index */
- BlockNumber pages_removed; /* # removed by bulk-delete operation */
+ BlockNumber pages_removed; /* # removed during vacuum operation */
double num_index_tuples; /* tuples remaining */
- double tuples_removed; /* # removed by bulk-delete operation */
+ double tuples_removed; /* # removed during vacuum operation */
BlockNumber pages_deleted; /* # unused pages in index */
BlockNumber pages_free; /* # pages available for reuse */
} IndexBulkDeleteResult;
/* Typedef for callback function to determine if a tuple is bulk-deletable */
typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state);
-/* Struct for additional arguments passed to vacuum-cleanup operation */
-typedef struct IndexVacuumCleanupInfo
-{
- bool vacuum_full; /* VACUUM FULL (we have exclusive lock) */
- int message_level; /* ereport level for progress messages */
- double num_heap_tuples; /* tuples remaining in heap */
-} IndexVacuumCleanupInfo;
-
/* Struct for heap-or-index scans of system tables */
typedef struct SysScanDescData
{
ItemPointer tids, int32 max_tids,
int32 *returned_tids);
-extern IndexBulkDeleteResult *index_bulk_delete(Relation indexRelation,
+extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
+ IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback,
void *callback_state);
-extern IndexBulkDeleteResult *index_vacuum_cleanup(Relation indexRelation,
- IndexVacuumCleanupInfo *info,
+extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
uint16 procnum);
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.68 2006/03/31 23:32:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.69 2006/05/02 22:25:10 tgl Exp $
*
* NOTES
* modeled after Margo Seltzer's hash implementation for unix.
extern Datum hashmarkpos(PG_FUNCTION_ARGS);
extern Datum hashrestrpos(PG_FUNCTION_ARGS);
extern Datum hashbulkdelete(PG_FUNCTION_ARGS);
+extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS);
/*
* Datatype-specific hash functions in hashfunc.c.
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.330 2006/05/02 15:23:16 teodor Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.331 2006/05/02 22:25:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200605022
+#define CATALOG_VERSION_NO 200605023
#endif
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.41 2006/05/02 11:28:55 teodor Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.42 2006/05/02 22:25:10 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
bool amcanmulticol; /* does AM support multi-column indexes? */
bool amoptionalkey; /* can query omit key for the first column? */
bool amindexnulls; /* does AM support NULL index entries? */
+ bool amstorage; /* can storage type differ from column type? */
bool amconcurrent; /* does AM support concurrent updates? */
bool amclusterable; /* does AM support cluster command? */
regproc aminsert; /* "insert this tuple" function */
* compiler constants for pg_am
* ----------------
*/
-#define Natts_pg_am 22
+#define Natts_pg_am 23
#define Anum_pg_am_amname 1
#define Anum_pg_am_amstrategies 2
#define Anum_pg_am_amsupport 3
#define Anum_pg_am_amcanmulticol 6
#define Anum_pg_am_amoptionalkey 7
#define Anum_pg_am_amindexnulls 8
-#define Anum_pg_am_amconcurrent 9
-#define Anum_pg_am_amclusterable 10
-#define Anum_pg_am_aminsert 11
-#define Anum_pg_am_ambeginscan 12
-#define Anum_pg_am_amgettuple 13
-#define Anum_pg_am_amgetmulti 14
-#define Anum_pg_am_amrescan 15
-#define Anum_pg_am_amendscan 16
-#define Anum_pg_am_ammarkpos 17
-#define Anum_pg_am_amrestrpos 18
-#define Anum_pg_am_ambuild 19
-#define Anum_pg_am_ambulkdelete 20
-#define Anum_pg_am_amvacuumcleanup 21
-#define Anum_pg_am_amcostestimate 22
+#define Anum_pg_am_amstorage 9
+#define Anum_pg_am_amconcurrent 10
+#define Anum_pg_am_amclusterable 11
+#define Anum_pg_am_aminsert 12
+#define Anum_pg_am_ambeginscan 13
+#define Anum_pg_am_amgettuple 14
+#define Anum_pg_am_amgetmulti 15
+#define Anum_pg_am_amrescan 16
+#define Anum_pg_am_amendscan 17
+#define Anum_pg_am_ammarkpos 18
+#define Anum_pg_am_amrestrpos 19
+#define Anum_pg_am_ambuild 20
+#define Anum_pg_am_ambulkdelete 21
+#define Anum_pg_am_amvacuumcleanup 22
+#define Anum_pg_am_amcostestimate 23
/* ----------------
* initial contents of pg_am
* ----------------
*/
-DATA(insert OID = 403 ( btree 5 1 1 t t t t t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate ));
+DATA(insert OID = 403 ( btree 5 1 1 t t t t f t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
-DATA(insert OID = 405 ( hash 1 1 0 f f f f t f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete - hashcostestimate ));
+DATA(insert OID = 405 ( hash 1 1 0 f f f f f t f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate ));
DESCR("hash index access method");
#define HASH_AM_OID 405
-DATA(insert OID = 783 ( gist 100 7 0 f t f f t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate ));
+DATA(insert OID = 783 ( gist 100 7 0 f t f f t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
-DATA(insert OID = 2742 ( gin 100 4 0 f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ));
+DATA(insert OID = 2742 ( gin 100 4 0 f f f f t t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.409 2006/05/02 11:28:55 teodor Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.410 2006/05/02 22:25:10 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DESCR("btree(internal)");
DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 f f t f v 3 2278 "2281 2281 2281" _null_ _null_ _null_ btbuild - _null_ ));
DESCR("btree(internal)");
-DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ btbulkdelete - _null_ ));
+DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 f f t f v 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ btbulkdelete - _null_ ));
DESCR("btree(internal)");
-DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ btvacuumcleanup - _null_ ));
+DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 2281" _null_ _null_ _null_ btvacuumcleanup - _null_ ));
DESCR("btree(internal)");
DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 f f t f v 7 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ btcostestimate - _null_ ));
DESCR("btree(internal)");
DESCR("hash(internal)");
DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 f f t f v 3 2278 "2281 2281 2281" _null_ _null_ _null_ hashbuild - _null_ ));
DESCR("hash(internal)");
-DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ hashbulkdelete - _null_ ));
+DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 f f t f v 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ hashbulkdelete - _null_ ));
+DESCR("hash(internal)");
+DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 2281" _null_ _null_ _null_ hashvacuumcleanup - _null_ ));
DESCR("hash(internal)");
DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 f f t f v 7 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ hashcostestimate - _null_ ));
DESCR("hash(internal)");
DESCR("gist(internal)");
DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 f f t f v 3 2278 "2281 2281 2281" _null_ _null_ _null_ gistbuild - _null_ ));
DESCR("gist(internal)");
-DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ gistbulkdelete - _null_ ));
+DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 f f t f v 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ gistbulkdelete - _null_ ));
+DESCR("gist(internal)");
+DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 2281" _null_ _null_ _null_ gistvacuumcleanup - _null_ ));
DESCR("gist(internal)");
-DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ gistvacuumcleanup - _null_ ));
DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 f f t f v 7 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gistcostestimate - _null_ ));
DESCR("gist(internal)");
DESCR("gin(internal)");
DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 f f t f v 3 2278 "2281 2281 2281" _null_ _null_ _null_ ginbuild - _null_ ));
DESCR("gin(internal)");
-DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ ginbulkdelete - _null_ ));
+DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 f f t f v 4 2281 "2281 2281 2281 2281" _null_ _null_ _null_ ginbulkdelete - _null_ ));
DESCR("gin(internal)");
-DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 f f t f v 3 2281 "2281 2281 2281" _null_ _null_ _null_ ginvacuumcleanup - _null_ ));
+DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 2281" _null_ _null_ _null_ ginvacuumcleanup - _null_ ));
DESCR("gin(internal)");
DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 f f t f v 7 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gincostestimate - _null_ ));
DESCR("gin(internal)");