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-20 17:22:38 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.121 2005/06/20 15:22:37 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-06-20 12:29:37 +02:00
|
|
|
MemoryContext tmpCtx;
|
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
|
|
|
|
|
|
|
|
|
|
|
#define ROTATEDIST(d) do { \
|
2005-06-20 12:29:37 +02:00
|
|
|
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
|
|
|
|
memset(tmp,0,sizeof(SplitedPageLayout)); \
|
2005-06-14 13:45:14 +02:00
|
|
|
tmp->next = (d); \
|
|
|
|
(d)=tmp; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
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 */
|
2005-06-20 12:29:37 +02:00
|
|
|
buffer = gistReadBuffer(index, P_NEW);
|
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
|
|
|
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
|
|
|
|
*/
|
2005-06-20 12:29:37 +02:00
|
|
|
buildstate.tmpCtx = 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-06-20 12:29:37 +02:00
|
|
|
MemoryContextDelete(buildstate.tmpCtx);
|
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
|
|
|
|
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-06-20 12:29:37 +02:00
|
|
|
MemoryContext oldCtx;
|
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-06-20 12:29:37 +02:00
|
|
|
oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
|
2005-05-17 02:59:30 +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
|
|
|
/* 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-06-20 12:29:37 +02:00
|
|
|
MemoryContextSwitchTo(oldCtx);
|
|
|
|
MemoryContextReset(buildstate->tmpCtx);
|
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-06-20 12:29:37 +02:00
|
|
|
MemoryContext oldCtx;
|
|
|
|
MemoryContext insertCtx;
|
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-06-20 12:29:37 +02:00
|
|
|
insertCtx = createTempGistContext();
|
|
|
|
oldCtx = MemoryContextSwitchTo(insertCtx);
|
2005-05-17 02:59:30 +02:00
|
|
|
|
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-06-20 12:29:37 +02:00
|
|
|
MemoryContextSwitchTo(oldCtx);
|
|
|
|
MemoryContextDelete(insertCtx);
|
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;
|
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;
|
2005-06-20 12:29:37 +02:00
|
|
|
SplitedPageLayout *dist=NULL, *ptr;
|
2005-06-14 13:45:14 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
if ( !state->r->rd_istemp ) {
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData *rdata;
|
|
|
|
|
|
|
|
rdata = formSplitRdata(state->r->rd_node, state->stack->blkno,
|
|
|
|
&(state->key), state->path, state->pathlen, dist);
|
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 ) {
|
2005-06-20 12:29:37 +02:00
|
|
|
gistnewroot(state->r, state->itup, state->ituplen, &(state->key));
|
2005-06-14 13:45:14 +02:00
|
|
|
state->needInsertComplete=false;
|
|
|
|
}
|
|
|
|
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;
|
2005-06-20 12:29:37 +02:00
|
|
|
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
|
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);
|
2005-06-20 12:29:37 +02:00
|
|
|
if ( !state->r->rd_istemp ) {
|
|
|
|
OffsetNumber noffs=0, offs[ MAXALIGN( sizeof(OffsetNumber) ) / sizeof(OffsetNumber) ];
|
|
|
|
XLogRecPtr recptr;
|
|
|
|
XLogRecData *rdata;
|
|
|
|
|
|
|
|
if ( state->stack->todelete ) {
|
|
|
|
offs[0] = state->stack->childoffnum;
|
|
|
|
noffs=1;
|
2005-06-14 13:45:14 +02:00
|
|
|
}
|
2005-06-20 12:29:37 +02:00
|
|
|
|
|
|
|
rdata = formUpdateRdata(state->r->rd_node, state->stack->blkno,
|
|
|
|
offs, noffs, false, state->itup, state->ituplen,
|
|
|
|
&(state->key), state->path, state->pathlen);
|
2005-06-14 13:45:14 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
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);
|
2005-06-20 12:29:37 +02:00
|
|
|
ItemPointerSetBlockNumber(&(newtup->t_tid), state->stack->blkno);
|
2005-06-14 13:45:14 +02:00
|
|
|
state->itup[0] = newtup;
|
|
|
|
state->ituplen = 1;
|
2005-06-20 12:29:37 +02:00
|
|
|
} else if (is_leaf) {
|
|
|
|
/* itup[0] store key to adjust parent, we set it to valid
|
|
|
|
to correct check by GistTupleIsInvalid macro in gistgetadjusted() */
|
|
|
|
ItemPointerSetBlockNumber(&(state->itup[0]->t_tid), state->stack->blkno);
|
|
|
|
GistTupleSetValid( state->itup[0] );
|
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 ) {
|
2005-06-20 12:29:37 +02:00
|
|
|
state->stack->buffer = gistReadBuffer(state->r, state->stack->blkno);
|
2005-06-14 13:45:14 +02:00
|
|
|
state->stack->page = (Page) BufferGetPage(state->stack->buffer);
|
2005-06-20 12:29:37 +02:00
|
|
|
|
|
|
|
if (!GistPageIsLeaf(state->stack->page))
|
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-20 12:29:37 +02:00
|
|
|
state->path=(BlockNumber*)palloc(MAXALIGN(sizeof(BlockNumber)*state->pathlen));
|
2005-06-14 13:45:14 +02:00
|
|
|
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-20 12:29:37 +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.
|
|
|
|
*/
|
2005-06-20 12:29:37 +02:00
|
|
|
|
2005-06-14 13:45:14 +02:00
|
|
|
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 ) {
|
|
|
|
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 */
|
2005-06-20 12:29:37 +02:00
|
|
|
if ( state->needInsertComplete && !state->r->rd_istemp )
|
|
|
|
gistxlogInsertCompletion(state->r->rd_node, &(state->key), 1);
|
|
|
|
}
|
2005-05-17 02:59:30 +02:00
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
static void
|
|
|
|
gistToRealOffset(OffsetNumber *arr, int len, OffsetNumber *reasloffset) {
|
|
|
|
int i;
|
2001-08-10 16:34:28 +02:00
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
for(i=0;i<len;i++)
|
|
|
|
arr[i] = reasloffset[ arr[i] ];
|
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
|
|
|
*/
|
2005-06-20 12:29:37 +02:00
|
|
|
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-20 12:29:37 +02:00
|
|
|
SplitedPageLayout **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;
|
2005-06-20 12:29:37 +02:00
|
|
|
int i, fakeoffset,
|
2001-03-22 05:01:46 +01:00
|
|
|
nlen;
|
2005-06-20 12:29:37 +02:00
|
|
|
OffsetNumber *realoffset;
|
|
|
|
IndexTuple *cleaneditup = itup;
|
|
|
|
int lencleaneditup = *len;
|
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
|
|
|
{
|
2005-06-20 12:29:37 +02:00
|
|
|
leftbuf = gistReadBuffer(r, P_NEW);
|
|
|
|
GISTInitBuffer(leftbuf, opaque->flags&F_LEAF);
|
1997-09-07 07:04:48 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
rightbuf = gistReadBuffer(r, P_NEW);
|
|
|
|
GISTInitBuffer(rightbuf, opaque->flags&F_LEAF);
|
1997-09-07 07:04:48 +02:00
|
|
|
rbknum = BufferGetBlockNumber(rightbuf);
|
|
|
|
right = (Page) BufferGetPage(rightbuf);
|
|
|
|
|
|
|
|
/* generate the item array */
|
2005-06-20 12:29:37 +02:00
|
|
|
realoffset = palloc((*len + 1) * sizeof(OffsetNumber));
|
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
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
fakeoffset = FirstOffsetNumber;
|
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;
|
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
if (!GistPageIsLeaf(p) && GistTupleIsInvalid( itup[i - 1] )) {
|
|
|
|
entryvec->n--;
|
|
|
|
/* remember position of invalid tuple */
|
|
|
|
realoffset[ entryvec->n ] = i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-08-22 20:24:26 +02:00
|
|
|
datum = index_getattr(itup[i - 1], 1, giststate->tupdesc, &IsNull);
|
2005-06-20 12:29:37 +02:00
|
|
|
gistdentryinit(giststate, 0, &(entryvec->vector[fakeoffset]),
|
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);
|
2005-06-20 12:29:37 +02:00
|
|
|
realoffset[ fakeoffset ] = i;
|
|
|
|
fakeoffset++;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
/*
|
|
|
|
* if it was invalid tuple then we need special processing. If
|
|
|
|
* it's possible, we move all invalid tuples on right page.
|
|
|
|
* We should remember, that union with invalid tuples
|
|
|
|
* is a invalid tuple.
|
|
|
|
*/
|
|
|
|
if ( entryvec->n != *len + 1 ) {
|
|
|
|
lencleaneditup = entryvec->n-1;
|
|
|
|
cleaneditup = (IndexTuple*)palloc(lencleaneditup * sizeof(IndexTuple));
|
|
|
|
for(i=1;i<entryvec->n;i++)
|
|
|
|
cleaneditup[i-1] = itup[ realoffset[ i ]-1 ];
|
|
|
|
|
|
|
|
if ( gistnospace( left, cleaneditup, lencleaneditup ) ) {
|
|
|
|
/* no space on left to put all good tuples, so picksplit */
|
|
|
|
gistUserPicksplit(r, entryvec, &v, cleaneditup, lencleaneditup, giststate);
|
|
|
|
v.spl_leftvalid = true;
|
|
|
|
v.spl_rightvalid = false;
|
|
|
|
gistToRealOffset( v.spl_left, v.spl_nleft, realoffset );
|
|
|
|
gistToRealOffset( v.spl_right, v.spl_nright, realoffset );
|
|
|
|
} else {
|
|
|
|
/* we can try to store all valid tuples on one page */
|
|
|
|
v.spl_right = (OffsetNumber*)palloc( entryvec->n * sizeof(OffsetNumber) );
|
|
|
|
v.spl_left = (OffsetNumber*)palloc( entryvec->n * sizeof(OffsetNumber) );
|
|
|
|
|
|
|
|
if ( lencleaneditup==0 ) {
|
|
|
|
/* all tuples are invalid, so moves half of its to right */
|
|
|
|
v.spl_leftvalid = v.spl_rightvalid = false;
|
|
|
|
v.spl_nright = 0;
|
|
|
|
v.spl_nleft = 0;
|
|
|
|
for(i=1;i<=*len;i++)
|
|
|
|
if ( i-1<*len/2 )
|
|
|
|
v.spl_left[ v.spl_nleft++ ] = i;
|
|
|
|
else
|
|
|
|
v.spl_right[ v.spl_nright++ ] = i;
|
|
|
|
} else {
|
|
|
|
/* we will not call gistUserPicksplit, just put good
|
|
|
|
tuples on left and invalid on right */
|
|
|
|
v.spl_nleft = lencleaneditup;
|
|
|
|
v.spl_nright = 0;
|
|
|
|
for(i=1;i<entryvec->n;i++)
|
|
|
|
v.spl_left[i-1] = i;
|
|
|
|
gistToRealOffset( v.spl_left, v.spl_nleft, realoffset );
|
|
|
|
v.spl_lattr[0] = v.spl_ldatum = (Datum)0;
|
|
|
|
v.spl_rattr[0] = v.spl_rdatum = (Datum)0;
|
|
|
|
v.spl_lisnull[0] = true;
|
|
|
|
v.spl_risnull[0] = true;
|
|
|
|
gistunionsubkey(r, giststate, itup, &v, true);
|
|
|
|
v.spl_leftvalid = true;
|
|
|
|
v.spl_rightvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* there is no invalid tuples, so usial processing */
|
|
|
|
gistUserPicksplit(r, entryvec, &v, itup, *len, giststate);
|
|
|
|
v.spl_leftvalid = v.spl_rightvalid = true;
|
2001-10-25 07:50:21 +02:00
|
|
|
}
|
2001-05-31 20:16:55 +02:00
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
|
2001-01-12 01:12:58 +01:00
|
|
|
/* form left and right vector */
|
2005-06-20 12:29:37 +02:00
|
|
|
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (*len+1));
|
|
|
|
rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (*len+1));
|
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
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
/* place invalid tuples on right page if itsn't done yet */
|
|
|
|
for (fakeoffset = entryvec->n; fakeoffset < *len+1 && lencleaneditup; fakeoffset++) {
|
|
|
|
rvectup[v.spl_nright++] = itup[realoffset[fakeoffset] - 1];
|
|
|
|
}
|
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))
|
|
|
|
{
|
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);
|
2001-03-22 05:01:46 +01:00
|
|
|
ReleaseBuffer(rightbuf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-12 01:12:58 +01:00
|
|
|
OffsetNumber l;
|
2005-06-20 17:22:38 +02:00
|
|
|
char *ptr;
|
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;
|
2005-06-20 17:22:38 +02:00
|
|
|
(*dist)->list = (IndexTupleData*)palloc( BLCKSZ );
|
|
|
|
ptr = (char*) ( (*dist)->list );
|
|
|
|
for(i=0;i<v.spl_nright;i++) {
|
|
|
|
memcpy( ptr, rvectup[i], IndexTupleSize( rvectup[i] ) );
|
|
|
|
ptr += IndexTupleSize( rvectup[i] );
|
|
|
|
}
|
|
|
|
(*dist)->lenlist = ptr - ( (char*) ( (*dist)->list ) );
|
2005-06-14 13:45:14 +02:00
|
|
|
(*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);
|
2005-06-20 12:29:37 +02:00
|
|
|
newtup[0] = ( v.spl_rightvalid ) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_rattrsize, v.spl_risnull)
|
|
|
|
: gist_form_invalid_tuple( rbknum );
|
|
|
|
ItemPointerSetBlockNumber(&(newtup[0]->t_tid), rbknum);
|
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
|
|
|
|
|
|
|
lntup = gistSplit(r, leftbuf, lvectup, &llen, dist, giststate);
|
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;
|
2005-06-20 17:22:38 +02:00
|
|
|
char *ptr;
|
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);
|
|
|
|
/* XLOG stuff */
|
|
|
|
ROTATEDIST(*dist);
|
|
|
|
(*dist)->block.blkno = BufferGetBlockNumber(leftbuf);
|
|
|
|
(*dist)->block.num = v.spl_nleft;
|
2005-06-20 17:22:38 +02:00
|
|
|
(*dist)->list = (IndexTupleData*)palloc( BLCKSZ );
|
|
|
|
ptr = (char*) ( (*dist)->list );
|
|
|
|
for(i=0;i<v.spl_nleft;i++) {
|
|
|
|
memcpy( ptr, lvectup[i], IndexTupleSize( lvectup[i] ) );
|
|
|
|
ptr += IndexTupleSize( lvectup[i] );
|
|
|
|
}
|
|
|
|
(*dist)->lenlist = ptr - ( (char*) ( (*dist)->list ) );
|
2005-06-14 13:45:14 +02:00
|
|
|
(*dist)->buffer = leftbuf;
|
|
|
|
|
2005-06-20 17:22:38 +02:00
|
|
|
if (BufferGetBlockNumber(buffer) != GIST_ROOT_BLKNO)
|
|
|
|
PageRestoreTempPage(left, p);
|
|
|
|
|
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);
|
2005-06-20 12:29:37 +02:00
|
|
|
newtup[nlen - 1] = ( v.spl_leftvalid ) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lattrsize, v.spl_lisnull)
|
|
|
|
: gist_form_invalid_tuple( lbknum );
|
|
|
|
ItemPointerSetBlockNumber(&(newtup[nlen - 1]->t_tid), lbknum);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
GistClearTuplesDeleted(p);
|
|
|
|
|
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
|
2005-06-20 12:29:37 +02:00
|
|
|
gistnewroot(Relation r, IndexTuple *itup, int len, ItemPointer key)
|
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-20 12:29:37 +02:00
|
|
|
buffer = gistReadBuffer(r, GIST_ROOT_BLKNO);
|
2005-06-14 13:45:14 +02:00
|
|
|
GISTInitBuffer(buffer, 0);
|
|
|
|
page = BufferGetPage(buffer);
|
|
|
|
|
|
|
|
gistfillbuffer(r, page, itup, len, FirstOffsetNumber);
|
2005-06-20 12:29:37 +02:00
|
|
|
if ( !r->rd_istemp ) {
|
2005-06-14 13:45:14 +02:00
|
|
|
XLogRecPtr recptr;
|
2005-06-20 12:29:37 +02:00
|
|
|
XLogRecData *rdata;
|
2005-06-14 13:45:14 +02:00
|
|
|
|
2005-06-20 12:29:37 +02:00
|
|
|
rdata = formUpdateRdata(r->rd_node, GIST_ROOT_BLKNO,
|
|
|
|
NULL, 0, false, itup, len,
|
|
|
|
key, NULL, 0);
|
2005-06-14 13:45:14 +02:00
|
|
|
|
|
|
|
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
|
|
|
WriteBuffer(buffer);
|
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
|
|
|
}
|
|
|
|
|