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
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1999-07-16 07:00:38 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.84 1999/07/16 04:58:37 momjian 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
|
|
|
|
* index_destroy() - Removes index relation from catalogs
|
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
|
|
|
|
1999-07-16 07:00:38 +02:00
|
|
|
#ifndef HAVE_MEMMOVE
|
|
|
|
#include <regex/utils.h>
|
|
|
|
#else
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
|
|
|
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "access/genam.h"
|
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "access/istrat.h"
|
|
|
|
#include "bootstrap/bootstrap.h"
|
|
|
|
#include "catalog/catname.h"
|
|
|
|
#include "catalog/heap.h"
|
|
|
|
#include "catalog/index.h"
|
|
|
|
#include "catalog/indexing.h"
|
1999-07-15 17:21:54 +02:00
|
|
|
#include "catalog/pg_index.h"
|
1998-01-13 05:05:12 +01:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "executor/executor.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "optimizer/clauses.h"
|
|
|
|
#include "optimizer/prep.h"
|
|
|
|
#include "parser/parse_func.h"
|
|
|
|
#include "storage/smgr.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/relcache.h"
|
|
|
|
#include "utils/syscache.h"
|
1999-02-02 04:45:56 +01:00
|
|
|
#include "utils/temprel.h"
|
1996-11-05 12:57:55 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* macros used in guessing how many tuples are on a page.
|
|
|
|
*/
|
1999-07-07 11:27:28 +02:00
|
|
|
#define AVG_ATTR_SIZE 8
|
|
|
|
#define NTUPLES_PER_PAGE(natts) \
|
|
|
|
((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / \
|
|
|
|
((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* non-export function prototypes */
|
1999-05-25 18:15:34 +02:00
|
|
|
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
|
|
|
|
bool istemp);
|
1997-09-08 23:56:23 +02:00
|
|
|
static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
|
1998-09-01 06:40:42 +02:00
|
|
|
static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
|
1997-09-08 23:56:23 +02:00
|
|
|
List *attributeList,
|
1998-09-01 05:29:17 +02:00
|
|
|
int numatts, AttrNumber *attNums);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
|
1999-02-02 04:45:56 +01:00
|
|
|
static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void InitializeAttributeOids(Relation indexRelation,
|
1997-09-07 07:04:48 +02:00
|
|
|
int numatts,
|
|
|
|
Oid indexoid);
|
1998-09-09 05:42:52 +02:00
|
|
|
static void
|
|
|
|
AppendAttributeTuples(Relation indexRelation, int numatts);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
1997-09-08 23:56:23 +02:00
|
|
|
FuncIndexInfo *funcInfo, int natts,
|
1998-09-01 06:40:42 +02:00
|
|
|
AttrNumber *attNums, Oid *classOids, Node *predicate,
|
1999-05-25 18:15:34 +02:00
|
|
|
List *attributeList, bool islossy, bool unique, bool primary);
|
1998-09-01 06:40:42 +02:00
|
|
|
static void DefaultBuild(Relation heapRelation, Relation indexRelation,
|
1998-09-01 05:29:17 +02:00
|
|
|
int numberOfAttributes, AttrNumber *attributeNumber,
|
1997-09-07 07:04:48 +02:00
|
|
|
IndexStrategy indexStrategy, uint16 parameterCount,
|
1998-09-01 06:40:42 +02:00
|
|
|
Datum *parameter, FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* sysatts is a structure containing attribute tuple forms
|
|
|
|
* for system attributes (numbered -1, -2, ...). This really
|
|
|
|
* should be generated or eliminated or moved elsewhere. -cim 1/19/91
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* typedef struct FormData_pg_attribute {
|
1997-09-07 07:04:48 +02:00
|
|
|
* Oid attrelid;
|
|
|
|
* NameData attname;
|
|
|
|
* Oid atttypid;
|
|
|
|
* uint32 attnvals;
|
|
|
|
* int16 attlen;
|
|
|
|
* AttrNumber attnum;
|
|
|
|
* uint32 attnelems;
|
|
|
|
* int32 attcacheoff;
|
1998-07-12 23:29:40 +02:00
|
|
|
* int32 atttypmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
* bool attbyval;
|
|
|
|
* bool attisset;
|
|
|
|
* char attalign;
|
|
|
|
* bool attnotnull;
|
|
|
|
* bool atthasdef;
|
1996-07-09 08:22:35 +02:00
|
|
|
* } FormData_pg_attribute;
|
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
static FormData_pg_attribute sysatts[] = {
|
1998-07-20 21:21:45 +02:00
|
|
|
{0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '\0', '\0', 'i', '\0', '\0'},
|
|
|
|
{0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
|
1998-08-26 19:12:12 +02:00
|
|
|
{0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
|
1998-07-20 21:21:45 +02:00
|
|
|
{0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
|
1998-08-26 19:12:12 +02:00
|
|
|
{0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
|
1998-07-20 21:21:45 +02:00
|
|
|
{0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'},
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* GetHeapRelationOid
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1999-02-02 04:45:56 +01:00
|
|
|
GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid indoid;
|
|
|
|
Oid heapoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
indoid = RelnameFindRelid(indexRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
if ((!istemp && OidIsValid(indoid)) ||
|
1999-05-25 18:15:34 +02:00
|
|
|
(istemp && get_temp_rel_by_name(indexRelationName) != NULL))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Cannot create index: '%s' already exists",
|
1997-09-07 07:04:48 +02:00
|
|
|
indexRelationName);
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
heapoid = RelnameFindRelid(heapRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (!OidIsValid(heapoid))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Cannot create index on '%s': relation does not exist",
|
1997-09-07 07:04:48 +02:00
|
|
|
heapRelationName);
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return heapoid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static TupleDesc
|
1997-09-08 23:56:23 +02:00
|
|
|
BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
TupleDesc funcTupDesc;
|
|
|
|
Oid retType;
|
|
|
|
char *funcname;
|
|
|
|
int4 nargs;
|
|
|
|
Oid *argtypes;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate and zero a tuple descriptor.
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* Lookup the function for the return type.
|
|
|
|
*/
|
|
|
|
funcname = FIgetname(funcInfo);
|
|
|
|
nargs = FIgetnArgs(funcInfo);
|
|
|
|
argtypes = FIgetArglist(funcInfo);
|
|
|
|
tuple = SearchSysCacheTuple(PRONAME,
|
|
|
|
PointerGetDatum(funcname),
|
|
|
|
Int32GetDatum(nargs),
|
|
|
|
PointerGetDatum(argtypes),
|
|
|
|
0);
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
1998-05-10 01:43:45 +02:00
|
|
|
func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the return type in pg_type for the type length.
|
|
|
|
*/
|
|
|
|
tuple = SearchSysCacheTuple(TYPOID,
|
|
|
|
ObjectIdGetDatum(retType),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assign some of the attributes values. Leave the rest as 0.
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
|
1997-09-07 07:04:48 +02:00
|
|
|
funcTupDesc->attrs[0]->atttypid = retType;
|
|
|
|
funcTupDesc->attrs[0]->attnum = 1;
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
|
1998-02-07 22:41:52 +01:00
|
|
|
funcTupDesc->attrs[0]->attcacheoff = -1;
|
|
|
|
funcTupDesc->attrs[0]->atttypmod = -1;
|
1998-09-01 05:29:17 +02:00
|
|
|
funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* make the attributes name the same as the functions
|
|
|
|
*/
|
|
|
|
namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
|
|
|
|
|
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
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static TupleDesc
|
1996-07-09 08:22:35 +02:00
|
|
|
ConstructTupleDescriptor(Oid heapoid,
|
1997-09-07 07:04:48 +02:00
|
|
|
Relation heapRelation,
|
1997-09-08 23:56:23 +02:00
|
|
|
List *attributeList,
|
1997-09-07 07:04:48 +02:00
|
|
|
int numatts,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attNums)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc heapTupDesc;
|
|
|
|
TupleDesc indexTupDesc;
|
|
|
|
IndexElem *IndexKey;
|
|
|
|
TypeName *IndexKeyType;
|
|
|
|
AttrNumber atnum; /* attributeNumber[attributeOffset] */
|
|
|
|
AttrNumber atind;
|
1998-09-01 05:29:17 +02:00
|
|
|
int natts; /* Form_pg_class->relnatts */
|
1997-09-08 04:41:22 +02:00
|
|
|
char *from; /* used to simplify memcpy below */
|
|
|
|
char *to; /* used to simplify memcpy below */
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* allocate the new tuple descriptor
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
natts = RelationGetForm(heapRelation)->relnatts;
|
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
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
for (i = 0; i < numatts; i += 1)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* get the attribute number and make sure it's valid
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
atnum = attNums[i];
|
|
|
|
if (atnum > natts)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Cannot create index: attribute %d does not exist",
|
1997-09-07 07:04:48 +02:00
|
|
|
atnum);
|
|
|
|
if (attributeList)
|
|
|
|
{
|
|
|
|
IndexKey = (IndexElem *) lfirst(attributeList);
|
1998-08-26 07:22:58 +02:00
|
|
|
IndexKeyType = IndexKey->typename;
|
1997-09-07 07:04:48 +02:00
|
|
|
attributeList = lnext(attributeList);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
IndexKeyType = NULL;
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
indexTupDesc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* determine which tuple descriptor to copy
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (!AttrNumberIsForUserDefinedAttr(atnum))
|
|
|
|
{
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* here we are indexing on a system attribute (-1...-12)
|
|
|
|
* so we convert atnum into a usable index 0...11 so we can
|
|
|
|
* use it to dereference the array sysatts[] which stores
|
|
|
|
* tuple descriptor information for system attributes.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
|
1997-09-07 07:04:48 +02:00
|
|
|
atind = (-atnum) - 1;
|
|
|
|
|
|
|
|
from = (char *) (&sysatts[atind]);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* ----------------
|
|
|
|
* here we are indexing on a normal attribute (1...n)
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
heapTupDesc = RelationGetDescr(heapRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
atind = AttrNumberGetAttrOffset(atnum);
|
|
|
|
|
|
|
|
from = (char *) (heapTupDesc->attrs[atind]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* now that we've determined the "from", let's copy
|
|
|
|
* the tuple desc data...
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
to = (char *) (indexTupDesc->attrs[i]);
|
|
|
|
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
((Form_pg_attribute) to)->attnum = i + 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
((Form_pg_attribute) to)->attnotnull = false;
|
|
|
|
((Form_pg_attribute) to)->atthasdef = false;
|
|
|
|
((Form_pg_attribute) to)->attcacheoff = -1;
|
|
|
|
((Form_pg_attribute) to)->atttypmod = -1;
|
|
|
|
((Form_pg_attribute) to)->attalign = 'i';
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if the keytype is defined, we need to change the tuple form's
|
|
|
|
* atttypid & attlen field to match that of the key's type
|
|
|
|
*/
|
|
|
|
if (IndexKeyType != NULL)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
tup = SearchSysCacheTuple(TYPNAME,
|
|
|
|
PointerGetDatum(IndexKeyType->name),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tup))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "create index: type '%s' undefined",
|
1997-09-07 07:04:48 +02:00
|
|
|
IndexKeyType->name);
|
1998-11-27 20:52:36 +01:00
|
|
|
((Form_pg_attribute) to)->atttypid = tup->t_data->t_oid;
|
1998-09-01 05:29:17 +02:00
|
|
|
((Form_pg_attribute) to)->attbyval =
|
|
|
|
((Form_pg_type) GETSTRUCT(tup))->typbyval;
|
|
|
|
((Form_pg_attribute) to)->attlen =
|
|
|
|
((Form_pg_type) GETSTRUCT(tup))->typlen;
|
|
|
|
((Form_pg_attribute) to)->attalign =
|
|
|
|
((Form_pg_type) GETSTRUCT(tup))->typalign;
|
|
|
|
((Form_pg_attribute) to)->atttypmod = IndexKeyType->typmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* now we have to drop in the proper relation descriptor
|
|
|
|
* into the copied tuple form's attrelid and we should be
|
|
|
|
* all set.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
((Form_pg_attribute) to)->attrelid = heapoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return indexTupDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1999-05-25 18:15:34 +02:00
|
|
|
* AccessMethodObjectIdGetForm
|
1997-09-07 07:04:48 +02:00
|
|
|
* Returns the formated access method tuple given its object identifier.
|
|
|
|
*
|
|
|
|
* XXX ADD INDEXING
|
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* Assumes object identifier is valid.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Form_pg_am
|
1998-09-01 05:29:17 +02:00
|
|
|
AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_am_desc;
|
|
|
|
HeapScanDesc pg_am_scan;
|
|
|
|
HeapTuple pg_am_tuple;
|
|
|
|
ScanKeyData key;
|
1999-06-19 06:54:23 +02:00
|
|
|
Form_pg_am aform;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* form a scan key for the pg_am relation
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
|
1998-04-27 06:08:07 +02:00
|
|
|
F_OIDEQ,
|
1997-09-07 07:04:48 +02:00
|
|
|
ObjectIdGetDatum(accessMethodObjectId));
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* fetch the desired access method tuple
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
pg_am_desc = heap_openr(AccessMethodRelationName);
|
1998-07-27 21:38:40 +02:00
|
|
|
pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
pg_am_tuple = heap_getnext(pg_am_scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* return NULL if not found
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (!HeapTupleIsValid(pg_am_tuple))
|
|
|
|
{
|
|
|
|
heap_endscan(pg_am_scan);
|
|
|
|
heap_close(pg_am_desc);
|
1998-09-01 05:29:17 +02:00
|
|
|
return NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* if found am tuple, then copy the form and return the copy
|
|
|
|
* ----------------
|
|
|
|
*/
|
1999-06-19 06:54:23 +02:00
|
|
|
aform = (Form_pg_am) palloc(sizeof *aform);
|
|
|
|
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
heap_endscan(pg_am_scan);
|
|
|
|
heap_close(pg_am_desc);
|
|
|
|
|
1999-06-19 06:54:23 +02:00
|
|
|
return aform;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ConstructIndexReldesc
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
|
|
|
{
|
|
|
|
extern GlobalMemory CacheCxt;
|
1997-09-08 04:41:22 +02:00
|
|
|
MemoryContext oldcxt;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* here we make certain to allocate the access method
|
|
|
|
* tuple within the cache context lest it vanish when the
|
|
|
|
* context changes
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (!CacheCxt)
|
|
|
|
CacheCxt = CreateGlobalMemory("Cache");
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* XXX missing the initialization of some other fields
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
indexRelation->rd_rel->relowner = GetUserId();
|
|
|
|
|
|
|
|
indexRelation->rd_rel->relam = amoid;
|
|
|
|
indexRelation->rd_rel->reltuples = 1; /* XXX */
|
|
|
|
indexRelation->rd_rel->relkind = RELKIND_INDEX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* UpdateRelationRelation
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1999-02-02 04:45:56 +01:00
|
|
|
UpdateRelationRelation(Relation indexRelation, char *temp_relname)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_class;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Oid tupleOid;
|
|
|
|
Relation idescs[Num_pg_class_indices];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pg_class = heap_openr(RelationRelationName);
|
|
|
|
|
|
|
|
/* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
|
|
|
|
tuple = heap_addheader(Natts_pg_class_fixed,
|
|
|
|
sizeof(*indexRelation->rd_rel),
|
|
|
|
(char *) indexRelation->rd_rel);
|
|
|
|
|
1998-09-09 05:42:52 +02:00
|
|
|
/* ----------------
|
|
|
|
* the new tuple must have the same oid as the relcache entry for the
|
|
|
|
* index. sure would be embarassing to do this sort of thing in polite
|
|
|
|
* company.
|
|
|
|
* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-11-27 20:52:36 +01:00
|
|
|
tuple->t_data->t_oid = RelationGetRelid(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_insert(pg_class, tuple);
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
if (temp_relname)
|
|
|
|
create_temp_relation(temp_relname, tuple);
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* During normal processing, we need to make sure that the system
|
|
|
|
* catalog indices are correct. Bootstrap (initdb) time doesn't
|
|
|
|
* require this, because we make sure that the indices are correct
|
|
|
|
* just before exiting.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
|
|
|
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
|
|
|
}
|
|
|
|
|
1998-11-27 20:52:36 +01:00
|
|
|
tupleOid = tuple->t_data->t_oid;
|
1997-09-07 07:04:48 +02:00
|
|
|
pfree(tuple);
|
|
|
|
heap_close(pg_class);
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return tupleOid;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* InitializeAttributeOids
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
InitializeAttributeOids(Relation indexRelation,
|
|
|
|
int numatts,
|
|
|
|
Oid indexoid)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupleDescriptor;
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
tupleDescriptor = RelationGetDescr(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < numatts; i += 1)
|
|
|
|
tupleDescriptor->attrs[i]->attrelid = indexoid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* AppendAttributeTuples
|
|
|
|
*
|
|
|
|
* XXX For now, only change the ATTNUM attribute value
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AppendAttributeTuples(Relation indexRelation, int numatts)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_attribute;
|
1998-09-01 06:40:42 +02:00
|
|
|
HeapTuple init_tuple,
|
|
|
|
cur_tuple = NULL,
|
|
|
|
new_tuple;
|
1997-09-08 04:41:22 +02:00
|
|
|
bool hasind;
|
|
|
|
Relation idescs[Num_pg_attr_indices];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
Datum value[Natts_pg_attribute];
|
|
|
|
char nullv[Natts_pg_attribute];
|
|
|
|
char replace[Natts_pg_attribute];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc indexTupDesc;
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* open the attribute relation
|
|
|
|
* XXX ADD INDEXING
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
pg_attribute = heap_openr(AttributeRelationName);
|
|
|
|
|
|
|
|
/* ----------------
|
1998-09-01 05:29:17 +02:00
|
|
|
* initialize *null, *replace and *value
|
1997-09-07 07:04:48 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-18 22:22:58 +02:00
|
|
|
MemSet(nullv, ' ', Natts_pg_attribute);
|
|
|
|
MemSet(replace, ' ', Natts_pg_attribute);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* create the first attribute tuple.
|
|
|
|
* XXX For now, only change the ATTNUM attribute value
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
replace[Anum_pg_attribute_attnum - 1] = 'r';
|
|
|
|
replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
|
|
|
|
|
|
|
|
value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
|
|
|
|
value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
init_tuple = heap_addheader(Natts_pg_attribute,
|
1999-05-25 18:15:34 +02:00
|
|
|
ATTRIBUTE_TUPLE_SIZE,
|
1998-09-01 06:40:42 +02:00
|
|
|
(char *) (indexRelation->rd_att->attrs[0]));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
hasind = false;
|
|
|
|
if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex)
|
|
|
|
{
|
|
|
|
hasind = true;
|
|
|
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* insert the first attribute tuple.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
cur_tuple = heap_modifytuple(init_tuple,
|
1998-09-01 06:40:42 +02:00
|
|
|
pg_attribute,
|
|
|
|
value,
|
|
|
|
nullv,
|
|
|
|
replace);
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(init_tuple);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
heap_insert(pg_attribute, cur_tuple);
|
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, cur_tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
1998-08-19 04:04:17 +02:00
|
|
|
* now we use the information in the index cur_tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
* descriptor to form the remaining attribute tuples.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
indexTupDesc = RelationGetDescr(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 1; i < numatts; i += 1)
|
|
|
|
{
|
|
|
|
/* ----------------
|
|
|
|
* process the remaining attributes...
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
memmove(GETSTRUCT(cur_tuple),
|
1997-09-07 07:04:48 +02:00
|
|
|
(char *) indexTupDesc->attrs[i],
|
1999-05-25 18:15:34 +02:00
|
|
|
ATTRIBUTE_TUPLE_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
new_tuple = heap_modifytuple(cur_tuple,
|
1998-09-01 06:40:42 +02:00
|
|
|
pg_attribute,
|
|
|
|
value,
|
|
|
|
nullv,
|
|
|
|
replace);
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(cur_tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
heap_insert(pg_attribute, new_tuple);
|
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
|
|
|
|
|
|
|
/* ----------------
|
1998-08-19 04:04:17 +02:00
|
|
|
* ModifyHeapTuple returns a new copy of a cur_tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
* so we free the original and use the copy..
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
cur_tuple = new_tuple;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
if (cur_tuple)
|
|
|
|
pfree(cur_tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_close(pg_attribute);
|
|
|
|
if (hasind)
|
|
|
|
CatalogCloseIndices(Num_pg_attr_indices, idescs);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* UpdateIndexRelation
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
UpdateIndexRelation(Oid indexoid,
|
|
|
|
Oid heapoid,
|
1997-09-08 23:56:23 +02:00
|
|
|
FuncIndexInfo *funcInfo,
|
1997-09-07 07:04:48 +02:00
|
|
|
int natts,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attNums,
|
|
|
|
Oid *classOids,
|
1997-09-08 23:56:23 +02:00
|
|
|
Node *predicate,
|
|
|
|
List *attributeList,
|
1997-09-07 07:04:48 +02:00
|
|
|
bool islossy,
|
1999-01-21 23:48:20 +01:00
|
|
|
bool unique,
|
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
|
|
|
IndexElem *IndexKey;
|
|
|
|
char *predString;
|
|
|
|
text *predText;
|
|
|
|
int predLen,
|
|
|
|
itupLen;
|
|
|
|
Relation pg_index;
|
|
|
|
HeapTuple tuple;
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
1998-09-01 05:29:17 +02:00
|
|
|
* allocate an Form_pg_index big enough to hold the
|
1997-09-07 07:04:48 +02:00
|
|
|
* index-predicate (if any) in string form
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (predicate != NULL)
|
|
|
|
{
|
|
|
|
predString = nodeToString(predicate);
|
|
|
|
predText = (text *) fmgr(F_TEXTIN, predString);
|
|
|
|
pfree(predString);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
predText = (text *) fmgr(F_TEXTIN, "");
|
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);
|
1999-05-25 18:15:34 +02:00
|
|
|
memset(indexForm, 0, sizeof(FormData_pg_index));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
memmove((char *) &indexForm->indpred, (char *) predText, predLen);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* store the oid information into the index tuple form
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
indexForm->indrelid = heapoid;
|
|
|
|
indexForm->indexrelid = indexoid;
|
|
|
|
indexForm->indproc = (PointerIsValid(funcInfo)) ?
|
|
|
|
FIgetProcOid(funcInfo) : InvalidOid;
|
|
|
|
indexForm->indislossy = islossy;
|
1999-01-21 23:48:20 +01:00
|
|
|
indexForm->indisprimary = primary;
|
1997-09-07 07:04:48 +02:00
|
|
|
indexForm->indisunique = unique;
|
|
|
|
|
|
|
|
indexForm->indhaskeytype = 0;
|
|
|
|
while (attributeList != NIL)
|
|
|
|
{
|
|
|
|
IndexKey = (IndexElem *) lfirst(attributeList);
|
1998-08-26 07:22:58 +02:00
|
|
|
if (IndexKey->typename != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
indexForm->indhaskeytype = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
attributeList = lnext(attributeList);
|
|
|
|
}
|
|
|
|
|
1997-09-18 22:22:58 +02:00
|
|
|
MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
|
|
|
|
MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* copy index key and op class information
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
for (i = 0; i < natts; i += 1)
|
|
|
|
{
|
|
|
|
indexForm->indkey[i] = attNums[i];
|
|
|
|
indexForm->indclass[i] = classOids[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have a functional index, add all attribute arguments
|
|
|
|
*/
|
|
|
|
if (PointerIsValid(funcInfo))
|
|
|
|
{
|
|
|
|
for (i = 1; i < FIgetnArgs(funcInfo); i++)
|
|
|
|
indexForm->indkey[i] = attNums[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
indexForm->indisclustered = '\0'; /* XXX constant */
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* open the system catalog index relation
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
pg_index = heap_openr(IndexRelationName);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* form a tuple to insert into pg_index
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
tuple = heap_addheader(Natts_pg_index,
|
|
|
|
itupLen,
|
|
|
|
(char *) indexForm);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* insert the tuple into the pg_index
|
|
|
|
* XXX ADD INDEX TUPLES TOO
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
heap_insert(pg_index, tuple);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* close the relation and free the tuple
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
heap_close(pg_index);
|
|
|
|
pfree(predText);
|
|
|
|
pfree(indexForm);
|
|
|
|
pfree(tuple);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* UpdateIndexPredicate
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *newPred;
|
|
|
|
char *predString;
|
|
|
|
text *predText;
|
|
|
|
Relation pg_index;
|
|
|
|
HeapTuple tuple;
|
|
|
|
HeapTuple newtup;
|
|
|
|
int i;
|
|
|
|
Datum values[Natts_pg_index];
|
|
|
|
char nulls[Natts_pg_index];
|
|
|
|
char replace[Natts_pg_index];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct newPred as a CNF expression equivalent to the OR of the
|
|
|
|
* original partial-index predicate ("oldPred") and the extension
|
|
|
|
* predicate ("predicate").
|
|
|
|
*
|
|
|
|
* This should really try to process the result to change things like
|
|
|
|
* "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
|
|
|
|
* that if the extension predicate is NULL (i.e., it is being extended
|
|
|
|
* to be a complete index), then newPred will be NULL - in effect,
|
|
|
|
* changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
|
|
|
|
*/
|
|
|
|
newPred = NULL;
|
|
|
|
if (predicate != NULL)
|
|
|
|
{
|
1999-02-03 22:18:02 +01:00
|
|
|
newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
|
1997-09-07 07:04:48 +02:00
|
|
|
lcons(make_andclause((List *) oldPred),
|
|
|
|
NIL)));
|
|
|
|
newPred = (Node *) cnfify((Expr *) newPred, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* translate the index-predicate to string form */
|
|
|
|
if (newPred != NULL)
|
|
|
|
{
|
|
|
|
predString = nodeToString(newPred);
|
|
|
|
predText = (text *) fmgr(F_TEXTIN, predString);
|
|
|
|
pfree(predString);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
predText = (text *) fmgr(F_TEXTIN, "");
|
|
|
|
|
|
|
|
/* open the index system catalog relation */
|
|
|
|
pg_index = heap_openr(IndexRelationName);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
tuple = SearchSysCacheTuple(INDEXRELID,
|
1998-09-01 06:40:42 +02:00
|
|
|
ObjectIdGetDatum(indexoid),
|
|
|
|
0, 0, 0);
|
1998-08-19 04:04:17 +02:00
|
|
|
Assert(HeapTupleIsValid(tuple));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
for (i = 0; i < Natts_pg_index; i++)
|
|
|
|
{
|
|
|
|
nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
|
|
|
|
replace[i] = ' ';
|
|
|
|
values[i] = (Datum) NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
replace[Anum_pg_index_indpred - 1] = 'r';
|
|
|
|
values[Anum_pg_index_indpred - 1] = (Datum) predText;
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
heap_replace(pg_index, &newtup->t_self, newtup, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(newtup);
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_close(pg_index);
|
|
|
|
pfree(predText);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* InitIndexStrategy
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
InitIndexStrategy(int numatts,
|
|
|
|
Relation indexRelation,
|
|
|
|
Oid accessMethodObjectId)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
IndexStrategy strategy;
|
|
|
|
RegProcedure *support;
|
|
|
|
uint16 amstrategies;
|
|
|
|
uint16 amsupport;
|
|
|
|
Oid attrelid;
|
|
|
|
Size strsize;
|
1997-09-07 07:04:48 +02:00
|
|
|
extern GlobalMemory CacheCxt;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* get information from the index relation descriptor
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
attrelid = indexRelation->rd_att->attrs[0]->attrelid;
|
|
|
|
amstrategies = indexRelation->rd_am->amstrategies;
|
|
|
|
amsupport = indexRelation->rd_am->amsupport;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* get the size of the strategy
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* allocate the new index strategy structure
|
|
|
|
*
|
|
|
|
* the index strategy has to be allocated in the same
|
|
|
|
* context as the relation descriptor cache or else
|
|
|
|
* it will be lost at the end of the transaction.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (!CacheCxt)
|
|
|
|
CacheCxt = CreateGlobalMemory("Cache");
|
|
|
|
|
|
|
|
strategy = (IndexStrategy)
|
|
|
|
MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
|
|
|
|
|
|
|
|
if (amsupport > 0)
|
|
|
|
{
|
|
|
|
strsize = numatts * (amsupport * sizeof(RegProcedure));
|
|
|
|
support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
|
|
|
|
strsize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
support = (RegProcedure *) NULL;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* fill in the index strategy structure with information
|
|
|
|
* from the catalogs. Note: we use heap override mode
|
|
|
|
* in order to be allowed to see the correct information in the
|
|
|
|
* catalogs, even though our transaction has not yet committed.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
setheapoverride(true);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
IndexSupportInitialize(strategy, support,
|
|
|
|
attrelid, accessMethodObjectId,
|
|
|
|
amstrategies, amsupport, numatts);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
setheapoverride(false);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* store the strategy information in the index reldesc
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
RelationSetIndexSupport(indexRelation, strategy, support);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* index_create
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_create(char *heapRelationName,
|
|
|
|
char *indexRelationName,
|
1997-09-08 23:56:23 +02:00
|
|
|
FuncIndexInfo *funcInfo,
|
|
|
|
List *attributeList,
|
1997-09-07 07:04:48 +02:00
|
|
|
Oid accessMethodObjectId,
|
1996-07-09 08:22:35 +02:00
|
|
|
int numatts,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attNums,
|
|
|
|
Oid *classObjectId,
|
1997-09-07 07:04:48 +02:00
|
|
|
uint16 parameterCount,
|
1997-09-08 23:56:23 +02:00
|
|
|
Datum *parameter,
|
|
|
|
Node *predicate,
|
1997-09-07 07:04:48 +02:00
|
|
|
bool islossy,
|
1999-01-21 23:48:20 +01:00
|
|
|
bool unique,
|
1999-05-25 18:15:34 +02:00
|
|
|
bool primary)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation heapRelation;
|
|
|
|
Relation indexRelation;
|
|
|
|
TupleDesc indexTupDesc;
|
|
|
|
Oid heapoid;
|
|
|
|
Oid indexoid;
|
|
|
|
PredInfo *predInfo;
|
1999-02-02 04:45:56 +01:00
|
|
|
bool istemp = (get_temp_rel_by_name(heapRelationName) != NULL);
|
1999-05-25 18:15:34 +02:00
|
|
|
char *temp_relname = NULL;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* check parameters
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (numatts < 1)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "must index at least one attribute");
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* get heap relation oid and open the heap relation
|
|
|
|
* XXX ADD INDEXING
|
|
|
|
* ----------------
|
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
heapRelation = heap_open(heapoid);
|
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
/*
|
|
|
|
* Only SELECT ... FOR UPDATE are allowed
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-12-15 13:47:01 +01:00
|
|
|
LockRelation(heapRelation, ShareLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* construct new tuple descriptor
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (PointerIsValid(funcInfo))
|
|
|
|
indexTupDesc = BuildFuncTupleDesc(funcInfo);
|
|
|
|
else
|
|
|
|
indexTupDesc = ConstructTupleDescriptor(heapoid,
|
|
|
|
heapRelation,
|
|
|
|
attributeList,
|
|
|
|
numatts,
|
|
|
|
attNums);
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
/* invalidate cache so possible non-temp index is masked by temp */
|
|
|
|
if (istemp)
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
Oid relid = RelnameFindRelid(indexRelationName);
|
1999-02-02 04:45:56 +01:00
|
|
|
|
|
|
|
if (relid != InvalidOid)
|
|
|
|
RelationForgetRelation(relid);
|
|
|
|
}
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
/* save user relation name because heap_create changes it */
|
|
|
|
if (istemp)
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
temp_relname = pstrdup(indexRelationName); /* save original value */
|
1999-02-02 04:45:56 +01:00
|
|
|
indexRelationName = palloc(NAMEDATALEN);
|
1999-05-25 18:15:34 +02:00
|
|
|
strcpy(indexRelationName, temp_relname); /* heap_create will
|
|
|
|
* change this */
|
1999-02-02 04:45:56 +01:00
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* create the index relation
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-11-28 05:40:40 +01:00
|
|
|
indexRelation = heap_create(indexRelationName,
|
1999-02-02 04:45:56 +01:00
|
|
|
indexTupDesc, false, istemp);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* construct the index relation descriptor
|
|
|
|
*
|
|
|
|
* XXX should have a proper way to create cataloged relations
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
ConstructIndexReldesc(indexRelation, accessMethodObjectId);
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* add index to catalogs
|
1998-09-09 05:42:52 +02:00
|
|
|
* (append RELATION tuple)
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
indexoid = UpdateRelationRelation(indexRelation, temp_relname);
|
1996-08-26 08:32:06 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* Now get the index procedure (only relevant for functional indices).
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (PointerIsValid(funcInfo))
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple proc_tup;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
proc_tup = SearchSysCacheTuple(PRONAME,
|
|
|
|
PointerGetDatum(FIgetname(funcInfo)),
|
|
|
|
Int32GetDatum(FIgetnArgs(funcInfo)),
|
|
|
|
PointerGetDatum(FIgetArglist(funcInfo)),
|
|
|
|
0);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!HeapTupleIsValid(proc_tup))
|
|
|
|
{
|
|
|
|
func_error("index_create", FIgetname(funcInfo),
|
1998-09-01 06:40:42 +02:00
|
|
|
FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-11-27 20:52:36 +01:00
|
|
|
FIgetProcOid(funcInfo) = proc_tup->t_data->t_oid;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* now update the object id's of all the attribute
|
|
|
|
* tuple forms in the index relation's tuple descriptor
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
InitializeAttributeOids(indexRelation, numatts, indexoid);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* append ATTRIBUTE tuples
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
AppendAttributeTuples(indexRelation, numatts);
|
|
|
|
|
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
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
UpdateIndexRelation(indexoid, heapoid, funcInfo,
|
|
|
|
numatts, attNums, classObjectId, predicate,
|
1999-01-21 23:48:20 +01:00
|
|
|
attributeList, islossy, unique, primary);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
predInfo = (PredInfo *) palloc(sizeof(PredInfo));
|
|
|
|
predInfo->pred = predicate;
|
|
|
|
predInfo->oldPred = NULL;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* initialize the index strategy
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* index. The heap and index relations are closed by index_build().
|
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
1997-03-19 08:44:45 +01:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
index_register(heapRelationName, indexRelationName, numatts, attNums,
|
|
|
|
parameterCount, parameter, funcInfo, predInfo);
|
|
|
|
}
|
|
|
|
else
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
heapRelation = heap_openr(heapRelationName);
|
|
|
|
index_build(heapRelation, indexRelation, numatts, attNums,
|
|
|
|
parameterCount, parameter, funcInfo, predInfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1999-02-02 04:45:56 +01:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_destroy
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
1997-09-07 07:04:48 +02:00
|
|
|
index_destroy(Oid indexId)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-08-21 01:01:24 +02:00
|
|
|
Relation userindexRelation;
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation indexRelation;
|
1998-08-21 01:01:24 +02:00
|
|
|
Relation relationRelation;
|
1998-08-21 00:07:46 +02:00
|
|
|
Relation attributeRelation;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tuple;
|
1999-05-25 18:15:34 +02:00
|
|
|
int16 attnum;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
Assert(OidIsValid(indexId));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
/* Open now to obtain lock by referencing table? bjm */
|
1998-08-21 01:01:24 +02:00
|
|
|
userindexRelation = index_open(indexId);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* fix RELATION relation
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-21 01:01:24 +02:00
|
|
|
relationRelation = heap_openr(RelationRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
tuple = SearchSysCacheTupleCopy(RELOID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
Assert(HeapTupleIsValid(tuple));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
heap_delete(relationRelation, &tuple->t_self, NULL);
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(tuple);
|
1998-08-21 01:01:24 +02:00
|
|
|
heap_close(relationRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* fix ATTRIBUTE relation
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-21 00:07:46 +02:00
|
|
|
attributeRelation = heap_openr(AttributeRelationName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
attnum = 1; /* indexes start at 1 */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
while (HeapTupleIsValid(tuple = SearchSysCacheTupleCopy(ATTNUM,
|
1998-09-01 06:40:42 +02:00
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
Int16GetDatum(attnum),
|
|
|
|
0, 0)))
|
1998-08-19 04:04:17 +02:00
|
|
|
{
|
1998-12-15 13:47:01 +01:00
|
|
|
heap_delete(attributeRelation, &tuple->t_self, NULL);
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(tuple);
|
|
|
|
attnum++;
|
|
|
|
}
|
1998-08-21 00:07:46 +02:00
|
|
|
heap_close(attributeRelation);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
/* does something only if it is a temp index */
|
|
|
|
remove_temp_relation(indexId);
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* fix INDEX relation
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
tuple = SearchSysCacheTupleCopy(INDEXRELID,
|
1998-09-01 06:40:42 +02:00
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
1999-02-02 04:45:56 +01:00
|
|
|
Assert(HeapTupleIsValid(tuple));
|
1998-08-21 00:07:46 +02:00
|
|
|
|
1998-08-21 01:01:24 +02:00
|
|
|
indexRelation = heap_openr(IndexRelationName);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-12-15 13:47:01 +01:00
|
|
|
heap_delete(indexRelation, &tuple->t_self, NULL);
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(tuple);
|
1998-08-21 01:01:24 +02:00
|
|
|
heap_close(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
1998-06-13 22:22:54 +02:00
|
|
|
* flush cache and physically remove the file
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-08-21 01:01:24 +02:00
|
|
|
ReleaseRelationBuffers(userindexRelation);
|
1998-06-13 22:22:54 +02:00
|
|
|
|
1999-05-17 02:27:45 +02:00
|
|
|
if (smgrunlink(DEFAULT_SMGR, userindexRelation) != SM_SUCCESS)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "amdestroyr: unlink: %m");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-21 01:01:24 +02:00
|
|
|
index_close(userindexRelation);
|
|
|
|
RelationForgetRelation(RelationGetRelid(userindexRelation));
|
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
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* FormIndexDatum
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
FormIndexDatum(int numberOfAttributes,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attributeNumber,
|
1997-09-07 07:04:48 +02:00
|
|
|
HeapTuple heapTuple,
|
|
|
|
TupleDesc heapDescriptor,
|
1997-09-08 23:56:23 +02:00
|
|
|
Datum *datum,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *nullv,
|
|
|
|
FuncIndexInfoPtr fInfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-09-09 05:42:52 +02:00
|
|
|
AttrNumber i;
|
|
|
|
int offset;
|
1997-09-08 04:41:22 +02:00
|
|
|
bool isNull;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* for each attribute we need from the heap tuple,
|
|
|
|
* get the attribute and stick it into the datum and
|
|
|
|
* null arrays.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
|
1998-09-09 05:42:52 +02:00
|
|
|
for (i = 1; i <= numberOfAttributes; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-09-09 05:42:52 +02:00
|
|
|
offset = AttrNumberGetAttrOffset(i);
|
|
|
|
|
|
|
|
datum[offset] = PointerGetDatum(GetIndexValue(heapTuple,
|
1998-09-01 06:40:42 +02:00
|
|
|
heapDescriptor,
|
1998-09-09 05:42:52 +02:00
|
|
|
offset,
|
1998-09-01 06:40:42 +02:00
|
|
|
attributeNumber,
|
|
|
|
fInfo,
|
|
|
|
&isNull));
|
1998-08-28 06:57:21 +02:00
|
|
|
|
1998-09-09 05:42:52 +02:00
|
|
|
nullv[offset] = (isNull) ? 'n' : ' ';
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* UpdateStats
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
UpdateStats(Oid relid, long reltuples, bool hasindex)
|
|
|
|
{
|
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;
|
|
|
|
long relpages;
|
|
|
|
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];
|
1998-09-01 06:40:42 +02:00
|
|
|
HeapScanDesc pg_class_scan = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* This routine handles updates for both the heap and index relation
|
|
|
|
* 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.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* 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.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
whichRel = RelationIdGetRelation(relid);
|
|
|
|
|
|
|
|
if (!RelationIsValid(whichRel))
|
1999-05-10 02:46:32 +02:00
|
|
|
elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* Find the RELATION relation tuple for the given relation.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
pg_class = heap_openr(RelationRelationName);
|
|
|
|
if (!RelationIsValid(pg_class))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "UpdateStats: could not open RELATION relation");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-20 17:16:59 +02:00
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
tuple = SearchSysCacheTupleCopy(RELOID,
|
|
|
|
ObjectIdGetDatum(relid),
|
|
|
|
0, 0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScanKeyData key[1];
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&key[0], 0,
|
1998-09-01 06:40:42 +02:00
|
|
|
ObjectIdAttributeNumber,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(relid));
|
1998-08-20 17:16:59 +02:00
|
|
|
|
|
|
|
pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
|
|
|
|
tuple = heap_getnext(pg_class_scan, 0);
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-08-20 17:16:59 +02:00
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
heap_endscan(pg_class_scan);
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_close(pg_class);
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "UpdateStats: cannot scan RELATION relation");
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1999-05-27 00:57:39 +02:00
|
|
|
* Figure values to insert.
|
|
|
|
*
|
|
|
|
* If we found zero tuples in the scan, do NOT believe it; instead put
|
|
|
|
* a bogus estimate into the statistics fields. Otherwise, the common
|
|
|
|
* pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
|
|
|
|
* 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.
|
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
|
|
|
|
reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
whichRel->rd_rel->relhasindex = hasindex;
|
|
|
|
whichRel->rd_rel->relpages = relpages;
|
|
|
|
whichRel->rd_rel->reltuples = reltuples;
|
|
|
|
|
1999-05-27 00:57:39 +02:00
|
|
|
/* ----------------
|
|
|
|
* Update statistics in pg_class.
|
|
|
|
* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* At bootstrap time, we don't need to worry about concurrency or
|
|
|
|
* visibility of changes, so we cheat.
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
rd_rel->relpages = relpages;
|
|
|
|
rd_rel->reltuples = reltuples;
|
|
|
|
rd_rel->relhasindex = hasindex;
|
1998-08-20 17:16:59 +02:00
|
|
|
WriteBuffer(pg_class_scan->rs_cbuf);
|
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++)
|
|
|
|
{
|
|
|
|
nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
|
|
|
|
replace[i] = ' ';
|
|
|
|
values[i] = (Datum) NULL;
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
replace[Anum_pg_class_relpages - 1] = 'r';
|
|
|
|
values[Anum_pg_class_relpages - 1] = (Datum) relpages;
|
|
|
|
replace[Anum_pg_class_reltuples - 1] = 'r';
|
|
|
|
values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
|
|
|
|
replace[Anum_pg_class_relhasindex - 1] = 'r';
|
|
|
|
values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
|
1998-12-15 13:47:01 +01:00
|
|
|
heap_replace(pg_class, &tuple->t_self, newtup, NULL);
|
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, newtup);
|
|
|
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
1998-09-09 05:42:52 +02:00
|
|
|
pfree(newtup);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-08-20 17:16:59 +02:00
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
pfree(tuple);
|
|
|
|
else
|
|
|
|
heap_endscan(pg_class_scan);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_close(pg_class);
|
|
|
|
heap_close(whichRel);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* FillDummyExprContext
|
|
|
|
* Sets up dummy ExprContext and TupleTableSlot objects for use
|
|
|
|
* with ExecQual.
|
1996-07-09 08:22:35 +02:00
|
|
|
* -------------------------
|
|
|
|
*/
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
FillDummyExprContext(ExprContext *econtext,
|
|
|
|
TupleTableSlot *slot,
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleDesc tupdesc,
|
|
|
|
Buffer buffer)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
econtext->ecxt_scantuple = slot;
|
|
|
|
econtext->ecxt_innertuple = NULL;
|
|
|
|
econtext->ecxt_outertuple = NULL;
|
|
|
|
econtext->ecxt_param_list_info = NULL;
|
|
|
|
econtext->ecxt_range_table = NULL;
|
|
|
|
|
|
|
|
slot->ttc_tupleDescriptor = tupdesc;
|
|
|
|
slot->ttc_buffer = buffer;
|
|
|
|
slot->ttc_shouldFree = false;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* DefaultBuild
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
DefaultBuild(Relation heapRelation,
|
1997-09-07 07:04:48 +02:00
|
|
|
Relation indexRelation,
|
|
|
|
int numberOfAttributes,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attributeNumber,
|
1997-09-07 07:04:48 +02:00
|
|
|
IndexStrategy indexStrategy, /* not used */
|
|
|
|
uint16 parameterCount, /* not used */
|
1998-09-01 06:40:42 +02:00
|
|
|
Datum *parameter, /* not used */
|
1997-09-07 07:04:48 +02:00
|
|
|
FuncIndexInfoPtr funcInfo,
|
1997-09-08 23:56:23 +02:00
|
|
|
PredInfo *predInfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapScanDesc scan;
|
|
|
|
HeapTuple heapTuple;
|
|
|
|
IndexTuple indexTuple;
|
|
|
|
TupleDesc heapDescriptor;
|
|
|
|
TupleDesc indexDescriptor;
|
|
|
|
Datum *datum;
|
|
|
|
char *nullv;
|
|
|
|
long reltuples,
|
|
|
|
indtuples;
|
1996-11-05 12:57:55 +01:00
|
|
|
#ifndef OMIT_PARTIAL_INDEX
|
1997-09-08 04:41:22 +02:00
|
|
|
ExprContext *econtext;
|
|
|
|
TupleTable tupleTable;
|
1997-09-07 07:04:48 +02:00
|
|
|
TupleTableSlot *slot;
|
1996-11-05 12:57:55 +01:00
|
|
|
#endif
|
1997-09-08 04:41:22 +02:00
|
|
|
Node *predicate;
|
|
|
|
Node *oldPred;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
InsertIndexResult insertResult;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* more & better checking is needed
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* get the tuple descriptors from the relations so we know
|
|
|
|
* how to form the index tuples..
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
heapDescriptor = RelationGetDescr(heapRelation);
|
|
|
|
indexDescriptor = RelationGetDescr(indexRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* datum and null are arrays in which we collect the index attributes
|
|
|
|
* when forming a new index tuple.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
|
|
|
|
nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* TupleTable and ExprContext objects for this purpose. --Nels, Feb
|
|
|
|
* '92
|
|
|
|
*/
|
|
|
|
|
|
|
|
predicate = predInfo->pred;
|
|
|
|
oldPred = predInfo->oldPred;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
#ifndef OMIT_PARTIAL_INDEX
|
1997-09-07 07:04:48 +02:00
|
|
|
if (predicate != NULL || oldPred != NULL)
|
|
|
|
{
|
|
|
|
tupleTable = ExecCreateTupleTable(1);
|
|
|
|
slot = ExecAllocTableSlot(tupleTable);
|
|
|
|
econtext = makeNode(ExprContext);
|
1998-09-01 06:40:42 +02:00
|
|
|
/* last parameter was junk being sent bjm 1998/08/17 */
|
1998-08-19 04:04:17 +02:00
|
|
|
FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-11-08 01:46:14 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
econtext = NULL;
|
|
|
|
tupleTable = 0;
|
|
|
|
slot = NULL;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
#endif /* OMIT_PARTIAL_INDEX */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* Ok, begin our scan of the base relation.
|
|
|
|
* ----------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
scan = heap_beginscan(heapRelation, /* relation */
|
|
|
|
0, /* start at end */
|
1998-09-01 06:40:42 +02:00
|
|
|
SnapshotNow, /* seeself */
|
1997-09-07 07:04:48 +02:00
|
|
|
0, /* number of keys */
|
|
|
|
(ScanKey) NULL); /* scan key */
|
|
|
|
|
|
|
|
reltuples = indtuples = 0;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* for each tuple in the base relation, we create an index
|
|
|
|
* tuple and add it to the index relation. We keep a running
|
|
|
|
* count of the number of tuples so that we can update pg_class
|
|
|
|
* with correct statistics when we're done building the index.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
reltuples++;
|
|
|
|
|
1999-05-27 00:57:39 +02:00
|
|
|
#ifndef OMIT_PARTIAL_INDEX
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
|
|
|
|
* this tuple if it was already in the existing partial index
|
|
|
|
*/
|
|
|
|
if (oldPred != NULL)
|
|
|
|
{
|
|
|
|
/* SetSlotContents(slot, heapTuple); */
|
|
|
|
slot->val = heapTuple;
|
|
|
|
if (ExecQual((List *) oldPred, econtext) == true)
|
|
|
|
{
|
|
|
|
indtuples++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip this tuple if it doesn't satisfy the partial-index
|
|
|
|
* predicate
|
|
|
|
*/
|
|
|
|
if (predicate != NULL)
|
|
|
|
{
|
|
|
|
/* SetSlotContents(slot, heapTuple); */
|
|
|
|
slot->val = heapTuple;
|
|
|
|
if (ExecQual((List *) predicate, econtext) == false)
|
|
|
|
continue;
|
|
|
|
}
|
1999-05-27 00:57:39 +02:00
|
|
|
#endif /* OMIT_PARTIAL_INDEX */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
indtuples++;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* FormIndexDatum fills in its datum and null parameters
|
|
|
|
* with attribute information taken from the given heap tuple.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
FormIndexDatum(numberOfAttributes, /* num attributes */
|
|
|
|
attributeNumber, /* array of att nums to extract */
|
|
|
|
heapTuple, /* tuple from base relation */
|
|
|
|
heapDescriptor, /* heap tuple's descriptor */
|
|
|
|
datum, /* return: array of attributes */
|
|
|
|
nullv, /* return: array of char's */
|
|
|
|
funcInfo);
|
|
|
|
|
|
|
|
indexTuple = index_formtuple(indexDescriptor,
|
|
|
|
datum,
|
|
|
|
nullv);
|
|
|
|
|
1998-11-27 20:52:36 +01:00
|
|
|
indexTuple->t_tid = heapTuple->t_self;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
insertResult = index_insert(indexRelation, datum, nullv,
|
1998-11-27 20:52:36 +01:00
|
|
|
&(heapTuple->t_self), heapRelation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (insertResult)
|
|
|
|
pfree(insertResult);
|
|
|
|
pfree(indexTuple);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
heap_endscan(scan);
|
|
|
|
|
1999-05-27 00:57:39 +02:00
|
|
|
#ifndef OMIT_PARTIAL_INDEX
|
1997-09-07 07:04:48 +02:00
|
|
|
if (predicate != NULL || oldPred != NULL)
|
|
|
|
{
|
|
|
|
ExecDestroyTupleTable(tupleTable, false);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1999-05-27 00:57:39 +02:00
|
|
|
#endif /* OMIT_PARTIAL_INDEX */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pfree(nullv);
|
|
|
|
pfree(datum);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Okay, now update the reltuples and relpages statistics for both the
|
|
|
|
* heap relation and the index. These statistics are used by the
|
|
|
|
* planner to choose a scan type. They are maintained generally by
|
|
|
|
* the vacuum daemon, but we update them here to make the index useful
|
|
|
|
* as soon as possible.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
UpdateStats(RelationGetRelid(heapRelation), reltuples, true);
|
|
|
|
UpdateStats(RelationGetRelid(indexRelation), indtuples, false);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (oldPred != NULL)
|
|
|
|
{
|
|
|
|
if (indtuples == reltuples)
|
|
|
|
predicate = NULL;
|
1998-08-19 04:04:17 +02:00
|
|
|
UpdateIndexPredicate(RelationGetRelid(indexRelation),
|
|
|
|
oldPred, predicate);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_build
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
index_build(Relation heapRelation,
|
1997-09-07 07:04:48 +02:00
|
|
|
Relation indexRelation,
|
|
|
|
int numberOfAttributes,
|
1998-09-01 05:29:17 +02:00
|
|
|
AttrNumber *attributeNumber,
|
1997-09-07 07:04:48 +02:00
|
|
|
uint16 parameterCount,
|
1997-09-08 23:56:23 +02:00
|
|
|
Datum *parameter,
|
|
|
|
FuncIndexInfo *funcInfo,
|
|
|
|
PredInfo *predInfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RegProcedure procedure;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* sanity checks
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
Assert(RelationIsValid(indexRelation));
|
|
|
|
Assert(PointerIsValid(indexRelation->rd_am));
|
|
|
|
|
|
|
|
procedure = indexRelation->rd_am->ambuild;
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* use the access method build procedure if supplied..
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (RegProcedureIsValid(procedure))
|
|
|
|
fmgr(procedure,
|
|
|
|
heapRelation,
|
|
|
|
indexRelation,
|
|
|
|
numberOfAttributes,
|
|
|
|
attributeNumber,
|
|
|
|
RelationGetIndexStrategy(indexRelation),
|
|
|
|
parameterCount,
|
|
|
|
parameter,
|
|
|
|
funcInfo,
|
|
|
|
predInfo);
|
|
|
|
else
|
|
|
|
DefaultBuild(heapRelation,
|
|
|
|
indexRelation,
|
|
|
|
numberOfAttributes,
|
|
|
|
attributeNumber,
|
|
|
|
RelationGetIndexStrategy(indexRelation),
|
|
|
|
parameterCount,
|
|
|
|
parameter,
|
|
|
|
funcInfo,
|
|
|
|
predInfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1996-11-13 21:56:15 +01:00
|
|
|
/*
|
|
|
|
* IndexIsUnique: given an index's relation OID, see if it
|
|
|
|
* is unique using the system cache.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
IndexIsUnique(Oid indexId)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tuple;
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_index index;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
tuple = SearchSysCacheTuple(INDEXRELID,
|
|
|
|
ObjectIdGetDatum(indexId),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
{
|
1999-05-10 02:46:32 +02:00
|
|
|
elog(ERROR, "IndexIsUnique: can't find index id %u",
|
1997-09-07 07:04:48 +02:00
|
|
|
indexId);
|
|
|
|
}
|
1998-09-01 05:29:17 +02:00
|
|
|
index = (Form_pg_index) GETSTRUCT(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
Assert(index->indexrelid == indexId);
|
|
|
|
|
|
|
|
return index->indisunique;
|
1996-11-13 21:56:15 +01:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-11-13 21:56:15 +01:00
|
|
|
/*
|
|
|
|
* IndexIsUniqueNoCache: same as above function, but don't use the
|
|
|
|
* system cache. if we are called from btbuild, the transaction
|
|
|
|
* that is adding the entry to pg_index has not been committed yet.
|
|
|
|
* the system cache functions will do a heap scan, but only with
|
|
|
|
* NowTimeQual, not SelfTimeQual, so it won't find tuples added
|
|
|
|
* by the current transaction (which is good, because if the transaction
|
|
|
|
* is aborted, you don't want the tuples sitting around in the cache).
|
|
|
|
* so anyway, we have to do our own scan with SelfTimeQual.
|
|
|
|
* this is only called when a new index is created, so it's OK
|
|
|
|
* if it's slow.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
IndexIsUniqueNoCache(Oid indexId)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_index;
|
|
|
|
ScanKeyData skey[1];
|
|
|
|
HeapScanDesc scandesc;
|
|
|
|
HeapTuple tuple;
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_index index;
|
1997-09-08 04:41:22 +02:00
|
|
|
bool isunique;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pg_index = heap_openr(IndexRelationName);
|
|
|
|
|
|
|
|
ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
|
|
|
|
Anum_pg_index_indexrelid,
|
1998-04-27 06:08:07 +02:00
|
|
|
(RegProcedure) F_OIDEQ,
|
1997-09-07 07:04:48 +02:00
|
|
|
ObjectIdGetDatum(indexId));
|
|
|
|
|
1998-07-27 21:38:40 +02:00
|
|
|
scandesc = heap_beginscan(pg_index, 0, SnapshotSelf, 1, skey);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
/* NO CACHE */
|
|
|
|
tuple = heap_getnext(scandesc, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
1999-05-10 02:46:32 +02:00
|
|
|
elog(ERROR, "IndexIsUniqueNoCache: can't find index id %u", indexId);
|
1998-08-19 04:04:17 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
index = (Form_pg_index) GETSTRUCT(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
Assert(index->indexrelid == indexId);
|
|
|
|
isunique = index->indisunique;
|
|
|
|
|
|
|
|
heap_endscan(scandesc);
|
|
|
|
heap_close(pg_index);
|
|
|
|
return isunique;
|
1996-11-13 21:56:15 +01:00
|
|
|
}
|