Commit e5734597 authored by Tom Lane's avatar Tom Lane

Clean up API for ambulkdelete/amvacuumcleanup as per today's discussion.

This formulation requires every AM to provide amvacuumcleanup, unlike before,
but it's surely a whole lot cleaner.  Also, add an 'amstorage' column to
pg_am so that we can get rid of hardwired knowledge in DefineOpClass().
parent d3171dd6
<!-- $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 Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
...@@ -394,6 +394,13 @@ ...@@ -394,6 +394,13 @@
<entry>Does the access method support null index entries?</entry> <entry>Does the access method support null index entries?</entry>
</row> </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> <row>
<entry><structfield>amconcurrent</structfield></entry> <entry><structfield>amconcurrent</structfield></entry>
<entry><type>bool</type></entry> <entry><type>bool</type></entry>
...@@ -401,6 +408,13 @@ ...@@ -401,6 +408,13 @@
<entry>Does the access method support concurrent updates?</entry> <entry>Does the access method support concurrent updates?</entry>
</row> </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> <row>
<entry><structfield>aminsert</structfield></entry> <entry><structfield>aminsert</structfield></entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></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"> <chapter id="indexam">
<title>Index Access Method Interface Definition</title> <title>Index Access Method Interface Definition</title>
...@@ -184,44 +184,52 @@ aminsert (Relation indexRelation, ...@@ -184,44 +184,52 @@ aminsert (Relation indexRelation,
<para> <para>
<programlisting> <programlisting>
IndexBulkDeleteResult * IndexBulkDeleteResult *
ambulkdelete (Relation indexRelation, ambulkdelete (IndexVacuumInfo *info,
IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback, IndexBulkDeleteCallback callback,
void *callback_state); void *callback_state);
</programlisting> </programlisting>
Delete tuple(s) from the index. This is a <quote>bulk delete</> operation 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 that is intended to be implemented by scanning the whole index and checking
each entry to see if it should be deleted. 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>, <literal>callback(<replaceable>TID</>, callback_state) returns bool</literal>,
to determine whether any particular index entry, as identified by its 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 referenced TID, is to be deleted. Must return either NULL or a palloc'd
struct containing statistics about the effects of the deletion operation. 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>
<para> <para>
If <literal>callback_state</> is NULL then no tuples are to be deleted. Because of limited <varname>maintenance_work_mem</>,
The index AM may choose to optimize this case (eg by not scanning the <function>ambulkdelete</> may need to be called more than once when many
index) but it is still expected to deliver accurate statistics. 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>
<para> <para>
<programlisting> <programlisting>
IndexBulkDeleteResult * IndexBulkDeleteResult *
amvacuumcleanup (Relation indexRelation, amvacuumcleanup (IndexVacuumInfo *info,
IndexVacuumCleanupInfo *info,
IndexBulkDeleteResult *stats); IndexBulkDeleteResult *stats);
</programlisting> </programlisting>
Clean up after a <command>VACUUM</command> operation (one or more Clean up after a <command>VACUUM</command> operation (zero or more
<function>ambulkdelete</> calls). An index access method does not have <function>ambulkdelete</> calls). This does not have to do anything
to provide this function (if so, the entry in <structname>pg_am</> must beyond returning index statistics, but it may perform bulk cleanup
be zero). If it is provided, it is typically used for bulk cleanup such as reclaiming empty index pages. <literal>stats</> is whatever the
such as reclaiming empty index pages. <literal>info</> last <function>ambulkdelete</> call returned, or NULL if
provides some additional arguments such as a message level for statistical <function>ambulkdelete</> was not called because no tuples needed to be
reports, and <literal>stats</> is whatever the last deleted. If the result is not NULL it must be a palloc'd struct.
<function>ambulkdelete</> call returned. <function>amvacuumcleanup</> The statistics it contains will be used to update <structname>pg_class</>,
may replace or modify this struct before returning it. If the result and will be reported by <command>VACUUM</> if <literal>VERBOSE</> is given.
is not NULL it must be a palloc'd struct. The statistics it contains It is OK to return NULL if the index was not changed at all during the
will be reported by <command>VACUUM</> if <literal>VERBOSE</> is given. <command>VACUUM</command> operation, but otherwise correct stats should
be returned.
</para> </para>
<para> <para>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -474,17 +474,25 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3 ...@@ -474,17 +474,25 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
Datum Datum
ginbulkdelete(PG_FUNCTION_ARGS) { ginbulkdelete(PG_FUNCTION_ARGS) {
Relation index = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
void *callback_state = (void *) PG_GETARG_POINTER(2); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation index = info->index;
BlockNumber blkno = GIN_ROOT_BLKNO; BlockNumber blkno = GIN_ROOT_BLKNO;
GinVacuumState gvs; GinVacuumState gvs;
Buffer buffer; Buffer buffer;
BlockNumber rootOfPostingTree[ BLCKSZ/ (sizeof(IndexTupleData)+sizeof(ItemId)) ]; BlockNumber rootOfPostingTree[ BLCKSZ/ (sizeof(IndexTupleData)+sizeof(ItemId)) ];
uint32 nRoot; 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.index = index;
gvs.result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); gvs.result = stats;
gvs.callback = callback; gvs.callback = callback;
gvs.callback_state = callback_state; gvs.callback_state = callback_state;
initGinState(&gvs.ginstate, index); initGinState(&gvs.ginstate, index);
...@@ -564,9 +572,9 @@ ginbulkdelete(PG_FUNCTION_ARGS) { ...@@ -564,9 +572,9 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
Datum Datum
ginvacuumcleanup(PG_FUNCTION_ARGS) { ginvacuumcleanup(PG_FUNCTION_ARGS) {
Relation index = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2); Relation index = info->index;
bool needLock = !RELATION_IS_LOCAL(index); bool needLock = !RELATION_IS_LOCAL(index);
BlockNumber npages, BlockNumber npages,
blkno; blkno;
...@@ -576,6 +584,15 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) { ...@@ -576,6 +584,15 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
BlockNumber lastBlock = GIN_ROOT_BLKNO, BlockNumber lastBlock = GIN_ROOT_BLKNO,
lastFilledBlock = 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) { if (info->vacuum_full) {
LockRelation(index, AccessExclusiveLock); LockRelation(index, AccessExclusiveLock);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -343,9 +343,9 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion) ...@@ -343,9 +343,9 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
Datum Datum
gistvacuumcleanup(PG_FUNCTION_ARGS) gistvacuumcleanup(PG_FUNCTION_ARGS)
{ {
Relation rel = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1); GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);
GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(2); Relation rel = info->index;
BlockNumber npages, BlockNumber npages,
blkno; blkno;
BlockNumber nFreePages, BlockNumber nFreePages,
...@@ -355,6 +355,19 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -355,6 +355,19 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
lastFilledBlock = GIST_ROOT_BLKNO; lastFilledBlock = GIST_ROOT_BLKNO;
bool needLock; 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 */ /* gistVacuumUpdate may cause hard work */
if (info->vacuum_full) if (info->vacuum_full)
{ {
...@@ -460,13 +473,6 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -460,13 +473,6 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
if (info->vacuum_full) if (info->vacuum_full)
UnlockRelation(rel, AccessExclusiveLock); 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); PG_RETURN_POINTER(stats);
} }
...@@ -509,36 +515,22 @@ pushStackIfSplited(Page page, GistBDItem *stack) ...@@ -509,36 +515,22 @@ pushStackIfSplited(Page page, GistBDItem *stack)
Datum Datum
gistbulkdelete(PG_FUNCTION_ARGS) gistbulkdelete(PG_FUNCTION_ARGS)
{ {
Relation rel = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1); GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);
void *callback_state = (void *) PG_GETARG_POINTER(2); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
GistBulkDeleteResult *result; void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
GistBDItem *stack, GistBDItem *stack,
*ptr; *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 = (GistBDItem *) palloc0(sizeof(GistBDItem));
stack->blkno = GIST_ROOT_BLKNO; stack->blkno = GIST_ROOT_BLKNO;
}
else
{
/* skip scan and set flag for gistvacuumcleanup */
stack = NULL;
result->std.num_index_tuples = -1;
}
while (stack) while (stack)
{ {
...@@ -601,11 +593,11 @@ gistbulkdelete(PG_FUNCTION_ARGS) ...@@ -601,11 +593,11 @@ gistbulkdelete(PG_FUNCTION_ARGS)
i--; i--;
maxoff--; maxoff--;
ntodelete++; ntodelete++;
result->std.tuples_removed += 1; stats->std.tuples_removed += 1;
Assert(maxoff == PageGetMaxOffsetNumber(page)); Assert(maxoff == PageGetMaxOffsetNumber(page));
} }
else else
result->std.num_index_tuples += 1; stats->std.num_index_tuples += 1;
} }
if (ntodelete) if (ntodelete)
...@@ -658,7 +650,7 @@ gistbulkdelete(PG_FUNCTION_ARGS) ...@@ -658,7 +650,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
stack->next = ptr; stack->next = ptr;
if (GistTupleIsInvalid(idxtuple)) if (GistTupleIsInvalid(idxtuple))
result->needFullVacuum = true; stats->needFullVacuum = true;
} }
} }
...@@ -671,13 +663,5 @@ gistbulkdelete(PG_FUNCTION_ARGS) ...@@ -671,13 +663,5 @@ gistbulkdelete(PG_FUNCTION_ARGS)
vacuum_delay_point(); vacuum_delay_point();
} }
needLock = !RELATION_IS_LOCAL(rel); PG_RETURN_POINTER(stats);
if (needLock)
LockRelationForExtension(rel, ExclusiveLock);
result->std.num_pages = RelationGetNumberOfBlocks(rel);
if (needLock)
UnlockRelationForExtension(rel, ExclusiveLock);
PG_RETURN_POINTER(result);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This file contains only the public interface routines. * This file contains only the public interface routines.
...@@ -478,11 +478,11 @@ hashrestrpos(PG_FUNCTION_ARGS) ...@@ -478,11 +478,11 @@ hashrestrpos(PG_FUNCTION_ARGS)
Datum Datum
hashbulkdelete(PG_FUNCTION_ARGS) hashbulkdelete(PG_FUNCTION_ARGS)
{ {
Relation rel = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
void *callback_state = (void *) PG_GETARG_POINTER(2); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
IndexBulkDeleteResult *result; void *callback_state = (void *) PG_GETARG_POINTER(3);
BlockNumber num_pages; Relation rel = info->index;
double tuples_removed; double tuples_removed;
double num_index_tuples; double num_index_tuples;
double orig_ntuples; double orig_ntuples;
...@@ -517,18 +517,6 @@ hashbulkdelete(PG_FUNCTION_ARGS) ...@@ -517,18 +517,6 @@ hashbulkdelete(PG_FUNCTION_ARGS)
cur_maxbucket = orig_maxbucket; cur_maxbucket = orig_maxbucket;
loop_top: 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) while (cur_bucket <= cur_maxbucket)
{ {
BlockNumber bucket_blkno; BlockNumber bucket_blkno;
...@@ -657,14 +645,37 @@ loop_top: ...@@ -657,14 +645,37 @@ loop_top:
_hash_wrtbuf(rel, metabuf); _hash_wrtbuf(rel, metabuf);
/* return statistics */ /* 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; * Post-VACUUM cleanup.
result->num_index_tuples = num_index_tuples; *
result->tuples_removed = tuples_removed; * 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);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
* index_open - open an index relation by relation OID * index_open - open an index relation by relation OID
...@@ -685,18 +685,16 @@ index_getmulti(IndexScanDesc scan, ...@@ -685,18 +685,16 @@ index_getmulti(IndexScanDesc scan,
* callback routine tells whether a given main-heap tuple is * callback routine tells whether a given main-heap tuple is
* to be deleted * 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 * return value is an optional palloc'd struct of statistics
* ---------------- * ----------------
*/ */
IndexBulkDeleteResult * IndexBulkDeleteResult *
index_bulk_delete(Relation indexRelation, index_bulk_delete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback, IndexBulkDeleteCallback callback,
void *callback_state) void *callback_state)
{ {
Relation indexRelation = info->index;
FmgrInfo *procedure; FmgrInfo *procedure;
IndexBulkDeleteResult *result; IndexBulkDeleteResult *result;
...@@ -704,8 +702,9 @@ index_bulk_delete(Relation indexRelation, ...@@ -704,8 +702,9 @@ index_bulk_delete(Relation indexRelation,
GET_REL_PROCEDURE(ambulkdelete); GET_REL_PROCEDURE(ambulkdelete);
result = (IndexBulkDeleteResult *) result = (IndexBulkDeleteResult *)
DatumGetPointer(FunctionCall3(procedure, DatumGetPointer(FunctionCall4(procedure,
PointerGetDatum(indexRelation), PointerGetDatum(info),
PointerGetDatum(stats),
PointerGetDatum((Pointer) callback), PointerGetDatum((Pointer) callback),
PointerGetDatum(callback_state))); PointerGetDatum(callback_state)));
...@@ -719,26 +718,20 @@ index_bulk_delete(Relation indexRelation, ...@@ -719,26 +718,20 @@ index_bulk_delete(Relation indexRelation,
* ---------------- * ----------------
*/ */
IndexBulkDeleteResult * IndexBulkDeleteResult *
index_vacuum_cleanup(Relation indexRelation, index_vacuum_cleanup(IndexVacuumInfo *info,
IndexVacuumCleanupInfo *info,
IndexBulkDeleteResult *stats) IndexBulkDeleteResult *stats)
{ {
Relation indexRelation = info->index;
FmgrInfo *procedure; FmgrInfo *procedure;
IndexBulkDeleteResult *result; IndexBulkDeleteResult *result;
RELATION_CHECKS; 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); GET_REL_PROCEDURE(amvacuumcleanup);
result = (IndexBulkDeleteResult *) result = (IndexBulkDeleteResult *)
DatumGetPointer(FunctionCall3(procedure, DatumGetPointer(FunctionCall2(procedure,
PointerGetDatum(indexRelation), PointerGetDatum(info),
PointerGetDatum((Pointer) info), PointerGetDatum(stats)));
PointerGetDatum((Pointer) stats)));
return result; return result;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -518,15 +518,15 @@ btrestrpos(PG_FUNCTION_ARGS) ...@@ -518,15 +518,15 @@ btrestrpos(PG_FUNCTION_ARGS)
Datum Datum
btbulkdelete(PG_FUNCTION_ARGS) btbulkdelete(PG_FUNCTION_ARGS)
{ {
Relation rel = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
void *callback_state = (void *) PG_GETARG_POINTER(2); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
IndexBulkDeleteResult *result; void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
double tuples_removed = 0; double tuples_removed = 0;
OffsetNumber deletable[MaxOffsetNumber]; OffsetNumber deletable[MaxOffsetNumber];
int ndeletable; int ndeletable;
Buffer buf; Buffer buf;
BlockNumber num_pages;
/* /*
* The outer loop iterates over index leaf pages, the inner over items on * The outer loop iterates over index leaf pages, the inner over items on
...@@ -543,14 +543,8 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -543,14 +543,8 @@ btbulkdelete(PG_FUNCTION_ARGS)
* further to its right, which the indexscan will have no pin on.) We can * 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 * skip obtaining exclusive lock on empty pages though, since no indexscan
* could be stopped on those. * 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); buf = _bt_get_endpoint(rel, 0, false);
else
buf = InvalidBuffer;
if (BufferIsValid(buf)) /* check for empty index */ if (BufferIsValid(buf)) /* check for empty index */
{ {
...@@ -626,14 +620,12 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -626,14 +620,12 @@ btbulkdelete(PG_FUNCTION_ARGS)
} }
/* return statistics */ /* return statistics */
num_pages = RelationGetNumberOfBlocks(rel); if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); stats->tuples_removed += tuples_removed;
result->num_pages = num_pages; /* btvacuumcleanup will fill in num_pages and num_index_tuples */
/* btvacuumcleanup will fill in num_index_tuples */
result->tuples_removed = tuples_removed;
PG_RETURN_POINTER(result); PG_RETURN_POINTER(stats);
} }
/* /*
...@@ -646,9 +638,9 @@ btbulkdelete(PG_FUNCTION_ARGS) ...@@ -646,9 +638,9 @@ btbulkdelete(PG_FUNCTION_ARGS)
Datum Datum
btvacuumcleanup(PG_FUNCTION_ARGS) btvacuumcleanup(PG_FUNCTION_ARGS)
{ {
Relation rel = (Relation) PG_GETARG_POINTER(0); IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2); Relation rel = info->index;
BlockNumber num_pages; BlockNumber num_pages;
BlockNumber blkno; BlockNumber blkno;
BlockNumber *freePages; BlockNumber *freePages;
...@@ -660,7 +652,9 @@ btvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -660,7 +652,9 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
MemoryContext oldcontext; MemoryContext oldcontext;
bool needLock; 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 * First find out the number of pages in the index. We must acquire the
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -339,6 +339,12 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck) ...@@ -339,6 +339,12 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck)
errmsg("cannot cluster on partial index \"%s\"", errmsg("cannot cluster on partial index \"%s\"",
RelationGetRelationName(OldIndex)))); 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) if (!OldIndex->rd_am->amindexnulls)
{ {
AttrNumber colno; AttrNumber colno;
...@@ -376,12 +382,6 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck) ...@@ -376,12 +382,6 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck)
RelationGetRelationName(OldIndex)))); 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 * Disallow clustering system relations. This will definitely NOT work
* for shared relations (we have no way to update pg_class rows in other * for shared relations (we have no way to update pg_class rows in other
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -77,11 +77,13 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -77,11 +77,13 @@ DefineOpClass(CreateOpClassStmt *stmt)
opclassoid; /* oid of opclass we create */ opclassoid; /* oid of opclass we create */
int numOperators, /* amstrategies value */ int numOperators, /* amstrategies value */
numProcs; /* amsupport value */ numProcs; /* amsupport value */
bool amstorage; /* amstorage flag */
List *operators; /* OpClassMember list for operators */ List *operators; /* OpClassMember list for operators */
List *procedures; /* OpClassMember list for support procs */ List *procedures; /* OpClassMember list for support procs */
ListCell *l; ListCell *l;
Relation rel; Relation rel;
HeapTuple tup; HeapTuple tup;
Form_pg_am pg_am;
Datum values[Natts_pg_opclass]; Datum values[Natts_pg_opclass];
char nulls[Natts_pg_opclass]; char nulls[Natts_pg_opclass];
AclResult aclresult; AclResult aclresult;
...@@ -111,8 +113,10 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -111,8 +113,10 @@ DefineOpClass(CreateOpClassStmt *stmt)
stmt->amname))); stmt->amname)));
amoid = HeapTupleGetOid(tup); amoid = HeapTupleGetOid(tup);
numOperators = ((Form_pg_am) GETSTRUCT(tup))->amstrategies; pg_am = (Form_pg_am) GETSTRUCT(tup);
numProcs = ((Form_pg_am) GETSTRUCT(tup))->amsupport; numOperators = pg_am->amstrategies;
numProcs = pg_am->amsupport;
amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */ /* XXX Should we make any privilege check against the AM? */
...@@ -270,20 +274,12 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -270,20 +274,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
/* Just drop the spec if same as column datatype */ /* Just drop the spec if same as column datatype */
if (storageoid == typeoid) if (storageoid == typeoid)
storageoid = InvalidOid; storageoid = InvalidOid;
else else if (!amstorage)
{
/*
* 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, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("storage type may not be different from data type for access method \"%s\"", errmsg("storage type may not be different from data type for access method \"%s\"",
stmt->amname))); stmt->amname)));
} }
}
rel = heap_open(OperatorClassRelationId, RowExclusiveLock); rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -230,7 +230,6 @@ static void vacuum_index(VacPageList vacpagelist, Relation indrel, ...@@ -230,7 +230,6 @@ static void vacuum_index(VacPageList vacpagelist, Relation indrel,
double num_tuples, int keep_tuples); double num_tuples, int keep_tuples);
static void scan_index(Relation indrel, double num_tuples); static void scan_index(Relation indrel, double num_tuples);
static bool tid_reaped(ItemPointer itemptr, void *state); 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, static void vac_update_fsm(Relation onerel, VacPageList fraged_pages,
BlockNumber rel_pages); BlockNumber rel_pages);
static VacPage copy_vac_page(VacPage vacpage); static VacPage copy_vac_page(VacPage vacpage);
...@@ -2933,7 +2932,7 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage) ...@@ -2933,7 +2932,7 @@ vacuum_page(Relation onerel, Buffer buffer, 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. * We use this when we have no deletions to do.
*/ */
...@@ -2941,25 +2940,17 @@ static void ...@@ -2941,25 +2940,17 @@ static void
scan_index(Relation indrel, double num_tuples) scan_index(Relation indrel, double num_tuples)
{ {
IndexBulkDeleteResult *stats; IndexBulkDeleteResult *stats;
IndexVacuumCleanupInfo vcinfo; IndexVacuumInfo ivinfo;
PGRUsage ru0; PGRUsage ru0;
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
/* ivinfo.index = indrel;
* Even though we're not planning to delete anything, we use the ivinfo.vacuum_full = true;
* ambulkdelete call, because (a) the scan happens within the index AM for ivinfo.message_level = elevel;
* more speed, and (b) it may want to pass private statistics to the ivinfo.num_heap_tuples = num_tuples;
* amvacuumcleanup call.
*/
stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
/* Do post-VACUUM cleanup, even though we deleted nothing */ stats = index_vacuum_cleanup(&ivinfo, NULL);
vcinfo.vacuum_full = true;
vcinfo.message_level = elevel;
vcinfo.num_heap_tuples = num_tuples;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
if (!stats) if (!stats)
return; return;
...@@ -2982,16 +2973,7 @@ scan_index(Relation indrel, double num_tuples) ...@@ -2982,16 +2973,7 @@ scan_index(Relation indrel, double num_tuples)
/* /*
* Check for tuple count mismatch. If the index is partial, then it's OK * 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. * 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)
{ {
if (stats->num_index_tuples > num_tuples || if (stats->num_index_tuples > num_tuples ||
...@@ -3023,20 +3005,21 @@ vacuum_index(VacPageList vacpagelist, Relation indrel, ...@@ -3023,20 +3005,21 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
double num_tuples, int keep_tuples) double num_tuples, int keep_tuples)
{ {
IndexBulkDeleteResult *stats; IndexBulkDeleteResult *stats;
IndexVacuumCleanupInfo vcinfo; IndexVacuumInfo ivinfo;
PGRUsage ru0; PGRUsage ru0;
pg_rusage_init(&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 */ /* 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 */ /* Do post-VACUUM cleanup */
vcinfo.vacuum_full = true; stats = index_vacuum_cleanup(&ivinfo, stats);
vcinfo.message_level = elevel;
vcinfo.num_heap_tuples = num_tuples + keep_tuples;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
if (!stats) if (!stats)
return; return;
...@@ -3061,16 +3044,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel, ...@@ -3061,16 +3044,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
/* /*
* Check for tuple count mismatch. If the index is partial, then it's OK * 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. * 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)
{ {
if (stats->num_index_tuples > num_tuples + keep_tuples || if (stats->num_index_tuples > num_tuples + keep_tuples ||
...@@ -3137,15 +3111,6 @@ tid_reaped(ItemPointer itemptr, void *state) ...@@ -3137,15 +3111,6 @@ tid_reaped(ItemPointer itemptr, void *state)
return true; return true;
} }
/*
* 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 * 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. * free space in the relation, discarding any old info the map may have.
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -96,10 +96,11 @@ static TransactionId FreezeLimit; ...@@ -96,10 +96,11 @@ static TransactionId FreezeLimit;
static void lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, static void lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
Relation *Irel, int nindexes); Relation *Irel, int nindexes);
static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats); 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, static void lazy_vacuum_index(Relation indrel,
double *index_tups_vacuumed, IndexBulkDeleteResult **stats,
BlockNumber *index_pages_removed, LVRelStats *vacrelstats);
static void lazy_cleanup_index(Relation indrel,
IndexBulkDeleteResult *stats,
LVRelStats *vacrelstats); LVRelStats *vacrelstats);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int tupindex, LVRelStats *vacrelstats); int tupindex, LVRelStats *vacrelstats);
...@@ -112,7 +113,6 @@ static void lazy_record_dead_tuple(LVRelStats *vacrelstats, ...@@ -112,7 +113,6 @@ static void lazy_record_dead_tuple(LVRelStats *vacrelstats,
static void lazy_record_free_space(LVRelStats *vacrelstats, static void lazy_record_free_space(LVRelStats *vacrelstats,
BlockNumber page, Size avail); BlockNumber page, Size avail);
static bool lazy_tid_reaped(ItemPointer itemptr, void *state); 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 void lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats);
static int vac_cmp_itemptr(const void *left, const void *right); static int vac_cmp_itemptr(const void *left, const void *right);
static int vac_cmp_page_spaces(const void *left, const void *right); static int vac_cmp_page_spaces(const void *left, const void *right);
...@@ -207,9 +207,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -207,9 +207,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
tups_vacuumed, tups_vacuumed,
nkeep, nkeep,
nunused; nunused;
double *index_tups_vacuumed; IndexBulkDeleteResult **indstats;
BlockNumber *index_pages_removed;
bool did_vacuum_index = false;
int i; int i;
PGRUsage ru0; PGRUsage ru0;
...@@ -224,15 +222,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -224,15 +222,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
empty_pages = 0; empty_pages = 0;
num_tuples = tups_vacuumed = nkeep = nunused = 0; num_tuples = tups_vacuumed = nkeep = nunused = 0;
/* indstats = (IndexBulkDeleteResult **)
* Because index vacuuming is done in multiple passes, we have to keep palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
* 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));
nblocks = RelationGetNumberOfBlocks(onerel); nblocks = RelationGetNumberOfBlocks(onerel);
vacrelstats->rel_pages = nblocks; vacrelstats->rel_pages = nblocks;
...@@ -263,10 +254,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -263,10 +254,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
/* Remove index entries */ /* Remove index entries */
for (i = 0; i < nindexes; i++) for (i = 0; i < nindexes; i++)
lazy_vacuum_index(Irel[i], lazy_vacuum_index(Irel[i],
&index_tups_vacuumed[i], &indstats[i],
&index_pages_removed[i],
vacrelstats); vacrelstats);
did_vacuum_index = true;
/* Remove tuples from heap */ /* Remove tuples from heap */
lazy_vacuum_heap(onerel, vacrelstats); lazy_vacuum_heap(onerel, vacrelstats);
/* Forget the now-vacuumed tuples, and press on */ /* Forget the now-vacuumed tuples, and press on */
...@@ -454,18 +443,15 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -454,18 +443,15 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
/* Remove index entries */ /* Remove index entries */
for (i = 0; i < nindexes; i++) for (i = 0; i < nindexes; i++)
lazy_vacuum_index(Irel[i], lazy_vacuum_index(Irel[i],
&index_tups_vacuumed[i], &indstats[i],
&index_pages_removed[i],
vacrelstats); vacrelstats);
/* Remove tuples from heap */ /* Remove tuples from heap */
lazy_vacuum_heap(onerel, vacrelstats); lazy_vacuum_heap(onerel, vacrelstats);
} }
else if (!did_vacuum_index)
{ /* Do post-vacuum cleanup and statistics update for each index */
/* Must do post-vacuum cleanup and statistics update anyway */
for (i = 0; i < nindexes; i++) for (i = 0; i < nindexes; i++)
lazy_scan_index(Irel[i], vacrelstats); lazy_cleanup_index(Irel[i], indstats[i], vacrelstats);
}
ereport(elevel, ereport(elevel,
(errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages", (errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
...@@ -591,15 +577,17 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, ...@@ -591,15 +577,17 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
} }
/* /*
* 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 static void
lazy_scan_index(Relation indrel, LVRelStats *vacrelstats) lazy_vacuum_index(Relation indrel,
IndexBulkDeleteResult **stats,
LVRelStats *vacrelstats)
{ {
IndexBulkDeleteResult *stats; IndexVacuumInfo ivinfo;
IndexVacuumCleanupInfo vcinfo;
PGRUsage ru0; PGRUsage ru0;
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
...@@ -613,20 +601,15 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats) ...@@ -613,20 +601,15 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
else else
LockRelation(indrel, AccessExclusiveLock); LockRelation(indrel, AccessExclusiveLock);
/* ivinfo.index = indrel;
* Even though we're not planning to delete anything, we use the ivinfo.vacuum_full = false;
* ambulkdelete call, because (a) the scan happens within the index AM for ivinfo.message_level = elevel;
* more speed, and (b) it may want to pass private statistics to the /* We don't yet know rel_tuples, so pass -1 */
* amvacuumcleanup call. ivinfo.num_heap_tuples = -1;
*/
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;
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. * Release lock acquired above.
...@@ -636,48 +619,22 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats) ...@@ -636,48 +619,22 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
else else
UnlockRelation(indrel, AccessExclusiveLock); 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, ereport(elevel,
(errmsg("index \"%s\" now contains %.0f row versions in %u pages", (errmsg("scanned index \"%s\" to remove %d row versions",
RelationGetRelationName(indrel), RelationGetRelationName(indrel),
stats->num_index_tuples, vacrelstats->num_dead_tuples),
stats->num_pages), errdetail("%s.", pg_rusage_show(&ru0))));
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);
} }
/* /*
* lazy_vacuum_index() -- vacuum one index relation. * lazy_cleanup_index() -- do post-vacuum cleanup for 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.
*/ */
static void static void
lazy_vacuum_index(Relation indrel, lazy_cleanup_index(Relation indrel,
double *index_tups_vacuumed, IndexBulkDeleteResult *stats,
BlockNumber *index_pages_removed,
LVRelStats *vacrelstats) LVRelStats *vacrelstats)
{ {
IndexBulkDeleteResult *stats; IndexVacuumInfo ivinfo;
IndexVacuumCleanupInfo vcinfo;
PGRUsage ru0; PGRUsage ru0;
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
...@@ -691,17 +648,12 @@ lazy_vacuum_index(Relation indrel, ...@@ -691,17 +648,12 @@ lazy_vacuum_index(Relation indrel,
else else
LockRelation(indrel, AccessExclusiveLock); LockRelation(indrel, AccessExclusiveLock);
/* Do bulk deletion */ ivinfo.index = indrel;
stats = index_bulk_delete(indrel, lazy_tid_reaped, (void *) vacrelstats); ivinfo.vacuum_full = false;
ivinfo.message_level = elevel;
/* Do post-VACUUM cleanup */ ivinfo.num_heap_tuples = vacrelstats->rel_tuples;
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;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats); stats = index_vacuum_cleanup(&ivinfo, stats);
/* /*
* Release lock acquired above. * Release lock acquired above.
...@@ -714,10 +666,6 @@ lazy_vacuum_index(Relation indrel, ...@@ -714,10 +666,6 @@ lazy_vacuum_index(Relation indrel,
if (!stats) if (!stats)
return; 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 */ /* now update statistics in pg_class */
vac_update_relstats(RelationGetRelid(indrel), vac_update_relstats(RelationGetRelid(indrel),
stats->num_pages, stats->num_pages,
...@@ -1134,15 +1082,6 @@ lazy_tid_reaped(ItemPointer itemptr, void *state) ...@@ -1134,15 +1082,6 @@ lazy_tid_reaped(ItemPointer itemptr, void *state)
return (res != NULL); return (res != NULL);
} }
/*
* 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 * 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. * free space in the relation, discarding any old info the map may have.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, 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.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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,13 +21,29 @@ ...@@ -21,13 +21,29 @@
/* /*
* 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, * Note that num_heap_tuples will not be valid during ambulkdelete,
* if it has one, which can modify the results as needed. Note that * only amvacuumcleanup.
* 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 typedef struct IndexVacuumInfo
* to communicate additional private data to vacuum-cleanup. {
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, * 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 * if any (ie the change in its total size on disk). pages_deleted and
...@@ -36,9 +52,9 @@ ...@@ -36,9 +52,9 @@
typedef struct IndexBulkDeleteResult typedef struct IndexBulkDeleteResult
{ {
BlockNumber num_pages; /* pages remaining in index */ 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 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_deleted; /* # unused pages in index */
BlockNumber pages_free; /* # pages available for reuse */ BlockNumber pages_free; /* # pages available for reuse */
} IndexBulkDeleteResult; } IndexBulkDeleteResult;
...@@ -46,14 +62,6 @@ typedef struct IndexBulkDeleteResult ...@@ -46,14 +62,6 @@ typedef struct IndexBulkDeleteResult
/* Typedef for callback function to determine if a tuple is bulk-deletable */ /* Typedef for callback function to determine if a tuple is bulk-deletable */
typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state); 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 */ /* Struct for heap-or-index scans of system tables */
typedef struct SysScanDescData typedef struct SysScanDescData
{ {
...@@ -98,11 +106,11 @@ extern bool index_getmulti(IndexScanDesc scan, ...@@ -98,11 +106,11 @@ extern bool index_getmulti(IndexScanDesc scan,
ItemPointer tids, int32 max_tids, ItemPointer tids, int32 max_tids,
int32 *returned_tids); int32 *returned_tids);
extern IndexBulkDeleteResult *index_bulk_delete(Relation indexRelation, extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback, IndexBulkDeleteCallback callback,
void *callback_state); void *callback_state);
extern IndexBulkDeleteResult *index_vacuum_cleanup(Relation indexRelation, extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info,
IndexVacuumCleanupInfo *info,
IndexBulkDeleteResult *stats); IndexBulkDeleteResult *stats);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum, extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
uint16 procnum); uint16 procnum);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, 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/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 * NOTES
* modeled after Margo Seltzer's hash implementation for unix. * modeled after Margo Seltzer's hash implementation for unix.
...@@ -233,6 +233,7 @@ extern Datum hashendscan(PG_FUNCTION_ARGS); ...@@ -233,6 +233,7 @@ extern Datum hashendscan(PG_FUNCTION_ARGS);
extern Datum hashmarkpos(PG_FUNCTION_ARGS); extern Datum hashmarkpos(PG_FUNCTION_ARGS);
extern Datum hashrestrpos(PG_FUNCTION_ARGS); extern Datum hashrestrpos(PG_FUNCTION_ARGS);
extern Datum hashbulkdelete(PG_FUNCTION_ARGS); extern Datum hashbulkdelete(PG_FUNCTION_ARGS);
extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS);
/* /*
* Datatype-specific hash functions in hashfunc.c. * Datatype-specific hash functions in hashfunc.c.
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, 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/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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200605022 #define CATALOG_VERSION_NO 200605023
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, 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/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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -50,6 +50,7 @@ CATALOG(pg_am,2601) ...@@ -50,6 +50,7 @@ CATALOG(pg_am,2601)
bool amcanmulticol; /* does AM support multi-column indexes? */ bool amcanmulticol; /* does AM support multi-column indexes? */
bool amoptionalkey; /* can query omit key for the first column? */ bool amoptionalkey; /* can query omit key for the first column? */
bool amindexnulls; /* does AM support NULL index entries? */ 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 amconcurrent; /* does AM support concurrent updates? */
bool amclusterable; /* does AM support cluster command? */ bool amclusterable; /* does AM support cluster command? */
regproc aminsert; /* "insert this tuple" function */ regproc aminsert; /* "insert this tuple" function */
...@@ -77,7 +78,7 @@ typedef FormData_pg_am *Form_pg_am; ...@@ -77,7 +78,7 @@ typedef FormData_pg_am *Form_pg_am;
* compiler constants for pg_am * 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_amname 1
#define Anum_pg_am_amstrategies 2 #define Anum_pg_am_amstrategies 2
#define Anum_pg_am_amsupport 3 #define Anum_pg_am_amsupport 3
...@@ -86,36 +87,37 @@ typedef FormData_pg_am *Form_pg_am; ...@@ -86,36 +87,37 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_amcanmulticol 6 #define Anum_pg_am_amcanmulticol 6
#define Anum_pg_am_amoptionalkey 7 #define Anum_pg_am_amoptionalkey 7
#define Anum_pg_am_amindexnulls 8 #define Anum_pg_am_amindexnulls 8
#define Anum_pg_am_amconcurrent 9 #define Anum_pg_am_amstorage 9
#define Anum_pg_am_amclusterable 10 #define Anum_pg_am_amconcurrent 10
#define Anum_pg_am_aminsert 11 #define Anum_pg_am_amclusterable 11
#define Anum_pg_am_ambeginscan 12 #define Anum_pg_am_aminsert 12
#define Anum_pg_am_amgettuple 13 #define Anum_pg_am_ambeginscan 13
#define Anum_pg_am_amgetmulti 14 #define Anum_pg_am_amgettuple 14
#define Anum_pg_am_amrescan 15 #define Anum_pg_am_amgetmulti 15
#define Anum_pg_am_amendscan 16 #define Anum_pg_am_amrescan 16
#define Anum_pg_am_ammarkpos 17 #define Anum_pg_am_amendscan 17
#define Anum_pg_am_amrestrpos 18 #define Anum_pg_am_ammarkpos 18
#define Anum_pg_am_ambuild 19 #define Anum_pg_am_amrestrpos 19
#define Anum_pg_am_ambulkdelete 20 #define Anum_pg_am_ambuild 20
#define Anum_pg_am_amvacuumcleanup 21 #define Anum_pg_am_ambulkdelete 21
#define Anum_pg_am_amcostestimate 22 #define Anum_pg_am_amvacuumcleanup 22
#define Anum_pg_am_amcostestimate 23
/* ---------------- /* ----------------
* initial contents of pg_am * 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"); DESCR("b-tree index access method");
#define BTREE_AM_OID 403 #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"); DESCR("hash index access method");
#define HASH_AM_OID 405 #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"); DESCR("GiST index access method");
#define GIST_AM_OID 783 #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"); DESCR("GIN index access method");
#define GIN_AM_OID 2742 #define GIN_AM_OID 2742
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, 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/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 * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -674,9 +674,9 @@ DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281" _ ...@@ -674,9 +674,9 @@ DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281" _
DESCR("btree(internal)"); 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_ )); 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)"); 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)"); 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)"); 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_ )); 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("btree(internal)");
...@@ -791,7 +791,9 @@ DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281" ...@@ -791,7 +791,9 @@ DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281"
DESCR("hash(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_ )); 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)"); 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)"); 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_ )); 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("hash(internal)");
...@@ -1055,9 +1057,10 @@ DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281" ...@@ -1055,9 +1057,10 @@ DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281"
DESCR("gist(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_ )); 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)"); 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)"); 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_ )); 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("gist(internal)");
...@@ -3832,9 +3835,9 @@ DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281" ...@@ -3832,9 +3835,9 @@ DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 f f t f v 1 2278 "2281"
DESCR("gin(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_ )); 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)"); 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)"); 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)"); 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_ )); 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)"); DESCR("gin(internal)");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment