1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* index.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* code to create and destroy POSTGRES index relations
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-01-24 20:43:33 +01:00
|
|
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2001-07-16 07:07:00 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.157 2001/07/16 05:06:57 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* INTERFACE ROUTINES
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_create() - Create a cataloged index relation
|
1999-12-10 04:56:14 +01:00
|
|
|
* index_drop() - Removes index relation from catalogs
|
2000-07-15 00:18:02 +02:00
|
|
|
* BuildIndexInfo() - Prepare to insert index tuples
|
|
|
|
* FormIndexDatum() - Construct datum vector for one index tuple
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "postgres.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-12-09 21:32:44 +01:00
|
|
|
#include <unistd.h>
|
1999-07-16 07:00:38 +02:00
|
|
|
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "access/genam.h"
|
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "access/istrat.h"
|
|
|
|
#include "bootstrap/bootstrap.h"
|
2000-11-08 23:10:03 +01:00
|
|
|
#include "catalog/catalog.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "catalog/catname.h"
|
|
|
|
#include "catalog/heap.h"
|
|
|
|
#include "catalog/index.h"
|
|
|
|
#include "catalog/indexing.h"
|
2000-06-15 05:33:12 +02:00
|
|
|
#include "catalog/pg_index.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_type.h"
|
1999-10-26 05:12:39 +02:00
|
|
|
#include "commands/comment.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "executor/executor.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "optimizer/clauses.h"
|
|
|
|
#include "optimizer/prep.h"
|
|
|
|
#include "parser/parse_func.h"
|
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
|
|
|
#include "storage/sinval.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "storage/smgr.h"
|
|
|
|
#include "utils/builtins.h"
|
2000-05-21 01:11:29 +02:00
|
|
|
#include "utils/catcache.h"
|
2000-05-28 19:56:29 +02:00
|
|
|
#include "utils/fmgroids.h"
|
2000-11-08 23:10:03 +01:00
|
|
|
#include "utils/inval.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "utils/relcache.h"
|
|
|
|
#include "utils/syscache.h"
|
1999-02-02 04:45:56 +01:00
|
|
|
#include "utils/temprel.h"
|
1996-11-05 12:57:55 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* macros used in guessing how many tuples are on a page.
|
|
|
|
*/
|
1999-07-07 11:27:28 +02:00
|
|
|
#define AVG_ATTR_SIZE 8
|
|
|
|
#define NTUPLES_PER_PAGE(natts) \
|
2001-05-07 02:43:27 +02:00
|
|
|
((BLCKSZ - MAXALIGN(sizeof(PageHeaderData))) / \
|
1999-07-07 11:27:28 +02:00
|
|
|
((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* non-export function prototypes */
|
1999-05-25 18:15:34 +02:00
|
|
|
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
|
2000-04-12 19:17:23 +02:00
|
|
|
bool istemp);
|
2000-07-15 00:18:02 +02:00
|
|
|
static TupleDesc BuildFuncTupleDesc(Oid funcOid);
|
2001-01-24 01:06:07 +01:00
|
|
|
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
|
2001-03-22 05:01:46 +01:00
|
|
|
int numatts, AttrNumber *attNums);
|
1997-09-08 04:41:22 +02:00
|
|
|
static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
|
1999-02-02 04:45:56 +01:00
|
|
|
static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void InitializeAttributeOids(Relation indexRelation,
|
2000-04-12 19:17:23 +02:00
|
|
|
int numatts, Oid indexoid);
|
1999-11-01 03:29:27 +01:00
|
|
|
static void AppendAttributeTuples(Relation indexRelation, int numatts);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
2001-03-22 05:01:46 +01:00
|
|
|
IndexInfo *indexInfo,
|
|
|
|
Oid *classOids,
|
|
|
|
bool islossy, bool primary);
|
2000-04-12 19:17:23 +02:00
|
|
|
static Oid IndexGetRelation(Oid indexId);
|
2000-12-08 07:17:58 +01:00
|
|
|
static bool activate_index(Oid indexId, bool activate, bool inplace);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
static bool reindexing = false;
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
2000-04-12 19:17:23 +02:00
|
|
|
SetReindexProcessing(bool reindexmode)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
bool old = reindexing;
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
reindexing = reindexmode;
|
|
|
|
return old;
|
|
|
|
}
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
bool
|
2000-04-12 19:17:23 +02:00
|
|
|
IsReindexProcessing(void)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
|
|
|
return reindexing;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* GetHeapRelationOid
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1999-02-02 04:45:56 +01:00
|
|
|
GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid indoid;
|
|
|
|
Oid heapoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
indoid = RelnameFindRelid(indexRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
if ((!istemp && OidIsValid(indoid)) ||
|
2000-12-23 00:12:07 +01:00
|
|
|
(istemp && is_temp_rel_name(indexRelationName)))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Cannot create index: '%s' already exists",
|
1997-09-07 07:04:48 +02:00
|
|
|
indexRelationName);
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
heapoid = RelnameFindRelid(heapRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (!OidIsValid(heapoid))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Cannot create index on '%s': relation does not exist",
|
1997-09-07 07:04:48 +02:00
|
|
|
heapRelationName);
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return heapoid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static TupleDesc
|
2000-07-15 00:18:02 +02:00
|
|
|
BuildFuncTupleDesc(Oid funcOid)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc funcTupDesc;
|
2000-07-15 00:18:02 +02:00
|
|
|
HeapTuple tuple;
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid retType;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
2001-01-24 01:06:07 +01:00
|
|
|
* Allocate and zero a tuple descriptor for a one-column tuple.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
funcTupDesc = CreateTemplateTupleDesc(1);
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
1997-09-18 22:22:58 +02:00
|
|
|
MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
2000-07-15 00:18:02 +02:00
|
|
|
* Lookup the function to get its name and return type.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCache(PROCOID,
|
|
|
|
ObjectIdGetDatum(funcOid),
|
|
|
|
0, 0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2000-07-15 00:18:02 +02:00
|
|
|
elog(ERROR, "Function %u does not exist", funcOid);
|
1997-09-07 07:04:48 +02:00
|
|
|
retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
|
|
|
|
|
|
|
|
/*
|
2000-07-15 00:18:02 +02:00
|
|
|
* make the attributes name the same as the functions
|
|
|
|
*/
|
|
|
|
namestrcpy(&funcTupDesc->attrs[0]->attname,
|
|
|
|
NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
|
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
/*
|
|
|
|
* Lookup the return type in pg_type for the type length etc.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCache(TYPEOID,
|
|
|
|
ObjectIdGetDatum(retType),
|
|
|
|
0, 0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2000-07-15 00:18:02 +02:00
|
|
|
elog(ERROR, "Type %u does not exist", retType);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assign some of the attributes values. Leave the rest as 0.
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
|
1997-09-07 07:04:48 +02:00
|
|
|
funcTupDesc->attrs[0]->atttypid = retType;
|
|
|
|
funcTupDesc->attrs[0]->attnum = 1;
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
|
1998-02-07 22:41:52 +01:00
|
|
|
funcTupDesc->attrs[0]->attcacheoff = -1;
|
|
|
|
funcTupDesc->attrs[0]->atttypmod = -1;
|
2001-01-24 01:06:07 +01:00
|
|
|
funcTupDesc->attrs[0]->attstorage = ((Form_pg_type) GETSTRUCT(tuple))->typstorage;
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return funcTupDesc;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* ConstructTupleDescriptor
|
2000-07-15 00:18:02 +02:00
|
|
|
*
|
|
|
|
* Build an index tuple descriptor for a new index (plain not functional)
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static TupleDesc
|
2001-01-24 01:06:07 +01:00
|
|
|
ConstructTupleDescriptor(Relation heapRelation,
|
1997-09-07 07:04:48 +02:00
|
|
|
int numatts,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attNums)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc heapTupDesc;
|
|
|
|
TupleDesc indexTupDesc;
|
2000-07-15 00:18:02 +02:00
|
|
|
int natts; /* #atts in heap rel --- for error checks */
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
heapTupDesc = RelationGetDescr(heapRelation);
|
|
|
|
natts = RelationGetForm(heapRelation)->relnatts;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* allocate the new tuple descriptor
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
indexTupDesc = CreateTemplateTupleDesc(numatts);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* for each attribute we are indexing, obtain its attribute
|
|
|
|
* tuple form from either the static table of system attribute
|
|
|
|
* tuple forms or the relation tuple descriptor
|
|
|
|
* ----------------
|
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
for (i = 0; i < numatts; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-15 00:18:02 +02:00
|
|
|
AttrNumber atnum; /* attributeNumber[attributeOffset] */
|
2001-01-24 01:06:07 +01:00
|
|
|
Form_pg_attribute from;
|
|
|
|
Form_pg_attribute to;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get the attribute number and make sure it's valid; determine
|
|
|
|
* which attribute descriptor to copy
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
atnum = attNums[i];
|
|
|
|
|
|
|
|
if (!AttrNumberIsForUserDefinedAttr(atnum))
|
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-05-07 02:43:27 +02:00
|
|
|
* here we are indexing on a system attribute (-1...-n)
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-05-07 02:43:27 +02:00
|
|
|
from = SystemAttributeDefinition(atnum);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* here we are indexing on a normal attribute (1...n)
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-01-24 01:06:07 +01:00
|
|
|
if (atnum > natts)
|
|
|
|
elog(ERROR, "Cannot create index: attribute %d does not exist",
|
|
|
|
atnum);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-05-07 02:43:27 +02:00
|
|
|
from = heapTupDesc->attrs[AttrNumberGetAttrOffset(atnum)];
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* now that we've determined the "from", let's copy the tuple desc
|
|
|
|
* data...
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-01-24 01:06:07 +01:00
|
|
|
indexTupDesc->attrs[i] = to =
|
|
|
|
(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
|
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* Fix the stuff that should not be the same as the underlying
|
|
|
|
* attr
|
2000-07-15 00:18:02 +02:00
|
|
|
*/
|
2001-01-24 01:06:07 +01:00
|
|
|
to->attnum = i + 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-05-07 02:43:27 +02:00
|
|
|
to->attstattarget = 0;
|
|
|
|
to->attcacheoff = -1;
|
2001-01-24 01:06:07 +01:00
|
|
|
to->attnotnull = false;
|
|
|
|
to->atthasdef = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-01-24 01:06:07 +01:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* We do not yet have the correct relation OID for the index, so
|
|
|
|
* just set it invalid for now. InitializeAttributeOids() will
|
|
|
|
* fix it later.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-01-24 01:06:07 +01:00
|
|
|
to->attrelid = InvalidOid;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return indexTupDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1999-05-25 18:15:34 +02:00
|
|
|
* AccessMethodObjectIdGetForm
|
2000-06-30 09:04:23 +02:00
|
|
|
* Returns an access method tuple given its object identifier,
|
|
|
|
* or NULL if no such AM tuple can be found.
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2000-06-30 09:04:23 +02:00
|
|
|
* Scanning is done using CurrentMemoryContext as working storage,
|
|
|
|
* but the returned tuple will be allocated in resultCxt (which is
|
|
|
|
* typically CacheMemoryContext).
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2000-06-30 09:04:23 +02:00
|
|
|
* There was a note here about adding indexing, but I don't see a need
|
2001-03-22 05:01:46 +01:00
|
|
|
* for it. There are so few tuples in pg_am that an indexscan would
|
2000-06-30 09:04:23 +02:00
|
|
|
* surely be slower.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Form_pg_am
|
2000-06-30 09:04:23 +02:00
|
|
|
AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
|
|
|
|
MemoryContext resultCxt)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_am_desc;
|
|
|
|
HeapScanDesc pg_am_scan;
|
|
|
|
HeapTuple pg_am_tuple;
|
|
|
|
ScanKeyData key;
|
1999-06-19 06:54:23 +02:00
|
|
|
Form_pg_am aform;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* form a scan key for the pg_am relation
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
|
1998-04-27 06:08:07 +02:00
|
|
|
F_OIDEQ,
|
1997-09-07 07:04:48 +02:00
|
|
|
ObjectIdGetDatum(accessMethodObjectId));
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* fetch the desired access method tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
|
1998-07-27 21:38:40 +02:00
|
|
|
pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
pg_am_tuple = heap_getnext(pg_am_scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* return NULL if not found
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (!HeapTupleIsValid(pg_am_tuple))
|
|
|
|
{
|
|
|
|
heap_endscan(pg_am_scan);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_am_desc, AccessShareLock);
|
1998-09-01 05:29:17 +02:00
|
|
|
return NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* if found AM tuple, then copy it into resultCxt and return the copy
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-06-30 09:04:23 +02:00
|
|
|
aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
|
1999-06-19 06:54:23 +02:00
|
|
|
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
heap_endscan(pg_am_scan);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_am_desc, AccessShareLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-06-19 06:54:23 +02:00
|
|
|
return aform;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ConstructIndexReldesc
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
|
|
|
{
|
2001-06-12 07:55:50 +02:00
|
|
|
/*
|
|
|
|
* Fill in a copy of relevant pg_am entry
|
|
|
|
*/
|
2000-06-30 09:04:23 +02:00
|
|
|
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
|
2001-06-12 07:55:50 +02:00
|
|
|
CacheMemoryContext);
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-06-12 07:55:50 +02:00
|
|
|
* Set up some additional fields of the index' pg_class entry.
|
|
|
|
* In particular, initialize knowledge of whether the index is shared.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
indexRelation->rd_rel->relowner = GetUserId();
|
|
|
|
indexRelation->rd_rel->relam = amoid;
|
2001-06-12 07:55:50 +02:00
|
|
|
indexRelation->rd_rel->relisshared =
|
|
|
|
IsSharedSystemRelationName(RelationGetPhysicalRelationName(indexRelation));
|
1997-09-07 07:04:48 +02:00
|
|
|
indexRelation->rd_rel->relkind = RELKIND_INDEX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* UpdateRelationRelation
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1999-02-02 04:45:56 +01:00
|
|
|
UpdateRelationRelation(Relation indexRelation, char *temp_relname)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_class;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Oid tupleOid;
|
|
|
|
Relation idescs[Num_pg_class_indices];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
|
|
|
|
tuple = heap_addheader(Natts_pg_class_fixed,
|
2000-06-17 06:56:39 +02:00
|
|
|
CLASS_TUPLE_SIZE,
|
2001-06-12 07:55:50 +02:00
|
|
|
(void *) indexRelation->rd_rel);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* the new tuple must have the same oid as the relcache entry for the
|
|
|
|
* index. sure would be embarrassing to do this sort of thing in
|
|
|
|
* polite company.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-11-27 20:52:36 +01:00
|
|
|
tuple->t_data->t_oid = RelationGetRelid(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_insert(pg_class, tuple);
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
if (temp_relname)
|
|
|
|
create_temp_relation(temp_relname, tuple);
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* During normal processing, we need to make sure that the system
|
|
|
|
* catalog indices are correct. Bootstrap (initdb) time doesn't
|
|
|
|
* require this, because we make sure that the indices are correct
|
|
|
|
* just before exiting.
|
|
|
|
*/
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!IsIgnoringSystemIndexes())
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
|
|
|
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
|
|
|
}
|
|
|
|
|
1998-11-27 20:52:36 +01:00
|
|
|
tupleOid = tuple->t_data->t_oid;
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_class, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return tupleOid;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* InitializeAttributeOids
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
InitializeAttributeOids(Relation indexRelation,
|
|
|
|
int numatts,
|
|
|
|
Oid indexoid)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupleDescriptor;
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
tupleDescriptor = RelationGetDescr(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < numatts; i += 1)
|
|
|
|
tupleDescriptor->attrs[i]->attrelid = indexoid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* AppendAttributeTuples
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AppendAttributeTuples(Relation indexRelation, int numatts)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_attribute;
|
|
|
|
bool hasind;
|
|
|
|
Relation idescs[Num_pg_attr_indices];
|
|
|
|
TupleDesc indexTupDesc;
|
2001-06-12 07:55:50 +02:00
|
|
|
HeapTuple new_tuple;
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* open the attribute relation
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
hasind = false;
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
hasind = true;
|
|
|
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-06-12 07:55:50 +02:00
|
|
|
* insert data from new index's tupdesc into pg_attribute
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
indexTupDesc = RelationGetDescr(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-12 07:55:50 +02:00
|
|
|
for (i = 0; i < numatts; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-06-12 07:55:50 +02:00
|
|
|
* There used to be very grotty code here to set these fields,
|
|
|
|
* but I think it's unnecessary. They should be set already.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-06-12 07:55:50 +02:00
|
|
|
Assert(indexTupDesc->attrs[i]->attnum == i+1);
|
|
|
|
Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-12 07:55:50 +02:00
|
|
|
new_tuple = heap_addheader(Natts_pg_attribute,
|
|
|
|
ATTRIBUTE_TUPLE_SIZE,
|
|
|
|
(void *) indexTupDesc->attrs[i]);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
heap_insert(pg_attribute, new_tuple);
|
2001-06-12 07:55:50 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (hasind)
|
1998-08-19 04:04:17 +02:00
|
|
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-12 07:55:50 +02:00
|
|
|
heap_freetuple(new_tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hasind)
|
|
|
|
CatalogCloseIndices(Num_pg_attr_indices, idescs);
|
2001-06-12 07:55:50 +02:00
|
|
|
|
|
|
|
heap_close(pg_attribute, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* UpdateIndexRelation
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
UpdateIndexRelation(Oid indexoid,
|
|
|
|
Oid heapoid,
|
2000-07-15 00:18:02 +02:00
|
|
|
IndexInfo *indexInfo,
|
1998-09-01 05:29:17 +02:00
|
|
|
Oid *classOids,
|
1997-09-07 07:04:48 +02:00
|
|
|
bool islossy,
|
1999-05-25 18:15:34 +02:00
|
|
|
bool primary)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_index indexForm;
|
1997-09-08 04:41:22 +02:00
|
|
|
char *predString;
|
|
|
|
text *predText;
|
|
|
|
int predLen,
|
|
|
|
itupLen;
|
|
|
|
Relation pg_index;
|
|
|
|
HeapTuple tuple;
|
|
|
|
int i;
|
1999-11-01 03:29:27 +01:00
|
|
|
Relation idescs[Num_pg_index_indices];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* allocate a Form_pg_index big enough to hold the index-predicate (if
|
|
|
|
* any) in string form
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-07-16 07:07:00 +02:00
|
|
|
if (indexInfo->ii_Predicate != NIL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-15 00:18:02 +02:00
|
|
|
predString = nodeToString(indexInfo->ii_Predicate);
|
2000-07-06 01:12:09 +02:00
|
|
|
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
2001-03-22 05:01:46 +01:00
|
|
|
CStringGetDatum(predString)));
|
1997-09-07 07:04:48 +02:00
|
|
|
pfree(predString);
|
|
|
|
}
|
|
|
|
else
|
2000-07-06 01:12:09 +02:00
|
|
|
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
2001-03-22 05:01:46 +01:00
|
|
|
CStringGetDatum("")));
|
1999-02-02 04:45:56 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
predLen = VARSIZE(predText);
|
|
|
|
itupLen = predLen + sizeof(FormData_pg_index);
|
1998-09-01 05:29:17 +02:00
|
|
|
indexForm = (Form_pg_index) palloc(itupLen);
|
2000-07-15 00:18:02 +02:00
|
|
|
MemSet(indexForm, 0, sizeof(FormData_pg_index));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* store information into the index tuple form
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
indexForm->indexrelid = indexoid;
|
2000-07-15 00:18:02 +02:00
|
|
|
indexForm->indrelid = heapoid;
|
|
|
|
indexForm->indproc = indexInfo->ii_FuncOid;
|
2001-05-15 03:12:59 +02:00
|
|
|
indexForm->indisclustered = false; /* not used */
|
1997-09-07 07:04:48 +02:00
|
|
|
indexForm->indislossy = islossy;
|
2001-05-15 05:49:35 +02:00
|
|
|
indexForm->indhaskeytype = true; /* used by GIST */
|
2000-07-15 00:18:02 +02:00
|
|
|
indexForm->indisunique = indexInfo->ii_Unique;
|
1999-01-21 23:48:20 +01:00
|
|
|
indexForm->indisprimary = primary;
|
2000-07-15 00:18:02 +02:00
|
|
|
memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* copy index key and op class information
|
2000-07-15 00:18:02 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* We zeroed the extra slots (if any) above --- that's essential.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
|
|
|
|
indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
|
|
|
indexForm->indclass[i] = classOids[i];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* open the system catalog index relation
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* form a tuple to insert into pg_index
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
tuple = heap_addheader(Natts_pg_index,
|
|
|
|
itupLen,
|
2001-06-12 07:55:50 +02:00
|
|
|
(void *) indexForm);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* insert the tuple into the pg_index
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
heap_insert(pg_index, tuple);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* add index tuples for it
|
1999-11-01 03:29:27 +01:00
|
|
|
*/
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!IsIgnoringSystemIndexes())
|
1999-11-01 03:29:27 +01:00
|
|
|
{
|
|
|
|
CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
|
|
|
|
CatalogCloseIndices(Num_pg_index_indices, idescs);
|
|
|
|
}
|
2000-07-15 00:18:02 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* close the relation and free the tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_index, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
pfree(predText);
|
|
|
|
pfree(indexForm);
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* InitIndexStrategy
|
2001-06-01 04:41:36 +02:00
|
|
|
*
|
|
|
|
* XXX this is essentially the same as relcache.c's
|
|
|
|
* IndexedAccessMethodInitialize(), and probably ought to be merged with it.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
InitIndexStrategy(int numatts,
|
|
|
|
Relation indexRelation,
|
|
|
|
Oid accessMethodObjectId)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
IndexStrategy strategy;
|
|
|
|
RegProcedure *support;
|
|
|
|
uint16 amstrategies;
|
|
|
|
uint16 amsupport;
|
|
|
|
Size strsize;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get information from the index relation descriptor
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
amstrategies = indexRelation->rd_am->amstrategies;
|
|
|
|
amsupport = indexRelation->rd_am->amsupport;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-06-01 04:41:36 +02:00
|
|
|
* compute the size of the strategy array
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* allocate the new index strategy structure
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* the index strategy has to be allocated in the same context as the
|
|
|
|
* relation descriptor cache or else it will be lost at the end of the
|
|
|
|
* transaction.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-06-28 05:33:33 +02:00
|
|
|
if (!CacheMemoryContext)
|
|
|
|
CreateCacheMemoryContext();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-28 05:33:33 +02:00
|
|
|
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
|
|
|
|
strsize);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (amsupport > 0)
|
|
|
|
{
|
|
|
|
strsize = numatts * (amsupport * sizeof(RegProcedure));
|
2000-06-28 05:33:33 +02:00
|
|
|
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
|
1997-09-07 07:04:48 +02:00
|
|
|
strsize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
support = (RegProcedure *) NULL;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* fill in the index strategy structure with information from the
|
|
|
|
* catalogs. First we must advance the command counter so that we
|
|
|
|
* will see the newly-entered index catalog tuples.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-01-18 00:57:48 +01:00
|
|
|
CommandCounterIncrement();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
IndexSupportInitialize(strategy, support,
|
2000-07-15 00:18:02 +02:00
|
|
|
&indexRelation->rd_uniqueindex,
|
2001-06-01 04:41:36 +02:00
|
|
|
RelationGetRelid(indexRelation),
|
|
|
|
accessMethodObjectId,
|
1997-09-07 07:04:48 +02:00
|
|
|
amstrategies, amsupport, numatts);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* store the strategy information in the index reldesc
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
RelationSetIndexSupport(indexRelation, strategy, support);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* index_create
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_create(char *heapRelationName,
|
|
|
|
char *indexRelationName,
|
2000-07-15 00:18:02 +02:00
|
|
|
IndexInfo *indexInfo,
|
1997-09-07 07:04:48 +02:00
|
|
|
Oid accessMethodObjectId,
|
1998-09-01 05:29:17 +02:00
|
|
|
Oid *classObjectId,
|
1997-09-07 07:04:48 +02:00
|
|
|
bool islossy,
|
2000-07-04 08:11:54 +02:00
|
|
|
bool primary,
|
|
|
|
bool allow_system_table_mods)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation heapRelation;
|
|
|
|
Relation indexRelation;
|
|
|
|
TupleDesc indexTupDesc;
|
|
|
|
Oid heapoid;
|
|
|
|
Oid indexoid;
|
2000-12-23 00:12:07 +01:00
|
|
|
bool istemp = is_temp_rel_name(heapRelationName);
|
1999-05-25 18:15:34 +02:00
|
|
|
char *temp_relname = NULL;
|
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
SetReindexProcessing(false);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* check parameters
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
if (indexInfo->ii_NumIndexAttrs < 1 ||
|
|
|
|
indexInfo->ii_NumKeyAttrs < 1)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "must index at least one attribute");
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2001-04-02 16:34:25 +02:00
|
|
|
if (heapRelationName && !allow_system_table_mods &&
|
|
|
|
IsSystemRelationName(heapRelationName) && IsNormalProcessingMode())
|
|
|
|
elog(ERROR, "User-defined indexes on system catalogs are not supported");
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get heap relation oid and open the heap relation
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
/*
|
1999-09-18 21:08:25 +02:00
|
|
|
* Only SELECT ... FOR UPDATE are allowed while doing this
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
heapRelation = heap_open(heapoid, ShareLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* construct new tuple descriptor
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
if (OidIsValid(indexInfo->ii_FuncOid))
|
|
|
|
indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
2001-01-24 01:06:07 +01:00
|
|
|
indexTupDesc = ConstructTupleDescriptor(heapRelation,
|
2000-07-15 00:18:02 +02:00
|
|
|
indexInfo->ii_NumKeyAttrs,
|
2001-03-22 05:01:46 +01:00
|
|
|
indexInfo->ii_KeyAttrNumbers);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
if (istemp)
|
|
|
|
{
|
2000-07-04 08:11:54 +02:00
|
|
|
/* save user relation name because heap_create changes it */
|
2001-03-22 05:01:46 +01:00
|
|
|
temp_relname = pstrdup(indexRelationName); /* save original value */
|
1999-02-02 04:45:56 +01:00
|
|
|
indexRelationName = palloc(NAMEDATALEN);
|
2001-03-22 05:01:46 +01:00
|
|
|
strcpy(indexRelationName, temp_relname); /* heap_create will
|
|
|
|
* change this */
|
1999-02-02 04:45:56 +01:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* create the index relation
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-19 00:44:35 +02:00
|
|
|
indexRelation = heap_create(indexRelationName, indexTupDesc,
|
2000-07-04 08:11:54 +02:00
|
|
|
istemp, false, allow_system_table_mods);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
|
|
|
* Obtain exclusive lock on it. Although no other backends can see it
|
|
|
|
* until we commit, this prevents deadlock-risk complaints from lock
|
|
|
|
* manager in cases such as CLUSTER.
|
|
|
|
*/
|
|
|
|
LockRelation(indexRelation, AccessExclusiveLock);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* construct the index relation descriptor
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* XXX should have a proper way to create cataloged relations
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
ConstructIndexReldesc(indexRelation, accessMethodObjectId);
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* add index to catalogs
|
1998-09-09 05:42:52 +02:00
|
|
|
* (append RELATION tuple)
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
indexoid = UpdateRelationRelation(indexRelation, temp_relname);
|
1996-08-26 08:32:06 +02:00
|
|
|
|
1999-11-04 09:01:09 +01:00
|
|
|
/*
|
|
|
|
* We create the disk file for this relation here
|
|
|
|
*/
|
|
|
|
heap_storage_create(indexRelation);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* now update the object id's of all the attribute tuple forms in the
|
|
|
|
* index relation's tuple descriptor
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
InitializeAttributeOids(indexRelation,
|
|
|
|
indexInfo->ii_NumIndexAttrs,
|
|
|
|
indexoid);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* append ATTRIBUTE tuples for the index
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* update pg_index
|
|
|
|
* (append INDEX tuple)
|
|
|
|
*
|
|
|
|
* Note that this stows away a representation of "predicate".
|
|
|
|
* (Or, could define a rule to maintain the predicate) --Nels, Feb '92
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
UpdateIndexRelation(indexoid, heapoid, indexInfo,
|
|
|
|
classObjectId, islossy, primary);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize the index strategy
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
|
|
|
|
indexRelation,
|
|
|
|
accessMethodObjectId);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is bootstrap (initdb) time, then we don't actually fill in
|
|
|
|
* the index yet. We'll be creating more indices and classes later,
|
|
|
|
* so we delay filling them in until just before we're done with
|
|
|
|
* bootstrapping. Otherwise, we call the routine that constructs the
|
1999-09-18 21:08:25 +02:00
|
|
|
* index.
|
|
|
|
*
|
2000-04-12 19:17:23 +02:00
|
|
|
* In normal processing mode, the heap and index relations are closed by
|
|
|
|
* index_build() --- but we continue to hold the ShareLock on the heap
|
2000-11-08 23:10:03 +01:00
|
|
|
* and the exclusive lock on the index that we acquired above, until
|
|
|
|
* end of transaction.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
1997-03-19 08:44:45 +01:00
|
|
|
{
|
2000-07-15 00:18:02 +02:00
|
|
|
index_register(heapRelationName, indexRelationName, indexInfo);
|
1999-09-18 21:08:25 +02:00
|
|
|
/* XXX shouldn't we close the heap and index rels here? */
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
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
|
|
|
index_build(heapRelation, indexRelation, indexInfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1999-02-02 04:45:56 +01:00
|
|
|
*
|
1999-12-10 04:56:14 +01:00
|
|
|
* index_drop
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
1999-12-10 04:56:14 +01:00
|
|
|
index_drop(Oid indexId)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-17 23:49:04 +02:00
|
|
|
Oid heapId;
|
1999-11-21 21:01:10 +01:00
|
|
|
Relation userHeapRelation;
|
|
|
|
Relation userIndexRelation;
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation indexRelation;
|
1998-08-21 01:01:24 +02:00
|
|
|
Relation relationRelation;
|
1998-08-21 00:07:46 +02:00
|
|
|
Relation attributeRelation;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tuple;
|
1999-05-25 18:15:34 +02:00
|
|
|
int16 attnum;
|
2000-11-08 23:10:03 +01:00
|
|
|
int i;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
Assert(OidIsValid(indexId));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* To drop an index safely, we must grab exclusive lock on its parent
|
|
|
|
* table; otherwise there could be other backends using 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
|
|
|
* Exclusive lock on the index alone is insufficient because another
|
|
|
|
* backend might be in the midst of devising a query plan that will use
|
|
|
|
* the index. The parser and planner take care to hold an appropriate
|
|
|
|
* lock on the parent table while working, but having them hold locks on
|
|
|
|
* all the indexes too seems overly complex. We do grab exclusive lock
|
|
|
|
* on the index too, just to be safe. Both locks must be held till end of
|
|
|
|
* transaction, else other backends will still see this index in pg_index.
|
1999-09-18 21:08:25 +02:00
|
|
|
*/
|
2000-06-17 23:49:04 +02:00
|
|
|
heapId = IndexGetRelation(indexId);
|
|
|
|
userHeapRelation = heap_open(heapId, AccessExclusiveLock);
|
1999-11-21 21:01:10 +01:00
|
|
|
|
|
|
|
userIndexRelation = index_open(indexId);
|
|
|
|
LockRelation(userIndexRelation, AccessExclusiveLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Note: unlike heap_drop_with_catalog, we do not need to prevent
|
|
|
|
* deletion of system indexes here; that's checked for upstream. If we
|
|
|
|
* did check it here, deletion of TOAST tables would fail...
|
1999-09-05 19:43:47 +02:00
|
|
|
*/
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1999-10-26 05:12:39 +02:00
|
|
|
* fix DESCRIPTION relation
|
|
|
|
*/
|
|
|
|
DeleteComments(indexId);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* fix RELATION relation
|
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-17 23:49:04 +02:00
|
|
|
/* Remove the pg_class tuple for the index itself */
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCacheCopy(RELOID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "index_drop: cache lookup failed for index %u",
|
|
|
|
indexId);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_delete(relationRelation, &tuple->t_self);
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
2000-06-17 23:49:04 +02:00
|
|
|
|
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* Update the pg_class tuple for the owning relation. We are
|
|
|
|
* presently too lazy to attempt to compute the new correct value of
|
|
|
|
* relhasindex (the next VACUUM will fix it if necessary). But we
|
|
|
|
* must send out a shared-cache-inval notice on the owning relation to
|
|
|
|
* ensure other backends update their relcache lists of indexes. So,
|
|
|
|
* unconditionally do setRelhasindex(true).
|
2000-06-17 23:49:04 +02:00
|
|
|
*/
|
2000-11-08 23:10:03 +01:00
|
|
|
setRelhasindex(heapId, true);
|
2000-06-17 23:49:04 +02:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(relationRelation, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* fix ATTRIBUTE relation
|
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
attnum = 1; /* indexes start at 1 */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
while (HeapTupleIsValid(tuple = SearchSysCacheCopy(ATTNUM,
|
1998-09-01 06:40:42 +02:00
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
Int16GetDatum(attnum),
|
2000-11-16 23:30:52 +01:00
|
|
|
0, 0)))
|
1998-08-19 04:04:17 +02:00
|
|
|
{
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_delete(attributeRelation, &tuple->t_self);
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
1998-08-19 04:04:17 +02:00
|
|
|
attnum++;
|
|
|
|
}
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(attributeRelation, RowExclusiveLock);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* fix INDEX relation
|
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
|
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCacheCopy(INDEXRELID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "index_drop: cache lookup failed for index %u",
|
|
|
|
indexId);
|
1998-08-21 00:07:46 +02:00
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_delete(indexRelation, &tuple->t_self);
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(indexRelation, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
1999-11-21 21:01:10 +01:00
|
|
|
* flush buffer cache and physically remove the file
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-11-08 23:10:03 +01:00
|
|
|
i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
|
|
|
|
if (i < 0)
|
|
|
|
elog(ERROR, "index_drop: FlushRelationBuffers returned %d", i);
|
1998-06-13 22:22:54 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
smgrunlink(DEFAULT_SMGR, userIndexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-11-21 21:01:10 +01:00
|
|
|
/*
|
|
|
|
* Close rels, but keep locks
|
|
|
|
*/
|
|
|
|
index_close(userIndexRelation);
|
|
|
|
heap_close(userHeapRelation, NoLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
|
|
|
RelationForgetRelation(indexId);
|
1999-11-16 05:14:03 +01:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/* if it's a temp index, clear the temp mapping table entry */
|
2000-10-11 23:28:19 +02:00
|
|
|
remove_temp_rel_by_relid(indexId);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_build support
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* BuildIndexInfo
|
|
|
|
* Construct an IndexInfo record given the index's pg_index tuple
|
|
|
|
*
|
|
|
|
* IndexInfo stores the information about the index that's needed by
|
|
|
|
* FormIndexDatum, which is used for both index_build() and later insertion
|
2001-03-22 05:01:46 +01:00
|
|
|
* of individual index tuples. Normally we build an IndexInfo for an index
|
2000-07-15 00:18:02 +02:00
|
|
|
* just once per command, and then use it for (potentially) many tuples.
|
|
|
|
* ----------------
|
|
|
|
*/
|
2001-03-22 05:01:46 +01:00
|
|
|
IndexInfo *
|
2000-07-15 00:18:02 +02:00
|
|
|
BuildIndexInfo(HeapTuple indexTuple)
|
|
|
|
{
|
|
|
|
Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
|
|
|
|
IndexInfo *ii = makeNode(IndexInfo);
|
|
|
|
int i;
|
|
|
|
int numKeys;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* count the number of keys, and copy them into the IndexInfo
|
2000-07-15 00:18:02 +02:00
|
|
|
*/
|
|
|
|
numKeys = 0;
|
|
|
|
for (i = 0; i < INDEX_MAX_KEYS &&
|
|
|
|
indexStruct->indkey[i] != InvalidAttrNumber; i++)
|
|
|
|
{
|
|
|
|
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
|
|
|
|
numKeys++;
|
|
|
|
}
|
|
|
|
ii->ii_NumKeyAttrs = numKeys;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Handle functional index.
|
2000-07-15 00:18:02 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* If we have a functional index then the number of attributes defined in
|
|
|
|
* the index must be 1 (the function's single return value).
|
|
|
|
* Otherwise it's same as number of keys.
|
2000-07-15 00:18:02 +02:00
|
|
|
*/
|
|
|
|
ii->ii_FuncOid = indexStruct->indproc;
|
|
|
|
|
|
|
|
if (OidIsValid(indexStruct->indproc))
|
|
|
|
{
|
|
|
|
ii->ii_NumIndexAttrs = 1;
|
|
|
|
/* Do a lookup on the function, too */
|
2001-03-22 05:01:46 +01:00
|
|
|
fmgr_info(indexStruct->indproc, &ii->ii_FuncInfo);
|
2000-07-15 00:18:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ii->ii_NumIndexAttrs = numKeys;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* If partial index, convert predicate into expression nodetree
|
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
|
|
|
if (VARSIZE(&indexStruct->indpred) > VARHDRSZ)
|
2000-07-15 00:18:02 +02:00
|
|
|
{
|
|
|
|
char *predString;
|
|
|
|
|
|
|
|
predString = DatumGetCString(DirectFunctionCall1(textout,
|
2001-03-22 05:01:46 +01:00
|
|
|
PointerGetDatum(&indexStruct->indpred)));
|
2000-07-15 00:18:02 +02:00
|
|
|
ii->ii_Predicate = stringToNode(predString);
|
|
|
|
pfree(predString);
|
|
|
|
}
|
|
|
|
else
|
2001-07-16 07:07:00 +02:00
|
|
|
ii->ii_Predicate = NIL;
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
/* Other info */
|
|
|
|
ii->ii_Unique = indexStruct->indisunique;
|
|
|
|
|
|
|
|
return ii;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* FormIndexDatum
|
2000-07-15 00:18:02 +02:00
|
|
|
* Construct Datum[] and nullv[] arrays for a new index tuple.
|
|
|
|
*
|
|
|
|
* indexInfo Info about the index
|
|
|
|
* heapTuple Heap tuple for which we must prepare an index entry
|
|
|
|
* heapDescriptor tupledesc for heap tuple
|
|
|
|
* resultCxt Temporary memory context for any palloc'd datums created
|
|
|
|
* datum Array of index Datums (output area)
|
|
|
|
* nullv Array of is-null indicators (output area)
|
|
|
|
*
|
|
|
|
* For largely historical reasons, we don't actually call index_formtuple()
|
|
|
|
* here, we just prepare its input arrays datum[] and nullv[].
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2000-07-15 00:18:02 +02:00
|
|
|
FormIndexDatum(IndexInfo *indexInfo,
|
1997-09-07 07:04:48 +02:00
|
|
|
HeapTuple heapTuple,
|
|
|
|
TupleDesc heapDescriptor,
|
2000-07-15 00:18:02 +02:00
|
|
|
MemoryContext resultCxt,
|
1997-09-08 23:56:23 +02:00
|
|
|
Datum *datum,
|
2000-07-15 00:18:02 +02:00
|
|
|
char *nullv)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-07-15 00:18:02 +02:00
|
|
|
MemoryContext oldContext;
|
|
|
|
int i;
|
|
|
|
Datum iDatum;
|
1997-09-08 04:41:22 +02:00
|
|
|
bool isNull;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
oldContext = MemoryContextSwitchTo(resultCxt);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
if (OidIsValid(indexInfo->ii_FuncOid))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Functional index --- compute the single index attribute
|
2000-07-15 00:18:02 +02:00
|
|
|
*/
|
2001-03-22 05:01:46 +01:00
|
|
|
FunctionCallInfoData fcinfo;
|
|
|
|
bool anynull = false;
|
1998-09-09 05:42:52 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
|
|
|
fcinfo.flinfo = &indexInfo->ii_FuncInfo;
|
|
|
|
fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
|
1998-08-28 06:57:21 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
|
|
|
|
{
|
|
|
|
fcinfo.arg[i] = heap_getattr(heapTuple,
|
|
|
|
indexInfo->ii_KeyAttrNumbers[i],
|
|
|
|
heapDescriptor,
|
|
|
|
&fcinfo.argnull[i]);
|
|
|
|
anynull |= fcinfo.argnull[i];
|
|
|
|
}
|
|
|
|
if (indexInfo->ii_FuncInfo.fn_strict && anynull)
|
|
|
|
{
|
|
|
|
/* force a null result for strict function */
|
|
|
|
iDatum = (Datum) 0;
|
|
|
|
isNull = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iDatum = FunctionCallInvoke(&fcinfo);
|
|
|
|
isNull = fcinfo.isnull;
|
|
|
|
}
|
|
|
|
datum[0] = iDatum;
|
|
|
|
nullv[0] = (isNull) ? 'n' : ' ';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Plain index --- for each attribute we need from the heap tuple,
|
|
|
|
* get the attribute and stick it into the datum and nullv arrays.
|
2000-07-15 00:18:02 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
|
|
|
{
|
|
|
|
iDatum = heap_getattr(heapTuple,
|
|
|
|
indexInfo->ii_KeyAttrNumbers[i],
|
|
|
|
heapDescriptor,
|
|
|
|
&isNull);
|
|
|
|
datum[i] = iDatum;
|
|
|
|
nullv[i] = (isNull) ? 'n' : ' ';
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldContext);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
/* --------------------------------------------
|
|
|
|
* Lock class info for update
|
|
|
|
* --------------------------------------------
|
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
static bool
|
|
|
|
LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
|
|
|
|
Buffer *buffer, bool confirmCommitted)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
|
|
|
HeapTuple classTuple;
|
|
|
|
bool test;
|
|
|
|
Relation relationRelation;
|
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* NOTE: get and hold RowExclusiveLock on pg_class, because caller
|
|
|
|
* will probably modify the rel's pg_class tuple later on.
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
|
|
|
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
2000-11-16 23:30:52 +01:00
|
|
|
classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(classTuple))
|
|
|
|
{
|
|
|
|
heap_close(relationRelation, NoLock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
rtup->t_self = classTuple->t_self;
|
|
|
|
ReleaseSysCache(classTuple);
|
|
|
|
|
2001-01-18 05:01:42 +01:00
|
|
|
while (1)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
ItemPointerData tidsave;
|
2001-01-18 05:01:42 +01:00
|
|
|
|
|
|
|
ItemPointerCopy(&(rtup->t_self), &tidsave);
|
|
|
|
test = heap_mark4update(relationRelation, rtup, buffer);
|
|
|
|
switch (test)
|
|
|
|
{
|
|
|
|
case HeapTupleSelfUpdated:
|
|
|
|
case HeapTupleMayBeUpdated:
|
|
|
|
break;
|
|
|
|
case HeapTupleUpdated:
|
|
|
|
ReleaseBuffer(*buffer);
|
|
|
|
if (!ItemPointerEquals(&(rtup->t_self), &tidsave))
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "LockClassinfoForUpdate couldn't lock relid %u", relid);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
RelationInvalidateHeapTuple(relationRelation, rtup);
|
|
|
|
if (confirmCommitted)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
HeapTupleHeader th = rtup->t_data;
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
|
|
|
|
elog(ERROR, "The tuple isn't committed");
|
|
|
|
if (th->t_infomask & HEAP_XMAX_COMMITTED)
|
|
|
|
if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE))
|
|
|
|
elog(ERROR, "The tuple is already deleted");
|
|
|
|
}
|
|
|
|
heap_close(relationRelation, NoLock);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------
|
|
|
|
* Indexes of the relation active ?
|
|
|
|
* ---------------------------------------------
|
|
|
|
*/
|
2000-04-12 19:17:23 +02:00
|
|
|
bool
|
|
|
|
IndexesAreActive(Oid relid, bool confirmCommitted)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
HeapTupleData tuple;
|
2000-02-18 10:30:20 +01:00
|
|
|
Relation indexRelation;
|
|
|
|
Buffer buffer;
|
2000-04-12 19:17:23 +02:00
|
|
|
HeapScanDesc scan;
|
|
|
|
ScanKeyData entry;
|
2000-02-18 10:30:20 +01:00
|
|
|
bool isactive;
|
|
|
|
|
|
|
|
if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
|
|
|
|
elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
|
2000-07-05 18:17:43 +02:00
|
|
|
if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
|
2001-03-22 05:01:46 +01:00
|
|
|
((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
|
2000-07-06 01:12:09 +02:00
|
|
|
elog(ERROR, "relation %u isn't an indexable relation", relid);
|
2000-02-18 10:30:20 +01:00
|
|
|
isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
|
|
|
|
ReleaseBuffer(buffer);
|
|
|
|
if (isactive)
|
|
|
|
return isactive;
|
|
|
|
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
|
|
|
|
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
|
2000-04-12 19:17:23 +02:00
|
|
|
F_OIDEQ, ObjectIdGetDatum(relid));
|
2000-02-18 10:30:20 +01:00
|
|
|
scan = heap_beginscan(indexRelation, false, SnapshotNow,
|
2000-04-12 19:17:23 +02:00
|
|
|
1, &entry);
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!heap_getnext(scan, 0))
|
|
|
|
isactive = true;
|
|
|
|
heap_endscan(scan);
|
2000-11-08 23:10:03 +01:00
|
|
|
heap_close(indexRelation, AccessShareLock);
|
2000-02-18 10:30:20 +01:00
|
|
|
return isactive;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
2000-11-08 23:10:03 +01:00
|
|
|
* set relhasindex of relation's pg_class entry
|
|
|
|
*
|
|
|
|
* NOTE: an important side-effect of this operation is that an SI invalidation
|
|
|
|
* message is sent out to all backends --- including me --- causing relcache
|
|
|
|
* entries to be flushed or updated with the new hasindex data.
|
|
|
|
* Therefore, we execute the update even if relhasindex has the right value
|
|
|
|
* already. Possible future improvement: skip the disk update and just send
|
|
|
|
* an SI message in that case.
|
2000-02-18 10:30:20 +01:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2000-11-08 23:10:03 +01:00
|
|
|
setRelhasindex(Oid relid, bool hasindex)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
|
|
|
Relation pg_class;
|
|
|
|
HeapTuple tuple;
|
2000-04-12 19:17:23 +02:00
|
|
|
HeapScanDesc pg_class_scan = NULL;
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
|
|
|
* Find the tuple to update in pg_class.
|
2000-02-18 10:30:20 +01:00
|
|
|
*/
|
|
|
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCacheCopy(RELOID,
|
|
|
|
ObjectIdGetDatum(relid),
|
|
|
|
0, 0, 0);
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScanKeyData key[1];
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&key[0], 0,
|
|
|
|
ObjectIdAttributeNumber,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(relid));
|
|
|
|
|
|
|
|
pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
|
|
|
|
tuple = heap_getnext(pg_class_scan, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
{
|
|
|
|
if (pg_class_scan)
|
|
|
|
heap_endscan(pg_class_scan);
|
|
|
|
heap_close(pg_class, RowExclusiveLock);
|
2000-11-08 23:10:03 +01:00
|
|
|
elog(ERROR, "setRelhasindex: cannot find relation %u in pg_class",
|
|
|
|
relid);
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Update hasindex in pg_class.
|
2000-02-18 10:30:20 +01:00
|
|
|
*/
|
2000-12-08 07:17:58 +01:00
|
|
|
if (pg_class_scan)
|
|
|
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
2000-11-08 23:10:03 +01:00
|
|
|
((Form_pg_class) GETSTRUCT(tuple))->relhasindex = hasindex;
|
2000-12-08 07:17:58 +01:00
|
|
|
if (pg_class_scan)
|
|
|
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
|
2000-11-08 23:10:03 +01:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
if (pg_class_scan)
|
|
|
|
{
|
2000-11-08 23:10:03 +01:00
|
|
|
/* Write the modified tuple in-place */
|
2000-02-18 10:30:20 +01:00
|
|
|
WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
|
2000-11-08 23:10:03 +01:00
|
|
|
/* Send out shared cache inval if necessary */
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
RelationInvalidateHeapTuple(pg_class, tuple);
|
2000-12-08 07:17:58 +01:00
|
|
|
BufferSync();
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_class, &tuple->t_self, tuple);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/* Keep the catalog indices up to date */
|
|
|
|
if (!IsIgnoringSystemIndexes())
|
|
|
|
{
|
|
|
|
Relation idescs[Num_pg_class_indices];
|
|
|
|
|
|
|
|
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
|
|
|
|
idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
|
|
|
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
|
|
|
}
|
|
|
|
}
|
2000-06-17 23:49:04 +02:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!pg_class_scan)
|
|
|
|
heap_freetuple(tuple);
|
|
|
|
else
|
|
|
|
heap_endscan(pg_class_scan);
|
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
heap_close(pg_class, RowExclusiveLock);
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
void
|
|
|
|
setNewRelfilenode(Relation relation)
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
Relation pg_class,
|
|
|
|
idescs[Num_pg_class_indices];
|
|
|
|
Oid newrelfilenode;
|
2000-12-08 07:17:58 +01:00
|
|
|
bool in_place_update = false;
|
2001-03-22 05:01:46 +01:00
|
|
|
HeapTupleData lockTupleData;
|
|
|
|
HeapTuple classTuple = NULL;
|
2000-12-08 07:17:58 +01:00
|
|
|
Buffer buffer;
|
2001-03-22 05:01:46 +01:00
|
|
|
RelationData workrel;
|
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
|
|
|
|
|
|
|
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
2001-03-22 05:01:46 +01:00
|
|
|
/* Fetch and lock the classTuple associated with this relation */
|
2000-12-08 07:17:58 +01:00
|
|
|
if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
|
|
|
|
elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
|
|
|
|
if (IsIgnoringSystemIndexes())
|
|
|
|
in_place_update = true;
|
|
|
|
/* Allocate a new relfilenode */
|
|
|
|
newrelfilenode = newoid();
|
|
|
|
/* update pg_class tuple with new relfilenode */
|
|
|
|
if (!in_place_update)
|
|
|
|
{
|
|
|
|
classTuple = heap_copytuple(&lockTupleData);
|
|
|
|
ReleaseBuffer(buffer);
|
|
|
|
((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_class, &classTuple->t_self, classTuple);
|
2000-12-08 07:17:58 +01:00
|
|
|
}
|
2001-01-24 01:36:17 +01:00
|
|
|
/* schedule unlinking old relfilenode */
|
2000-12-08 07:17:58 +01:00
|
|
|
smgrunlink(DEFAULT_SMGR, relation);
|
|
|
|
/* cleanup pg_internal.init if necessary */
|
|
|
|
if (relation->rd_isnailed)
|
|
|
|
unlink(RELCACHE_INIT_FILENAME);
|
|
|
|
/* create another storage file. Is it a little ugly ? */
|
|
|
|
memcpy((char *) &workrel, relation, sizeof(RelationData));
|
|
|
|
workrel.rd_node.relNode = newrelfilenode;
|
|
|
|
heap_storage_create(&workrel);
|
2001-01-18 08:29:04 +01:00
|
|
|
smgrclose(DEFAULT_SMGR, &workrel);
|
2000-12-08 07:17:58 +01:00
|
|
|
/* update pg_class tuple with new relfilenode in place */
|
|
|
|
if (in_place_update)
|
|
|
|
{
|
|
|
|
classTuple = &lockTupleData;
|
|
|
|
/* Send out shared cache inval if necessary */
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
RelationInvalidateHeapTuple(pg_class, classTuple);
|
|
|
|
/* Update the buffer in-place */
|
|
|
|
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
|
|
|
((Form_pg_class) GETSTRUCT(classTuple))->relfilenode = newrelfilenode;
|
|
|
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
|
|
|
WriteBuffer(buffer);
|
|
|
|
BufferSync();
|
|
|
|
}
|
|
|
|
/* Keep the catalog indices up to date */
|
|
|
|
if (!in_place_update && pg_class->rd_rel->relhasindex)
|
|
|
|
{
|
|
|
|
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
|
2001-03-22 05:01:46 +01:00
|
|
|
idescs);
|
2000-12-08 07:17:58 +01:00
|
|
|
CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
|
|
|
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
|
|
|
}
|
|
|
|
heap_close(pg_class, NoLock);
|
2001-01-18 08:29:04 +01:00
|
|
|
if (!in_place_update)
|
|
|
|
heap_freetuple(classTuple);
|
2000-12-08 07:17:58 +01:00
|
|
|
/* Make sure the relfilenode change */
|
|
|
|
CommandCounterIncrement();
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* UpdateStats
|
2001-05-07 02:43:27 +02:00
|
|
|
*
|
|
|
|
* Update pg_class' relpages and reltuples statistics for the given relation
|
|
|
|
* (which can be either a table or an index). Note that this is not used
|
|
|
|
* in the context of VACUUM.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2001-05-07 02:43:27 +02:00
|
|
|
UpdateStats(Oid relid, double reltuples)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation whichRel;
|
|
|
|
Relation pg_class;
|
1998-08-19 04:04:17 +02:00
|
|
|
HeapTuple tuple;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple newtup;
|
2001-06-28 01:31:40 +02:00
|
|
|
BlockNumber relpages;
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
|
|
|
Form_pg_class rd_rel;
|
|
|
|
Relation idescs[Num_pg_class_indices];
|
|
|
|
Datum values[Natts_pg_class];
|
|
|
|
char nulls[Natts_pg_class];
|
|
|
|
char replace[Natts_pg_class];
|
2000-04-12 19:17:23 +02:00
|
|
|
HeapScanDesc pg_class_scan = NULL;
|
2000-02-18 10:30:20 +01:00
|
|
|
bool in_place_upd;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This routine handles updates for both the heap and index relation
|
2001-03-22 07:16:21 +01:00
|
|
|
* statistics. In order to guarantee that we're able to *see* the
|
|
|
|
* index relation tuple, we bump the command counter id here. The
|
|
|
|
* index relation tuple was created in the current transaction.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* CommandCounterIncrement() flushes invalid cache entries, including
|
|
|
|
* those for the heap and index relations for which we're updating
|
|
|
|
* statistics. Now that the cache is flushed, it's safe to open the
|
|
|
|
* relation again. We need the relation open in order to figure out
|
|
|
|
* how many blocks it contains.
|
|
|
|
*/
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
/*
|
|
|
|
* Can't use heap_open here since we don't know if it's an index...
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
whichRel = RelationIdGetRelation(relid);
|
|
|
|
|
|
|
|
if (!RelationIsValid(whichRel))
|
1999-05-10 02:46:32 +02:00
|
|
|
elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/* Grab lock to be held till end of xact (probably redundant...) */
|
1999-09-18 21:08:25 +02:00
|
|
|
LockRelation(whichRel, ShareLock);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Find the RELATION relation tuple for the given relation.
|
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-01-18 05:01:42 +01:00
|
|
|
in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
|
2000-11-08 23:10:03 +01:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!in_place_upd)
|
1998-08-20 17:16:59 +02:00
|
|
|
{
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCacheCopy(RELOID,
|
|
|
|
ObjectIdGetDatum(relid),
|
|
|
|
0, 0, 0);
|
1998-08-20 17:16:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScanKeyData key[1];
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&key[0], 0,
|
1998-09-01 06:40:42 +02:00
|
|
|
ObjectIdAttributeNumber,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(relid));
|
1998-08-20 17:16:59 +02:00
|
|
|
|
|
|
|
pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
|
|
|
|
tuple = heap_getnext(pg_class_scan, 0);
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-02-18 10:30:20 +01:00
|
|
|
if (pg_class_scan)
|
1998-08-20 17:16:59 +02:00
|
|
|
heap_endscan(pg_class_scan);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_class, RowExclusiveLock);
|
2000-11-08 23:10:03 +01:00
|
|
|
elog(ERROR, "UpdateStats: cannot find relation %u in pg_class",
|
|
|
|
relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1999-05-27 00:57:39 +02:00
|
|
|
* Figure values to insert.
|
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* If we found zero tuples in the scan, do NOT believe it; instead put a
|
|
|
|
* bogus estimate into the statistics fields. Otherwise, the common
|
1999-05-27 00:57:39 +02:00
|
|
|
* pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
|
2001-03-22 07:16:21 +01:00
|
|
|
* with zero size statistics until a VACUUM is done. The optimizer
|
|
|
|
* will generate very bad plans if the stats claim the table is empty
|
|
|
|
* when it is actually sizable. See also CREATE TABLE in heap.c.
|
2001-05-07 02:43:27 +02:00
|
|
|
*
|
|
|
|
* Note: this path is also taken during bootstrap, because bootstrap.c
|
|
|
|
* passes reltuples = 0 after loading a table. We have to estimate some
|
|
|
|
* number for reltuples based on the actual number of pages.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
relpages = RelationGetNumberOfBlocks(whichRel);
|
|
|
|
|
1999-05-27 00:57:39 +02:00
|
|
|
if (reltuples == 0)
|
|
|
|
{
|
|
|
|
if (relpages == 0)
|
|
|
|
{
|
|
|
|
/* Bogus defaults for a virgin table, same as heap.c */
|
|
|
|
reltuples = 1000;
|
|
|
|
relpages = 10;
|
|
|
|
}
|
|
|
|
else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
|
|
|
|
{
|
|
|
|
/* Empty index, leave bogus defaults in place */
|
|
|
|
reltuples = 1000;
|
|
|
|
}
|
|
|
|
else
|
2001-06-28 01:31:40 +02:00
|
|
|
reltuples = (double) relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
|
1999-05-27 00:57:39 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* We shouldn't have to do this, but we do... Modify the reldesc in
|
|
|
|
* place with the new values so that the cache contains the latest
|
|
|
|
* copy.
|
|
|
|
*/
|
2001-06-28 01:31:40 +02:00
|
|
|
whichRel->rd_rel->relpages = (int32) relpages;
|
1997-09-07 07:04:48 +02:00
|
|
|
whichRel->rd_rel->reltuples = reltuples;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Update statistics in pg_class.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-02-18 10:30:20 +01:00
|
|
|
if (in_place_upd)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* At bootstrap time, we don't need to worry about concurrency or
|
2001-03-22 05:01:46 +01:00
|
|
|
* visibility of changes, so we cheat. Also cheat if REINDEX.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
2000-12-08 07:17:58 +01:00
|
|
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
2001-06-28 01:31:40 +02:00
|
|
|
rd_rel->relpages = (int32) relpages;
|
1997-09-07 07:04:48 +02:00
|
|
|
rd_rel->reltuples = reltuples;
|
2000-12-08 07:17:58 +01:00
|
|
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
|
1999-09-24 02:25:33 +02:00
|
|
|
WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);
|
2000-11-08 23:10:03 +01:00
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
RelationInvalidateHeapTuple(pg_class, tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-27 00:57:39 +02:00
|
|
|
/* During normal processing, must work harder. */
|
|
|
|
|
|
|
|
for (i = 0; i < Natts_pg_class; i++)
|
|
|
|
{
|
2001-05-07 02:43:27 +02:00
|
|
|
nulls[i] = ' ';
|
1999-05-27 00:57:39 +02:00
|
|
|
replace[i] = ' ';
|
|
|
|
values[i] = (Datum) NULL;
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
replace[Anum_pg_class_relpages - 1] = 'r';
|
2001-06-28 01:31:40 +02:00
|
|
|
values[Anum_pg_class_relpages - 1] = Int32GetDatum((int32) relpages);
|
1997-09-07 07:04:48 +02:00
|
|
|
replace[Anum_pg_class_reltuples - 1] = 'r';
|
2001-05-07 02:43:27 +02:00
|
|
|
values[Anum_pg_class_reltuples - 1] = Float4GetDatum((float4) reltuples);
|
1998-08-19 04:04:17 +02:00
|
|
|
newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_class, &tuple->t_self, newtup);
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!IsIgnoringSystemIndexes())
|
|
|
|
{
|
|
|
|
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
|
|
|
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
|
|
|
}
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(newtup);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!pg_class_scan)
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
1998-08-20 17:16:59 +02:00
|
|
|
else
|
|
|
|
heap_endscan(pg_class_scan);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_class, RowExclusiveLock);
|
|
|
|
/* Cheating a little bit since we didn't open it with heap_open... */
|
2000-11-08 23:10:03 +01:00
|
|
|
heap_close(whichRel, NoLock);
|
1996-07-09 08:22:35 +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
|
|
|
/*
|
|
|
|
* index_build - invoke access-method-specific index build procedure
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_build(Relation heapRelation,
|
|
|
|
Relation indexRelation,
|
|
|
|
IndexInfo *indexInfo)
|
|
|
|
{
|
|
|
|
RegProcedure procedure;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sanity checks
|
|
|
|
*/
|
|
|
|
Assert(RelationIsValid(indexRelation));
|
|
|
|
Assert(PointerIsValid(indexRelation->rd_am));
|
|
|
|
|
|
|
|
procedure = indexRelation->rd_am->ambuild;
|
|
|
|
Assert(RegProcedureIsValid(procedure));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call the access method's build procedure
|
|
|
|
*/
|
|
|
|
OidFunctionCall3(procedure,
|
|
|
|
PointerGetDatum(heapRelation),
|
|
|
|
PointerGetDatum(indexRelation),
|
|
|
|
PointerGetDatum(indexInfo));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IndexBuildHeapScan - scan the heap relation to find tuples to be indexed
|
2000-06-18 01:41:51 +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
|
|
|
* This is called back from an access-method-specific index build procedure
|
|
|
|
* after the AM has done whatever setup it needs. The parent heap relation
|
|
|
|
* is scanned to find tuples that should be entered into the index. Each
|
|
|
|
* such tuple is passed to the AM's callback routine, which does the right
|
|
|
|
* things to add it to the new index. After we return, the AM's index
|
|
|
|
* build procedure does whatever cleanup is needed; in particular, it should
|
|
|
|
* close the heap and index relations.
|
2000-06-18 01:41:51 +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
|
|
|
* The total count of heap tuples is returned. This is for updating pg_class
|
|
|
|
* statistics. (It's annoying not to be able to do that here, but we can't
|
|
|
|
* do it until after the relation is closed.) Note that the index AM itself
|
|
|
|
* must keep track of the number of index tuples; we don't do so here because
|
|
|
|
* the AM might reject some of the tuples for its own reasons, such as being
|
|
|
|
* unable to store NULLs.
|
1996-07-09 08:22:35 +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
|
|
|
double
|
|
|
|
IndexBuildHeapScan(Relation heapRelation,
|
|
|
|
Relation indexRelation,
|
|
|
|
IndexInfo *indexInfo,
|
|
|
|
IndexBuildCallback callback,
|
|
|
|
void *callback_state)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapScanDesc scan;
|
|
|
|
HeapTuple heapTuple;
|
|
|
|
TupleDesc heapDescriptor;
|
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
|
|
|
Datum attdata[INDEX_MAX_KEYS];
|
|
|
|
char nulls[INDEX_MAX_KEYS];
|
|
|
|
double reltuples;
|
2001-07-16 07:07:00 +02:00
|
|
|
List *predicate = indexInfo->ii_Predicate;
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleTable tupleTable;
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleTableSlot *slot;
|
2000-07-15 00:18:02 +02:00
|
|
|
ExprContext *econtext;
|
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
|
|
|
Snapshot snapshot;
|
|
|
|
TransactionId XmaxRecent;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01: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
|
|
|
* sanity checks
|
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
|
|
|
Assert(OidIsValid(indexRelation->rd_rel->relam));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
heapDescriptor = RelationGetDescr(heapRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is a predicate (partial) index, we will need to evaluate
|
|
|
|
* the predicate using ExecQual, which requires the current tuple to
|
|
|
|
* be in a slot of a TupleTable. In addition, ExecQual must have an
|
|
|
|
* ExprContext referring to that slot. Here, we initialize dummy
|
2000-07-15 00:18:02 +02:00
|
|
|
* TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
|
|
|
|
*
|
|
|
|
* We construct the ExprContext anyway since we need a per-tuple
|
|
|
|
* temporary memory context for function evaluation -- tgl July 00
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-07-16 07:07:00 +02:00
|
|
|
if (predicate != NIL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
tupleTable = ExecCreateTupleTable(1);
|
|
|
|
slot = ExecAllocTableSlot(tupleTable);
|
2001-01-29 01:39:20 +01:00
|
|
|
ExecSetSlotDescriptor(slot, heapDescriptor, false);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-11-08 01:46:14 +01:00
|
|
|
else
|
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
tupleTable = NULL;
|
1996-11-08 01:46:14 +01:00
|
|
|
slot = NULL;
|
|
|
|
}
|
2000-07-15 00:18:02 +02:00
|
|
|
econtext = MakeExprContext(slot, TransactionCommandContext);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01: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
|
|
|
* Ok, begin our scan of the base relation. We use SnapshotAny
|
|
|
|
* because we must retrieve all tuples and do our own time qual checks.
|
1996-07-09 08:22:35 +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
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
snapshot = SnapshotNow;
|
|
|
|
XmaxRecent = InvalidTransactionId;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snapshot = SnapshotAny;
|
|
|
|
GetXmaxRecent(&XmaxRecent);
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
scan = heap_beginscan(heapRelation, /* relation */
|
|
|
|
0, /* start at end */
|
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
|
|
|
snapshot, /* seeself */
|
1997-09-07 07:04:48 +02:00
|
|
|
0, /* number of keys */
|
|
|
|
(ScanKey) NULL); /* scan key */
|
|
|
|
|
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
|
|
|
reltuples = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01: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
|
|
|
* Scan all tuples in the base relation.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
|
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
|
|
|
bool tupleIsAlive;
|
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
|
|
|
if (snapshot == SnapshotAny)
|
|
|
|
{
|
|
|
|
/* do our own time qual check */
|
|
|
|
bool indexIt;
|
|
|
|
uint16 sv_infomask;
|
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
|
|
|
/*
|
|
|
|
* HeapTupleSatisfiesVacuum may update tuple's hint status bits.
|
|
|
|
* We could possibly get away with not locking the buffer here,
|
|
|
|
* since caller should hold ShareLock on the relation, but let's
|
|
|
|
* be conservative about it.
|
|
|
|
*/
|
|
|
|
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
|
|
|
|
sv_infomask = heapTuple->t_data->t_infomask;
|
2001-03-22 05:01:46 +01: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
|
|
|
switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, XmaxRecent))
|
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
|
|
|
case HEAPTUPLE_DEAD:
|
|
|
|
indexIt = false;
|
|
|
|
tupleIsAlive = false;
|
|
|
|
break;
|
|
|
|
case HEAPTUPLE_LIVE:
|
|
|
|
indexIt = true;
|
|
|
|
tupleIsAlive = true;
|
|
|
|
break;
|
|
|
|
case HEAPTUPLE_RECENTLY_DEAD:
|
|
|
|
/*
|
|
|
|
* If tuple is recently deleted then we must index it
|
|
|
|
* anyway to keep VACUUM from complaining.
|
|
|
|
*/
|
|
|
|
indexIt = true;
|
|
|
|
tupleIsAlive = false;
|
|
|
|
break;
|
|
|
|
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
|
|
|
/*
|
|
|
|
* This should not happen, if caller holds ShareLock on
|
|
|
|
* the parent relation.
|
|
|
|
*/
|
|
|
|
elog(ERROR, "IndexBuildHeapScan: concurrent insert in progress");
|
|
|
|
indexIt = tupleIsAlive = false; /* keep compiler quiet */
|
|
|
|
break;
|
|
|
|
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
|
|
|
/*
|
|
|
|
* This should not happen, if caller holds ShareLock on
|
|
|
|
* the parent relation.
|
|
|
|
*/
|
|
|
|
elog(ERROR, "IndexBuildHeapScan: concurrent delete in progress");
|
|
|
|
indexIt = tupleIsAlive = false; /* keep compiler quiet */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "Unexpected HeapTupleSatisfiesVacuum result");
|
|
|
|
indexIt = tupleIsAlive = false; /* keep compiler quiet */
|
|
|
|
break;
|
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
|
|
|
|
|
|
|
/* check for hint-bit update by HeapTupleSatisfiesVacuum */
|
|
|
|
if (sv_infomask != heapTuple->t_data->t_infomask)
|
|
|
|
SetBufferCommitInfoNeedsSave(scan->rs_cbuf);
|
|
|
|
|
|
|
|
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
|
|
|
|
|
|
|
|
if (! indexIt)
|
|
|
|
continue;
|
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
|
|
|
else
|
|
|
|
{
|
|
|
|
/* heap_getnext did the time qual check */
|
|
|
|
tupleIsAlive = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
reltuples += 1;
|
|
|
|
|
|
|
|
MemoryContextReset(econtext->ecxt_per_tuple_memory);
|
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
|
|
|
* In a partial index, discard tuples that don't satisfy the
|
|
|
|
* predicate. We can also discard recently-dead tuples, since
|
|
|
|
* VACUUM doesn't complain about tuple count mismatch for partial
|
|
|
|
* indexes.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-07-16 07:07:00 +02:00
|
|
|
if (predicate != NIL)
|
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
|
|
|
if (! tupleIsAlive)
|
|
|
|
continue;
|
|
|
|
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
|
2001-07-16 07:07:00 +02:00
|
|
|
if (!ExecQual(predicate, econtext, false))
|
1997-09-07 07:04:48 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01: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
|
|
|
* For the current heap tuple, extract all the attributes we use
|
|
|
|
* in this index, and note which are null. This also performs
|
|
|
|
* evaluation of the function, if this is a functional index.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
FormIndexDatum(indexInfo,
|
|
|
|
heapTuple,
|
|
|
|
heapDescriptor,
|
|
|
|
econtext->ecxt_per_tuple_memory,
|
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
|
|
|
attdata,
|
|
|
|
nulls);
|
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
|
|
|
/*
|
|
|
|
* You'd think we should go ahead and build the index tuple here,
|
|
|
|
* but some index AMs want to do further processing on the
|
|
|
|
* data first. So pass the attdata and nulls arrays, instead.
|
|
|
|
*/
|
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
|
|
|
/* Call the AM's callback routine to process the tuple */
|
|
|
|
callback(indexRelation, heapTuple, attdata, nulls, tupleIsAlive,
|
|
|
|
callback_state);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
heap_endscan(scan);
|
|
|
|
|
2001-07-16 07:07:00 +02:00
|
|
|
if (predicate != NIL)
|
1999-12-10 04:56:14 +01:00
|
|
|
ExecDropTupleTable(tupleTable, true);
|
2000-07-15 00:18:02 +02:00
|
|
|
FreeExprContext(econtext);
|
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
|
|
|
return reltuples;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-21 21:01:10 +01:00
|
|
|
/*
|
|
|
|
* IndexGetRelation: given an index's relation OID, get the OID of the
|
2000-04-12 19:17:23 +02:00
|
|
|
* relation it is an index on. Uses the system cache.
|
1999-11-21 21:01:10 +01:00
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
IndexGetRelation(Oid indexId)
|
|
|
|
{
|
|
|
|
HeapTuple tuple;
|
|
|
|
Form_pg_index index;
|
2000-11-16 23:30:52 +01:00
|
|
|
Oid result;
|
1999-11-21 21:01:10 +01:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCache(INDEXRELID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
1999-11-21 21:01:10 +01:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "IndexGetRelation: can't find index id %u",
|
|
|
|
indexId);
|
|
|
|
index = (Form_pg_index) GETSTRUCT(tuple);
|
|
|
|
Assert(index->indexrelid == indexId);
|
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
result = index->indrelid;
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
return result;
|
1999-11-21 21:01:10 +01:00
|
|
|
}
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
/* ---------------------------------
|
|
|
|
* activate_index -- activate/deactivate the specified index.
|
2000-07-15 00:18:02 +02:00
|
|
|
* Note that currently PostgreSQL doesn't hold the
|
2000-02-18 10:30:20 +01:00
|
|
|
* status per index
|
|
|
|
* ---------------------------------
|
|
|
|
*/
|
2000-06-09 00:38:00 +02:00
|
|
|
static bool
|
2000-12-08 07:17:58 +01:00
|
|
|
activate_index(Oid indexId, bool activate, bool inplace)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
if (!activate) /* Currently does nothing */
|
2000-02-18 10:30:20 +01:00
|
|
|
return true;
|
2000-12-08 07:17:58 +01:00
|
|
|
return reindex_index(indexId, false, inplace);
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
/* --------------------------------
|
|
|
|
* reindex_index - This routine is used to recreate an index
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
bool
|
2000-12-08 07:17:58 +01:00
|
|
|
reindex_index(Oid indexId, bool force, bool inplace)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
Relation iRel,
|
|
|
|
indexRelation,
|
|
|
|
heapRelation;
|
|
|
|
ScanKeyData entry;
|
|
|
|
HeapScanDesc scan;
|
|
|
|
HeapTuple indexTuple,
|
|
|
|
classTuple;
|
2000-07-15 00:18:02 +02:00
|
|
|
IndexInfo *indexInfo;
|
2000-04-12 19:17:23 +02:00
|
|
|
Oid heapId,
|
|
|
|
accessMethodId;
|
2000-02-18 10:30:20 +01:00
|
|
|
bool old;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* REINDEX within a transaction block is dangerous, because if the
|
|
|
|
* transaction is later rolled back we have no way to undo truncation
|
|
|
|
* of the index's physical file. Disallow it.
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
|
|
|
if (IsTransactionBlock())
|
|
|
|
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
old = SetReindexProcessing(true);
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
/* Scan pg_index to find the index's pg_index entry */
|
2000-02-18 10:30:20 +01:00
|
|
|
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
|
|
|
|
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(indexId));
|
|
|
|
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
|
|
|
|
indexTuple = heap_getnext(scan, 0);
|
|
|
|
if (!HeapTupleIsValid(indexTuple))
|
2000-07-15 00:18:02 +02:00
|
|
|
elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
/* Get OID of index's parent table */
|
|
|
|
heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
|
|
|
|
/* Fetch info needed for index_build */
|
|
|
|
indexInfo = BuildIndexInfo(indexTuple);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
/* Complete the scan and close pg_index */
|
|
|
|
heap_endscan(scan);
|
|
|
|
heap_close(indexRelation, AccessShareLock);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
|
|
|
/* Fetch the classTuple associated with this index */
|
2000-11-16 23:30:52 +01:00
|
|
|
classTuple = SearchSysCache(RELOID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
2000-02-18 10:30:20 +01:00
|
|
|
if (!HeapTupleIsValid(classTuple))
|
2000-07-15 00:18:02 +02:00
|
|
|
elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
|
2000-02-18 10:30:20 +01:00
|
|
|
accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(classTuple);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
|
|
|
/* Open our index relation */
|
|
|
|
heapRelation = heap_open(heapId, ExclusiveLock);
|
|
|
|
if (heapRelation == NULL)
|
|
|
|
elog(ERROR, "reindex_index: can't open heap relation");
|
2000-07-15 00:18:02 +02:00
|
|
|
iRel = index_open(indexId);
|
|
|
|
if (iRel == NULL)
|
|
|
|
elog(ERROR, "reindex_index: can't open index relation");
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
if (!inplace)
|
2001-03-22 05:01:46 +01:00
|
|
|
{
|
2001-06-12 07:55:50 +02:00
|
|
|
inplace = iRel->rd_rel->relisshared;
|
2001-02-23 10:26:14 +01:00
|
|
|
if (!inplace)
|
|
|
|
setNewRelfilenode(iRel);
|
|
|
|
}
|
2000-02-18 10:30:20 +01:00
|
|
|
/* Obtain exclusive lock on it, just to be sure */
|
|
|
|
LockRelation(iRel, AccessExclusiveLock);
|
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
if (inplace)
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* Release any buffers associated with this index. If they're
|
|
|
|
* dirty, they're just dropped without bothering to flush to disk.
|
|
|
|
*/
|
2000-12-08 07:17:58 +01:00
|
|
|
DropRelationBuffers(iRel);
|
|
|
|
|
|
|
|
/* Now truncate the actual data and set blocks to zero */
|
|
|
|
smgrtruncate(DEFAULT_SMGR, iRel, 0);
|
|
|
|
iRel->rd_nblocks = 0;
|
2001-06-28 01:31:40 +02:00
|
|
|
iRel->rd_targblock = InvalidBlockNumber;
|
2000-12-08 07:17:58 +01:00
|
|
|
}
|
2000-02-18 10:30:20 +01:00
|
|
|
|
|
|
|
/* Initialize the index and rebuild */
|
2000-07-15 00:18:02 +02:00
|
|
|
InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
|
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
|
|
|
index_build(heapRelation, iRel, indexInfo);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
* index_build will close both the heap and index relations (but not
|
2001-03-22 05:01:46 +01:00
|
|
|
* give up the locks we hold on them). So we're done.
|
2000-02-18 10:30:20 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
SetReindexProcessing(old);
|
2000-07-15 00:18:02 +02:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ----------------------------
|
2000-04-12 19:17:23 +02:00
|
|
|
* activate_indexes_of_a_table
|
2000-02-18 10:30:20 +01:00
|
|
|
* activate/deactivate indexes of the specified table.
|
|
|
|
* ----------------------------
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
activate_indexes_of_a_table(Oid relid, bool activate)
|
|
|
|
{
|
|
|
|
if (IndexesAreActive(relid, true))
|
|
|
|
{
|
|
|
|
if (!activate)
|
2000-11-08 23:10:03 +01:00
|
|
|
setRelhasindex(relid, false);
|
2000-02-18 10:30:20 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (activate)
|
|
|
|
reindex_relation(relid, false);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
/* --------------------------------
|
|
|
|
* reindex_relation - This routine is used to recreate indexes
|
|
|
|
* of a relation.
|
|
|
|
* --------------------------------
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
reindex_relation(Oid relid, bool force)
|
|
|
|
{
|
|
|
|
Relation indexRelation;
|
2000-04-12 19:17:23 +02:00
|
|
|
ScanKeyData entry;
|
|
|
|
HeapScanDesc scan;
|
2000-02-18 10:30:20 +01:00
|
|
|
HeapTuple indexTuple;
|
2000-04-12 19:17:23 +02:00
|
|
|
bool old,
|
|
|
|
reindexed;
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
bool deactivate_needed,
|
|
|
|
overwrite,
|
|
|
|
upd_pg_class_inplace;
|
|
|
|
|
|
|
|
Relation rel;
|
|
|
|
|
|
|
|
overwrite = upd_pg_class_inplace = deactivate_needed = false;
|
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* avoid heap_update() pg_class tuples while processing reindex for
|
|
|
|
* pg_class.
|
|
|
|
*/
|
2000-12-08 07:17:58 +01:00
|
|
|
if (IsIgnoringSystemIndexes())
|
|
|
|
upd_pg_class_inplace = true;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
/*
|
|
|
|
* ignore the indexes of the target system relation while processing
|
|
|
|
* reindex.
|
2001-03-22 05:01:46 +01:00
|
|
|
*/
|
2000-12-08 07:17:58 +01:00
|
|
|
rel = RelationIdGetRelation(relid);
|
|
|
|
if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
|
|
|
|
deactivate_needed = true;
|
2001-03-22 05:01:46 +01:00
|
|
|
#ifndef ENABLE_REINDEX_NAILED_RELATIONS
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nailed relations are never updated. We couldn't keep the
|
|
|
|
* consistency between the relation descriptors and pg_class tuples.
|
|
|
|
*/
|
2000-12-08 07:17:58 +01:00
|
|
|
if (rel->rd_isnailed)
|
|
|
|
{
|
|
|
|
if (IsIgnoringSystemIndexes())
|
|
|
|
{
|
|
|
|
overwrite = true;
|
|
|
|
deactivate_needed = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "the target relation %u is nailed", relid);
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
|
|
|
|
2001-02-23 10:26:14 +01:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* Shared system indexes must be overwritten because it's impossible
|
|
|
|
* to update pg_class tuples of all databases.
|
2001-02-23 10:26:14 +01:00
|
|
|
*/
|
2001-06-12 07:55:50 +02:00
|
|
|
if (rel->rd_rel->relisshared)
|
2001-02-23 10:26:14 +01:00
|
|
|
{
|
|
|
|
if (IsIgnoringSystemIndexes())
|
|
|
|
{
|
|
|
|
overwrite = true;
|
|
|
|
deactivate_needed = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "the target relation %u is shared", relid);
|
|
|
|
}
|
2000-12-08 07:17:58 +01:00
|
|
|
RelationClose(rel);
|
2001-05-30 22:52:34 +02:00
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
old = SetReindexProcessing(true);
|
2000-12-08 07:17:58 +01:00
|
|
|
if (deactivate_needed)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-12-08 07:17:58 +01:00
|
|
|
if (IndexesAreActive(relid, upd_pg_class_inplace))
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
2000-12-08 07:17:58 +01:00
|
|
|
if (!force)
|
|
|
|
{
|
|
|
|
SetReindexProcessing(old);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
activate_indexes_of_a_table(relid, false);
|
|
|
|
CommandCounterIncrement();
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
indexRelation = heap_openr(IndexRelationName, AccessShareLock);
|
|
|
|
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid,
|
2000-04-12 19:17:23 +02:00
|
|
|
F_OIDEQ, ObjectIdGetDatum(relid));
|
2000-02-18 10:30:20 +01:00
|
|
|
scan = heap_beginscan(indexRelation, false, SnapshotNow,
|
2000-04-12 19:17:23 +02:00
|
|
|
1, &entry);
|
2000-02-18 10:30:20 +01:00
|
|
|
reindexed = false;
|
|
|
|
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
|
|
|
|
|
2000-12-08 07:17:58 +01:00
|
|
|
if (activate_index(index->indexrelid, true, overwrite))
|
2000-02-18 10:30:20 +01:00
|
|
|
reindexed = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reindexed = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
heap_endscan(scan);
|
|
|
|
heap_close(indexRelation, AccessShareLock);
|
|
|
|
if (reindexed)
|
2001-05-19 00:35:51 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Ok,we could use the reindexed indexes of the target system
|
|
|
|
* relation now.
|
|
|
|
*/
|
2000-12-08 07:17:58 +01:00
|
|
|
if (deactivate_needed)
|
|
|
|
{
|
|
|
|
if (!overwrite && relid == RelOid_pg_class)
|
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For pg_class, relhasindex should be set to true here in
|
|
|
|
* place.
|
2000-12-08 07:17:58 +01:00
|
|
|
*/
|
|
|
|
setRelhasindex(relid, true);
|
|
|
|
CommandCounterIncrement();
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* However the following setRelhasindex() is needed to
|
|
|
|
* keep consistency with WAL.
|
2000-12-08 07:17:58 +01:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
setRelhasindex(relid, true);
|
|
|
|
}
|
|
|
|
}
|
2000-02-18 10:30:20 +01:00
|
|
|
SetReindexProcessing(old);
|
2000-12-08 07:17:58 +01:00
|
|
|
|
2000-03-01 06:39:24 +01:00
|
|
|
return reindexed;
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|