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 | |
parent | a30bc7c75a54910a78d1939bd32f5d91164ba8a4 (diff) |
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')
-rw-r--r-- | src/backend/commands/cluster.c | 66 | ||||
-rw-r--r-- | src/backend/commands/command.c | 21 | ||||
-rw-r--r-- | src/backend/commands/copy.c | 241 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 312 | ||||
-rw-r--r-- | src/backend/commands/vacuum.c | 110 |
5 files changed, 242 insertions, 508 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 38539707cd8..5c176254d66 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.57 2000/07/04 06:11:27 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.58 2000/07/14 22:17:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -198,35 +198,31 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) Relation OldIndex, NewHeap; HeapTuple Old_pg_index_Tuple, - Old_pg_index_relation_Tuple, - pg_proc_Tuple; + Old_pg_index_relation_Tuple; Form_pg_index Old_pg_index_Form; Form_pg_class Old_pg_index_relation_Form; - Form_pg_proc pg_proc_Form; + IndexInfo *indexInfo; char *NewIndexName; - AttrNumber *attnumP; - int natts; - FuncIndexInfo *finfo; NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock); OldIndex = index_open(OIDOldIndex); /* * OK. Create a new (temporary) index for the one that's already here. - * To do this I get the info from pg_index, re-build the FunctInfo if - * I have to, and add a new index with a temporary name. + * To do this I get the info from pg_index, and add a new index with + * a temporary name. */ - Old_pg_index_Tuple = SearchSysCacheTuple(INDEXRELID, + Old_pg_index_Tuple = SearchSysCacheTupleCopy(INDEXRELID, ObjectIdGetDatum(RelationGetRelid(OldIndex)), - 0, 0, 0); - + 0, 0, 0); Assert(Old_pg_index_Tuple); Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple); - Old_pg_index_relation_Tuple = SearchSysCacheTuple(RELOID, - ObjectIdGetDatum(RelationGetRelid(OldIndex)), - 0, 0, 0); + indexInfo = BuildIndexInfo(Old_pg_index_Tuple); + Old_pg_index_relation_Tuple = SearchSysCacheTupleCopy(RELOID, + ObjectIdGetDatum(RelationGetRelid(OldIndex)), + 0, 0, 0); Assert(Old_pg_index_relation_Tuple); Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple); @@ -234,50 +230,12 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) NewIndexName = palloc(NAMEDATALEN); /* XXX */ snprintf(NewIndexName, NAMEDATALEN, "temp_%x", OIDOldIndex); - /* - * Ugly as it is, the only way I have of working out the number of - * attribues is to count them. Mostly there'll be just one but I've - * got to be sure. - */ - for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0; - natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber; - attnumP++, natts++); - - /* - * If this is a functional index, I need to rebuild the functional - * component to pass it to the defining procedure. - */ - if (Old_pg_index_Form->indproc != InvalidOid) - { - finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo)); - FIgetnArgs(finfo) = natts; - FIgetProcOid(finfo) = Old_pg_index_Form->indproc; - - pg_proc_Tuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(Old_pg_index_Form->indproc), - 0, 0, 0); - - Assert(pg_proc_Tuple); - pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple); - namecpy(&(finfo->funcName), &(pg_proc_Form->proname)); - natts = 1; /* function result is a single column */ - } - else - { - finfo = (FuncIndexInfo *) NULL; - } - index_create(RelationGetRelationName(NewHeap), NewIndexName, - finfo, - NULL, /* type info is in the old index */ + indexInfo, Old_pg_index_relation_Form->relam, - natts, - Old_pg_index_Form->indkey, Old_pg_index_Form->indclass, - (Node *) NULL, /* XXX where's the predicate? */ Old_pg_index_Form->indislossy, - Old_pg_index_Form->indisunique, Old_pg_index_Form->indisprimary, allowSystemTableMods); diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 6648e66f4e3..be24c696a7c 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.88 2000/07/05 23:11:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.89 2000/07/14 22:17:42 tgl Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -1205,7 +1205,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent) char toast_relname[NAMEDATALEN + 1]; char toast_idxname[NAMEDATALEN + 1]; Relation toast_rel; - AttrNumber attNums[1]; + IndexInfo *indexInfo; Oid classObjectId[1]; /* @@ -1334,11 +1334,20 @@ AlterTableCreateToastTable(const char *relationName, bool silent) CommandCounterIncrement(); /* create index on chunk_id */ - attNums[0] = 1; + + indexInfo = makeNode(IndexInfo); + indexInfo->ii_NumIndexAttrs = 1; + indexInfo->ii_NumKeyAttrs = 1; + indexInfo->ii_KeyAttrNumbers[0] = 1; + indexInfo->ii_Predicate = NULL; + indexInfo->ii_FuncOid = InvalidOid; + indexInfo->ii_Unique = false; + classObjectId[0] = OID_OPS_OID; - index_create(toast_relname, toast_idxname, NULL, NULL, BTREE_AM_OID, - 1, attNums, classObjectId, - (Node *) NULL, false, false, false, true); + + index_create(toast_relname, toast_idxname, indexInfo, + BTREE_AM_OID, classObjectId, + false, false, true); /* make the index visible in this transaction */ CommandCounterIncrement(); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 355b218e640..52100e92dd9 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.118 2000/07/12 02:36:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.119 2000/07/14 22:17:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -50,10 +50,6 @@ static Oid GetOutputFunction(Oid type); static Oid GetTypeElement(Oid type); static Oid GetInputFunction(Oid type); static Oid IsTypeByVal(Oid type); -static void GetIndexRelations(Oid main_relation_oid, - int *n_indices, - Relation **index_rels); - static void CopyReadNewline(FILE *fp, int *newline); static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print); @@ -576,53 +572,35 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p } static void -CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print) +CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, + char *delim, char *null_print) { HeapTuple tuple; - AttrNumber attr_count; + TupleDesc tupDesc; Form_pg_attribute *attr; + AttrNumber attr_count; FmgrInfo *in_functions; + Oid *elements; + int32 *typmod; int i; Oid in_func_oid; Datum *values; - char *nulls, - *index_nulls; + char *nulls; bool *byval; bool isnull; - bool has_index; int done = 0; char *string = NULL, *ptr; - Relation *index_rels; int32 len, null_ct, null_id; int32 ntuples, tuples_read = 0; bool reading_to_eof = true; - Oid *elements; - int32 *typmod; - FuncIndexInfo *finfo, - **finfoP = NULL; - TupleDesc *itupdescArr; - HeapTuple pgIndexTup; - Form_pg_index *pgIndexP = NULL; - int *indexNatts = NULL; - char *predString; - Node **indexPred = NULL; - TupleDesc rtupdesc; + RelationInfo *relationInfo; EState *estate = makeNode(EState); /* for ExecConstraints() */ -#ifndef OMIT_PARTIAL_INDEX - ExprContext *econtext = NULL; TupleTable tupleTable; - TupleTableSlot *slot = NULL; -#endif - int natts; - AttrNumber *attnumP; - Datum *idatum; - int n_indices; - InsertIndexResult indexRes; - TupleDesc tupDesc; + TupleTableSlot *slot; Oid loaded_oid = InvalidOid; bool skip_tuple = false; @@ -630,71 +608,26 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null attr = tupDesc->attrs; attr_count = tupDesc->natts; - has_index = false; - /* - * This may be a scalar or a functional index. We initialize all - * kinds of arrays here to avoid doing extra work at every tuple copy. + * We need a RelationInfo so we can use the regular executor's + * index-entry-making machinery. (There used to be a huge amount + * of code here that basically duplicated execUtils.c ...) */ + relationInfo = makeNode(RelationInfo); + relationInfo->ri_RangeTableIndex = 1; /* dummy */ + relationInfo->ri_RelationDesc = rel; + relationInfo->ri_NumIndices = 0; + relationInfo->ri_IndexRelationDescs = NULL; + relationInfo->ri_IndexRelationInfo = NULL; - if (rel->rd_rel->relhasindex) - { - GetIndexRelations(RelationGetRelid(rel), &n_indices, &index_rels); - if (n_indices > 0) - { - has_index = true; - itupdescArr = (TupleDesc *) palloc(n_indices * sizeof(TupleDesc)); - pgIndexP = (Form_pg_index *) palloc(n_indices * sizeof(Form_pg_index)); - indexNatts = (int *) palloc(n_indices * sizeof(int)); - finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo)); - finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *)); - indexPred = (Node **) palloc(n_indices * sizeof(Node *)); - for (i = 0; i < n_indices; i++) - { - itupdescArr[i] = RelationGetDescr(index_rels[i]); - pgIndexTup = SearchSysCacheTuple(INDEXRELID, - ObjectIdGetDatum(RelationGetRelid(index_rels[i])), - 0, 0, 0); - Assert(pgIndexTup); - pgIndexP[i] = (Form_pg_index) GETSTRUCT(pgIndexTup); - for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0; - natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber; - attnumP++, natts++); - if (pgIndexP[i]->indproc != InvalidOid) - { - FIgetnArgs(&finfo[i]) = natts; - natts = 1; - FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc; - *(FIgetname(&finfo[i])) = '\0'; - finfoP[i] = &finfo[i]; - } - else - finfoP[i] = (FuncIndexInfo *) NULL; - indexNatts[i] = natts; - if (VARSIZE(&pgIndexP[i]->indpred) != 0) - { - predString = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(&pgIndexP[i]->indpred))); - indexPred[i] = stringToNode(predString); - pfree(predString); -#ifndef OMIT_PARTIAL_INDEX - /* make dummy ExprContext for use by ExecQual */ - if (econtext == NULL) - { - tupleTable = ExecCreateTupleTable(1); - slot = ExecAllocTableSlot(tupleTable); - rtupdesc = RelationGetDescr(rel); - ExecSetSlotDescriptor(slot, rtupdesc); - econtext = MakeExprContext(slot, - TransactionCommandContext); - } -#endif /* OMIT_PARTIAL_INDEX */ - } - else - indexPred[i] = NULL; - } - } - } + ExecOpenIndices(relationInfo); + + estate->es_result_relation_info = relationInfo; + + /* Set up a dummy tuple table too */ + tupleTable = ExecCreateTupleTable(1); + slot = ExecAllocTableSlot(tupleTable); + ExecSetSlotDescriptor(slot, tupDesc); if (!binary) { @@ -723,16 +656,13 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null reading_to_eof = false; } - values = (Datum *) palloc(sizeof(Datum) * attr_count); - nulls = (char *) palloc(attr_count); - index_nulls = (char *) palloc(attr_count); - idatum = (Datum *) palloc(sizeof(Datum) * attr_count); + values = (Datum *) palloc(attr_count * sizeof(Datum)); + nulls = (char *) palloc(attr_count * sizeof(char)); byval = (bool *) palloc(attr_count * sizeof(bool)); for (i = 0; i < attr_count; i++) { nulls[i] = ' '; - index_nulls[i] = ' '; #ifdef _DROP_COLUMN_HACK__ if (COLUMN_IS_DROPPED(attr[i])) { @@ -873,6 +803,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null tuple->t_data->t_oid = loaded_oid; skip_tuple = false; + /* BEFORE ROW INSERT Triggers */ if (rel->trigdesc && rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) @@ -893,45 +824,25 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null if (!skip_tuple) { /* ---------------- - * Check the constraints of a tuple + * Check the constraints of the tuple * ---------------- */ if (rel->rd_att->constr) ExecConstraints("CopyFrom", rel, tuple, estate); + /* ---------------- + * OK, store the tuple and create index entries for it + * ---------------- + */ heap_insert(rel, tuple); - if (has_index) + if (relationInfo->ri_NumIndices > 0) { - for (i = 0; i < n_indices; i++) - { -#ifndef OMIT_PARTIAL_INDEX - if (indexPred[i] != NULL) - { - /* - * if tuple doesn't satisfy predicate, don't - * update index - */ - slot->val = tuple; - /* SetSlotContents(slot, tuple); */ - if (!ExecQual((List *) indexPred[i], econtext, false)) - continue; - } -#endif /* OMIT_PARTIAL_INDEX */ - FormIndexDatum(indexNatts[i], - (AttrNumber *) &(pgIndexP[i]->indkey[0]), - tuple, - tupDesc, - idatum, - index_nulls, - finfoP[i]); - indexRes = index_insert(index_rels[i], idatum, index_nulls, - &(tuple->t_self), rel); - if (indexRes) - pfree(indexRes); - } + ExecStoreTuple(tuple, slot, InvalidBuffer, false); + ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); } + /* AFTER ROW INSERT Triggers */ if (rel->trigdesc && rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0) @@ -948,8 +859,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null if (!binary) pfree((void *) values[i]); } - else if (nulls[i] == 'n') - nulls[i] = ' '; + /* reset nulls[] array for next time */ + nulls[i] = ' '; } heap_freetuple(tuple); @@ -958,11 +869,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null if (!reading_to_eof && ntuples == tuples_read) done = true; } + + /* + * Done, clean up + */ lineno = 0; + pfree(values); pfree(nulls); - pfree(index_nulls); - pfree(idatum); pfree(byval); if (!binary) @@ -972,21 +886,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null pfree(typmod); } - if (has_index) - { - for (i = 0; i < n_indices; i++) - { - if (index_rels[i] == NULL) - continue; - /* see comments in ExecOpenIndices() in execUtils.c */ - if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID && - (index_rels[i])->rd_rel->relam != HASH_AM_OID) - UnlockRelation(index_rels[i], AccessExclusiveLock); - index_close(index_rels[i]); - } - } -} + ExecDropTupleTable(tupleTable, true); + ExecCloseIndices(relationInfo); +} static Oid @@ -1054,52 +957,6 @@ IsTypeByVal(Oid type) return InvalidOid; } -/* - * Given the OID of a relation, return an array of index relation descriptors - * and the number of index relations. These relation descriptors are open - * using index_open(). - * - * Space for the array itself is palloc'ed. - */ - -static void -GetIndexRelations(Oid main_relation_oid, - int *n_indices, - Relation **index_rels) -{ - Relation relation; - List *indexoidlist, - *indexoidscan; - int i; - - relation = heap_open(main_relation_oid, AccessShareLock); - indexoidlist = RelationGetIndexList(relation); - - *n_indices = length(indexoidlist); - - if (*n_indices > 0) - *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation)); - else - *index_rels = NULL; - - i = 0; - foreach(indexoidscan, indexoidlist) - { - Oid indexoid = lfirsti(indexoidscan); - Relation index = index_open(indexoid); - - /* see comments in ExecOpenIndices() in execUtils.c */ - if (index != NULL && - index->rd_rel->relam != BTREE_AM_OID && - index->rd_rel->relam != HASH_AM_OID) - LockRelation(index, AccessExclusiveLock); - (*index_rels)[i] = index; - i++; - } - - freeList(indexoidlist); - heap_close(relation, AccessShareLock); -} /* * Reads input from fp until an end of line is seen. 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) { diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 71682baa8cd..ee0ebeb4bb7 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.162 2000/07/05 16:17:38 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.163 2000/07/14 22:17:42 tgl Exp $ * *------------------------------------------------------------------------- @@ -28,6 +28,7 @@ #include "catalog/index.h" #include "commands/vacuum.h" #include "miscadmin.h" +#include "nodes/execnodes.h" #include "storage/sinval.h" #include "storage/smgr.h" #include "tcop/tcopprot.h" @@ -71,7 +72,8 @@ static void reap_page(VacPageList vacpagelist, VacPage vacpage); static void vpage_insert(VacPageList vacpagelist, VacPage vpnew); static void get_indices(Relation relation, int *nindices, Relation **Irel); static void close_indices(int nindices, Relation *Irel); -static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc); +static IndexInfo **get_index_desc(Relation onerel, int nindices, + Relation *Irel); static void *vac_find_eq(void *bot, int nelem, int size, void *elm, int (*compar) (const void *, const void *)); static int vac_cmp_blk(const void *left, const void *right); @@ -948,9 +950,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, newitemid; HeapTupleData tuple, newtup; - TupleDesc tupdesc = NULL; - Datum *idatum = NULL; - char *inulls = NULL; + TupleDesc tupdesc; + IndexInfo **indexInfo = NULL; + Datum idatum[INDEX_MAX_KEYS]; + char inulls[INDEX_MAX_KEYS]; InsertIndexResult iresult; VacPageListData Nvacpagelist; VacPage cur_page = NULL, @@ -958,8 +961,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, vacpage, *curpage; int cur_item = 0; - IndDesc *Idesc, - *idcur; int last_move_dest_block = -1, last_vacuum_block, i = 0; @@ -980,13 +981,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, myXID = GetCurrentTransactionId(); myCID = GetCurrentCommandId(); + tupdesc = RelationGetDescr(onerel); + if (Irel != (Relation *) NULL) /* preparation for index' inserts */ - { - get_index_desc(onerel, nindices, Irel, &Idesc); - tupdesc = RelationGetDescr(onerel); - idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof(*idatum)); - inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof(*inulls)); - } + indexInfo = get_index_desc(onerel, nindices, Irel); Nvacpagelist.num_pages = 0; num_fraged_pages = fraged_pages->num_pages; @@ -1456,15 +1454,22 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, if (Irel != (Relation *) NULL) { - for (i = 0, idcur = Idesc; i < nindices; i++, idcur++) + /* + * XXX using CurrentMemoryContext here means + * intra-vacuum memory leak for functional indexes. + * Should fix someday. + * + * XXX This code fails to handle partial indexes! + * Probably should change it to use ExecOpenIndices. + */ + for (i = 0; i < nindices; i++) { - FormIndexDatum(idcur->natts, - (AttrNumber *) &(idcur->tform->indkey[0]), + FormIndexDatum(indexInfo[i], &newtup, tupdesc, + CurrentMemoryContext, idatum, - inulls, - idcur->finfoP); + inulls); iresult = index_insert(Irel[i], idatum, inulls, @@ -1575,15 +1580,22 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", /* insert index' tuples if needed */ if (Irel != (Relation *) NULL) { - for (i = 0, idcur = Idesc; i < nindices; i++, idcur++) + /* + * XXX using CurrentMemoryContext here means + * intra-vacuum memory leak for functional indexes. + * Should fix someday. + * + * XXX This code fails to handle partial indexes! + * Probably should change it to use ExecOpenIndices. + */ + for (i = 0; i < nindices; i++) { - FormIndexDatum(idcur->natts, - (AttrNumber *) &(idcur->tform->indkey[0]), + FormIndexDatum(indexInfo[i], &newtup, tupdesc, + CurrentMemoryContext, idatum, - inulls, - idcur->finfoP); + inulls); iresult = index_insert(Irel[i], idatum, inulls, @@ -1821,10 +1833,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", if (Irel != (Relation *) NULL) /* pfree index' allocations */ { - pfree(Idesc); - pfree(idatum); - pfree(inulls); close_indices(nindices, Irel); + pfree(indexInfo); } pfree(vacpage); @@ -2347,46 +2357,30 @@ close_indices(int nindices, Relation *Irel) } -static void -get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc) +/* + * Obtain IndexInfo data for each index on the rel + */ +static IndexInfo ** +get_index_desc(Relation onerel, int nindices, Relation *Irel) { - IndDesc *idcur; - HeapTuple cachetuple; - AttrNumber *attnumP; - int natts; + IndexInfo **indexInfo; int i; + HeapTuple cachetuple; - *Idesc = (IndDesc *) palloc(nindices * sizeof(IndDesc)); + indexInfo = (IndexInfo **) palloc(nindices * sizeof(IndexInfo *)); - for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++) + for (i = 0; i < nindices; i++) { - cachetuple = SearchSysCacheTupleCopy(INDEXRELID, + cachetuple = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(RelationGetRelid(Irel[i])), - 0, 0, 0); - Assert(cachetuple); - - /* - * we never free the copy we make, because Idesc needs it for - * later - */ - idcur->tform = (Form_pg_index) GETSTRUCT(cachetuple); - for (attnumP = &(idcur->tform->indkey[0]), natts = 0; - natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber; - attnumP++, natts++); - if (idcur->tform->indproc != InvalidOid) - { - idcur->finfoP = &(idcur->finfo); - FIgetnArgs(idcur->finfoP) = natts; - natts = 1; - FIgetProcOid(idcur->finfoP) = idcur->tform->indproc; - *(FIgetname(idcur->finfoP)) = '\0'; - } - else - idcur->finfoP = (FuncIndexInfo *) NULL; - - idcur->natts = natts; + 0, 0, 0); + if (!HeapTupleIsValid(cachetuple)) + elog(ERROR, "get_index_desc: index %u not found", + RelationGetRelid(Irel[i])); + indexInfo[i] = BuildIndexInfo(cachetuple); } + return indexInfo; } |