diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-07-14 22:18:02 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-07-14 22:18:02 +0000 |
commit | 6bfe64032efd043f80a495a495331dcfc2d9f05c (patch) | |
tree | d0cc092d38bdea690a79e4aebfa4629e1db54e96 /src/backend/commands/indexcmds.c | |
parent | a30bc7c75a54910a78d1939bd32f5d91164ba8a4 (diff) | |
download | postgresql-6bfe64032efd043f80a495a495331dcfc2d9f05c.tar.gz postgresql-6bfe64032efd043f80a495a495331dcfc2d9f05c.zip |
Cleanup of code for creating index entries. Functional indexes with
pass-by-ref data types --- eg, an index on lower(textfield) --- no longer
leak memory during index creation or update. Clean up a lot of redundant
code ... did you know that copy, vacuum, truncate, reindex, extend index,
and bootstrap each basically duplicated the main executor's logic for
extracting information about an index and preparing index entries?
Functional indexes should be a little faster now too, due to removal
of repeated function lookups.
CREATE INDEX 'opt_type' clause is deimplemented by these changes,
but I haven't removed it from the parser yet (need to merge with
Thomas' latest change set first).
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) { |