aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/cluster.c55
-rw-r--r--src/backend/commands/indexcmds.c310
-rw-r--r--src/backend/commands/tablecmds.c124
-rw-r--r--src/backend/commands/vacuum.c11
4 files changed, 221 insertions, 279 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 09ef0ac598e..87062782456 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.109 2003/05/14 03:26:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.110 2003/05/28 16:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -214,7 +214,7 @@ cluster(ClusterStmt *stmt)
/* Start a new transaction for each relation. */
StartTransactionCommand();
- SetQuerySnapshot(); /* might be needed for functional index */
+ SetQuerySnapshot(); /* might be needed for functions in indexes */
cluster_rel(rvtc, true);
CommitTransactionCommand();
}
@@ -320,7 +320,7 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
* seqscan pass over the table to copy the missing rows, but that seems
* expensive and tedious.
*/
- if (VARSIZE(&OldIndex->rd_index->indpred) > VARHDRSZ) /* partial? */
+ if (!heap_attisnull(OldIndex->rd_indextuple, Anum_pg_index_indpred))
elog(ERROR, "CLUSTER: cannot cluster on partial index");
if (!OldIndex->rd_am->amindexnulls)
{
@@ -332,14 +332,24 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
* at the first column; multicolumn-capable AMs are *required* to
* index nulls in columns after the first.
*/
- if (OidIsValid(OldIndex->rd_index->indproc))
- elog(ERROR, "CLUSTER: cannot cluster on functional index when index access method does not handle nulls");
colno = OldIndex->rd_index->indkey[0];
- if (colno > 0) /* system columns are non-null */
+ if (colno > 0)
+ {
+ /* ordinary user attribute */
if (!OldHeap->rd_att->attrs[colno - 1]->attnotnull)
elog(ERROR, "CLUSTER: cannot cluster when index access method does not handle nulls"
"\n\tYou may be able to work around this by marking column \"%s\" NOT NULL",
NameStr(OldHeap->rd_att->attrs[colno - 1]->attname));
+ }
+ else if (colno < 0)
+ {
+ /* system column --- okay, always non-null */
+ }
+ else
+ {
+ /* index expression, lose... */
+ elog(ERROR, "CLUSTER: cannot cluster on expressional index when index access method does not handle nulls");
+ }
}
/*
@@ -557,43 +567,24 @@ get_indexattr_list(Relation OldHeap, Oid OldIndex)
foreach(indlist, RelationGetIndexList(OldHeap))
{
Oid indexOID = lfirsto(indlist);
- HeapTuple indexTuple;
- HeapTuple classTuple;
- Form_pg_index indexForm;
- Form_pg_class classForm;
+ Relation oldIndex;
IndexAttrs *attrs;
- indexTuple = SearchSysCache(INDEXRELID,
- ObjectIdGetDatum(indexOID),
- 0, 0, 0);
- if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "Cache lookup failed for index %u", indexOID);
- indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
- Assert(indexForm->indexrelid == indexOID);
+ oldIndex = index_open(indexOID);
attrs = (IndexAttrs *) palloc(sizeof(IndexAttrs));
attrs->indexOID = indexOID;
- attrs->indexInfo = BuildIndexInfo(indexForm);
+ attrs->indexName = pstrdup(NameStr(oldIndex->rd_rel->relname));
+ attrs->accessMethodOID = oldIndex->rd_rel->relam;
+ attrs->indexInfo = BuildIndexInfo(oldIndex);
attrs->classOID = (Oid *)
palloc(sizeof(Oid) * attrs->indexInfo->ii_NumIndexAttrs);
- memcpy(attrs->classOID, indexForm->indclass,
+ memcpy(attrs->classOID, oldIndex->rd_index->indclass,
sizeof(Oid) * attrs->indexInfo->ii_NumIndexAttrs);
/* We adjust the isclustered attribute to correct new state */
attrs->isclustered = (indexOID == OldIndex);
- /* Name and access method of each index come from pg_class */
- classTuple = SearchSysCache(RELOID,
- ObjectIdGetDatum(indexOID),
- 0, 0, 0);
- if (!HeapTupleIsValid(classTuple))
- elog(ERROR, "Cache lookup failed for index %u", indexOID);
- classForm = (Form_pg_class) GETSTRUCT(classTuple);
-
- attrs->indexName = pstrdup(NameStr(classForm->relname));
- attrs->accessMethodOID = classForm->relam;
-
- ReleaseSysCache(classTuple);
- ReleaseSysCache(indexTuple);
+ index_close(oldIndex);
/*
* Cons the gathered data into the list. We do not care about
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 6a371587368..4186a145795 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.99 2003/05/14 03:26:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.100 2003/05/28 16:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,6 +32,7 @@
#include "optimizer/prep.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
+#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "utils/acl.h"
#include "utils/builtins.h"
@@ -39,19 +40,13 @@
#include "utils/syscache.h"
-#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->funcname != NIL)
-
/* non-export function prototypes */
-static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
-static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
- IndexElem *funcIndex,
- Oid relId,
- char *accessMethodName, Oid accessMethodId);
-static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
+static void CheckPredicate(List *predList);
+static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
List *attList,
Oid relId,
char *accessMethodName, Oid accessMethodId);
-static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
+static Oid GetIndexOpClass(List *opclass, Oid attrType,
char *accessMethodName, Oid accessMethodId);
static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId);
@@ -59,8 +54,8 @@ static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId);
* DefineIndex
* Creates a new index.
*
- * 'attributeList' is a list of IndexElem specifying either a functional
- * index or a list of attributes to index on.
+ * 'attributeList' is a list of IndexElem specifying columns and expressions
+ * to index on.
* 'predicate' is the qual specified in the where clause.
* 'rangetable' is needed to interpret the predicate.
*/
@@ -156,6 +151,16 @@ DefineIndex(RangeVar *heapRelation,
ReleaseSysCache(tuple);
/*
+ * If a range table was created then check that only the base rel is
+ * mentioned.
+ */
+ if (rangetable != NIL)
+ {
+ if (length(rangetable) != 1 || getrelid(1, rangetable) != relationId)
+ elog(ERROR, "index expressions and predicates may refer only to the base relation");
+ }
+
+ /*
* Convert the partial-index predicate from parsetree form to an
* implicit-AND qual expression, for easier evaluation at runtime.
* While we are at it, we reduce it to a canonical (CNF or DNF) form
@@ -164,14 +169,14 @@ DefineIndex(RangeVar *heapRelation,
if (predicate)
{
cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
- CheckPredicate(cnfPred, rangetable, relationId);
+ CheckPredicate(cnfPred);
}
/*
* Check that all of the attributes in a primary key are marked
* as not null, otherwise attempt to ALTER TABLE .. SET NOT NULL
*/
- if (primary && !IsFuncIndex(attributeList))
+ if (primary)
{
List *keys;
@@ -180,6 +185,9 @@ DefineIndex(RangeVar *heapRelation,
IndexElem *key = (IndexElem *) lfirst(keys);
HeapTuple atttuple;
+ if (!key->name)
+ elog(ERROR, "primary keys cannot be expressions");
+
/* System attributes are never null, so no problem */
if (SystemAttributeByName(key->name, rel->rd_rel->relhasoids))
continue;
@@ -216,43 +224,16 @@ DefineIndex(RangeVar *heapRelation,
* structure
*/
indexInfo = makeNode(IndexInfo);
+ indexInfo->ii_NumIndexAttrs = numberOfAttributes;
+ indexInfo->ii_Expressions = NIL; /* for now */
+ indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_Predicate = cnfPred;
indexInfo->ii_PredicateState = NIL;
- indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = unique;
- if (IsFuncIndex(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);
-
- indexInfo->ii_NumIndexAttrs = 1;
- indexInfo->ii_NumKeyAttrs = nargs;
-
- classObjectId = (Oid *) palloc(sizeof(Oid));
-
- FuncIndexArgs(indexInfo, classObjectId, funcIndex,
+ classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
+ ComputeIndexAttrs(indexInfo, classObjectId, attributeList,
relationId, accessMethodName, accessMethodId);
- }
- else
- {
- indexInfo->ii_NumIndexAttrs = numberOfAttributes;
- indexInfo->ii_NumKeyAttrs = numberOfAttributes;
-
- classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
-
- NormIndexAttrs(indexInfo, classObjectId, attributeList,
- relationId, accessMethodName, accessMethodId);
- }
index_create(relationId, indexRelationName,
indexInfo, accessMethodId, classObjectId,
@@ -271,8 +252,7 @@ DefineIndex(RangeVar *heapRelation,
/*
* CheckPredicate
- * Checks that the given list of partial-index predicates refer
- * (via the given range table) only to the given base relation oid.
+ * Checks that the given list of partial-index predicates is valid.
*
* This used to also constrain the form of the predicate to forms that
* indxpath.c could do something with. However, that seems overly
@@ -281,14 +261,9 @@ DefineIndex(RangeVar *heapRelation,
* any evaluatable predicate will work. So accept any predicate here
* (except ones requiring a plan), and let indxpath.c fend for itself.
*/
-
static void
-CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
+CheckPredicate(List *predList)
{
- if (length(rangeTable) != 1 || getrelid(1, rangeTable) != baseRelOid)
- elog(ERROR,
- "Partial-index predicates may refer only to the base relation");
-
/*
* We don't currently support generation of an actual query plan for a
* predicate, only simple scalar expressions; hence these
@@ -301,119 +276,19 @@ CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
/*
* A predicate using mutable functions is probably wrong, for the same
- * reasons that we don't allow a functional index to use one.
+ * reasons that we don't allow an index expression to use one.
*/
if (contain_mutable_functions((Node *) predList))
elog(ERROR, "Functions in index predicate must be marked IMMUTABLE");
}
-
static void
-FuncIndexArgs(IndexInfo *indexInfo,
- Oid *classOidP,
- IndexElem *funcIndex,
- Oid relId,
- char *accessMethodName,
- Oid accessMethodId)
-{
- Oid argTypes[FUNC_MAX_ARGS];
- List *arglist;
- int nargs = 0;
- int i;
- FuncDetailCode fdresult;
- 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(argTypes, 0, sizeof(argTypes));
-
- foreach(arglist, funcIndex->args)
- {
- char *arg = strVal(lfirst(arglist));
- HeapTuple tuple;
- Form_pg_attribute att;
-
- tuple = SearchSysCacheAttName(relId, arg);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "DefineIndex: column \"%s\" named in key does not exist", arg);
- att = (Form_pg_attribute) GETSTRUCT(tuple);
- 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.
- */
- fdresult = func_get_detail(funcIndex->funcname, funcIndex->args,
- nargs, argTypes,
- &funcid, &rettype, &retset,
- &true_typeids);
- if (fdresult != FUNCDETAIL_NORMAL)
- {
- if (fdresult == FUNCDETAIL_AGGREGATE)
- elog(ERROR, "DefineIndex: functional index may not use an aggregate function");
- else if (fdresult == FUNCDETAIL_COERCION)
- elog(ERROR, "DefineIndex: functional index must use a real function, not a type coercion"
- "\n\tTry specifying the index opclass you want to use, instead");
- else
- func_error("DefineIndex", funcIndex->funcname, nargs, argTypes,
- NULL);
- }
-
- if (retset)
- elog(ERROR, "DefineIndex: cannot index on a function returning a set");
-
- for (i = 0; i < nargs; i++)
- {
- if (!IsBinaryCoercible(argTypes[i], true_typeids[i]))
- func_error("DefineIndex", funcIndex->funcname, nargs, true_typeids,
- "Index function must be binary-compatible with table datatype");
- }
-
- /*
- * Require that the function be marked immutable. Using a mutable
- * function for a functional index is highly questionable, since if
- * you aren't going to get the same result for the same data every
- * time, it's not clear what the index entries mean at all.
- */
- if (func_volatile(funcid) != PROVOLATILE_IMMUTABLE)
- elog(ERROR, "DefineIndex: index function must be marked IMMUTABLE");
-
- /* Process opclass, using func return type as default type */
-
- classOidP[0] = GetAttrOpClass(funcIndex, rettype,
- accessMethodName, accessMethodId);
-
- /* OK, return results */
-
- indexInfo->ii_FuncOid = funcid;
- /* Need to do the fmgr function lookup now, too */
- fmgr_info(funcid, &indexInfo->ii_FuncInfo);
-}
-
-static void
-NormIndexAttrs(IndexInfo *indexInfo,
- Oid *classOidP,
- List *attList, /* list of IndexElem's */
- Oid relId,
- char *accessMethodName,
- Oid accessMethodId)
+ComputeIndexAttrs(IndexInfo *indexInfo,
+ Oid *classOidP,
+ List *attList, /* list of IndexElem's */
+ Oid relId,
+ char *accessMethodName,
+ Oid accessMethodId)
{
List *rest;
int attn = 0;
@@ -424,31 +299,75 @@ NormIndexAttrs(IndexInfo *indexInfo,
foreach(rest, attList)
{
IndexElem *attribute = (IndexElem *) lfirst(rest);
- HeapTuple atttuple;
- Form_pg_attribute attform;
-
- if (attribute->name == NULL)
- elog(ERROR, "missing attribute for define index");
-
- atttuple = SearchSysCacheAttName(relId, attribute->name);
- if (!HeapTupleIsValid(atttuple))
- elog(ERROR, "DefineIndex: attribute \"%s\" not found",
- attribute->name);
- attform = (Form_pg_attribute) GETSTRUCT(atttuple);
+ Oid atttype;
- indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
+ if (attribute->name != NULL)
+ {
+ /* Simple index attribute */
+ HeapTuple atttuple;
+ Form_pg_attribute attform;
+
+ Assert(attribute->expr == NULL);
+ atttuple = SearchSysCacheAttName(relId, attribute->name);
+ if (!HeapTupleIsValid(atttuple))
+ elog(ERROR, "DefineIndex: attribute \"%s\" not found",
+ attribute->name);
+ attform = (Form_pg_attribute) GETSTRUCT(atttuple);
+ indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
+ atttype = attform->atttypid;
+ ReleaseSysCache(atttuple);
+ }
+ else if (attribute->expr && IsA(attribute->expr, Var))
+ {
+ /* Tricky tricky, he wrote (column) ... treat as simple attr */
+ Var *var = (Var *) attribute->expr;
- classOidP[attn] = GetAttrOpClass(attribute, attform->atttypid,
- accessMethodName, accessMethodId);
+ indexInfo->ii_KeyAttrNumbers[attn] = var->varattno;
+ atttype = get_atttype(relId, var->varattno);
+ }
+ else
+ {
+ /* Index expression */
+ Assert(attribute->expr != NULL);
+ indexInfo->ii_KeyAttrNumbers[attn] = 0; /* marks expression */
+ indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
+ attribute->expr);
+ atttype = exprType(attribute->expr);
+
+ /*
+ * We don't currently support generation of an actual query plan
+ * for an index expression, only simple scalar expressions;
+ * hence these restrictions.
+ */
+ if (contain_subplans(attribute->expr))
+ elog(ERROR, "Cannot use subselect in index expression");
+ if (contain_agg_clause(attribute->expr))
+ elog(ERROR, "Cannot use aggregate in index expression");
+
+ /*
+ * A expression using mutable functions is probably wrong,
+ * since if you aren't going to get the same result for the same
+ * data every time, it's not clear what the index entries mean at
+ * all.
+ */
+ if (contain_mutable_functions(attribute->expr))
+ elog(ERROR, "Functions in index expression must be marked IMMUTABLE");
+ }
- ReleaseSysCache(atttuple);
+ classOidP[attn] = GetIndexOpClass(attribute->opclass,
+ atttype,
+ accessMethodName,
+ accessMethodId);
attn++;
}
}
+/*
+ * Resolve possibly-defaulted operator class specification
+ */
static Oid
-GetAttrOpClass(IndexElem *attribute, Oid attrType,
- char *accessMethodName, Oid accessMethodId)
+GetIndexOpClass(List *opclass, Oid attrType,
+ char *accessMethodName, Oid accessMethodId)
{
char *schemaname;
char *opcname;
@@ -456,7 +375,32 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
Oid opClassId,
opInputType;
- if (attribute->opclass == NIL)
+ /*
+ * Release 7.0 removed network_ops, timespan_ops, and
+ * datetime_ops, so we ignore those opclass names
+ * so the default *_ops is used. This can be
+ * removed in some later release. bjm 2000/02/07
+ *
+ * Release 7.1 removes lztext_ops, so suppress that too
+ * for a while. tgl 2000/07/30
+ *
+ * Release 7.2 renames timestamp_ops to timestamptz_ops,
+ * so suppress that too for awhile. I'm starting to
+ * think we need a better approach. tgl 2000/10/01
+ */
+ if (length(opclass) == 1)
+ {
+ char *claname = strVal(lfirst(opclass));
+
+ if (strcmp(claname, "network_ops") == 0 ||
+ strcmp(claname, "timespan_ops") == 0 ||
+ strcmp(claname, "datetime_ops") == 0 ||
+ strcmp(claname, "lztext_ops") == 0 ||
+ strcmp(claname, "timestamp_ops") == 0)
+ opclass = NIL;
+ }
+
+ if (opclass == NIL)
{
/* no operator class specified, so find the default */
opClassId = GetDefaultOpClass(attrType, accessMethodId);
@@ -473,7 +417,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
*/
/* deconstruct the name list */
- DeconstructQualifiedName(attribute->opclass, &schemaname, &opcname);
+ DeconstructQualifiedName(opclass, &schemaname, &opcname);
if (schemaname)
{
@@ -501,7 +445,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: operator class \"%s\" not supported by access method \"%s\"",
- NameListToString(attribute->opclass), accessMethodName);
+ NameListToString(opclass), accessMethodName);
/*
* Verify that the index operator class accepts this datatype. Note
@@ -512,7 +456,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
if (!IsBinaryCoercible(attrType, opInputType))
elog(ERROR, "operator class \"%s\" does not accept data type %s",
- NameListToString(attribute->opclass), format_type_be(attrType));
+ NameListToString(opclass), format_type_be(attrType));
ReleaseSysCache(tuple);
@@ -773,7 +717,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
for (i = 0; i < relcnt; i++)
{
StartTransactionCommand();
- SetQuerySnapshot(); /* might be needed for functional index */
+ SetQuerySnapshot(); /* might be needed for functions in indexes */
if (reindex_relation(relids[i], force))
elog(NOTICE, "relation %u was reindexed", relids[i]);
CommitTransactionCommand();
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 5f60ab9cf01..349fb8f3917 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.72 2003/04/29 22:13:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.73 2003/05/28 16:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1103,6 +1103,7 @@ renameatt(Oid myrelid,
Relation attrelation;
HeapTuple atttup;
Form_pg_attribute attform;
+ int attnum;
List *indexoidlist;
List *indexoidscan;
@@ -1178,7 +1179,8 @@ renameatt(Oid myrelid,
oldattname);
attform = (Form_pg_attribute) GETSTRUCT(atttup);
- if (attform->attnum < 0)
+ attnum = attform->attnum;
+ if (attnum < 0)
elog(ERROR, "renameatt: system attribute \"%s\" may not be renamed",
oldattname);
@@ -1217,43 +1219,48 @@ renameatt(Oid myrelid,
{
Oid indexoid = lfirsto(indexoidscan);
HeapTuple indextup;
+ Form_pg_index indexform;
+ int i;
/*
- * First check to see if index is a functional index. If so, its
- * column name is a function name and shouldn't be renamed here.
+ * Scan through index columns to see if there's any simple index
+ * entries for this attribute. We ignore expressional entries.
*/
indextup = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexoid),
0, 0, 0);
if (!HeapTupleIsValid(indextup))
elog(ERROR, "renameatt: can't find index id %u", indexoid);
- if (OidIsValid(((Form_pg_index) GETSTRUCT(indextup))->indproc))
- {
- ReleaseSysCache(indextup);
- continue;
- }
- ReleaseSysCache(indextup);
+ indexform = (Form_pg_index) GETSTRUCT(indextup);
- /*
- * Okay, look to see if any column name of the index matches the
- * old attribute name.
- */
- atttup = SearchSysCacheCopyAttName(indexoid, oldattname);
- if (!HeapTupleIsValid(atttup))
- continue; /* Nope, so ignore it */
+ for (i = 0; i < indexform->indnatts; i++)
+ {
+ if (attnum != indexform->indkey[i])
+ continue;
+ /*
+ * Found one, rename it.
+ */
+ atttup = SearchSysCacheCopy(ATTNUM,
+ ObjectIdGetDatum(indexoid),
+ Int16GetDatum(i + 1),
+ 0, 0);
+ if (!HeapTupleIsValid(atttup))
+ continue; /* should we raise an error? */
+ /*
+ * Update the (copied) attribute tuple.
+ */
+ namestrcpy(&(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
+ newattname);
- /*
- * Update the (copied) attribute tuple.
- */
- namestrcpy(&(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
- newattname);
+ simple_heap_update(attrelation, &atttup->t_self, atttup);
- simple_heap_update(attrelation, &atttup->t_self, atttup);
+ /* keep system catalog indexes current */
+ CatalogUpdateIndexes(attrelation, atttup);
- /* keep system catalog indexes current */
- CatalogUpdateIndexes(attrelation, atttup);
+ heap_freetuple(atttup);
+ }
- heap_freetuple(atttup);
+ ReleaseSysCache(indextup);
}
freeList(indexoidlist);
@@ -1986,8 +1993,7 @@ AlterTableAlterColumnDropNotNull(Oid myrelid, bool recurse,
* Loop over each attribute in the primary key and see if it
* matches the to-be-altered attribute
*/
- for (i = 0; i < INDEX_MAX_KEYS &&
- indexStruct->indkey[i] != InvalidAttrNumber; i++)
+ for (i = 0; i < indexStruct->indnatts; i++)
{
if (indexStruct->indkey[i] == attnum)
elog(ERROR, "ALTER TABLE: Attribute \"%s\" is in a primary key", colName);
@@ -3185,9 +3191,10 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
/*
* Now build the list of PK attributes from the indkey definition
+ * (we assume a primary key cannot have expressional elements)
*/
*attnamelist = NIL;
- for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
+ for (i = 0; i < indexStruct->indnatts; i++)
{
int pkattno = indexStruct->indkey[i];
@@ -3241,26 +3248,40 @@ transformFkeyCheckAttrs(Relation pkrel,
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
/*
- * Must be unique, not a functional index, and not a partial index
+ * Must have the right number of columns; must be unique and not a
+ * partial index; forget it if there are any expressions, too
*/
- if (indexStruct->indisunique &&
- indexStruct->indproc == InvalidOid &&
- VARSIZE(&indexStruct->indpred) <= VARHDRSZ)
+ if (indexStruct->indnatts == numattrs &&
+ indexStruct->indisunique &&
+ heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
+ heap_attisnull(indexTuple, Anum_pg_index_indexprs))
{
- for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
- ;
- if (i == numattrs)
+ /*
+ * The given attnum list may match the index columns in any
+ * order. Check that each list is a subset of the other.
+ */
+ for (i = 0; i < numattrs; i++)
+ {
+ found = false;
+ for (j = 0; j < numattrs; j++)
+ {
+ if (attnums[i] == indexStruct->indkey[j])
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ }
+ if (found)
{
- /*
- * The given attnum list may match the index columns in any
- * order. Check that each list is a subset of the other.
- */
for (i = 0; i < numattrs; i++)
{
found = false;
for (j = 0; j < numattrs; j++)
{
- if (attnums[i] == indexStruct->indkey[j])
+ if (attnums[j] == indexStruct->indkey[i])
{
found = true;
break;
@@ -3269,23 +3290,6 @@ transformFkeyCheckAttrs(Relation pkrel,
if (!found)
break;
}
- if (found)
- {
- for (i = 0; i < numattrs; i++)
- {
- found = false;
- for (j = 0; j < numattrs; j++)
- {
- if (attnums[j] == indexStruct->indkey[i])
- {
- found = true;
- break;
- }
- }
- if (!found)
- break;
- }
- }
}
}
ReleaseSysCache(indexTuple);
@@ -4020,12 +4024,12 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = 2;
- indexInfo->ii_NumKeyAttrs = 2;
indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_KeyAttrNumbers[1] = 2;
+ indexInfo->ii_Expressions = NIL;
+ indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_Predicate = NIL;
indexInfo->ii_PredicateState = NIL;
- indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = true;
classObjectId[0] = OID_BTREE_OPS_OID;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index b5a8f7f3a17..93701b611ed 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.254 2003/05/27 17:49:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.255 2003/05/28 16:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -304,7 +304,7 @@ vacuum(VacuumStmt *vacstmt)
if (vacstmt->vacuum)
{
StartTransactionCommand();
- SetQuerySnapshot(); /* might be needed for functional index */
+ SetQuerySnapshot(); /* might be needed for functions in indexes */
}
else
old_context = MemoryContextSwitchTo(anl_context);
@@ -728,7 +728,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
/* Begin a transaction for vacuuming this relation */
StartTransactionCommand();
- SetQuerySnapshot(); /* might be needed for functional index */
+ SetQuerySnapshot(); /* might be needed for functions in indexes */
/*
* Check for user-requested abort. Note we want this to be inside a
@@ -3028,7 +3028,10 @@ vac_is_partial_index(Relation indrel)
return true;
/* Otherwise, look to see if there's a partial-index predicate */
- return (VARSIZE(&indrel->rd_index->indpred) > VARHDRSZ);
+ if (!heap_attisnull(indrel->rd_indextuple, Anum_pg_index_indpred))
+ return true;
+
+ return false;
}