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
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, 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
|
2002-07-14 23:08:08 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.183 2002/07/14 21:08:08 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"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/dependency.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "catalog/heap.h"
|
|
|
|
#include "catalog/index.h"
|
|
|
|
#include "catalog/indexing.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/pg_constraint.h"
|
2000-06-15 05:33:12 +02:00
|
|
|
#include "catalog/pg_index.h"
|
2001-08-22 20:24:26 +02:00
|
|
|
#include "catalog/pg_opclass.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#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"
|
2002-03-26 20:17:02 +01:00
|
|
|
#include "utils/lsyscache.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "utils/relcache.h"
|
|
|
|
#include "utils/syscache.h"
|
1996-11-05 12:57:55 +01:00
|
|
|
|
2002-03-26 20:17:02 +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 */
|
2001-08-22 20:24:26 +02:00
|
|
|
static TupleDesc BuildFuncTupleDesc(Oid funcOid,
|
2001-10-25 07:50:21 +02:00
|
|
|
Oid *classObjectId);
|
2001-01-24 01:06:07 +01:00
|
|
|
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
|
2001-10-25 07:50:21 +02:00
|
|
|
int numatts, AttrNumber *attNums,
|
|
|
|
Oid *classObjectId);
|
2002-03-31 08:26:32 +02:00
|
|
|
static void UpdateRelationRelation(Relation indexRelation);
|
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-10-25 07:50:21 +02:00
|
|
|
IndexInfo *indexInfo,
|
|
|
|
Oid *classOids,
|
|
|
|
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
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static TupleDesc
|
2001-08-22 20:24:26 +02:00
|
|
|
BuildFuncTupleDesc(Oid funcOid,
|
|
|
|
Oid *classObjectId)
|
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;
|
2001-08-22 20:24:26 +02:00
|
|
|
Oid keyType;
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid retType;
|
2001-08-22 20:24:26 +02:00
|
|
|
Form_pg_type typeTup;
|
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
|
|
|
/*
|
2001-08-22 20:24:26 +02:00
|
|
|
* Check the opclass to see if it provides a keytype (overriding the
|
|
|
|
* function result type).
|
|
|
|
*/
|
|
|
|
tuple = SearchSysCache(CLAOID,
|
|
|
|
ObjectIdGetDatum(classObjectId[0]),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "Opclass %u does not exist", classObjectId[0]);
|
|
|
|
keyType = ((Form_pg_opclass) GETSTRUCT(tuple))->opckeytype;
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
if (!OidIsValid(keyType))
|
|
|
|
keyType = retType;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lookup the key 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,
|
2001-08-22 20:24:26 +02:00
|
|
|
ObjectIdGetDatum(keyType),
|
2000-11-16 23:30:52 +01:00
|
|
|
0, 0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2001-08-22 20:24:26 +02:00
|
|
|
elog(ERROR, "Type %u does not exist", keyType);
|
|
|
|
typeTup = (Form_pg_type) GETSTRUCT(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assign some of the attributes values. Leave the rest as 0.
|
|
|
|
*/
|
|
|
|
funcTupDesc->attrs[0]->attnum = 1;
|
2001-08-22 20:24:26 +02:00
|
|
|
funcTupDesc->attrs[0]->atttypid = keyType;
|
|
|
|
funcTupDesc->attrs[0]->attlen = typeTup->typlen;
|
|
|
|
funcTupDesc->attrs[0]->attbyval = typeTup->typbyval;
|
1998-02-07 22:41:52 +01:00
|
|
|
funcTupDesc->attrs[0]->attcacheoff = -1;
|
|
|
|
funcTupDesc->attrs[0]->atttypmod = -1;
|
2001-08-22 20:24:26 +02:00
|
|
|
funcTupDesc->attrs[0]->attstorage = typeTup->typstorage;
|
|
|
|
funcTupDesc->attrs[0]->attalign = typeTup->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,
|
2001-08-22 20:24:26 +02:00
|
|
|
AttrNumber *attNums,
|
|
|
|
Oid *classObjectId)
|
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;
|
2001-08-22 20:24:26 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
Oid keyType;
|
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-08-10 20:57:42 +02:00
|
|
|
from = SystemAttributeDefinition(atnum,
|
2001-10-25 07:50:21 +02:00
|
|
|
heapRelation->rd_rel->relhasoids);
|
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)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "cannot create index: column %d does not exist",
|
2001-01-24 01:06:07 +01:00
|
|
|
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;
|
2001-08-22 20:24:26 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the opclass to see if it provides a keytype (overriding
|
|
|
|
* the attribute type).
|
|
|
|
*/
|
|
|
|
tuple = SearchSysCache(CLAOID,
|
|
|
|
ObjectIdGetDatum(classObjectId[i]),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "Opclass %u does not exist", classObjectId[i]);
|
|
|
|
keyType = ((Form_pg_opclass) GETSTRUCT(tuple))->opckeytype;
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
if (OidIsValid(keyType) && keyType != to->atttypid)
|
|
|
|
{
|
|
|
|
/* index value and heap value have different types */
|
|
|
|
Form_pg_type typeTup;
|
|
|
|
|
|
|
|
tuple = SearchSysCache(TYPEOID,
|
|
|
|
ObjectIdGetDatum(keyType),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "Type %u does not exist", keyType);
|
|
|
|
typeTup = (Form_pg_type) GETSTRUCT(tuple);
|
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
to->atttypid = keyType;
|
|
|
|
to->atttypmod = -1;
|
|
|
|
to->attlen = typeTup->typlen;
|
|
|
|
to->attbyval = typeTup->typbyval;
|
|
|
|
to->attalign = typeTup->typalign;
|
2001-08-22 20:24:26 +02:00
|
|
|
to->attstorage = typeTup->typstorage;
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return indexTupDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* UpdateRelationRelation
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2002-03-26 20:17:02 +01:00
|
|
|
static void
|
2002-03-31 08:26:32 +02:00
|
|
|
UpdateRelationRelation(Relation indexRelation)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_class;
|
|
|
|
HeapTuple tuple;
|
|
|
|
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
|
|
|
/*
|
2002-03-26 20:17:02 +01:00
|
|
|
* the new tuple must have the oid already chosen 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);
|
2002-05-22 00:05:55 +02:00
|
|
|
simple_heap_insert(pg_class, tuple);
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* 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-10-25 07:50:21 +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-10-25 07:50:21 +02:00
|
|
|
Assert(indexTupDesc->attrs[i]->attnum == i + 1);
|
2001-06-12 07:55:50 +02:00
|
|
|
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
|
|
|
|
2002-05-22 00:05:55 +02:00
|
|
|
simple_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,
|
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-10-25 07:50:21 +02:00
|
|
|
indexForm->indisclustered = false; /* not used */
|
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
|
|
|
*/
|
2002-05-22 00:05:55 +02:00
|
|
|
simple_heap_insert(pg_index, tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* index_create
|
2001-08-10 20:57:42 +02:00
|
|
|
*
|
|
|
|
* Returns OID of the created index.
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2001-08-10 20:57:42 +02:00
|
|
|
Oid
|
2002-03-26 20:17:02 +01:00
|
|
|
index_create(Oid heapRelationId,
|
2002-03-31 08:26:32 +02:00
|
|
|
const 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,
|
2000-07-04 08:11:54 +02:00
|
|
|
bool primary,
|
2002-07-12 20:43:19 +02:00
|
|
|
bool isconstraint,
|
2000-07-04 08:11:54 +02:00
|
|
|
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;
|
2002-04-27 23:24:34 +02:00
|
|
|
bool shared_relation;
|
2002-03-26 20:17:02 +01:00
|
|
|
Oid namespaceId;
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid indexoid;
|
2002-07-12 20:43:19 +02:00
|
|
|
int i;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
SetReindexProcessing(false);
|
|
|
|
|
2002-03-26 20:17:02 +01:00
|
|
|
/*
|
|
|
|
* Only SELECT ... FOR UPDATE are allowed while doing this
|
|
|
|
*/
|
|
|
|
heapRelation = heap_open(heapRelationId, ShareLock);
|
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
/*
|
|
|
|
* The index will be in the same namespace as its parent table,
|
|
|
|
* and is shared across databases if and only if the parent is.
|
|
|
|
*/
|
2002-03-26 20:17:02 +01:00
|
|
|
namespaceId = RelationGetNamespace(heapRelation);
|
2002-04-27 23:24:34 +02:00
|
|
|
shared_relation = heapRelation->rd_rel->relisshared;
|
2002-03-26 20:17:02 +01:00
|
|
|
|
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)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "must index at least one column");
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2002-03-26 20:17:02 +01:00
|
|
|
if (!allow_system_table_mods &&
|
2002-04-12 22:38:31 +02:00
|
|
|
IsSystemRelation(heapRelation) &&
|
2002-03-26 20:17:02 +01:00
|
|
|
IsNormalProcessingMode())
|
2001-04-02 16:34:25 +02:00
|
|
|
elog(ERROR, "User-defined indexes on system catalogs are not supported");
|
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
/*
|
|
|
|
* We cannot allow indexing a shared relation after initdb (because
|
|
|
|
* there's no way to make the entry in other databases' pg_class).
|
|
|
|
* Unfortunately we can't distinguish initdb from a manually started
|
|
|
|
* standalone backend. However, we can at least prevent this mistake
|
|
|
|
* under normal multi-user operation.
|
|
|
|
*/
|
|
|
|
if (shared_relation && IsUnderPostmaster)
|
|
|
|
elog(ERROR, "Shared indexes cannot be created after initdb");
|
|
|
|
|
2002-03-31 08:26:32 +02:00
|
|
|
if (get_relname_relid(indexRelationName, namespaceId))
|
2002-03-26 20:17:02 +01:00
|
|
|
elog(ERROR, "index named \"%s\" already exists",
|
|
|
|
indexRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-08-22 20:24:26 +02:00
|
|
|
* construct tuple descriptor for index tuples
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-15 00:18:02 +02:00
|
|
|
if (OidIsValid(indexInfo->ii_FuncOid))
|
2001-08-22 20:24:26 +02:00
|
|
|
indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid,
|
|
|
|
classObjectId);
|
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-10-25 07:50:21 +02:00
|
|
|
indexInfo->ii_KeyAttrNumbers,
|
2001-08-22 20:24:26 +02:00
|
|
|
classObjectId);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-03-31 08:26:32 +02:00
|
|
|
* create the index relation (but don't create storage yet)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-03-26 20:17:02 +01:00
|
|
|
indexRelation = heap_create(indexRelationName,
|
|
|
|
namespaceId,
|
|
|
|
indexTupDesc,
|
2002-04-27 23:24:34 +02:00
|
|
|
shared_relation,
|
2002-03-31 08:26:32 +02:00
|
|
|
false,
|
|
|
|
allow_system_table_mods);
|
2002-03-26 20:17:02 +01:00
|
|
|
indexoid = RelationGetRelid(indexRelation);
|
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
|
|
|
/*
|
2002-04-27 23:24:34 +02:00
|
|
|
* Fill in fields of the index's pg_class entry that are not set
|
|
|
|
* correctly by heap_create.
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2002-04-27 23:24:34 +02:00
|
|
|
* XXX should have a cleaner way to create cataloged indexes
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-04-27 23:24:34 +02:00
|
|
|
indexRelation->rd_rel->relowner = GetUserId();
|
|
|
|
indexRelation->rd_rel->relam = accessMethodObjectId;
|
|
|
|
indexRelation->rd_rel->relkind = RELKIND_INDEX;
|
|
|
|
indexRelation->rd_rel->relhasoids = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
/*
|
|
|
|
* store index's pg_class entry
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-03-31 08:26:32 +02:00
|
|
|
UpdateRelationRelation(indexRelation);
|
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
|
|
|
* ----------------
|
|
|
|
*/
|
2002-03-26 20:17:02 +01:00
|
|
|
UpdateIndexRelation(indexoid, heapRelationId, indexInfo,
|
2001-08-21 18:36:06 +02:00
|
|
|
classObjectId, primary);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-07-12 20:43:19 +02:00
|
|
|
* Register constraint and dependencies for the index.
|
|
|
|
*
|
|
|
|
* If the index is from a CONSTRAINT clause, construct a pg_constraint
|
|
|
|
* entry. The index is then linked to the constraint, which in turn is
|
|
|
|
* linked to the table. If it's not a CONSTRAINT, make the dependency
|
|
|
|
* directly on the table.
|
|
|
|
*
|
|
|
|
* During bootstrap we can't register any dependencies, and we don't
|
|
|
|
* try to make a constraint either.
|
|
|
|
*/
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
ObjectAddress myself,
|
|
|
|
referenced;
|
|
|
|
|
|
|
|
myself.classId = RelOid_pg_class;
|
|
|
|
myself.objectId = indexoid;
|
|
|
|
myself.objectSubId = 0;
|
|
|
|
|
|
|
|
if (isconstraint)
|
|
|
|
{
|
|
|
|
char constraintType;
|
|
|
|
Oid conOid;
|
|
|
|
|
|
|
|
if (primary)
|
|
|
|
constraintType = CONSTRAINT_PRIMARY;
|
|
|
|
else if (indexInfo->ii_Unique)
|
|
|
|
constraintType = CONSTRAINT_UNIQUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
elog(ERROR, "index_create: constraint must be PRIMARY or UNIQUE");
|
|
|
|
constraintType = 0; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
|
|
|
conOid = CreateConstraintEntry(indexRelationName,
|
|
|
|
namespaceId,
|
|
|
|
constraintType,
|
|
|
|
false, /* isDeferrable */
|
|
|
|
false, /* isDeferred */
|
|
|
|
heapRelationId,
|
|
|
|
indexInfo->ii_KeyAttrNumbers,
|
|
|
|
indexInfo->ii_NumIndexAttrs,
|
|
|
|
InvalidOid, /* no domain */
|
|
|
|
InvalidOid, /* no foreign key */
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
' ',
|
|
|
|
' ',
|
|
|
|
' ',
|
|
|
|
NULL, /* Constraint Bin & Src */
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
referenced.classId = get_system_catalog_relid(ConstraintRelationName);
|
|
|
|
referenced.objectId = conOid;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
|
|
|
{
|
|
|
|
referenced.classId = RelOid_pg_class;
|
|
|
|
referenced.objectId = heapRelationId;
|
|
|
|
referenced.objectSubId = indexInfo->ii_KeyAttrNumbers[i];
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the dependency on the function (if appropriate) */
|
|
|
|
if (OidIsValid(indexInfo->ii_FuncOid))
|
|
|
|
{
|
|
|
|
referenced.classId = RelOid_pg_proc;
|
|
|
|
referenced.objectId = indexInfo->ii_FuncOid;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in the index strategy structure with information from the
|
2001-10-07 01:21:45 +02:00
|
|
|
* 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
|
|
|
*/
|
2001-10-07 01:21:45 +02:00
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
|
|
RelationInitIndexAccessInfo(indexRelation);
|
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
|
|
|
{
|
2002-03-26 20:17:02 +01:00
|
|
|
index_register(heapRelationId, indexoid, 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);
|
2001-08-10 20:57:42 +02:00
|
|
|
|
|
|
|
return indexoid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
1999-12-10 04:56:14 +01:00
|
|
|
* index_drop
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2002-07-12 20:43:19 +02:00
|
|
|
* NOTE: this routine should now only be called through performDeletion(),
|
|
|
|
* else associated dependencies won't be cleaned up.
|
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;
|
|
|
|
HeapTuple tuple;
|
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
|
2001-10-25 07:50:21 +02:00
|
|
|
* 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
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* fix RELATION relation
|
|
|
|
*/
|
2002-07-14 23:08:08 +02:00
|
|
|
DeleteRelationTuple(indexId);
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* fix ATTRIBUTE relation
|
|
|
|
*/
|
2002-07-14 23:08:08 +02:00
|
|
|
DeleteAttributeTuples(indexId);
|
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);
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
tuple = SearchSysCache(INDEXRELID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
2000-11-16 23:30:52 +01:00
|
|
|
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);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(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
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
/*
|
|
|
|
* We are presently too lazy to attempt to compute the new correct value
|
|
|
|
* of relhasindex (the next VACUUM will fix it if necessary). So there is
|
|
|
|
* no need to update the pg_class tuple for the owning relation.
|
|
|
|
* But we must send out a shared-cache-inval notice on the owning relation
|
|
|
|
* to ensure other backends update their relcache lists of indexes.
|
|
|
|
*/
|
|
|
|
CacheInvalidateRelcache(heapId);
|
|
|
|
|
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);
|
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-10-25 07:50:21 +02:00
|
|
|
IndexInfo *
|
2002-02-19 21:11:20 +01:00
|
|
|
BuildIndexInfo(Form_pg_index indexStruct)
|
2000-07-15 00:18:02 +02:00
|
|
|
{
|
|
|
|
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
|
2001-10-25 07:50:21 +02:00
|
|
|
* 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);
|
2002-05-22 00:05:55 +02:00
|
|
|
test = heap_mark4update(relationRelation, rtup, buffer,
|
|
|
|
GetCurrentCommandId());
|
2001-01-18 05:01:42 +01:00
|
|
|
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
|
|
|
}
|
2002-03-03 18:47:56 +01:00
|
|
|
CacheInvalidateHeapTuple(relationRelation, rtup);
|
2000-02-18 10:30:20 +01:00
|
|
|
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));
|
2002-05-21 01:51:44 +02:00
|
|
|
scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
|
|
|
|
if (heap_getnext(scan, ForwardScanDirection) == NULL)
|
|
|
|
isactive = true; /* no indexes, so report "active" */
|
2000-02-18 10:30:20 +01:00
|
|
|
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
|
|
|
|
*
|
2001-08-10 20:57:42 +02:00
|
|
|
* If isprimary is TRUE, we are defining a primary index, so also set
|
2001-10-25 07:50:21 +02:00
|
|
|
* relhaspkey to TRUE. Otherwise, leave relhaspkey alone.
|
2001-08-10 20:57:42 +02:00
|
|
|
*
|
|
|
|
* If reltoastidxid is not InvalidOid, also set reltoastidxid to that value.
|
|
|
|
* This is only used for TOAST relations.
|
|
|
|
*
|
2000-11-08 23:10:03 +01:00
|
|
|
* NOTE: an important side-effect of this operation is that an SI invalidation
|
|
|
|
* message is sent out to all backends --- including me --- causing relcache
|
2002-03-03 18:47:56 +01:00
|
|
|
* entries to be flushed or updated with the new hasindex data. This must
|
|
|
|
* happen even if we find that no change is needed in the pg_class row.
|
2000-02-18 10:30:20 +01:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2001-08-10 20:57:42 +02:00
|
|
|
setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
|
|
|
Relation pg_class;
|
|
|
|
HeapTuple tuple;
|
2001-08-10 20:57:42 +02:00
|
|
|
Form_pg_class classtuple;
|
2002-03-03 18:47:56 +01:00
|
|
|
bool dirty = false;
|
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);
|
|
|
|
|
2001-08-10 20:57:42 +02: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));
|
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
|
|
|
|
tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
/*
|
2001-08-10 20:57:42 +02:00
|
|
|
* Update fields in the pg_class tuple.
|
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);
|
2001-08-10 20:57:42 +02:00
|
|
|
|
|
|
|
classtuple = (Form_pg_class) GETSTRUCT(tuple);
|
2002-03-03 18:47:56 +01:00
|
|
|
|
|
|
|
if (classtuple->relhasindex != hasindex)
|
|
|
|
{
|
|
|
|
classtuple->relhasindex = hasindex;
|
|
|
|
dirty = true;
|
|
|
|
}
|
2001-08-10 20:57:42 +02:00
|
|
|
if (isprimary)
|
2002-03-03 18:47:56 +01:00
|
|
|
{
|
|
|
|
if (!classtuple->relhaspkey)
|
|
|
|
{
|
|
|
|
classtuple->relhaspkey = true;
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
}
|
2001-08-10 20:57:42 +02:00
|
|
|
if (OidIsValid(reltoastidxid))
|
|
|
|
{
|
|
|
|
Assert(classtuple->relkind == RELKIND_TOASTVALUE);
|
2002-03-03 18:47:56 +01:00
|
|
|
if (classtuple->reltoastidxid != reltoastidxid)
|
|
|
|
{
|
|
|
|
classtuple->reltoastidxid = reltoastidxid;
|
|
|
|
dirty = true;
|
|
|
|
}
|
2001-08-10 20:57:42 +02:00
|
|
|
}
|
|
|
|
|
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())
|
2002-03-03 18:47:56 +01:00
|
|
|
CacheInvalidateHeapTuple(pg_class, tuple);
|
2000-12-08 07:17:58 +01:00
|
|
|
BufferSync();
|
2000-02-18 10:30:20 +01:00
|
|
|
}
|
2002-03-03 18:47:56 +01:00
|
|
|
else if (dirty)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
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);
|
|
|
|
}
|
|
|
|
}
|
2002-03-03 18:47:56 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* no need to change tuple, but force relcache rebuild anyway */
|
|
|
|
CacheInvalidateRelcache(relid);
|
|
|
|
}
|
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;
|
|
|
|
|
2002-04-12 22:38:31 +02:00
|
|
|
Assert(!IsSystemRelation(relation) || relation->rd_rel->relkind == RELKIND_INDEX);
|
2000-12-08 07:17:58 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
/* 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())
|
2002-03-03 18:47:56 +01:00
|
|
|
CacheInvalidateHeapTuple(pg_class, classTuple);
|
2000-12-08 07:17:58 +01:00
|
|
|
/* 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-10-25 07:50:21 +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
|
|
|
/*
|
2001-11-02 17:30:29 +01:00
|
|
|
* Grabbing lock here is probably redundant ...
|
1999-09-18 21:08:25 +02:00
|
|
|
*/
|
2001-11-02 17:30:29 +01:00
|
|
|
whichRel = relation_open(relid, ShareLock);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
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
|
|
|
|
2002-05-21 01:51:44 +02:00
|
|
|
pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
|
|
|
|
tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
|
1998-08-20 17:16:59 +02:00
|
|
|
}
|
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
|
2001-10-25 07:50:21 +02:00
|
|
|
* 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-10-25 22:37:30 +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
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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())
|
2002-03-03 18:47:56 +01:00
|
|
|
CacheInvalidateHeapTuple(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);
|
2001-11-02 17:30:29 +01:00
|
|
|
relation_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
|
|
|
*
|
2001-10-25 07:50:21 +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
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* do 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;
|
2001-08-26 18:56:03 +02:00
|
|
|
TransactionId OldestXmin;
|
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
|
2001-10-25 07:50:21 +02:00
|
|
|
* 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;
|
2001-08-26 18:56:03 +02:00
|
|
|
OldestXmin = InvalidTransactionId;
|
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
|
|
|
|
{
|
|
|
|
snapshot = SnapshotAny;
|
2001-08-26 18:56:03 +02:00
|
|
|
OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
|
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
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
scan = heap_beginscan(heapRelation, /* relation */
|
2001-10-25 07:50:21 +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
|
|
|
*/
|
2002-05-21 01:51:44 +02:00
|
|
|
while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
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
|
|
|
|
2002-01-06 01:37:44 +01:00
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
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 */
|
2001-10-25 07:50:21 +02:00
|
|
|
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
|
|
|
/*
|
2001-10-25 07:50:21 +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.
|
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
|
|
|
*/
|
|
|
|
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
|
|
|
|
sv_infomask = heapTuple->t_data->t_infomask;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2001-08-26 18:56:03 +02:00
|
|
|
switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin))
|
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:
|
2001-10-25 07:50:21 +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 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:
|
2001-10-25 07:50:21 +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
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* Since caller should hold ShareLock or better, we
|
|
|
|
* should not see any tuples inserted by open
|
|
|
|
* transactions --- unless it's our own transaction.
|
|
|
|
* (Consider INSERT followed by CREATE INDEX within a
|
|
|
|
* transaction.)
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
*/
|
2002-06-15 21:54:24 +02:00
|
|
|
if (!TransactionIdIsCurrentTransactionId(
|
|
|
|
HeapTupleHeaderGetXmin(heapTuple->t_data)))
|
2001-09-26 23:09:27 +02:00
|
|
|
elog(ERROR, "IndexBuildHeapScan: concurrent insert in progress");
|
|
|
|
indexIt = true;
|
|
|
|
tupleIsAlive = true;
|
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
|
|
|
break;
|
|
|
|
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
2001-10-25 07:50:21 +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
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* Since caller should hold ShareLock or better, we
|
|
|
|
* should not see any tuples deleted by open
|
|
|
|
* transactions --- unless it's our own transaction.
|
|
|
|
* (Consider DELETE followed by CREATE INDEX within a
|
|
|
|
* transaction.)
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
*/
|
2002-06-15 21:54:24 +02:00
|
|
|
if (!TransactionIdIsCurrentTransactionId(
|
|
|
|
HeapTupleHeaderGetXmax(heapTuple->t_data)))
|
2001-09-26 23:09:27 +02:00
|
|
|
elog(ERROR, "IndexBuildHeapScan: concurrent delete in progress");
|
|
|
|
indexIt = true;
|
|
|
|
tupleIsAlive = false;
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "Unexpected HeapTupleSatisfiesVacuum result");
|
2001-10-25 07:50:21 +02:00
|
|
|
indexIt = tupleIsAlive = false; /* keep compiler quiet */
|
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
|
|
|
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);
|
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
if (!indexIt)
|
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
|
|
|
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
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
if (!tupleIsAlive)
|
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
|
|
|
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
|
2001-10-25 07:50:21 +02:00
|
|
|
* in this index, and note which are null. This also performs
|
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
|
|
|
* 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,
|
2001-10-25 07:50:21 +02:00
|
|
|
* but some index AMs want to do further processing on the data
|
|
|
|
* first. So pass the attdata and nulls arrays, instead.
|
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
|
|
|
*/
|
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,
|
|
|
|
heapRelation;
|
2000-07-15 00:18:02 +02:00
|
|
|
IndexInfo *indexInfo;
|
2001-10-07 01:21:45 +02:00
|
|
|
Oid heapId;
|
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.
|
2001-11-20 03:46:13 +01:00
|
|
|
*
|
|
|
|
* XXX if we're not doing an inplace rebuild, wouldn't this be okay?
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
|
|
|
if (IsTransactionBlock())
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "REINDEX cannot run inside a transaction block");
|
2000-11-08 23:10:03 +01:00
|
|
|
|
2001-11-20 03:46:13 +01:00
|
|
|
/*
|
|
|
|
* Open our index relation and get an exclusive lock on it.
|
|
|
|
*
|
|
|
|
* Note: doing this before opening the parent heap relation means
|
|
|
|
* there's a possibility for deadlock failure against another xact
|
|
|
|
* that is doing normal accesses to the heap and index. However,
|
|
|
|
* it's not real clear why you'd be needing to do REINDEX on a table
|
|
|
|
* that's in active use, so I'd rather have the protection of making
|
|
|
|
* sure the index is locked down.
|
|
|
|
*/
|
|
|
|
iRel = index_open(indexId);
|
|
|
|
if (iRel == NULL)
|
|
|
|
elog(ERROR, "reindex_index: can't open index relation");
|
|
|
|
LockRelation(iRel, AccessExclusiveLock);
|
|
|
|
|
2000-02-18 10:30:20 +01:00
|
|
|
old = SetReindexProcessing(true);
|
2000-07-15 00:18:02 +02:00
|
|
|
|
|
|
|
/* Get OID of index's parent table */
|
2002-02-19 21:11:20 +01:00
|
|
|
heapId = iRel->rd_index->indrelid;
|
2000-07-15 00:18:02 +02:00
|
|
|
/* Fetch info needed for index_build */
|
2002-02-19 21:11:20 +01:00
|
|
|
indexInfo = BuildIndexInfo(iRel->rd_index);
|
2000-02-18 10:30:20 +01:00
|
|
|
|
2001-11-20 03:46:13 +01:00
|
|
|
/* Open the parent heap relation */
|
2000-02-18 10:30:20 +01:00
|
|
|
heapRelation = heap_open(heapId, ExclusiveLock);
|
|
|
|
if (heapRelation == NULL)
|
|
|
|
elog(ERROR, "reindex_index: can't open heap relation");
|
|
|
|
|
2001-11-20 03:46:13 +01:00
|
|
|
/*
|
|
|
|
* Force inplace processing if it's a shared index. Necessary because
|
|
|
|
* we have no way to update relfilenode in other databases.
|
|
|
|
*/
|
|
|
|
if (iRel->rd_rel->relisshared)
|
|
|
|
inplace = true;
|
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
|
|
|
* 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
|
|
|
}
|
2001-11-20 03:46:13 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We'll build a new physical relation for the index.
|
|
|
|
*/
|
|
|
|
setNewRelfilenode(iRel);
|
|
|
|
}
|
2000-02-18 10:30:20 +01:00
|
|
|
|
|
|
|
/* Initialize the index and rebuild */
|
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)
|
2001-08-10 20:57:42 +02:00
|
|
|
setRelhasindex(relid, false, false, InvalidOid);
|
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;
|
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
|
|
|
|
2001-08-18 01:50:00 +02:00
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* Ensure to hold an exclusive lock throughout the transaction. The
|
|
|
|
* lock could be less intensive but now it's AccessExclusiveLock for
|
|
|
|
* simplicity.
|
2001-08-18 01:50:00 +02:00
|
|
|
*/
|
|
|
|
rel = heap_open(relid, AccessExclusiveLock);
|
2001-10-25 07:50:21 +02: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
|
|
|
*/
|
2002-04-12 22:38:31 +02:00
|
|
|
if (!IsIgnoringSystemIndexes() && IsSystemRelation(rel))
|
2000-12-08 07:17:58 +01:00
|
|
|
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-11-05 18:46:40 +01:00
|
|
|
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
2001-03-22 05:01:46 +01:00
|
|
|
|
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);
|
|
|
|
}
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-08-18 01:50:00 +02:00
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* Continue to hold the lock.
|
2001-08-18 01:50:00 +02:00
|
|
|
*/
|
|
|
|
heap_close(rel, NoLock);
|
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));
|
2002-05-21 01:51:44 +02:00
|
|
|
scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry);
|
2000-02-18 10:30:20 +01:00
|
|
|
reindexed = false;
|
2002-05-21 01:51:44 +02:00
|
|
|
while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
2000-02-18 10:30:20 +01:00
|
|
|
{
|
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
|
|
|
*/
|
2001-08-10 20:57:42 +02:00
|
|
|
setRelhasindex(relid, true, false, InvalidOid);
|
2000-12-08 07:17:58 +01:00
|
|
|
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
|
|
|
*/
|
|
|
|
}
|
2001-08-10 20:57:42 +02:00
|
|
|
setRelhasindex(relid, true, false, InvalidOid);
|
2000-12-08 07:17:58 +01:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|