1996-08-26 22:02:12 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* gist.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* interface routines for the postgres GiST index access method.
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
|
|
|
*
|
2004-12-31 23:04:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2001-05-30 21:53:40 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2005-06-14 13:45:14 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.119 2005/06/14 11:45:13 teodor Exp $
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1996-10-20 10:32:11 +02:00
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "access/genam.h"
|
2005-05-17 05:34:18 +02:00
|
|
|
#include "access/gist_private.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "access/gistscan.h"
|
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "catalog/index.h"
|
2004-02-10 04:42:45 +01:00
|
|
|
#include "commands/vacuum.h"
|
1999-09-18 21:08:25 +02:00
|
|
|
#include "miscadmin.h"
|
2005-05-17 02:59:30 +02:00
|
|
|
#include "utils/memutils.h"
|
1996-10-21 07:11:00 +02:00
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/* Working state for gistbuild and its callback */
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GISTSTATE giststate;
|
|
|
|
int numindexattrs;
|
|
|
|
double indtuples;
|
2005-05-17 02:59:30 +02:00
|
|
|
MemoryContext tmpCxt;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
} GISTBuildState;
|
|
|
|
|
|
|
|
|
1996-08-26 22:02:12 +02:00
|
|
|
/* non-export function prototypes */
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
static void gistbuildCallback(Relation index,
|
2001-10-25 07:50:21 +02:00
|
|
|
HeapTuple htup,
|
2005-03-21 02:24:04 +01:00
|
|
|
Datum *values,
|
|
|
|
bool *isnull,
|
2001-10-25 07:50:21 +02:00
|
|
|
bool tupleIsAlive,
|
|
|
|
void *state);
|
2001-03-22 05:01:46 +01:00
|
|
|
static void gistdoinsert(Relation r,
|
|
|
|
IndexTuple itup,
|
|
|
|
GISTSTATE *GISTstate);
|
2005-06-14 13:45:14 +02:00
|
|
|
static void gistfindleaf(GISTInsertState *state,
|
2001-03-22 05:01:46 +01:00
|
|
|
GISTSTATE *giststate);
|
2005-06-14 13:45:14 +02:00
|
|
|
|
|
|
|
|
|
|
|
typedef struct PageLayout {
|
|
|
|
gistxlogPage block;
|
|
|
|
OffsetNumber *list;
|
|
|
|
Buffer buffer; /* to write after all proceed */
|
|
|
|
|
|
|
|
struct PageLayout *next;
|
|
|
|
} PageLayout;
|
|
|
|
|
|
|
|
|
|
|
|
#define ROTATEDIST(d) do { \
|
|
|
|
PageLayout *tmp=(PageLayout*)palloc(sizeof(PageLayout)); \
|
|
|
|
memset(tmp,0,sizeof(PageLayout)); \
|
|
|
|
tmp->next = (d); \
|
|
|
|
(d)=tmp; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
static IndexTuple *gistSplit(Relation r,
|
|
|
|
Buffer buffer,
|
|
|
|
IndexTuple *itup,
|
|
|
|
int *len,
|
2005-06-14 13:45:14 +02:00
|
|
|
PageLayout **dist,
|
2005-03-21 02:24:04 +01:00
|
|
|
GISTSTATE *giststate);
|
2005-06-14 13:45:14 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
#undef GISTDEBUG
|
2001-05-30 21:53:40 +02:00
|
|
|
|
1999-07-19 04:06:15 +02:00
|
|
|
#ifdef GISTDEBUG
|
2001-01-12 01:12:58 +01:00
|
|
|
static void gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff);
|
1999-07-19 04:06:15 +02:00
|
|
|
#endif
|
1996-08-26 22:02:12 +02:00
|
|
|
|
|
|
|
/*
|
2005-05-17 02:59:30 +02:00
|
|
|
* Create and return a temporary memory context for use by GiST. We
|
|
|
|
* _always_ invoke user-provided methods in a temporary memory
|
|
|
|
* context, so that memory leaks in those functions cannot cause
|
|
|
|
* problems. Also, we use some additional temporary contexts in the
|
|
|
|
* GiST code itself, to avoid the need to do some awkward manual
|
|
|
|
* memory management.
|
|
|
|
*/
|
|
|
|
MemoryContext
|
|
|
|
createTempGistContext(void)
|
|
|
|
{
|
|
|
|
return AllocSetContextCreate(CurrentMemoryContext,
|
|
|
|
"GiST temporary context",
|
|
|
|
ALLOCSET_DEFAULT_MINSIZE,
|
|
|
|
ALLOCSET_DEFAULT_INITSIZE,
|
|
|
|
ALLOCSET_DEFAULT_MAXSIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routine to build an index. Basically calls insert over and over.
|
|
|
|
*
|
|
|
|
* XXX: it would be nice to implement some sort of bulk-loading
|
|
|
|
* algorithm, but it is not clear how to do that.
|
2001-05-07 02:43:27 +02:00
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
gistbuild(PG_FUNCTION_ARGS)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
|
|
|
Relation index = (Relation) PG_GETARG_POINTER(1);
|
|
|
|
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
double reltuples;
|
|
|
|
GISTBuildState buildstate;
|
|
|
|
Buffer buffer;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We expect to be called exactly once for any index relation. If
|
|
|
|
* that's not the case, big trouble's what we have.
|
|
|
|
*/
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
if (RelationGetNumberOfBlocks(index) != 0)
|
2003-07-21 22:29:40 +02:00
|
|
|
elog(ERROR, "index \"%s\" already contains data",
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
RelationGetRelationName(index));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
/* no locking is needed */
|
|
|
|
initGISTstate(&buildstate.giststate, index);
|
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/* initialize the root page */
|
|
|
|
buffer = ReadBuffer(index, P_NEW);
|
|
|
|
GISTInitBuffer(buffer, F_LEAF);
|
2005-06-14 13:45:14 +02:00
|
|
|
if ( !index->rd_istemp ) {
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData rdata;
|
|
|
|
Page page;
|
|
|
|
|
|
|
|
rdata.buffer = InvalidBuffer;
|
|
|
|
rdata.data = (char*)&(index->rd_node);
|
|
|
|
rdata.len = sizeof(RelFileNode);
|
|
|
|
rdata.next = NULL;
|
|
|
|
|
|
|
|
page = BufferGetPage(buffer);
|
|
|
|
|
|
|
|
START_CRIT_SECTION();
|
|
|
|
|
|
|
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX, &rdata);
|
|
|
|
PageSetLSN(page, recptr);
|
|
|
|
PageSetTLI(page, ThisTimeLineID);
|
|
|
|
|
|
|
|
END_CRIT_SECTION();
|
|
|
|
}
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
WriteBuffer(buffer);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
/* build the index */
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;
|
|
|
|
buildstate.indtuples = 0;
|
2005-05-17 02:59:30 +02:00
|
|
|
/*
|
|
|
|
* create a temporary memory context that is reset once for each
|
|
|
|
* tuple inserted into the index
|
|
|
|
*/
|
|
|
|
buildstate.tmpCxt = createTempGistContext();
|
2000-07-15 00:18:02 +02:00
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/* do the heap scan */
|
|
|
|
reltuples = IndexBuildHeapScan(heap, index, indexInfo,
|
2005-05-17 02:59:30 +02:00
|
|
|
gistbuildCallback, (void *) &buildstate);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* okay, all heap tuples are indexed */
|
2005-05-17 02:59:30 +02:00
|
|
|
MemoryContextDelete(buildstate.tmpCxt);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-05-11 08:24:55 +02:00
|
|
|
/* since we just counted the # of tuples, may as well update stats */
|
|
|
|
IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);
|
1996-08-26 22:02:12 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
freeGISTstate(&buildstate.giststate);
|
2005-05-17 02:59:30 +02:00
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
#ifdef GISTDEBUG
|
2005-05-17 02:59:30 +02:00
|
|
|
gist_dumptree(index, 0, GIST_ROOT_BLKNO, 0);
|
2001-01-12 01:12:58 +01:00
|
|
|
#endif
|
2000-06-14 07:24:50 +02:00
|
|
|
PG_RETURN_VOID();
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/*
|
|
|
|
* Per-tuple callback from IndexBuildHeapScan
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
gistbuildCallback(Relation index,
|
|
|
|
HeapTuple htup,
|
2005-03-21 02:24:04 +01:00
|
|
|
Datum *values,
|
|
|
|
bool *isnull,
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
bool tupleIsAlive,
|
|
|
|
void *state)
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
GISTBuildState *buildstate = (GISTBuildState *) state;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
IndexTuple itup;
|
|
|
|
GISTENTRY tmpcentry;
|
|
|
|
int i;
|
2005-05-17 02:59:30 +02:00
|
|
|
MemoryContext oldCxt;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
/* GiST cannot index tuples with leading NULLs */
|
2005-03-21 02:24:04 +01:00
|
|
|
if (isnull[0])
|
2001-10-25 07:50:21 +02:00
|
|
|
return;
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
oldCxt = MemoryContextSwitchTo(buildstate->tmpCxt);
|
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/* immediately compress keys to normalize */
|
|
|
|
for (i = 0; i < buildstate->numindexattrs; i++)
|
|
|
|
{
|
2005-03-21 02:24:04 +01:00
|
|
|
if (isnull[i])
|
|
|
|
values[i] = (Datum) 0;
|
2001-10-25 07:50:21 +02:00
|
|
|
else
|
|
|
|
{
|
2005-03-21 02:24:04 +01:00
|
|
|
gistcentryinit(&buildstate->giststate, i, &tmpcentry, values[i],
|
2004-01-07 19:56:30 +01:00
|
|
|
NULL, NULL, (OffsetNumber) 0,
|
2005-05-17 02:59:30 +02:00
|
|
|
-1 /* size is currently bogus */, TRUE, FALSE);
|
2005-03-21 02:24:04 +01:00
|
|
|
values[i] = tmpcentry.key;
|
2001-08-10 16:34:28 +02:00
|
|
|
}
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* form an index tuple and point it at the heap tuple */
|
2005-03-21 02:24:04 +01:00
|
|
|
itup = index_form_tuple(buildstate->giststate.tupdesc, values, isnull);
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
itup->t_tid = htup->t_self;
|
|
|
|
|
2001-08-10 16:34:28 +02:00
|
|
|
/*
|
|
|
|
* Since we already have the index relation locked, we call
|
2001-10-25 07:50:21 +02:00
|
|
|
* gistdoinsert directly. Normal access method calls dispatch through
|
|
|
|
* gistinsert, which locks the relation for write. This is the right
|
|
|
|
* thing to do if you're inserting single tups, but not when you're
|
|
|
|
* initializing the whole index at once.
|
2001-08-10 16:34:28 +02:00
|
|
|
*/
|
2005-03-21 02:24:04 +01:00
|
|
|
gistdoinsert(index, itup, &buildstate->giststate);
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
2001-08-10 16:34:28 +02:00
|
|
|
buildstate->indtuples += 1;
|
2005-05-17 02:59:30 +02:00
|
|
|
MemoryContextSwitchTo(oldCxt);
|
|
|
|
MemoryContextReset(buildstate->tmpCxt);
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
}
|
|
|
|
|
1996-08-26 22:02:12 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* gistinsert -- wrapper for GiST tuple insertion.
|
1996-08-26 22:02:12 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This is the public interface routine for tuple insertion in GiSTs.
|
|
|
|
* It doesn't do any work; just locks the relation and passes the buck.
|
1996-08-26 22:02:12 +02:00
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
gistinsert(PG_FUNCTION_ARGS)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
Relation r = (Relation) PG_GETARG_POINTER(0);
|
2005-03-21 02:24:04 +01:00
|
|
|
Datum *values = (Datum *) PG_GETARG_POINTER(1);
|
|
|
|
bool *isnull = (bool *) PG_GETARG_POINTER(2);
|
2001-03-22 05:01:46 +01:00
|
|
|
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
2000-06-13 09:35:40 +02:00
|
|
|
#ifdef NOT_USED
|
2001-03-22 05:01:46 +01:00
|
|
|
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
2002-05-24 20:57:57 +02:00
|
|
|
bool checkUnique = PG_GETARG_BOOL(5);
|
2000-06-13 09:35:40 +02:00
|
|
|
#endif
|
1997-09-08 04:41:22 +02:00
|
|
|
IndexTuple itup;
|
|
|
|
GISTSTATE giststate;
|
|
|
|
GISTENTRY tmpentry;
|
|
|
|
int i;
|
2005-05-17 02:59:30 +02:00
|
|
|
MemoryContext oldCxt;
|
|
|
|
MemoryContext insertCxt;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since GIST is not marked "amconcurrent" in pg_am, caller should
|
2001-10-25 07:50:21 +02:00
|
|
|
* have acquired exclusive lock on index relation. We need no locking
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* here.
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
/* GiST cannot index tuples with leading NULLs */
|
2005-03-21 02:24:04 +01:00
|
|
|
if (isnull[0])
|
|
|
|
PG_RETURN_BOOL(false);
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
insertCxt = createTempGistContext();
|
|
|
|
oldCxt = MemoryContextSwitchTo(insertCxt);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
initGISTstate(&giststate, r);
|
|
|
|
|
|
|
|
/* immediately compress keys to normalize */
|
|
|
|
for (i = 0; i < r->rd_att->natts; i++)
|
|
|
|
{
|
2005-03-21 02:24:04 +01:00
|
|
|
if (isnull[i])
|
|
|
|
values[i] = (Datum) 0;
|
2001-10-25 07:50:21 +02:00
|
|
|
else
|
|
|
|
{
|
2005-03-21 02:24:04 +01:00
|
|
|
gistcentryinit(&giststate, i, &tmpentry, values[i],
|
2004-01-07 19:56:30 +01:00
|
|
|
NULL, NULL, (OffsetNumber) 0,
|
2005-05-17 02:59:30 +02:00
|
|
|
-1 /* size is currently bogus */, TRUE, FALSE);
|
2005-03-21 02:24:04 +01:00
|
|
|
values[i] = tmpentry.key;
|
2001-08-10 16:34:28 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2005-03-21 02:24:04 +01:00
|
|
|
itup = index_form_tuple(giststate.tupdesc, values, isnull);
|
1997-09-07 07:04:48 +02:00
|
|
|
itup->t_tid = *ht_ctid;
|
|
|
|
|
2005-03-21 02:24:04 +01:00
|
|
|
gistdoinsert(r, itup, &giststate);
|
1998-12-15 13:47:01 +01:00
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
/* cleanup */
|
2001-10-25 07:50:21 +02:00
|
|
|
freeGISTstate(&giststate);
|
2005-05-17 02:59:30 +02:00
|
|
|
MemoryContextSwitchTo(oldCxt);
|
|
|
|
MemoryContextDelete(insertCxt);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-03-21 02:24:04 +01:00
|
|
|
PG_RETURN_BOOL(true);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
/*
|
|
|
|
* Workhouse routine for doing insertion into a GiST index. Note that
|
|
|
|
* this routine assumes it is invoked in a short-lived memory context,
|
|
|
|
* so it does not bother releasing palloc'd allocations.
|
|
|
|
*/
|
2001-03-22 05:01:46 +01:00
|
|
|
static void
|
2005-05-17 02:59:30 +02:00
|
|
|
gistdoinsert(Relation r, IndexTuple itup, GISTSTATE *giststate)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
GISTInsertState state;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
memset(&state, 0, sizeof(GISTInsertState));
|
2001-01-12 01:12:58 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
state.itup = (IndexTuple *) palloc(sizeof(IndexTuple));
|
|
|
|
state.itup[0] = (IndexTuple) palloc(IndexTupleSize(itup));
|
|
|
|
memcpy(state.itup[0], itup, IndexTupleSize(itup));
|
|
|
|
state.ituplen=1;
|
|
|
|
state.r = r;
|
|
|
|
state.key = itup->t_tid;
|
|
|
|
state.needInsertComplete = true;
|
|
|
|
state.xlog_mode = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
state.stack = (GISTInsertStack*)palloc(sizeof(GISTInsertStack));
|
|
|
|
memset( state.stack, 0, sizeof(GISTInsertStack));
|
|
|
|
state.stack->blkno=GIST_ROOT_BLKNO;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
gistfindleaf(&state, giststate);
|
|
|
|
gistmakedeal(&state, giststate);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
static bool
|
|
|
|
gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|
|
|
bool is_splitted = false;
|
|
|
|
|
|
|
|
if (gistnospace(state->stack->page, state->itup, state->ituplen))
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
/* no space for insertion */
|
|
|
|
IndexTuple *itvec,
|
|
|
|
*newitup;
|
|
|
|
int tlen,olen;
|
|
|
|
PageLayout *dist=NULL, *ptr;
|
|
|
|
|
|
|
|
memset(&dist, 0, sizeof(PageLayout));
|
|
|
|
is_splitted = true;
|
|
|
|
itvec = gistextractbuffer(state->stack->buffer, &tlen);
|
|
|
|
olen=tlen;
|
|
|
|
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
|
|
|
|
newitup = gistSplit(state->r, state->stack->buffer, itvec, &tlen, &dist, giststate);
|
|
|
|
|
|
|
|
if ( !state->r->rd_istemp && !state->xlog_mode) {
|
|
|
|
gistxlogPageSplit xlrec;
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData *rdata;
|
|
|
|
int i, npage = 0, cur=1;
|
|
|
|
|
|
|
|
ptr=dist;
|
|
|
|
while( ptr ) {
|
|
|
|
npage++;
|
|
|
|
ptr=ptr->next;
|
|
|
|
}
|
2001-01-12 01:12:58 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
rdata = (XLogRecData*)palloc(sizeof(XLogRecData)*(npage*2 + state->ituplen + 2));
|
|
|
|
|
|
|
|
xlrec.node = state->r->rd_node;
|
|
|
|
xlrec.origblkno = state->stack->blkno;
|
|
|
|
xlrec.npage = npage;
|
|
|
|
xlrec.nitup = state->ituplen;
|
|
|
|
xlrec.todeleteoffnum = ( state->stack->todelete ) ? state->stack->childoffnum : InvalidOffsetNumber;
|
|
|
|
xlrec.key = state->key;
|
|
|
|
xlrec.pathlen = (uint16)state->pathlen;
|
|
|
|
|
|
|
|
rdata[0].buffer = InvalidBuffer;
|
|
|
|
rdata[0].data = (char *) &xlrec;
|
|
|
|
rdata[0].len = sizeof( gistxlogPageSplit );
|
|
|
|
rdata[0].next = NULL;
|
|
|
|
|
|
|
|
if ( state->pathlen>=0 ) {
|
|
|
|
rdata[0].next = &(rdata[1]);
|
|
|
|
rdata[1].buffer = InvalidBuffer;
|
|
|
|
rdata[1].data = (char *) (state->path);
|
|
|
|
rdata[1].len = sizeof( BlockNumber ) * state->pathlen;
|
|
|
|
rdata[1].next = NULL;
|
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* new tuples */
|
|
|
|
for(i=0;i<state->ituplen;i++) {
|
|
|
|
rdata[cur].buffer = InvalidBuffer;
|
|
|
|
rdata[cur].data = (char*)(state->itup[i]);
|
|
|
|
rdata[cur].len = IndexTupleSize(state->itup[i]);
|
|
|
|
rdata[cur-1].next = &(rdata[cur]);
|
|
|
|
cur++;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* new page layout */
|
|
|
|
ptr=dist;
|
|
|
|
while(ptr) {
|
|
|
|
rdata[cur].buffer = InvalidBuffer;
|
|
|
|
rdata[cur].data = (char*)&(ptr->block);
|
|
|
|
rdata[cur].len = sizeof(gistxlogPage);
|
|
|
|
rdata[cur-1].next = &(rdata[cur]);
|
|
|
|
cur++;
|
|
|
|
|
|
|
|
rdata[cur].buffer = InvalidBuffer;
|
|
|
|
rdata[cur].data = (char*)(ptr->list);
|
|
|
|
rdata[cur].len = MAXALIGN(sizeof(OffsetNumber)*ptr->block.num);
|
|
|
|
if ( rdata[cur].len > sizeof(OffsetNumber)*ptr->block.num )
|
|
|
|
rdata[cur].data = repalloc( rdata[cur].data, rdata[cur].len );
|
|
|
|
rdata[cur-1].next = &(rdata[cur]);
|
|
|
|
rdata[cur].next=NULL;
|
|
|
|
cur++;
|
|
|
|
|
|
|
|
ptr=ptr->next;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
START_CRIT_SECTION();
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
|
|
|
|
ptr = dist;
|
|
|
|
while(ptr) {
|
|
|
|
PageSetLSN(BufferGetPage(ptr->buffer), recptr);
|
|
|
|
PageSetTLI(BufferGetPage(ptr->buffer), ThisTimeLineID);
|
|
|
|
ptr=ptr->next;
|
2001-01-12 01:12:58 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
END_CRIT_SECTION();
|
2001-01-12 01:12:58 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
ptr = dist;
|
|
|
|
while(ptr) {
|
|
|
|
WriteBuffer(ptr->buffer);
|
|
|
|
ptr=ptr->next;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
state->itup = newitup;
|
|
|
|
state->ituplen = tlen; /* now tlen >= 2 */
|
2001-01-12 01:12:58 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
if ( state->stack->blkno == GIST_ROOT_BLKNO ) {
|
|
|
|
gistnewroot(state->r, state->itup, state->ituplen, &(state->key), state->xlog_mode);
|
|
|
|
state->needInsertComplete=false;
|
|
|
|
}
|
|
|
|
if ( state->xlog_mode )
|
|
|
|
LockBuffer(state->stack->buffer, BUFFER_LOCK_UNLOCK);
|
|
|
|
ReleaseBuffer(state->stack->buffer);
|
2001-03-22 05:01:46 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-05-15 06:08:29 +02:00
|
|
|
/* enough space */
|
2005-06-14 13:45:14 +02:00
|
|
|
OffsetNumber off, l;
|
2001-01-12 01:12:58 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
off = (PageIsEmpty(state->stack->page)) ?
|
2001-03-22 05:01:46 +01:00
|
|
|
FirstOffsetNumber
|
2001-01-12 01:12:58 +01:00
|
|
|
:
|
2005-06-14 13:45:14 +02:00
|
|
|
OffsetNumberNext(PageGetMaxOffsetNumber(state->stack->page));
|
|
|
|
l = gistfillbuffer(state->r, state->stack->page, state->itup, state->ituplen, off);
|
|
|
|
if ( !state->r->rd_istemp && !state->xlog_mode) {
|
|
|
|
gistxlogEntryUpdate xlrec;
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData *rdata = (XLogRecData*)palloc( sizeof(XLogRecData) * ( state->ituplen + 2 ) );
|
|
|
|
int i, cur=0;
|
|
|
|
|
|
|
|
xlrec.node = state->r->rd_node;
|
|
|
|
xlrec.blkno = state->stack->blkno;
|
|
|
|
xlrec.todeleteoffnum = ( state->stack->todelete ) ? state->stack->childoffnum : InvalidOffsetNumber;
|
|
|
|
xlrec.key = state->key;
|
|
|
|
xlrec.pathlen = (uint16)state->pathlen;
|
|
|
|
|
|
|
|
rdata[0].buffer = InvalidBuffer;
|
|
|
|
rdata[0].data = (char *) &xlrec;
|
|
|
|
rdata[0].len = sizeof( gistxlogEntryUpdate );
|
|
|
|
rdata[0].next = NULL;
|
|
|
|
|
|
|
|
if ( state->pathlen>=0 ) {
|
|
|
|
rdata[0].next = &(rdata[1]);
|
|
|
|
rdata[1].buffer = InvalidBuffer;
|
|
|
|
rdata[1].data = (char *) (state->path);
|
|
|
|
rdata[1].len = sizeof( BlockNumber ) * state->pathlen;
|
|
|
|
rdata[1].next = NULL;
|
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=1; i<=state->ituplen; i++) { /* adding tuples */
|
|
|
|
rdata[i+cur].buffer = InvalidBuffer;
|
|
|
|
rdata[i+cur].data = (char*)(state->itup[i-1]);
|
|
|
|
rdata[i+cur].len = IndexTupleSize(state->itup[i-1]);
|
|
|
|
rdata[i+cur].next = NULL;
|
|
|
|
rdata[i-1+cur].next = &(rdata[i+cur]);
|
|
|
|
}
|
|
|
|
|
|
|
|
START_CRIT_SECTION();
|
|
|
|
|
|
|
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_ENTRY_UPDATE, rdata);
|
|
|
|
PageSetLSN(state->stack->page, recptr);
|
|
|
|
PageSetTLI(state->stack->page, ThisTimeLineID);
|
|
|
|
|
|
|
|
END_CRIT_SECTION();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( state->stack->blkno == GIST_ROOT_BLKNO )
|
|
|
|
state->needInsertComplete=false;
|
1996-08-26 22:02:12 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
if ( state->xlog_mode )
|
|
|
|
LockBuffer(state->stack->buffer, BUFFER_LOCK_UNLOCK);
|
|
|
|
WriteBuffer(state->stack->buffer);
|
|
|
|
|
|
|
|
if (state->ituplen > 1)
|
|
|
|
{ /* previous is_splitted==true */
|
2001-03-22 05:01:46 +01:00
|
|
|
/*
|
|
|
|
* child was splited, so we must form union for insertion in
|
|
|
|
* parent
|
|
|
|
*/
|
2005-06-14 13:45:14 +02:00
|
|
|
IndexTuple newtup = gistunion(state->r, state->itup, state->ituplen, giststate);
|
|
|
|
ItemPointerSet(&(newtup->t_tid), state->stack->blkno, FirstOffsetNumber);
|
|
|
|
state->itup[0] = newtup;
|
|
|
|
state->ituplen = 1;
|
2001-01-12 01:12:58 +01:00
|
|
|
}
|
|
|
|
}
|
2005-06-14 13:45:14 +02:00
|
|
|
return is_splitted;
|
2001-01-12 01:12:58 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
static void
|
|
|
|
gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
ItemId iid;
|
|
|
|
IndexTuple oldtup;
|
|
|
|
GISTInsertStack *ptr;
|
2005-05-17 02:59:30 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* walk down */
|
|
|
|
while( true ) {
|
|
|
|
GISTPageOpaque opaque;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
state->stack->buffer = ReadBuffer(state->r, state->stack->blkno);
|
|
|
|
state->stack->page = (Page) BufferGetPage(state->stack->buffer);
|
|
|
|
opaque = (GISTPageOpaque) PageGetSpecialPointer(state->stack->page);
|
|
|
|
|
|
|
|
if (!(opaque->flags & F_LEAF))
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
/*
|
|
|
|
* This is an internal page, so continue to walk down the
|
|
|
|
* tree. We find the child node that has the minimum insertion
|
|
|
|
* penalty and recursively invoke ourselves to modify that
|
|
|
|
* node. Once the recursive call returns, we may need to
|
|
|
|
* adjust the parent node for two reasons: the child node
|
|
|
|
* split, or the key in this node needs to be adjusted for the
|
|
|
|
* newly inserted key below us.
|
|
|
|
*/
|
|
|
|
GISTInsertStack *item=(GISTInsertStack*)palloc(sizeof(GISTInsertStack));
|
|
|
|
|
|
|
|
state->stack->childoffnum = gistchoose(state->r, state->stack->page, state->itup[0], giststate);
|
|
|
|
|
|
|
|
iid = PageGetItemId(state->stack->page, state->stack->childoffnum);
|
|
|
|
oldtup = (IndexTuple) PageGetItem(state->stack->page, iid);
|
|
|
|
item->blkno = ItemPointerGetBlockNumber(&(oldtup->t_tid));
|
|
|
|
item->parent = state->stack;
|
|
|
|
item->todelete = false;
|
|
|
|
state->stack = item;
|
|
|
|
} else
|
|
|
|
break;
|
2001-05-31 20:16:55 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* now state->stack->(page, buffer and blkno) points to leaf page, so insert */
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* form state->path to work xlog */
|
|
|
|
ptr = state->stack;
|
|
|
|
state->pathlen=1;
|
|
|
|
while( ptr ) {
|
|
|
|
state->pathlen++;
|
|
|
|
ptr=ptr->parent;
|
2001-10-25 07:50:21 +02:00
|
|
|
}
|
2005-06-14 13:45:14 +02:00
|
|
|
state->path=(BlockNumber*)palloc(sizeof(BlockNumber)*state->pathlen);
|
|
|
|
ptr = state->stack;
|
|
|
|
state->pathlen=0;
|
|
|
|
while( ptr ) {
|
|
|
|
state->path[ state->pathlen ] = ptr->blkno;
|
|
|
|
state->pathlen++;
|
|
|
|
ptr=ptr->parent;
|
2001-01-12 01:12:58 +01:00
|
|
|
}
|
2005-06-14 13:45:14 +02:00
|
|
|
state->pathlen--;
|
|
|
|
state->path++;
|
2001-05-31 20:16:55 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
void
|
|
|
|
gistmakedeal(GISTInsertState *state, GISTSTATE *giststate) {
|
|
|
|
int is_splitted;
|
|
|
|
ItemId iid;
|
|
|
|
IndexTuple oldtup, newtup;
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* walk up */
|
|
|
|
while( true ) {
|
|
|
|
/*
|
|
|
|
* After this call: 1. if child page was splited, then itup
|
|
|
|
* contains keys for each page 2. if child page wasn't splited,
|
|
|
|
* then itup contains additional for adjustment of current key
|
|
|
|
*/
|
1996-08-26 22:02:12 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
is_splitted = gistplacetopage(state, giststate );
|
2001-01-12 01:12:58 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* pop page from stack */
|
|
|
|
state->stack = state->stack->parent;
|
|
|
|
state->pathlen--;
|
|
|
|
state->path++;
|
|
|
|
|
|
|
|
/* stack is void */
|
|
|
|
if ( ! state->stack )
|
|
|
|
break;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* child did not split */
|
|
|
|
if (!is_splitted)
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
/* parent's tuple */
|
|
|
|
iid = PageGetItemId(state->stack->page, state->stack->childoffnum);
|
|
|
|
oldtup = (IndexTuple) PageGetItem(state->stack->page, iid);
|
|
|
|
newtup = gistgetadjusted(state->r, oldtup, state->itup[0], giststate);
|
|
|
|
|
|
|
|
if (!newtup) /* not need to update key */
|
|
|
|
break;
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
state->itup[0] = newtup;
|
2001-10-25 07:50:21 +02:00
|
|
|
}
|
2005-06-14 13:45:14 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This node's key has been modified, either because a child
|
|
|
|
* split occurred or because we needed to adjust our key for
|
|
|
|
* an insert in a child node. Therefore, remove the old
|
|
|
|
* version of this node's key.
|
|
|
|
*/
|
|
|
|
gistadjscans(state->r, GISTOP_DEL, state->stack->blkno, state->stack->childoffnum);
|
|
|
|
PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);
|
|
|
|
if ( !state->r->rd_istemp )
|
|
|
|
state->stack->todelete = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if child was splitted, new key for child will be inserted in
|
|
|
|
* the end list of child, so we must say to any scans that page is
|
|
|
|
* changed beginning from 'child' offset
|
|
|
|
*/
|
|
|
|
if (is_splitted)
|
|
|
|
gistadjscans(state->r, GISTOP_SPLIT, state->stack->blkno, state->stack->childoffnum);
|
|
|
|
} /* while */
|
|
|
|
|
|
|
|
/* release all buffers */
|
|
|
|
while( state->stack ) {
|
|
|
|
if ( state->xlog_mode )
|
|
|
|
LockBuffer(state->stack->buffer, BUFFER_LOCK_UNLOCK);
|
|
|
|
ReleaseBuffer(state->stack->buffer);
|
|
|
|
state->stack = state->stack->parent;
|
2005-05-17 02:59:30 +02:00
|
|
|
}
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* say to xlog that insert is completed */
|
|
|
|
if ( !state->xlog_mode && state->needInsertComplete && !state->r->rd_istemp ) {
|
|
|
|
gistxlogInsertComplete xlrec;
|
|
|
|
XLogRecData rdata;
|
|
|
|
|
|
|
|
xlrec.node = state->r->rd_node;
|
|
|
|
xlrec.key = state->key;
|
|
|
|
|
|
|
|
rdata.buffer = InvalidBuffer;
|
|
|
|
rdata.data = (char *) &xlrec;
|
|
|
|
rdata.len = sizeof( gistxlogInsertComplete );
|
|
|
|
rdata.next = NULL;
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
START_CRIT_SECTION();
|
2005-05-17 02:59:30 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
XLogInsert(RM_GIST_ID, XLOG_GIST_INSERT_COMPLETE, &rdata);
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
END_CRIT_SECTION();
|
2001-08-10 16:34:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-08-26 22:02:12 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* gistSplit -- split a page in the tree.
|
1996-08-26 22:02:12 +02:00
|
|
|
*/
|
2001-01-12 01:12:58 +01:00
|
|
|
static IndexTuple *
|
1996-08-26 22:02:12 +02:00
|
|
|
gistSplit(Relation r,
|
1997-09-07 07:04:48 +02:00
|
|
|
Buffer buffer,
|
2001-01-12 01:12:58 +01:00
|
|
|
IndexTuple *itup, /* contains compressed entry */
|
|
|
|
int *len,
|
2005-06-14 13:45:14 +02:00
|
|
|
PageLayout **dist,
|
2005-03-21 02:24:04 +01:00
|
|
|
GISTSTATE *giststate)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Page p;
|
2001-03-22 05:01:46 +01:00
|
|
|
Buffer leftbuf,
|
|
|
|
rightbuf;
|
|
|
|
Page left,
|
|
|
|
right;
|
|
|
|
IndexTuple *lvectup,
|
|
|
|
*rvectup,
|
|
|
|
*newtup;
|
|
|
|
BlockNumber lbknum,
|
|
|
|
rbknum;
|
1997-09-08 04:41:22 +02:00
|
|
|
GISTPageOpaque opaque;
|
|
|
|
GIST_SPLITVEC v;
|
2004-08-29 07:07:03 +02:00
|
|
|
GistEntryVector *entryvec;
|
2001-10-25 07:50:21 +02:00
|
|
|
int i,
|
2001-03-22 05:01:46 +01:00
|
|
|
nlen;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
p = (Page) BufferGetPage(buffer);
|
|
|
|
opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The root of the tree is the first block in the relation. If we're
|
|
|
|
* about to split the root, we need to do some hocus-pocus to enforce
|
|
|
|
* this guarantee.
|
|
|
|
*/
|
2005-05-17 02:59:30 +02:00
|
|
|
if (BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
leftbuf = ReadBuffer(r, P_NEW);
|
|
|
|
GISTInitBuffer(leftbuf, opaque->flags);
|
|
|
|
lbknum = BufferGetBlockNumber(leftbuf);
|
|
|
|
left = (Page) BufferGetPage(leftbuf);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
leftbuf = buffer;
|
|
|
|
IncrBufferRefCount(buffer);
|
|
|
|
lbknum = BufferGetBlockNumber(buffer);
|
|
|
|
left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData));
|
|
|
|
}
|
|
|
|
|
|
|
|
rightbuf = ReadBuffer(r, P_NEW);
|
|
|
|
GISTInitBuffer(rightbuf, opaque->flags);
|
|
|
|
rbknum = BufferGetBlockNumber(rightbuf);
|
|
|
|
right = (Page) BufferGetPage(rightbuf);
|
|
|
|
|
|
|
|
/* generate the item array */
|
2004-03-30 17:45:33 +02:00
|
|
|
entryvec = palloc(GEVHDRSZ + (*len + 1) * sizeof(GISTENTRY));
|
|
|
|
entryvec->n = *len + 1;
|
2005-05-17 02:59:30 +02:00
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
for (i = 1; i <= *len; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2005-05-17 02:59:30 +02:00
|
|
|
Datum datum;
|
|
|
|
bool IsNull;
|
|
|
|
|
2001-08-22 20:24:26 +02:00
|
|
|
datum = index_getattr(itup[i - 1], 1, giststate->tupdesc, &IsNull);
|
2004-03-30 17:45:33 +02:00
|
|
|
gistdentryinit(giststate, 0, &(entryvec->vector[i]),
|
2001-10-25 07:50:21 +02:00
|
|
|
datum, r, p, i,
|
2005-05-17 02:59:30 +02:00
|
|
|
ATTSIZE(datum, giststate->tupdesc, 1, IsNull),
|
|
|
|
FALSE, IsNull);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
/*
|
|
|
|
* now let the user-defined picksplit function set up the split
|
|
|
|
* vector; in entryvec have no null value!!
|
|
|
|
*/
|
2001-05-31 20:16:55 +02:00
|
|
|
FunctionCall2(&giststate->picksplitFn[0],
|
2001-03-22 05:01:46 +01:00
|
|
|
PointerGetDatum(entryvec),
|
|
|
|
PointerGetDatum(&v));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
/* compatibility with old code */
|
|
|
|
if (v.spl_left[v.spl_nleft - 1] == InvalidOffsetNumber)
|
|
|
|
v.spl_left[v.spl_nleft - 1] = (OffsetNumber) *len;
|
|
|
|
if (v.spl_right[v.spl_nright - 1] == InvalidOffsetNumber)
|
|
|
|
v.spl_right[v.spl_nright - 1] = (OffsetNumber) *len;
|
|
|
|
|
|
|
|
v.spl_lattr[0] = v.spl_ldatum;
|
2001-05-31 20:16:55 +02:00
|
|
|
v.spl_rattr[0] = v.spl_rdatum;
|
2001-08-10 16:34:28 +02:00
|
|
|
v.spl_lisnull[0] = false;
|
|
|
|
v.spl_risnull[0] = false;
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
/*
|
|
|
|
* if index is multikey, then we must to try get smaller bounding box
|
|
|
|
* for subkey(s)
|
|
|
|
*/
|
|
|
|
if (r->rd_att->natts > 1)
|
|
|
|
{
|
2005-05-17 02:59:30 +02:00
|
|
|
int MaxGrpId;
|
|
|
|
|
2002-11-13 01:39:48 +01:00
|
|
|
v.spl_idgrp = (int *) palloc0(sizeof(int) * (*len + 1));
|
|
|
|
v.spl_grpflag = (char *) palloc0(sizeof(char) * (*len + 1));
|
2001-10-25 07:50:21 +02:00
|
|
|
v.spl_ngrp = (int *) palloc(sizeof(int) * (*len + 1));
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2004-03-30 17:45:33 +02:00
|
|
|
MaxGrpId = gistfindgroup(giststate, entryvec->vector, &v);
|
2001-05-31 20:16:55 +02:00
|
|
|
|
|
|
|
/* form union of sub keys for each page (l,p) */
|
2001-10-25 07:50:21 +02:00
|
|
|
gistunionsubkey(r, giststate, itup, &v);
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
/*
|
|
|
|
* if possible, we insert equivalent tuples with control by
|
|
|
|
* penalty for a subkey(s)
|
|
|
|
*/
|
|
|
|
if (MaxGrpId > 1)
|
|
|
|
gistadjsubkey(r, itup, len, &v, giststate);
|
|
|
|
}
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
/* form left and right vector */
|
2001-03-22 05:01:46 +01:00
|
|
|
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nleft);
|
|
|
|
rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nright);
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
for (i = 0; i < v.spl_nleft; i++)
|
|
|
|
lvectup[i] = itup[v.spl_left[i] - 1];
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
for (i = 0; i < v.spl_nright; i++)
|
|
|
|
rvectup[i] = itup[v.spl_right[i] - 1];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-05-17 02:59:30 +02:00
|
|
|
/* write on disk (may need another split) */
|
2001-03-22 05:01:46 +01:00
|
|
|
if (gistnospace(right, rvectup, v.spl_nright))
|
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
int i;
|
|
|
|
PageLayout *d, *origd=*dist;
|
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
nlen = v.spl_nright;
|
2005-06-14 13:45:14 +02:00
|
|
|
newtup = gistSplit(r, rightbuf, rvectup, &nlen, dist, giststate);
|
|
|
|
/* XLOG stuff */
|
|
|
|
d=*dist;
|
|
|
|
/* translate offsetnumbers to our */
|
|
|
|
while( d && d!=origd ) {
|
|
|
|
for(i=0;i<d->block.num;i++)
|
|
|
|
d->list[i] = v.spl_right[ d->list[i]-1 ];
|
|
|
|
d=d->next;
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
ReleaseBuffer(rightbuf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-12 01:12:58 +01:00
|
|
|
OffsetNumber l;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
l = gistfillbuffer(r, right, rvectup, v.spl_nright, FirstOffsetNumber);
|
|
|
|
/* XLOG stuff */
|
|
|
|
ROTATEDIST(*dist);
|
|
|
|
(*dist)->block.blkno = BufferGetBlockNumber(rightbuf);
|
|
|
|
(*dist)->block.num = v.spl_nright;
|
|
|
|
(*dist)->list = v.spl_right;
|
|
|
|
(*dist)->buffer = rightbuf;
|
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
nlen = 1;
|
2001-03-22 05:01:46 +01:00
|
|
|
newtup = (IndexTuple *) palloc(sizeof(IndexTuple) * 1);
|
2001-10-25 07:50:21 +02:00
|
|
|
newtup[0] = gistFormTuple(giststate, r, v.spl_rattr, v.spl_rattrsize, v.spl_risnull);
|
2005-06-14 13:45:14 +02:00
|
|
|
ItemPointerSet(&(newtup[0]->t_tid), rbknum, FirstOffsetNumber);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
if (gistnospace(left, lvectup, v.spl_nleft))
|
|
|
|
{
|
|
|
|
int llen = v.spl_nleft;
|
2001-01-12 01:12:58 +01:00
|
|
|
IndexTuple *lntup;
|
2005-06-14 13:45:14 +02:00
|
|
|
int i;
|
|
|
|
PageLayout *d, *origd=*dist;
|
|
|
|
|
|
|
|
lntup = gistSplit(r, leftbuf, lvectup, &llen, dist, giststate);
|
|
|
|
|
|
|
|
/* XLOG stuff */
|
|
|
|
d=*dist;
|
|
|
|
/* translate offsetnumbers to our */
|
|
|
|
while( d && d!=origd ) {
|
|
|
|
for(i=0;i<d->block.num;i++)
|
|
|
|
d->list[i] = v.spl_left[ d->list[i]-1 ];
|
|
|
|
d=d->next;
|
|
|
|
}
|
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
ReleaseBuffer(leftbuf);
|
2001-01-12 01:12:58 +01:00
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
newtup = gistjoinvector(newtup, &nlen, lntup, llen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-12 01:12:58 +01:00
|
|
|
OffsetNumber l;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
l = gistfillbuffer(r, left, lvectup, v.spl_nleft, FirstOffsetNumber);
|
2005-05-17 02:59:30 +02:00
|
|
|
if (BufferGetBlockNumber(buffer) != GIST_ROOT_BLKNO)
|
2001-01-12 01:12:58 +01:00
|
|
|
PageRestoreTempPage(left, p);
|
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
/* XLOG stuff */
|
|
|
|
ROTATEDIST(*dist);
|
|
|
|
(*dist)->block.blkno = BufferGetBlockNumber(leftbuf);
|
|
|
|
(*dist)->block.num = v.spl_nleft;
|
|
|
|
(*dist)->list = v.spl_left;
|
|
|
|
(*dist)->buffer = leftbuf;
|
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
nlen += 1;
|
2005-05-17 02:59:30 +02:00
|
|
|
newtup = (IndexTuple *) repalloc(newtup, sizeof(IndexTuple) * nlen);
|
2001-10-25 07:50:21 +02:00
|
|
|
newtup[nlen - 1] = gistFormTuple(giststate, r, v.spl_lattr, v.spl_lattrsize, v.spl_lisnull);
|
2005-06-14 13:45:14 +02:00
|
|
|
ItemPointerSet(&(newtup[nlen - 1]->t_tid), lbknum, FirstOffsetNumber);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
*len = nlen;
|
|
|
|
return newtup;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-08-26 22:02:12 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
void
|
|
|
|
gistnewroot(Relation r, IndexTuple *itup, int len, ItemPointer key, bool xlog_mode)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
2005-06-14 13:45:14 +02:00
|
|
|
Buffer buffer;
|
1997-09-08 04:41:22 +02:00
|
|
|
Page page;
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
buffer = (xlog_mode) ? XLogReadBuffer(false, r, GIST_ROOT_BLKNO) : ReadBuffer(r, GIST_ROOT_BLKNO);
|
|
|
|
GISTInitBuffer(buffer, 0);
|
|
|
|
page = BufferGetPage(buffer);
|
|
|
|
|
|
|
|
gistfillbuffer(r, page, itup, len, FirstOffsetNumber);
|
|
|
|
if ( !xlog_mode && !r->rd_istemp ) {
|
|
|
|
gistxlogEntryUpdate xlrec;
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData *rdata = (XLogRecData*)palloc( sizeof(XLogRecData) * ( len + 1 ) );
|
|
|
|
int i;
|
|
|
|
|
|
|
|
xlrec.node = r->rd_node;
|
|
|
|
xlrec.blkno = GIST_ROOT_BLKNO;
|
|
|
|
xlrec.todeleteoffnum = InvalidOffsetNumber;
|
|
|
|
xlrec.key = *key;
|
|
|
|
xlrec.pathlen=0;
|
|
|
|
|
|
|
|
rdata[0].buffer = InvalidBuffer;
|
|
|
|
rdata[0].data = (char *) &xlrec;
|
|
|
|
rdata[0].len = sizeof( gistxlogEntryUpdate );
|
|
|
|
rdata[0].next = NULL;
|
|
|
|
|
|
|
|
for(i=1; i<=len; i++) {
|
|
|
|
rdata[i].buffer = InvalidBuffer;
|
|
|
|
rdata[i].data = (char*)(itup[i-1]);
|
|
|
|
rdata[i].len = IndexTupleSize(itup[i-1]);
|
|
|
|
rdata[i].next = NULL;
|
|
|
|
rdata[i-1].next = &(rdata[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
START_CRIT_SECTION();
|
|
|
|
|
|
|
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_NEW_ROOT, rdata);
|
|
|
|
PageSetLSN(page, recptr);
|
|
|
|
PageSetTLI(page, ThisTimeLineID);
|
|
|
|
|
|
|
|
END_CRIT_SECTION();
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
2005-06-14 13:45:14 +02:00
|
|
|
if ( xlog_mode )
|
|
|
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
|
|
|
WriteBuffer(buffer);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
/*
|
|
|
|
* Bulk deletion of all index entries pointing to a set of heap tuples.
|
|
|
|
* The set of target tuples is specified via a callback routine that tells
|
|
|
|
* whether any given heap tuple (identified by ItemPointer) is being deleted.
|
|
|
|
*
|
|
|
|
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
IndexBulkDeleteResult *result;
|
2001-10-25 07:50:21 +02:00
|
|
|
BlockNumber num_pages;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
double tuples_removed;
|
|
|
|
double num_index_tuples;
|
|
|
|
IndexScanDesc iscan;
|
|
|
|
|
|
|
|
tuples_removed = 0;
|
|
|
|
num_index_tuples = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since GIST is not marked "amconcurrent" in pg_am, caller should
|
2001-10-25 07:50:21 +02:00
|
|
|
* have acquired exclusive lock on index relation. We need no locking
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX generic implementation --- should be improved!
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* walk through the entire index */
|
2004-01-07 19:56:30 +01:00
|
|
|
iscan = index_beginscan(NULL, rel, SnapshotAny, 0, NULL);
|
2002-05-24 20:57:57 +02:00
|
|
|
/* including killed tuples */
|
|
|
|
iscan->ignore_killed_tuples = false;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
while (index_getnext_indexitem(iscan, ForwardScanDirection))
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
{
|
2004-02-10 04:42:45 +01:00
|
|
|
vacuum_delay_point();
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
if (callback(&iscan->xs_ctup.t_self, callback_state))
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
{
|
2002-05-21 01:51:44 +02:00
|
|
|
ItemPointerData indextup = iscan->currentItemData;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
BlockNumber blkno;
|
|
|
|
OffsetNumber offnum;
|
|
|
|
Buffer buf;
|
|
|
|
Page page;
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
blkno = ItemPointerGetBlockNumber(&indextup);
|
|
|
|
offnum = ItemPointerGetOffsetNumber(&indextup);
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
|
|
|
/* adjust any scans that will be affected by this deletion */
|
|
|
|
gistadjscans(rel, GISTOP_DEL, blkno, offnum);
|
|
|
|
|
|
|
|
/* delete the index tuple */
|
|
|
|
buf = ReadBuffer(rel, blkno);
|
|
|
|
page = BufferGetPage(buf);
|
|
|
|
|
|
|
|
PageIndexTupleDelete(page, offnum);
|
2005-06-14 13:45:14 +02:00
|
|
|
if ( !rel->rd_istemp ) {
|
|
|
|
gistxlogEntryUpdate xlrec;
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData rdata;
|
|
|
|
|
|
|
|
xlrec.node = rel->rd_node;
|
|
|
|
xlrec.blkno = blkno;
|
|
|
|
xlrec.todeleteoffnum = offnum;
|
|
|
|
xlrec.pathlen=0;
|
|
|
|
ItemPointerSetInvalid( &(xlrec.key) );
|
|
|
|
|
|
|
|
rdata.buffer = InvalidBuffer;
|
|
|
|
rdata.data = (char *) &xlrec;
|
|
|
|
rdata.len = sizeof( gistxlogEntryUpdate );
|
|
|
|
rdata.next = NULL;
|
|
|
|
|
|
|
|
START_CRIT_SECTION();
|
|
|
|
|
|
|
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_ENTRY_DELETE, &rdata);
|
|
|
|
PageSetLSN(page, recptr);
|
|
|
|
PageSetTLI(page, ThisTimeLineID);
|
|
|
|
|
|
|
|
END_CRIT_SECTION();
|
|
|
|
}
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
|
|
|
WriteBuffer(buf);
|
|
|
|
|
|
|
|
tuples_removed += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
num_index_tuples += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
index_endscan(iscan);
|
|
|
|
|
|
|
|
/* return statistics */
|
|
|
|
num_pages = RelationGetNumberOfBlocks(rel);
|
|
|
|
|
2003-02-24 01:57:17 +01:00
|
|
|
result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
result->num_pages = num_pages;
|
|
|
|
result->num_index_tuples = num_index_tuples;
|
2003-02-22 01:45:05 +01:00
|
|
|
result->tuples_removed = tuples_removed;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
initGISTstate(GISTSTATE *giststate, Relation index)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
int i;
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-08-21 18:36:06 +02:00
|
|
|
if (index->rd_att->natts > INDEX_MAX_KEYS)
|
2003-07-21 22:29:40 +02:00
|
|
|
elog(ERROR, "numberOfAttributes %d > %d",
|
2001-08-21 18:36:06 +02:00
|
|
|
index->rd_att->natts, INDEX_MAX_KEYS);
|
|
|
|
|
2001-08-22 20:24:26 +02:00
|
|
|
giststate->tupdesc = index->rd_att;
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2001-08-21 18:36:06 +02:00
|
|
|
for (i = 0; i < index->rd_att->natts; i++)
|
|
|
|
{
|
2001-10-07 01:21:45 +02:00
|
|
|
fmgr_info_copy(&(giststate->consistentFn[i]),
|
2005-05-17 02:59:30 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
|
|
|
fmgr_info_copy(&(giststate->unionFn[i]),
|
2001-10-25 07:50:21 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_UNION_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
|
|
|
fmgr_info_copy(&(giststate->compressFn[i]),
|
2005-05-17 02:59:30 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
|
|
|
fmgr_info_copy(&(giststate->decompressFn[i]),
|
2005-05-17 02:59:30 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
|
|
|
fmgr_info_copy(&(giststate->penaltyFn[i]),
|
2001-10-25 07:50:21 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_PENALTY_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
|
|
|
fmgr_info_copy(&(giststate->picksplitFn[i]),
|
2005-05-17 02:59:30 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
|
|
|
fmgr_info_copy(&(giststate->equalFn[i]),
|
2001-10-25 07:50:21 +02:00
|
|
|
index_getprocinfo(index, i + 1, GIST_EQUAL_PROC),
|
2001-10-07 01:21:45 +02:00
|
|
|
CurrentMemoryContext);
|
2001-05-31 20:16:55 +02:00
|
|
|
}
|
2001-08-22 20:24:26 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-08-22 20:24:26 +02:00
|
|
|
void
|
2001-10-25 07:50:21 +02:00
|
|
|
freeGISTstate(GISTSTATE *giststate)
|
|
|
|
{
|
2001-08-22 20:24:26 +02:00
|
|
|
/* no work */
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GISTDEBUG
|
2001-01-12 01:12:58 +01:00
|
|
|
static void
|
|
|
|
gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
|
1996-08-26 22:02:12 +02:00
|
|
|
{
|
2001-01-12 01:12:58 +01:00
|
|
|
Buffer buffer;
|
1997-09-08 04:41:22 +02:00
|
|
|
Page page;
|
2001-01-12 01:12:58 +01:00
|
|
|
GISTPageOpaque opaque;
|
|
|
|
IndexTuple which;
|
2001-03-22 05:01:46 +01:00
|
|
|
ItemId iid;
|
|
|
|
OffsetNumber i,
|
|
|
|
maxoff;
|
|
|
|
BlockNumber cblk;
|
|
|
|
char *pred;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
pred = (char *) palloc(sizeof(char) * level + 1);
|
2001-01-12 01:12:58 +01:00
|
|
|
MemSet(pred, '\t', level);
|
2001-03-22 05:01:46 +01:00
|
|
|
pred[level] = '\0';
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
buffer = ReadBuffer(r, blk);
|
|
|
|
page = (Page) BufferGetPage(buffer);
|
|
|
|
opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
maxoff = PageGetMaxOffsetNumber(page);
|
|
|
|
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "%sPage: %d %s blk: %d maxoff: %d free: %d", pred,
|
2001-05-31 20:16:55 +02:00
|
|
|
coff, (opaque->flags & F_LEAF) ? "LEAF" : "INTE", (int) blk,
|
|
|
|
(int) maxoff, PageGetFreeSpace(page));
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
|
|
|
{
|
2001-01-12 01:12:58 +01:00
|
|
|
iid = PageGetItemId(page, i);
|
|
|
|
which = (IndexTuple) PageGetItem(page, iid);
|
|
|
|
cblk = ItemPointerGetBlockNumber(&(which->t_tid));
|
2001-03-22 05:01:46 +01:00
|
|
|
#ifdef PRINTTUPLE
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "%s Tuple. blk: %d size: %d", pred, (int) cblk,
|
2001-05-31 20:16:55 +02:00
|
|
|
IndexTupleSize(which));
|
2001-03-22 05:01:46 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!(opaque->flags & F_LEAF))
|
|
|
|
gist_dumptree(r, level + 1, cblk, i);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
2001-01-12 01:12:58 +01:00
|
|
|
ReleaseBuffer(buffer);
|
|
|
|
pfree(pred);
|
1996-08-26 22:02:12 +02:00
|
|
|
}
|
2001-11-05 18:46:40 +01:00
|
|
|
#endif /* defined GISTDEBUG */
|
2000-10-21 17:43:36 +02:00
|
|
|
|