diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/cluster.c | 55 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 310 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 124 | ||||
-rw-r--r-- | src/backend/commands/vacuum.c | 11 |
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; } |