diff options
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r-- | src/backend/commands/indexcmds.c | 312 |
1 files changed, 114 insertions, 198 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index efe8a44180a..6ede4f51c12 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.34 2000/07/05 23:11:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.35 2000/07/14 22:17:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #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" @@ -47,14 +48,14 @@ 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, +static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP, + IndexElem *funcIndex, + Oid relId, char *accessMethodName, Oid accessMethodId); -static void NormIndexAttrs(List *attList, AttrNumber *attNumP, - Oid *opOidP, Oid relId, +static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP, + List *attList, + 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 char *GetDefaultOpClass(Oid atttypid); @@ -67,10 +68,7 @@ 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, @@ -86,16 +84,15 @@ 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) @@ -108,21 +105,8 @@ DefineIndex(char *heapRelationName, * 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 @@ -131,13 +115,22 @@ DefineIndex(char *heapRelationName, PointerGetDatum(accessMethodName), 0, 0, 0); if (!HeapTupleIsValid(tuple)) - { 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 */ foreach(pl, parameterList) @@ -145,7 +138,7 @@ DefineIndex(char *heapRelationName, DefElem *param = (DefElem *) lfirst(pl); if (!strcasecmp(param->defname, "islossy")) - lossy = TRUE; + lossy = true; else elog(NOTICE, "Unrecognized index attribute \"%s\" ignored", param->defname); @@ -169,55 +162,51 @@ DefineIndex(char *heapRelationName, 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 @@ -232,83 +221,48 @@ DefineIndex(char *heapRelationName, /* * 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); if (!HeapTupleIsValid(tuple)) - { elog(ERROR, "ExtendIndex: index \"%s\" not found", indexRelationName); - } indexId = tuple->t_data->t_oid; accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam; /* - * find pg_index tuple + * Extract info from the pg_index tuple for the index */ tuple = SearchSysCacheTuple(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; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - { - if (index->indkey[i] == InvalidAttrNumber) - break; - } - numberOfAttributes = i; + indexInfo = BuildIndexInfo(tuple); + oldPred = indexInfo->ii_Predicate; - 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); @@ -316,8 +270,11 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) /* * 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) { @@ -326,47 +283,20 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) 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 */ } @@ -431,15 +361,15 @@ CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid) 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; + Oid argTypes[FUNC_MAX_ARGS]; + List *arglist; HeapTuple tuple; Oid retType; int argn = 0; @@ -447,68 +377,77 @@ FuncIndexArgs(IndexElem *funcIndex, /* * 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)); Form_pg_attribute att; tuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relId), - PointerGetDatum(arg), 0, 0); - + 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[argn] = att->attnum; + argTypes[argn] = att->atttypid; + argn++; } /* ---------------- * Lookup the function procedure to get its OID and result type. + * + * XXX need to accept binary-compatible functions here, not just + * an exact match. * ---------------- */ tuple = SearchSysCacheTuple(PROCNAME, - PointerGetDatum(FIgetname(funcInfo)), - Int32GetDatum(FIgetnArgs(funcInfo)), - PointerGetDatum(FIgetArglist(funcInfo)), + PointerGetDatum(funcIndex->name), + Int32GetDatum(indexInfo->ii_NumKeyAttrs), + PointerGetDatum(argTypes), 0); - if (!HeapTupleIsValid(tuple)) { - func_error("DefineIndex", FIgetname(funcInfo), - FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL); + func_error("DefineIndex", funcIndex->name, + indexInfo->ii_NumKeyAttrs, argTypes, NULL); } - FIsetProcOid(funcInfo, tuple->t_data->t_oid); + indexInfo->ii_FuncOid = tuple->t_data->t_oid; retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype; - /* Process type and opclass, using func return type as default */ + /* Process opclass, using func return type as default type */ - ProcessAttrTypename(funcIndex, retType, -1); + classOidP[0] = GetAttrOpClass(funcIndex, retType, + accessMethodName, accessMethodId); - *opOidP = GetAttrOpClass(funcIndex, retType, - accessMethodName, accessMethodId); + /* Need to do the fmgr function lookup now, too */ + + fmgr_info(indexInfo->ii_FuncOid, & 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; @@ -524,36 +463,13 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */ 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; + attn++; } } @@ -626,7 +542,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType, * * 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... + * If pg_opclass is wrong then we're probably screwed anyway... */ if (doTypeCheck) { |