* indexcmds.c
* POSTGRES define, extend and remove index code.
*
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.34 2000/07/05 23:11:11 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.46 2001/03/22 03:59:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/catname.h"
#include "catalog/heap.h"
#include "catalog/index.h"
+#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_database.h"
#include "catalog/pg_index.h"
static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
-static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo,
- AttrNumber *attNumP, Oid *opOidP, Oid relId,
- char *accessMethodName, Oid accessMethodId);
-static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
- Oid *opOidP, Oid relId,
- char *accessMethodName, Oid accessMethodId);
-static void ProcessAttrTypename(IndexElem *attribute,
- Oid defType, int32 defTypmod);
-static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
- char *accessMethodName, Oid accessMethodId);
+static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
+ IndexElem *funcIndex,
+ Oid relId,
+ char *accessMethodName, Oid accessMethodId);
+static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
+ List *attList,
+ Oid relId,
+ char *accessMethodName, Oid accessMethodId);
+static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
+ char *accessMethodName, Oid accessMethodId);
static char *GetDefaultOpClass(Oid atttypid);
/*
* index or a list of attributes to index on.
* 'parameterList' is a list of DefElem specified in the with clause.
* 'predicate' is the qual specified in the where clause.
- * 'rangetable' is for the predicate
- *
- * Exceptions:
- * XXX
+ * 'rangetable' is needed to interpret the predicate
*/
void
DefineIndex(char *heapRelationName,
Oid *classObjectId;
Oid accessMethodId;
Oid relationId;
+ IndexInfo *indexInfo;
int numberOfAttributes;
- AttrNumber *attributeNumberA;
- HeapTuple tuple;
- FuncIndexInfo fInfo;
- List *cnfPred = NULL;
+ List *cnfPred = NIL;
bool lossy = false;
List *pl;
/*
- * count attributes
+ * count attributes in index
*/
numberOfAttributes = length(attributeList);
if (numberOfAttributes <= 0)
* compute heap relation id
*/
if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid)
- {
elog(ERROR, "DefineIndex: relation \"%s\" not found",
heapRelationName);
- }
-
- /*
- * XXX Hardwired hacks to check for limitations on supported index types.
- * We really ought to be learning this info from entries in the pg_am
- * table, instead of having it wired in here!
- */
- if (unique && strcmp(accessMethodName, "btree") != 0)
- elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
-
- if (numberOfAttributes > 1 && strcmp(accessMethodName, "btree") != 0)
- elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
/*
* compute access method id
*/
- tuple = SearchSysCacheTuple(AMNAME,
- PointerGetDatum(accessMethodName),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- {
+ accessMethodId = GetSysCacheOid(AMNAME,
+ PointerGetDatum(accessMethodName),
+ 0, 0, 0);
+ if (!OidIsValid(accessMethodId))
elog(ERROR, "DefineIndex: access method \"%s\" not found",
accessMethodName);
- }
- accessMethodId = tuple->t_data->t_oid;
+
+ /*
+ * XXX Hardwired hacks to check for limitations on supported index
+ * types. We really ought to be learning this info from entries in the
+ * pg_am table, instead of having it wired in here!
+ */
+ if (unique && accessMethodId != BTREE_AM_OID)
+ elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
+
+ if (numberOfAttributes > 1 && accessMethodId != BTREE_AM_OID)
+ elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
/*
* WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
DefElem *param = (DefElem *) lfirst(pl);
if (!strcasecmp(param->defname, "islossy"))
- lossy = TRUE;
+ lossy = true;
else
elog(NOTICE, "Unrecognized index attribute \"%s\" ignored",
param->defname);
if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false))
elog(ERROR, "Existing indexes are inactive. REINDEX first");
+ /*
+ * Prepare arguments for index_create, primarily an IndexInfo
+ * structure
+ */
+ indexInfo = makeNode(IndexInfo);
+ indexInfo->ii_Predicate = (Node *) cnfPred;
+ indexInfo->ii_FuncOid = InvalidOid;
+ indexInfo->ii_Unique = unique;
+
if (IsFuncIndex(attributeList))
{
- IndexElem *funcIndex = lfirst(attributeList);
+ IndexElem *funcIndex = (IndexElem *) lfirst(attributeList);
int nargs;
+ /* Parser should have given us only one list item, but check */
+ if (numberOfAttributes != 1)
+ elog(ERROR, "Functional index can only have one attribute");
+
nargs = length(funcIndex->args);
if (nargs > INDEX_MAX_KEYS)
elog(ERROR, "Index function can take at most %d arguments",
INDEX_MAX_KEYS);
- FIsetnArgs(&fInfo, nargs);
-
- namestrcpy(&fInfo.funcName, funcIndex->name);
-
- attributeNumberA = (AttrNumber *) palloc(nargs *
- sizeof attributeNumberA[0]);
+ indexInfo->ii_NumIndexAttrs = 1;
+ indexInfo->ii_NumKeyAttrs = nargs;
classObjectId = (Oid *) palloc(sizeof(Oid));
- FuncIndexArgs(funcIndex, &fInfo, attributeNumberA,
- classObjectId, relationId,
- accessMethodName, accessMethodId);
-
- index_create(heapRelationName, indexRelationName,
- &fInfo, NULL,
- accessMethodId, numberOfAttributes, attributeNumberA,
- classObjectId,
- (Node *) cnfPred,
- lossy, unique, primary, allowSystemTableMods);
+ FuncIndexArgs(indexInfo, classObjectId, funcIndex,
+ relationId, accessMethodName, accessMethodId);
}
else
{
- attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
- sizeof attributeNumberA[0]);
+ indexInfo->ii_NumIndexAttrs = numberOfAttributes;
+ indexInfo->ii_NumKeyAttrs = numberOfAttributes;
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
- NormIndexAttrs(attributeList, attributeNumberA,
- classObjectId, relationId,
- accessMethodName, accessMethodId);
-
- index_create(heapRelationName, indexRelationName,
- NULL, attributeList,
- accessMethodId, numberOfAttributes, attributeNumberA,
- classObjectId,
- (Node *) cnfPred,
- lossy, unique, primary, allowSystemTableMods);
+ NormIndexAttrs(indexInfo, classObjectId, attributeList,
+ relationId, accessMethodName, accessMethodId);
}
+ index_create(heapRelationName, indexRelationName,
+ indexInfo, accessMethodId, classObjectId,
+ lossy, primary, allowSystemTableMods);
+
/*
* We update the relation's pg_class tuple even if it already has
- * relhasindex = true. This is needed to cause a shared-cache-inval
+ * relhasindex = true. This is needed to cause a shared-cache-inval
* message to be sent for the pg_class tuple, which will cause other
* backends to flush their relcache entries and in particular their
* cached lists of the indexes for this relation.
*/
- setRelhasindexInplace(relationId, true, false);
+ setRelhasindex(relationId, true);
}
/*
* ExtendIndex
* Extends a partial index.
- *
- * Exceptions:
- * XXX
*/
void
ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
{
- Oid *classObjectId;
- Oid accessMethodId;
- Oid indexId,
+ Relation heapRelation;
+ Relation indexRelation;
+ Oid accessMethodId,
+ indexId,
relationId;
- Oid indproc;
- int numberOfAttributes;
- AttrNumber *attributeNumberA;
HeapTuple tuple;
- FuncIndexInfo fInfo;
- FuncIndexInfo *funcInfo = NULL;
- bool unique;
Form_pg_index index;
- Node *oldPred = NULL;
- List *cnfPred = NULL;
- PredInfo *predInfo;
- Relation heapRelation;
- Relation indexRelation;
- int i;
+ List *cnfPred = NIL;
+ IndexInfo *indexInfo;
+ Node *oldPred;
/*
- * compute index relation id and access method id
+ * Get index's relation id and access method id from pg_class
*/
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(indexRelationName),
- 0, 0, 0);
+ tuple = SearchSysCache(RELNAME,
+ PointerGetDatum(indexRelationName),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- {
elog(ERROR, "ExtendIndex: index \"%s\" not found",
indexRelationName);
- }
indexId = tuple->t_data->t_oid;
accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
+ ReleaseSysCache(tuple);
/*
- * find pg_index tuple
+ * Extract info from the pg_index tuple for the index
*/
- tuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(indexId),
- 0, 0, 0);
+ tuple = SearchSysCache(INDEXRELID,
+ ObjectIdGetDatum(indexId),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- {
elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
indexRelationName);
- }
-
- /*
- * Extract info from the pg_index tuple
- */
index = (Form_pg_index) GETSTRUCT(tuple);
Assert(index->indexrelid == indexId);
relationId = index->indrelid;
- indproc = index->indproc;
- unique = index->indisunique;
+ indexInfo = BuildIndexInfo(tuple);
+ oldPred = indexInfo->ii_Predicate;
+ ReleaseSysCache(tuple);
- for (i = 0; i < INDEX_MAX_KEYS; i++)
- {
- if (index->indkey[i] == InvalidAttrNumber)
- break;
- }
- numberOfAttributes = i;
-
- if (VARSIZE(&index->indpred) != 0)
- {
- char *predString;
-
- predString = DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(&index->indpred)));
- oldPred = stringToNode(predString);
- pfree(predString);
- }
if (oldPred == NULL)
elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
indexRelationName);
/*
* Convert the extension predicate from parsetree form to plan form,
* so it can be readily evaluated during index creation. Note:
- * "predicate" comes in as a list containing (1) the predicate itself
- * (a where_clause), and (2) a corresponding range table.
+ * "predicate" comes in two parts (1) the predicate expression itself,
+ * and (2) a corresponding range table.
+ *
+ * XXX I think this code is broken --- index_build expects a single
+ * expression not a list --- tgl Jul 00
*/
if (rangetable != NIL)
{
CheckPredicate(cnfPred, rangetable, relationId);
}
- /* make predInfo list to pass to index_build */
- predInfo = (PredInfo *) palloc(sizeof(PredInfo));
- predInfo->pred = (Node *) cnfPred;
- predInfo->oldPred = oldPred;
-
- attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
- sizeof attributeNumberA[0]);
- classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
-
-
- for (i = 0; i < numberOfAttributes; i++)
- {
- attributeNumberA[i] = index->indkey[i];
- classObjectId[i] = index->indclass[i];
- }
-
- if (indproc != InvalidOid)
- {
- funcInfo = &fInfo;
- FIsetnArgs(funcInfo, numberOfAttributes);
-
- tuple = SearchSysCacheTuple(PROCOID,
- ObjectIdGetDatum(indproc),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "ExtendIndex: index procedure %u not found",
- indproc);
-
- namecpy(&(funcInfo->funcName),
- &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
-
- FIsetProcOid(funcInfo, tuple->t_data->t_oid);
- }
+ /* pass new predicate to index_build */
+ indexInfo->ii_Predicate = (Node *) cnfPred;
+ /* Open heap and index rels, and get suitable locks */
heapRelation = heap_open(relationId, ShareLock);
indexRelation = index_open(indexId);
- InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
+ /* Obtain exclusive lock on it, just to be sure */
+ LockRelation(indexRelation, AccessExclusiveLock);
+
+ InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
+ indexRelation, accessMethodId);
- index_build(heapRelation, indexRelation, numberOfAttributes,
- attributeNumberA, funcInfo, predInfo, unique);
+ index_build(heapRelation, indexRelation, indexInfo, oldPred);
/* heap and index rels are closed as a side-effect of index_build */
}
static void
-FuncIndexArgs(IndexElem *funcIndex,
- FuncIndexInfo *funcInfo,
- AttrNumber *attNumP,
- Oid *opOidP,
+FuncIndexArgs(IndexInfo *indexInfo,
+ Oid *classOidP,
+ IndexElem *funcIndex,
Oid relId,
char *accessMethodName,
Oid accessMethodId)
{
- List *rest;
- HeapTuple tuple;
- Oid retType;
- int argn = 0;
+ Oid argTypes[FUNC_MAX_ARGS];
+ List *arglist;
+ int nargs = 0;
+ int i;
+ Oid funcid;
+ Oid rettype;
+ bool retset;
+ Oid *true_typeids;
/*
* process the function arguments, which are a list of T_String
* (someday ought to allow more general expressions?)
+ *
+ * Note caller already checked that list is not too long.
*/
- MemSet(funcInfo->arglist, 0, FUNC_MAX_ARGS * sizeof(Oid));
+ MemSet(argTypes, 0, sizeof(argTypes));
- foreach(rest, funcIndex->args)
+ foreach(arglist, funcIndex->args)
{
- char *arg = strVal(lfirst(rest));
+ char *arg = strVal(lfirst(arglist));
+ HeapTuple tuple;
Form_pg_attribute att;
- tuple = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relId),
- PointerGetDatum(arg), 0, 0);
-
+ tuple = SearchSysCache(ATTNAME,
+ ObjectIdGetDatum(relId),
+ PointerGetDatum(arg),
+ 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
att = (Form_pg_attribute) GETSTRUCT(tuple);
- *attNumP++ = att->attnum;
- funcInfo->arglist[argn++] = att->atttypid;
+ indexInfo->ii_KeyAttrNumbers[nargs] = att->attnum;
+ argTypes[nargs] = att->atttypid;
+ ReleaseSysCache(tuple);
+ nargs++;
}
/* ----------------
* Lookup the function procedure to get its OID and result type.
+ *
+ * We rely on parse_func.c to find the correct function in the
+ * possible presence of binary-compatible types. However, parse_func
+ * may do too much: it will accept a function that requires run-time
+ * coercion of input types, and the executor is not currently set up
+ * to support that. So, check to make sure that the selected function
+ * has exact-match or binary-compatible input types.
* ----------------
*/
- tuple = SearchSysCacheTuple(PROCNAME,
- PointerGetDatum(FIgetname(funcInfo)),
- Int32GetDatum(FIgetnArgs(funcInfo)),
- PointerGetDatum(FIgetArglist(funcInfo)),
- 0);
+ if (!func_get_detail(funcIndex->name, nargs, argTypes,
+ &funcid, &rettype, &retset, &true_typeids))
+ func_error("DefineIndex", funcIndex->name, nargs, argTypes, NULL);
- if (!HeapTupleIsValid(tuple))
+ if (retset)
+ elog(ERROR, "DefineIndex: cannot index on a function returning a set");
+
+ for (i = 0; i < nargs; i++)
{
- func_error("DefineIndex", FIgetname(funcInfo),
- FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
+ if (argTypes[i] != true_typeids[i] &&
+ !IS_BINARY_COMPATIBLE(argTypes[i], true_typeids[i]))
+ func_error("DefineIndex", funcIndex->name, nargs, argTypes,
+ "Index function must be binary-compatible with table datatype");
}
- FIsetProcOid(funcInfo, tuple->t_data->t_oid);
- retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
+ /* Process opclass, using func return type as default type */
- /* Process type and opclass, using func return type as default */
+ classOidP[0] = GetAttrOpClass(funcIndex, rettype,
+ accessMethodName, accessMethodId);
- ProcessAttrTypename(funcIndex, retType, -1);
+ /* OK, return results */
- *opOidP = GetAttrOpClass(funcIndex, retType,
- accessMethodName, accessMethodId);
+ indexInfo->ii_FuncOid = funcid;
+ /* Need to do the fmgr function lookup now, too */
+ fmgr_info(funcid, &indexInfo->ii_FuncInfo);
}
static void
-NormIndexAttrs(List *attList, /* list of IndexElem's */
- AttrNumber *attNumP,
+NormIndexAttrs(IndexInfo *indexInfo,
Oid *classOidP,
+ List *attList, /* list of IndexElem's */
Oid relId,
char *accessMethodName,
Oid accessMethodId)
{
List *rest;
+ int attn = 0;
/*
* process attributeList
*/
foreach(rest, attList)
{
- IndexElem *attribute = lfirst(rest);
+ IndexElem *attribute = (IndexElem *) lfirst(rest);
HeapTuple atttuple;
Form_pg_attribute attform;
if (attribute->name == NULL)
elog(ERROR, "missing attribute for define index");
- atttuple = SearchSysCacheTupleCopy(ATTNAME,
- ObjectIdGetDatum(relId),
- PointerGetDatum(attribute->name),
- 0, 0);
+ atttuple = SearchSysCache(ATTNAME,
+ ObjectIdGetDatum(relId),
+ PointerGetDatum(attribute->name),
+ 0, 0);
if (!HeapTupleIsValid(atttuple))
elog(ERROR, "DefineIndex: attribute \"%s\" not found",
attribute->name);
attform = (Form_pg_attribute) GETSTRUCT(atttuple);
- *attNumP++ = attform->attnum;
-
- ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod);
+ indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
- *classOidP++ = GetAttrOpClass(attribute, attform->atttypid,
- accessMethodName, accessMethodId);
+ classOidP[attn] = GetAttrOpClass(attribute, attform->atttypid,
+ accessMethodName, accessMethodId);
- heap_freetuple(atttuple);
- }
-}
-
-static void
-ProcessAttrTypename(IndexElem *attribute,
- Oid defType, int32 defTypmod)
-{
- HeapTuple tuple;
-
- /* build a type node so we can set the proper alignment, etc. */
- if (attribute->typename == NULL)
- {
- tuple = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(defType),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "DefineIndex: type for attribute \"%s\" undefined",
- attribute->name);
-
- attribute->typename = makeNode(TypeName);
- attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
- attribute->typename->typmod = defTypmod;
+ ReleaseSysCache(atttuple);
+ attn++;
}
}
doTypeCheck = false;
}
- tuple = SearchSysCacheTuple(CLANAME,
- PointerGetDatum(attribute->class),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
+ opClassId = GetSysCacheOid(CLANAME,
+ PointerGetDatum(attribute->class),
+ 0, 0, 0);
+ if (!OidIsValid(opClassId))
elog(ERROR, "DefineIndex: opclass \"%s\" not found",
attribute->class);
- opClassId = tuple->t_data->t_oid;
/*
- * Assume the opclass is supported by this index access method
- * if we can find at least one relevant entry in pg_amop.
+ * Assume the opclass is supported by this index access method if we
+ * can find at least one relevant entry in pg_amop.
*/
ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_amop_amopid,
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
- if (! HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
- {
+ if (!HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
elog(ERROR, "DefineIndex: opclass \"%s\" not supported by access method \"%s\"",
attribute->class, accessMethodName);
- }
oprId = ((Form_pg_amop) GETSTRUCT(tuple))->amopopr;
heap_close(relation, AccessShareLock);
/*
- * Make sure the operators associated with this opclass actually accept
- * the column data type. This prevents possible coredumps caused by
- * user errors like applying text_ops to an int4 column. We will accept
- * an opclass as OK if the operator's input datatype is binary-compatible
- * with the actual column datatype. Note we assume that all the operators
- * associated with an opclass accept the same datatypes, so checking the
- * first one we happened to find in the table is sufficient.
+ * Make sure the operators associated with this opclass actually
+ * accept the column data type. This prevents possible coredumps
+ * caused by user errors like applying text_ops to an int4 column. We
+ * will accept an opclass as OK if the operator's input datatype is
+ * binary-compatible with the actual column datatype. Note we assume
+ * that all the operators associated with an opclass accept the same
+ * datatypes, so checking the first one we happened to find in the
+ * table is sufficient.
*
* If the opclass was the default for the datatype, assume we can skip
- * this check --- that saves a few cycles in the most common case.
- * If pg_opclass is messed up then we're probably screwed anyway...
+ * this check --- that saves a few cycles in the most common case. If
+ * pg_opclass is wrong then we're probably screwed anyway...
*/
if (doTypeCheck)
{
- tuple = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(oprId),
- 0, 0, 0);
+ tuple = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oprId),
+ 0, 0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tuple);
- Oid opInputType = (optup->oprkind == 'l') ?
- optup->oprright : optup->oprleft;
+ Oid opInputType = (optup->oprkind == 'l') ?
+ optup->oprright : optup->oprleft;
if (attrType != opInputType &&
- ! IS_BINARY_COMPATIBLE(attrType, opInputType))
+ !IS_BINARY_COMPATIBLE(attrType, opInputType))
elog(ERROR, "DefineIndex: opclass \"%s\" does not accept datatype \"%s\"",
attribute->class, typeidTypeName(attrType));
+ ReleaseSysCache(tuple);
}
}
GetDefaultOpClass(Oid atttypid)
{
HeapTuple tuple;
+ char *result;
- tuple = SearchSysCacheTuple(CLADEFTYPE,
- ObjectIdGetDatum(atttypid),
- 0, 0, 0);
+ tuple = SearchSysCache(CLADEFTYPE,
+ ObjectIdGetDatum(atttypid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
return NULL;
- return nameout(&((Form_pg_opclass) GETSTRUCT(tuple))->opcname);
+ result = pstrdup(NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname));
+
+ ReleaseSysCache(tuple);
+ return result;
}
/*
*
* Exceptions:
* BadArg if name is invalid.
- * "WARN" if index nonexistent.
+ * "ERROR" if index nonexistent.
* ...
*/
void
{
HeapTuple tuple;
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(name),
- 0, 0, 0);
-
+ tuple = SearchSysCache(RELNAME,
+ PointerGetDatum(name),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "index \"%s\" nonexistent", name);
+ elog(ERROR, "index \"%s\" does not exist", name);
if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
- {
elog(ERROR, "relation \"%s\" is of type \"%c\"",
- name,
- ((Form_pg_class) GETSTRUCT(tuple))->relkind);
- }
+ name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
index_drop(tuple->t_data->t_oid);
+
+ ReleaseSysCache(tuple);
}
/*
ReindexIndex(const char *name, bool force /* currently unused */ )
{
HeapTuple tuple;
+ bool overwrite = false;
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(name),
- 0, 0, 0);
+ /* ----------------
+ * 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.
+ * ----------------
+ */
+ if (IsTransactionBlock())
+ elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
+ tuple = SearchSysCache(RELNAME,
+ PointerGetDatum(name),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "index \"%s\" nonexistent", name);
+ elog(ERROR, "index \"%s\" does not exist", name);
if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
- {
elog(ERROR, "relation \"%s\" is of type \"%c\"",
- name,
- ((Form_pg_class) GETSTRUCT(tuple))->relkind);
- }
-
- if (!reindex_index(tuple->t_data->t_oid, force))
- elog(NOTICE, "index '%s' wasn't reindexed", name);
+ name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
+
+#ifdef OLD_FILE_NAMING
+ if (!reindex_index(tuple->t_data->t_oid, force, false))
+#else
+ if (IsIgnoringSystemIndexes())
+ overwrite = true;
+ if (!reindex_index(tuple->t_data->t_oid, force, overwrite))
+#endif /* OLD_FILE_NAMING */
+ elog(NOTICE, "index \"%s\" wasn't reindexed", name);
+
+ ReleaseSysCache(tuple);
}
/*
{
HeapTuple tuple;
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(name),
- 0, 0, 0);
+ /* ----------------
+ * 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.
+ * ----------------
+ */
+ if (IsTransactionBlock())
+ elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
+ tuple = SearchSysCache(RELNAME,
+ PointerGetDatum(name),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "table \"%s\" nonexistent", name);
+ elog(ERROR, "table \"%s\" does not exist", name);
if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION)
- {
elog(ERROR, "relation \"%s\" is of type \"%c\"",
- name,
- ((Form_pg_class) GETSTRUCT(tuple))->relkind);
- }
+ name, ((Form_pg_class) GETSTRUCT(tuple))->relkind);
if (!reindex_relation(tuple->t_data->t_oid, force))
- elog(NOTICE, "table '%s' wasn't reindexed", name);
+ elog(NOTICE, "table \"%s\" wasn't reindexed", name);
+
+ ReleaseSysCache(tuple);
}
/*
{
Relation relation,
relationRelation;
- HeapTuple usertuple,
- dbtuple,
+ HeapTuple dbtuple,
tuple;
HeapScanDesc scan;
- int4 user_id,
- db_owner;
- bool superuser;
+ int4 db_owner;
Oid db_id;
- char *username;
ScanKeyData scankey;
MemoryContext private_context;
MemoryContext old;
AssertArg(dbname);
- username = GetPgUserName();
- usertuple = SearchSysCacheTuple(SHADOWNAME, PointerGetDatum(username),
- 0, 0, 0);
- if (!HeapTupleIsValid(usertuple))
- elog(ERROR, "Current user \"%s\" is invalid.", username);
- user_id = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesysid;
- superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper;
-
relation = heap_openr(DatabaseRelationName, AccessShareLock);
ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname,
F_NAMEEQ, NameGetDatum(dbname));
scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scankey);
dbtuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(dbtuple))
- elog(ERROR, "Database \"%s\" doesn't exist", dbname);
+ elog(ERROR, "Database \"%s\" does not exist", dbname);
db_id = dbtuple->t_data->t_oid;
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
heap_endscan(scan);
heap_close(relation, NoLock);
- if (user_id != db_owner && !superuser)
+ if (GetUserId() != db_owner && !superuser())
elog(ERROR, "REINDEX DATABASE: Permission denied.");
if (db_id != MyDatabaseId)
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
/*
- * We cannot run inside a user transaction block; if we were
- * inside a transaction, then our commit- and
- * start-transaction-command calls would not have the intended effect!
+ * We cannot run inside a user transaction block; if we were inside a
+ * transaction, then our commit- and start-transaction-command calls
+ * would not have the intended effect!
*/
if (IsTransactionBlock())
elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
/*
- * Create a memory context that will survive forced transaction commits
- * we do below. Since it is a child of QueryContext, it will go away
- * eventually even if we suffer an error; there's no need for special
- * abort cleanup logic.
+ * Create a memory context that will survive forced transaction
+ * commits we do below. Since it is a child of QueryContext, it will
+ * go away eventually even if we suffer an error; there's no need for
+ * special abort cleanup logic.
*/
private_context = AllocSetContextCreate(QueryContext,
"ReindexDatabase",
{
StartTransactionCommand();
if (reindex_relation(relids[i], force))
- elog(NOTICE, "relation %d was reindexed", relids[i]);
+ elog(NOTICE, "relation %u was reindexed", relids[i]);
CommitTransactionCommand();
}
StartTransactionCommand();