diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c index ef188d0e41..fe956ead37 100644 --- a/src/backend/access/index/istrat.c +++ b/src/backend/access/index/istrat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.40 2000/01/26 05:55:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.41 2000/02/18 09:29:16 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -477,8 +477,9 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation, { HeapTuple tuple; HeapScanDesc scan = NULL; + bool cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized(); - if (!IsBootstrapProcessingMode()) + if (cachesearch) { tuple = SearchSysCacheTuple(OPEROID, ObjectIdGetDatum(operatorObjectId), @@ -501,7 +502,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation, if (!HeapTupleIsValid(tuple)) { - if (IsBootstrapProcessingMode()) + if (!cachesearch) heap_endscan(scan); elog(ERROR, "OperatorObjectIdFillScanKeyEntry: unknown operator %u", operatorObjectId); @@ -512,7 +513,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation, fmgr_info(entry->sk_procedure, &entry->sk_func); entry->sk_nargs = entry->sk_func.fn_nargs; - if (IsBootstrapProcessingMode()) + if (!cachesearch) heap_endscan(scan); if (!RegProcedureIsValid(entry->sk_procedure)) @@ -546,8 +547,9 @@ IndexSupportInitialize(IndexStrategy indexStrategy, AttrNumber attributeNumber; int attributeIndex; Oid operatorClassObjectId[INDEX_MAX_KEYS]; + bool cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized(); - if (!IsBootstrapProcessingMode()) + if (cachesearch) { tuple = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(indexObjectId), @@ -589,7 +591,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy, operatorClassObjectId[attributeIndex] = iform->indclass[attributeIndex]; } - if (IsBootstrapProcessingMode()) + if (!cachesearch) { heap_endscan(scan); heap_close(relation, AccessShareLock); diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index fa8decce13..da5dd70332 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -12,7 +12,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.52 2000/01/26 05:55:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.53 2000/02/18 09:29:54 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -310,16 +310,22 @@ btbuild(Relation heap, { Oid hrelid = RelationGetRelid(heap); Oid irelid = RelationGetRelid(index); + bool inplace = IsReindexProcessing(); heap_close(heap, NoLock); index_close(index); + /* UpdateStats(hrelid, nhtups, true); UpdateStats(irelid, nitups, false); + */ + UpdateStats(hrelid, nhtups, inplace); + UpdateStats(irelid, nitups, inplace); if (oldPred != NULL) { if (nitups == nhtups) pred = NULL; - UpdateIndexPredicate(irelid, oldPred, pred); + if (!inplace) + UpdateIndexPredicate(irelid, oldPred, pred); } } diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 58e1744558..e5b521b67c 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.60 2000/01/29 16:58:29 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.61 2000/02/18 09:30:20 inoue Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -147,6 +147,7 @@ #include "access/nbtree.h" #include "catalog/heap.h" +#include "catalog/index.h" #include "commands/async.h" #include "commands/sequence.h" #include "commands/vacuum.h" @@ -850,6 +851,7 @@ StartTransaction() */ s->state = TRANS_START; + SetReindexProcessing(false); /* ---------------- * generate a new transaction id * ---------------- @@ -1046,8 +1048,8 @@ AbortTransaction() AtAbort_Notify(); CloseSequences(); AtEOXact_portals(); - if (VacuumRunning) - vc_abort(); + if (CommonSpecialPortalIsOpen()) + CommonSpecialPortalClose(); RecordTransactionAbort(); RelationPurgeLocalRelation(false); DropNoNameRels(); diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index e8afa33de2..8e129a460a 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.79 2000/01/26 05:56:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.80 2000/02/18 09:28:39 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -292,6 +292,7 @@ BootstrapMain(int argc, char *argv[]) dbName = argv[optind]; SetProcessingMode(BootstrapProcessing); + IgnoreSystemIndexes(true); if (!DataDir) { diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 2840e40633..271dc3ed97 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.121 2000/02/15 03:36:34 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.122 2000/02/18 09:28:40 inoue Exp $ * * * INTERFACE ROUTINES @@ -713,7 +713,7 @@ AddNewRelationTuple(Relation pg_class_desc, if (temp_relname) create_temp_relation(temp_relname, tup); - if (!IsBootstrapProcessingMode()) + if (!IsIgnoringSystemIndexes()) { /* * First, open the catalog indices and insert index tuples for the @@ -1263,8 +1263,7 @@ heap_truncate(char *relname) rel->rd_nblocks = 0; /* If this relation has indexes, truncate the indexes too */ - if (rel->rd_rel->relhasindex) - RelationTruncateIndexes(rel); + RelationTruncateIndexes(rel); /* * Close the relation, but keep exclusive lock on it until commit. @@ -1491,8 +1490,8 @@ heap_drop_with_catalog(const char *relname) * remove indexes if necessary * ---------------- */ - if (rel->rd_rel->relhasindex) - RelationRemoveIndexes(rel); + /* should ignore relhasindex */ + RelationRemoveIndexes(rel); /* ---------------- * remove rules if necessary diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 6040d09f24..b7d49ed3bc 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.104 2000/01/26 05:56:10 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.105 2000/02/18 09:28:41 inoue Exp $ * * * INTERFACE ROUTINES @@ -44,6 +44,7 @@ #include "utils/relcache.h" #include "utils/syscache.h" #include "utils/temprel.h" +#include "utils/inval.h" /* * macros used in guessing how many tuples are on a page. @@ -75,6 +76,17 @@ static void DefaultBuild(Relation heapRelation, Relation indexRelation, Datum *parameter, FuncIndexInfoPtr funcInfo, PredInfo *predInfo); static Oid IndexGetRelation(Oid indexId); +static bool reindexing = false; +extern bool SetReindexProcessing(bool reindexmode) +{ + bool old = reindexing; + reindexing = reindexmode; + return old; +} +extern bool IsReindexProcessing(void) +{ + return reindexing; +} /* ---------------------------------------------------------------- * sysatts is a structure containing attribute tuple forms * for system attributes (numbered -1, -2, ...). This really @@ -484,7 +496,7 @@ UpdateRelationRelation(Relation indexRelation, char *temp_relname) * just before exiting. */ - if (!IsBootstrapProcessingMode()) + if (!IsIgnoringSystemIndexes()) { CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple); @@ -569,7 +581,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts) (char *) (indexRelation->rd_att->attrs[0])); hasind = false; - if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex) + if (!IsIgnoringSystemIndexes() && pg_attribute->rd_rel->relhasindex) { hasind = true; CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs); @@ -758,7 +770,7 @@ UpdateIndexRelation(Oid indexoid, * insert the index tuple into the pg_index * ---------------- */ - if (!IsBootstrapProcessingMode()) + if (!IsIgnoringSystemIndexes()) { CatalogOpenIndices(Num_pg_index_indices, Name_pg_index_indices, idescs); CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple); @@ -956,6 +968,7 @@ index_create(char *heapRelationName, * check parameters * ---------------- */ + SetReindexProcessing(false); if (numatts < 1) elog(ERROR, "must index at least one attribute"); @@ -1271,12 +1284,217 @@ FormIndexDatum(int numberOfAttributes, } +/* -------------------------------------------- + * Lock class info for update + * -------------------------------------------- + */ +static +bool LockClassinfoForUpdate(Oid relid, HeapTuple rtup, Buffer *buffer, bool confirmCommitted) +{ + HeapTuple classTuple; + Form_pg_class pgcform; + bool test; + Relation relationRelation; + + classTuple = SearchSysCacheTuple(RELOID, PointerGetDatum(relid), + 0, 0, 0); + if (!HeapTupleIsValid(classTuple)) + return false; + rtup->t_self = classTuple->t_self; + pgcform = (Form_pg_class) GETSTRUCT(classTuple); + relationRelation = heap_openr(RelationRelationName, RowShareLock); + test = heap_mark4update(relationRelation, rtup, buffer); + switch (test) + { + case HeapTupleSelfUpdated: + case HeapTupleMayBeUpdated: + break; + default: + elog(ERROR, "LockStatsForUpdate couldn't lock relid %u", relid); + return false; + } + RelationInvalidateHeapTuple(relationRelation, rtup); + if (confirmCommitted) + { + HeapTupleHeader th = rtup->t_data; + if (!(th->t_infomask & HEAP_XMIN_COMMITTED)) + elog(ERROR, "The tuple isn't committed"); + if (th->t_infomask & HEAP_XMAX_COMMITTED) + if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE)) + elog(ERROR, "The tuple is already deleted"); + } + heap_close(relationRelation, NoLock); + return true; +} + +/* --------------------------------------------- + * Indexes of the relation active ? + * --------------------------------------------- + */ +bool IndexesAreActive(Oid relid, bool confirmCommitted) +{ + HeapTupleData tuple; + Relation indexRelation; + Buffer buffer; + HeapScanDesc scan; + ScanKeyData entry; + bool isactive; + + if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted)) + elog(ERROR, "IndexesAreActive couldn't lock %u", relid); + if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION) + elog(ERROR, "relation %u isn't an relation", relid); + isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex; + ReleaseBuffer(buffer); + if (isactive) + return isactive; + indexRelation = heap_openr(IndexRelationName, AccessShareLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, + F_OIDEQ, ObjectIdGetDatum(relid)); + scan = heap_beginscan(indexRelation, false, SnapshotNow, + 1, &entry); + if (!heap_getnext(scan, 0)) + isactive = true; + heap_endscan(scan); + heap_close(indexRelation, NoLock); + return isactive; +} + +/* ---------------- + * set relhasindex of pg_class in place + * ---------------- + */ +void +setRelhasindexInplace(Oid relid, bool hasindex, bool immediate) +{ + Relation whichRel; + Relation pg_class; + HeapTuple tuple; + Form_pg_class rd_rel; + HeapScanDesc pg_class_scan = NULL; + + /* ---------------- + * This routine handles updates for only the heap relation + * hasindex. In order to guarantee that we're able to *see* the index + * relation tuple, we bump the command counter id here. + * ---------------- + */ + CommandCounterIncrement(); + + /* ---------------- + * CommandCounterIncrement() flushes invalid cache entries, including + * those for the heap and index relations for which we're updating + * statistics. Now that the cache is flushed, it's safe to open the + * relation again. We need the relation open in order to figure out + * how many blocks it contains. + * ---------------- + */ + + whichRel = heap_open(relid, ShareLock); + + if (!RelationIsValid(whichRel)) + elog(ERROR, "setRelhasindexInplace: cannot open relation id %u", relid); + + /* ---------------- + * Find the RELATION relation tuple for the given relation. + * ---------------- + */ + pg_class = heap_openr(RelationRelationName, RowExclusiveLock); + if (!RelationIsValid(pg_class)) + elog(ERROR, "setRelhasindexInplace: could not open RELATION relation"); + + if (!IsIgnoringSystemIndexes()) + { + tuple = SearchSysCacheTupleCopy(RELOID, + ObjectIdGetDatum(relid), 0, 0, 0); + } + else + { + ScanKeyData key[1]; + + ScanKeyEntryInitialize(&key[0], 0, + ObjectIdAttributeNumber, + F_OIDEQ, + ObjectIdGetDatum(relid)); + + pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key); + tuple = heap_getnext(pg_class_scan, 0); + } + + if (!HeapTupleIsValid(tuple)) + { + if (pg_class_scan) + heap_endscan(pg_class_scan); + heap_close(pg_class, RowExclusiveLock); + elog(ERROR, "setRelhasindexInplace: cannot scan RELATION relation"); + } + /* + * Confirm that target tuple is locked by this transaction + * in case of immedaite updation. + */ + if (immediate) + { + HeapTupleHeader th = tuple->t_data; + if (!(th->t_infomask & HEAP_XMIN_COMMITTED)) + elog(ERROR, "Immediate hasindex updation can be done only for committed tuples %x", th->t_infomask); + if (th->t_infomask & HEAP_XMAX_INVALID) + elog(ERROR, "Immediate hasindex updation can be done only for locked tuples %x", th->t_infomask); + if (th->t_infomask & HEAP_XMAX_COMMITTED) + elog(ERROR, "Immediate hasindex updation can be done only for locked tuples %x", th->t_infomask); + if (!(th->t_infomask & HEAP_MARKED_FOR_UPDATE)) + elog(ERROR, "Immediate hasindex updation can be done only for locked tuples %x", th->t_infomask); + if (!(TransactionIdIsCurrentTransactionId(th->t_xmax))) + elog(ERROR, "The updating tuple is already locked by another backend"); + } + + /* + * We shouldn't have to do this, but we do... Modify the reldesc in + * place with the new values so that the cache contains the latest + * copy. + */ + whichRel->rd_rel->relhasindex = hasindex; + + /* ---------------- + * Update hasindex in pg_class. + * ---------------- + */ + if (pg_class_scan) + { + + if (!IsBootstrapProcessingMode()) + ImmediateInvalidateSharedHeapTuple(pg_class, tuple); + rd_rel = (Form_pg_class) GETSTRUCT(tuple); + rd_rel->relhasindex = hasindex; + WriteNoReleaseBuffer(pg_class_scan->rs_cbuf); + } + else + { + HeapTupleData htup; + Buffer buffer; + + htup.t_self = tuple->t_self; + heap_fetch(pg_class, SnapshotNow, &htup, &buffer); + ImmediateInvalidateSharedHeapTuple(pg_class, tuple); + rd_rel = (Form_pg_class) GETSTRUCT(&htup); + rd_rel->relhasindex = hasindex; + WriteBuffer(buffer); + } + + if (!pg_class_scan) + heap_freetuple(tuple); + else + heap_endscan(pg_class_scan); + + heap_close(pg_class, NoLock); + heap_close(whichRel, NoLock); +} + /* ---------------- * UpdateStats * ---------------- */ void -UpdateStats(Oid relid, long reltuples, bool hasindex) +UpdateStats(Oid relid, long reltuples, bool inplace) { Relation whichRel; Relation pg_class; @@ -1289,7 +1507,8 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) Datum values[Natts_pg_class]; char nulls[Natts_pg_class]; char replace[Natts_pg_class]; - HeapScanDesc pg_class_scan = NULL; + HeapScanDesc pg_class_scan = NULL; + bool in_place_upd; /* ---------------- * This routine handles updates for both the heap and index relation @@ -1327,7 +1546,8 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) if (!RelationIsValid(pg_class)) elog(ERROR, "UpdateStats: could not open RELATION relation"); - if (!IsBootstrapProcessingMode()) + in_place_upd = (inplace || IsBootstrapProcessingMode()); + if (!in_place_upd) { tuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(relid), @@ -1348,7 +1568,7 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) if (!HeapTupleIsValid(tuple)) { - if (IsBootstrapProcessingMode()) + if (pg_class_scan) heap_endscan(pg_class_scan); heap_close(pg_class, RowExclusiveLock); elog(ERROR, "UpdateStats: cannot scan RELATION relation"); @@ -1389,7 +1609,6 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) * place with the new values so that the cache contains the latest * copy. */ - whichRel->rd_rel->relhasindex = hasindex; whichRel->rd_rel->relpages = relpages; whichRel->rd_rel->reltuples = reltuples; @@ -1397,17 +1616,18 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) * Update statistics in pg_class. * ---------------- */ - if (IsBootstrapProcessingMode()) + if (in_place_upd) { /* * At bootstrap time, we don't need to worry about concurrency or * visibility of changes, so we cheat. */ + if (!IsBootstrapProcessingMode()) + ImmediateInvalidateSharedHeapTuple(pg_class, tuple); rd_rel = (Form_pg_class) GETSTRUCT(tuple); rd_rel->relpages = relpages; rd_rel->reltuples = reltuples; - rd_rel->relhasindex = hasindex; WriteNoReleaseBuffer(pg_class_scan->rs_cbuf); } else @@ -1425,18 +1645,18 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) values[Anum_pg_class_relpages - 1] = (Datum) relpages; replace[Anum_pg_class_reltuples - 1] = 'r'; values[Anum_pg_class_reltuples - 1] = (Datum) reltuples; - replace[Anum_pg_class_relhasindex - 1] = 'r'; - values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex); - newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace); heap_update(pg_class, &tuple->t_self, newtup, NULL); - CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); - CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup); - CatalogCloseIndices(Num_pg_class_indices, idescs); + if (!IsIgnoringSystemIndexes()) + { + CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup); + CatalogCloseIndices(Num_pg_class_indices, idescs); + } heap_freetuple(newtup); } - if (!IsBootstrapProcessingMode()) + if (!pg_class_scan) heap_freetuple(tuple); else heap_endscan(pg_class_scan); @@ -1668,16 +1888,18 @@ DefaultBuild(Relation heapRelation, { Oid hrelid = RelationGetRelid(heapRelation); Oid irelid = RelationGetRelid(indexRelation); + bool inplace = IsReindexProcessing(); heap_close(heapRelation, NoLock); index_close(indexRelation); - UpdateStats(hrelid, reltuples, true); - UpdateStats(irelid, indtuples, false); + UpdateStats(hrelid, reltuples, inplace); + UpdateStats(irelid, indtuples, inplace); if (oldPred != NULL) { if (indtuples == reltuples) predicate = NULL; - UpdateIndexPredicate(irelid, oldPred, predicate); + if (!inplace) + UpdateIndexPredicate(irelid, oldPred, predicate); } } } @@ -1826,3 +2048,226 @@ IndexIsUniqueNoCache(Oid indexId) heap_close(pg_index, AccessShareLock); return isunique; } + + +/* --------------------------------- + * activate_index -- activate/deactivate the specified index. + * Note that currelntly PostgreSQL doesn't hold the + * status per index + * --------------------------------- + */ +bool +activate_index(Oid indexId, bool activate) +{ + if (!activate) /* Currently does nothing */ + return true; + return reindex_index(indexId, false); +} + +/* -------------------------------- + * reindex_index - This routine is used to recreate an index + * -------------------------------- + */ +bool +reindex_index(Oid indexId, bool force) +{ + Relation iRel, indexRelation, heapRelation; + ScanKeyData entry; + HeapScanDesc scan; + HeapTuple indexTuple, procTuple, classTuple; + Form_pg_index index; + Oid heapId, procId, accessMethodId; + Node *oldPred = NULL; + PredInfo *predInfo; + List *cnfPred = NULL; + AttrNumber *attributeNumberA; + FuncIndexInfo fInfo, *funcInfo = NULL; + int i, numberOfAttributes; + char *predString; + bool old; + + old = SetReindexProcessing(true); + /* Scan pg_index to find indexes on heapRelation */ + indexRelation = heap_openr(IndexRelationName, AccessShareLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ, + ObjectIdGetDatum(indexId)); + scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry); + indexTuple = heap_getnext(scan, 0); + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "reindex_index index %d tuple is invalid", indexId); + + /* + * For the index, fetch index attributes so we can apply index_build + */ + index = (Form_pg_index) GETSTRUCT(indexTuple); + heapId = index->indrelid; + procId = index->indproc; + + for (i = 0; i < INDEX_MAX_KEYS; i++) + { + if (index->indkey[i] == InvalidAttrNumber) + break; + } + numberOfAttributes = i; + + /* If a valid where predicate, compute predicate Node */ + if (VARSIZE(&index->indpred) != 0) + { + predString = fmgr(F_TEXTOUT, &index->indpred); + oldPred = stringToNode(predString); + pfree(predString); + } + predInfo = (PredInfo *) palloc(sizeof(PredInfo)); + predInfo->pred = (Node *) cnfPred; + predInfo->oldPred = oldPred; + + /* Assign Index keys to attributes array */ + attributeNumberA = (AttrNumber *) palloc(numberOfAttributes * sizeof(AttrNumber)); + for (i = 0; i < numberOfAttributes; i++) + attributeNumberA[i] = index->indkey[i]; + + /* If this is a procedural index, initialize our FuncIndexInfo */ + if (procId != InvalidOid) + { + funcInfo = &fInfo; + FIsetnArgs(funcInfo, numberOfAttributes); + procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId), + 0, 0, 0); + if (!HeapTupleIsValid(procTuple)) + elog(ERROR, "RelationTruncateIndexes: index procedure not found"); + namecpy(&(funcInfo->funcName), + &(((Form_pg_proc) GETSTRUCT(procTuple))->proname)); + FIsetProcOid(funcInfo, procTuple->t_data->t_oid); + } + + /* Fetch the classTuple associated with this index */ + classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId), 0, 0, 0); + if (!HeapTupleIsValid(classTuple)) + elog(ERROR, "RelationTruncateIndexes: index access method not found"); + accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam; + + /* Open our index relation */ + iRel = index_open(indexId); + if (iRel == NULL) + elog(ERROR, "reindex_index: can't open index relation"); + heapRelation = heap_open(heapId, ExclusiveLock); + if (heapRelation == NULL) + elog(ERROR, "reindex_index: can't open heap relation"); + + /* Obtain exclusive lock on it, just to be sure */ + LockRelation(iRel, AccessExclusiveLock); + + /* + * Release any buffers associated with this index. If they're dirty, + * they're just dropped without bothering to flush to disk. + */ + ReleaseRelationBuffers(iRel); + if (FlushRelationBuffers(iRel, (BlockNumber) 0, false) < 0) + elog(ERROR, "reindex_index: unable to flush index from buffer pool"); + + /* Now truncate the actual data and set blocks to zero */ + smgrtruncate(DEFAULT_SMGR, iRel, 0); + iRel->rd_nblocks = 0; + + /* Initialize the index and rebuild */ + InitIndexStrategy(numberOfAttributes, iRel, accessMethodId); + index_build(heapRelation, iRel, numberOfAttributes, + attributeNumberA, 0, NULL, funcInfo, predInfo); + + /* + * index_build will close both the heap and index relations + * (but not give up the locks we hold on them). That's fine + * for the index, but we need to open the heap again. We need + * no new lock, since this backend still has the exclusive lock + * grabbed by heap_truncate. + */ + iRel = index_open(indexId); + Assert(iRel != NULL); + + /* Complete the scan and close pg_index */ + heap_endscan(scan); + heap_close(indexRelation, AccessShareLock); + SetReindexProcessing(old); + return true; +} + +/* + * ---------------------------- + * activate_indexes_of_a_table + * activate/deactivate indexes of the specified table. + * ---------------------------- + */ +bool +activate_indexes_of_a_table(Oid relid, bool activate) +{ + if (IndexesAreActive(relid, true)) + { + if (!activate) + setRelhasindexInplace(relid, false, true); + else + { + return false; + } + } + else + { + if (activate) + reindex_relation(relid, false); + else + { + return false; + } + } + return true; +} +/* -------------------------------- + * reindex_relation - This routine is used to recreate indexes + * of a relation. + * -------------------------------- + */ +bool +reindex_relation(Oid relid, bool force) +{ + Relation indexRelation; + ScanKeyData entry; + HeapScanDesc scan; + HeapTuple indexTuple; + bool old, reindexed; + + old = SetReindexProcessing(true); + if (IndexesAreActive(relid, true)) + { + if (!force) + { + SetReindexProcessing(old); + return false; + } + activate_indexes_of_a_table(relid, false); + } + + indexRelation = heap_openr(IndexRelationName, AccessShareLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, + F_OIDEQ, ObjectIdGetDatum(relid)); + scan = heap_beginscan(indexRelation, false, SnapshotNow, + 1, &entry); + reindexed = false; + while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0))) + { + Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple); + if (activate_index(index->indexrelid, true)) + reindexed = true; + else + { + reindexed = false; + break; + } + } + heap_endscan(scan); + heap_close(indexRelation, AccessShareLock); + if (reindexed) + { + setRelhasindexInplace(relid, true, false); + } + SetReindexProcessing(old); + return true; +} diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 2afd6b6909..41337da77f 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.58 2000/01/26 05:56:10 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.59 2000/02/18 09:28:41 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -92,6 +92,8 @@ CatalogOpenIndices(int nIndices, char **names, Relation *idescs) { int i; + if (IsIgnoringSystemIndexes()) + return; for (i = 0; i < nIndices; i++) idescs[i] = index_openr(names[i]); } @@ -104,6 +106,8 @@ CatalogCloseIndices(int nIndices, Relation *idescs) { int i; + if (IsIgnoringSystemIndexes()) + return; for (i = 0; i < nIndices; i++) index_close(idescs[i]); } @@ -131,6 +135,8 @@ CatalogIndexInsert(Relation *idescs, *finfoP; int i; + if (IsIgnoringSystemIndexes()) + return; heapDescriptor = RelationGetDescr(heapRelation); for (i = 0; i < nIndices; i++) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index f5de425b2b..cbd7b26ae8 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.20 2000/01/26 05:56:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.21 2000/02/18 09:29:37 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -17,12 +17,15 @@ #include "access/genam.h" #include "access/heapam.h" +#include "catalog/catname.h" #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/pg_index.h" #include "catalog/pg_opclass.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "catalog/pg_database.h" +#include "catalog/pg_shadow.h" #include "commands/defrem.h" #include "optimizer/clauses.h" #include "optimizer/planmain.h" @@ -30,6 +33,9 @@ #include "parser/parsetree.h" #include "utils/builtins.h" #include "utils/syscache.h" +#include "miscadmin.h" /* ReindexDatabase() */ +#include "utils/portal.h" /* ReindexDatabase() */ +#include "catalog/catalog.h" /* ReindexDatabase() */ #define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args!=NULL) @@ -149,6 +155,8 @@ DefineIndex(char *heapRelationName, CheckPredicate(cnfPred, rangetable, relationId); } + if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false)) + elog(ERROR, "existent indexes are inactive. REINDEX first"); if (IsFuncIndex(attributeList)) { IndexElem *funcIndex = lfirst(attributeList); @@ -195,6 +203,7 @@ DefineIndex(char *heapRelationName, classObjectId, parameterCount, parameterA, (Node *) cnfPred, lossy, unique, primary); } + setRelhasindexInplace(relationId, true, false); } @@ -570,3 +579,163 @@ RemoveIndex(char *name) index_drop(tuple->t_data->t_oid); } + +/* + * Reindex + * Recreate an index. + * + * Exceptions: + * "ERROR" if index nonexistent. + * ... + */ +void +ReindexIndex(const char *name, bool force /* currently unused */) +{ + HeapTuple tuple; + + tuple = SearchSysCacheTuple(RELNAME, + PointerGetDatum(name), + 0, 0, 0); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "index \"%s\" nonexistent", name); + + if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX) + { + elog(ERROR, "relation \"%s\" is of type \"%c\"", + name, + ((Form_pg_class) GETSTRUCT(tuple))->relkind); + } + + reindex_index(tuple->t_data->t_oid, force); +} + +/* + * ReindexTable + * Recreate indexes of a table. + * + * Exceptions: + * "ERROR" if table nonexistent. + * ... + */ +void +ReindexTable(const char *name, bool force) +{ + HeapTuple tuple; + + tuple = SearchSysCacheTuple(RELNAME, + PointerGetDatum(name), + 0, 0, 0); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "table \"%s\" nonexistent", name); + + if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION) + { + elog(ERROR, "relation \"%s\" is of type \"%c\"", + name, + ((Form_pg_class) GETSTRUCT(tuple))->relkind); + } + + reindex_relation(tuple->t_data->t_oid, force); +} + +/* + * ReindexDatabase + * Recreate indexes of a database. + * + * Exceptions: + * "ERROR" if table nonexistent. + * ... + */ +extern Oid MyDatabaseId; +void +ReindexDatabase(const char *dbname, bool force, bool all) +{ + Relation relation, relationRelation; + HeapTuple usertuple, dbtuple, tuple; + HeapScanDesc scan; + int4 user_id, db_owner; + bool superuser; + Oid db_id; + char *username; + ScanKeyData scankey; + PortalVariableMemory pmem; + MemoryContext old; + int relcnt, relalc, i, oncealc = 200; + Oid *relids = (Oid *) NULL; + + AssertArg(dbname); + + username = GetPgUserName(); + usertuple = SearchSysCacheTuple(SHADOWNAME, PointerGetDatum(username), + 0, 0, 0); + if (!HeapTupleIsValid(usertuple)) + elog(ERROR, "Current user '%s' is invalid.", username); + user_id = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesysid; + superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper; + + relation = heap_openr(DatabaseRelationName, AccessShareLock); + ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname, + F_NAMEEQ, NameGetDatum(dbname)); + scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scankey); + dbtuple = heap_getnext(scan, 0); + if (!HeapTupleIsValid(dbtuple)) + elog(ERROR, "Database '%s' doesn't exist", dbname); + db_id = dbtuple->t_data->t_oid; + db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba; + heap_endscan(scan); + if (user_id != db_owner && !superuser) + elog(ERROR, "REINDEX DATABASE: Permission denied."); + + if (db_id != MyDatabaseId) + elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database."); + + heap_close(relation, NoLock); + /** reindex_database(db_id, force, !all); **/ + + CommonSpecialPortalOpen(); + pmem = CommonSpecialPortalGetMemory(); + relationRelation = heap_openr(RelationRelationName, AccessShareLock); + scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL); + relcnt = relalc = 0; + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) + { + if (!all) + { + if (!IsSystemRelationName(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname))) + continue; + if (((Form_pg_class) GETSTRUCT(tuple))->relhasrules) + continue; + } + if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION) + { + old = MemoryContextSwitchTo((MemoryContext) pmem); + if (relcnt == 0) + { + relalc = oncealc; + relids = palloc(sizeof(Oid) * relalc); + } + else if (relcnt >= relalc) + { + relalc *= 2; + relids = repalloc(relids, sizeof(Oid) * relalc); + } + MemoryContextSwitchTo(old); + relids[relcnt] = tuple->t_data->t_oid; + relcnt++; + } + } + heap_endscan(scan); + heap_close(relationRelation, AccessShareLock); + + CommitTransactionCommand(); + for (i = 0; i < relcnt; i++) + { + StartTransactionCommand(); + reindex_relation(relids[i], force); + CommitTransactionCommand(); + } + CommonSpecialPortalClose(); + StartTransactionCommand(); +} diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 0b0b3cf2ec..9a4286a500 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.60 2000/02/13 13:21:10 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.61 2000/02/18 09:29:37 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -433,15 +433,18 @@ RelationBuildTriggers(Relation relation) Trigger *build; Relation tgrel; Form_pg_trigger pg_trigger; - Relation irel; + Relation irel = (Relation) NULL; ScanKeyData skey; HeapTupleData tuple; - IndexScanDesc sd; + IndexScanDesc sd = (IndexScanDesc) NULL; + HeapScanDesc tgscan = (HeapScanDesc) NULL; + HeapTuple htup; RetrieveIndexResult indexRes; Buffer buffer; struct varlena *val; bool isnull; int found; + bool hasindex; MemSet(trigdesc, 0, sizeof(TriggerDesc)); @@ -452,25 +455,41 @@ RelationBuildTriggers(Relation relation) ObjectIdGetDatum(RelationGetRelid(relation))); tgrel = heap_openr(TriggerRelationName, AccessShareLock); - irel = index_openr(TriggerRelidIndex); - sd = index_beginscan(irel, false, 1, &skey); + hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes()); + if (hasindex) + { + irel = index_openr(TriggerRelidIndex); + sd = index_beginscan(irel, false, 1, &skey); + } + else + tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey); for (found = 0;;) { - indexRes = index_getnext(sd, ForwardScanDirection); - if (!indexRes) - break; + if (hasindex) + { + indexRes = index_getnext(sd, ForwardScanDirection); + if (!indexRes) + break; - tuple.t_self = indexRes->heap_iptr; - heap_fetch(tgrel, SnapshotNow, &tuple, &buffer); - pfree(indexRes); - if (!tuple.t_data) - continue; + tuple.t_self = indexRes->heap_iptr; + heap_fetch(tgrel, SnapshotNow, &tuple, &buffer); + pfree(indexRes); + if (!tuple.t_data) + continue; + htup = &tuple; + } + else + { + htup = heap_getnext(tgscan, 0); + if (!HeapTupleIsValid(htup)) + break; + } if (found == ntrigs) elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s", RelationGetRelationName(relation)); - pg_trigger = (Form_pg_trigger) GETSTRUCT(&tuple); + pg_trigger = (Form_pg_trigger) GETSTRUCT(htup); if (triggers == NULL) triggers = (Trigger *) palloc(sizeof(Trigger)); @@ -478,7 +497,7 @@ RelationBuildTriggers(Relation relation) triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger)); build = &(triggers[found]); - build->tgoid = tuple.t_data->t_oid; + build->tgoid = htup->t_data->t_oid; build->tgname = nameout(&pg_trigger->tgname); build->tgfoid = pg_trigger->tgfoid; build->tgfunc.fn_addr = NULL; @@ -489,7 +508,7 @@ RelationBuildTriggers(Relation relation) build->tginitdeferred = pg_trigger->tginitdeferred; build->tgnargs = pg_trigger->tgnargs; memcpy(build->tgattr, &(pg_trigger->tgattr), FUNC_MAX_ARGS * sizeof(int16)); - val = (struct varlena *) fastgetattr(&tuple, + val = (struct varlena *) fastgetattr(htup, Anum_pg_trigger_tgargs, tgrel->rd_att, &isnull); if (isnull) @@ -500,7 +519,7 @@ RelationBuildTriggers(Relation relation) char *p; int i; - val = (struct varlena *) fastgetattr(&tuple, + val = (struct varlena *) fastgetattr(htup, Anum_pg_trigger_tgargs, tgrel->rd_att, &isnull); if (isnull) @@ -518,7 +537,8 @@ RelationBuildTriggers(Relation relation) build->tgargs = NULL; found++; - ReleaseBuffer(buffer); + if (hasindex) + ReleaseBuffer(buffer); } if (found < ntrigs) @@ -526,8 +546,13 @@ RelationBuildTriggers(Relation relation) ntrigs - found, RelationGetRelationName(relation)); - index_endscan(sd); - index_close(irel); + if (hasindex) + { + index_endscan(sd); + index_close(irel); + } + else + heap_endscan(tgscan); heap_close(tgrel, AccessShareLock); /* Build trigdesc */ @@ -1460,7 +1485,7 @@ void DeferredTriggerSetState(ConstraintsSetStmt *stmt) { Relation tgrel; - Relation irel; + Relation irel = (Relation) NULL; List *l; List *ls; List *lnext; @@ -1468,6 +1493,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) MemoryContext oldcxt; bool found; DeferredTriggerStatus state; + bool hasindex; /* ---------- * Handle SET CONSTRAINTS ALL ... @@ -1548,13 +1574,17 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) * ---------- */ tgrel = heap_openr(TriggerRelationName, AccessShareLock); - irel = index_openr(TriggerConstrNameIndex); + hasindex = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes()); + if (hasindex) + irel = index_openr(TriggerConstrNameIndex); foreach (l, stmt->constraints) { ScanKeyData skey; HeapTupleData tuple; - IndexScanDesc sd; + IndexScanDesc sd = (IndexScanDesc) NULL; + HeapScanDesc tgscan = (HeapScanDesc) NULL; + HeapTuple htup; RetrieveIndexResult indexRes; Buffer buffer; Form_pg_trigger pg_trigger; @@ -1577,7 +1607,10 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) (RegProcedure) F_NAMEEQ, PointerGetDatum((char *)lfirst(l))); - sd = index_beginscan(irel, false, 1, &skey); + if (hasindex) + sd = index_beginscan(irel, false, 1, &skey); + else + tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey); /* ---------- * ... and search for the constraint trigger row @@ -1586,33 +1619,43 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) found = false; for (;;) { - indexRes = index_getnext(sd, ForwardScanDirection); - if (!indexRes) - break; - - tuple.t_self = indexRes->heap_iptr; - heap_fetch(tgrel, SnapshotNow, &tuple, &buffer); - pfree(indexRes); - if (!tuple.t_data) + if (hasindex) { - ReleaseBuffer(buffer); - continue; + indexRes = index_getnext(sd, ForwardScanDirection); + if (!indexRes) + break; + + tuple.t_self = indexRes->heap_iptr; + heap_fetch(tgrel, SnapshotNow, &tuple, &buffer); + pfree(indexRes); + if (!tuple.t_data) + { + continue; + } + htup = &tuple; + } + else + { + htup = heap_getnext(tgscan, 0); + if (!HeapTupleIsValid(htup)) + break; } /* ---------- * If we found some, check that they fit the deferrability * ---------- */ - pg_trigger = (Form_pg_trigger) GETSTRUCT(&tuple); + pg_trigger = (Form_pg_trigger) GETSTRUCT(htup); if (stmt->deferred & !pg_trigger->tgdeferrable) elog(ERROR, "Constraint '%s' is not deferrable", (char *)lfirst(l)); - constr_oid = tuple.t_data->t_oid; + constr_oid = htup->t_data->t_oid; loid = lappend(loid, (Node *)constr_oid); found = true; - ReleaseBuffer(buffer); + if (hasindex) + ReleaseBuffer(buffer); } /* ---------- @@ -1622,9 +1665,13 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) if (!found) elog(ERROR, "Constraint '%s' does not exist", (char *)lfirst(l)); - index_endscan(sd); + if (hasindex) + index_endscan(sd); + else + heap_endscan(tgscan); } - index_close(irel); + if (hasindex) + index_close(irel); heap_close(tgrel, AccessShareLock); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 5274be3bdf..ef84459a71 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.138 2000/01/26 05:56:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.139 2000/02/18 09:29:37 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -51,7 +51,7 @@ #endif -bool VacuumRunning = false; +bool CommonSpecialPortalInUse = false; static Portal vc_portal; @@ -99,6 +99,53 @@ static bool vc_enough_space(VPageDescr vpd, Size len); static char *vc_show_rusage(struct rusage * ru0); +/* + * This routines handle a special cross-transaction portal. + * However it is automatically closed in case of abort. + */ +void CommonSpecialPortalOpen(void) +{ + char *pname; + + /* + * Create a portal for safe memory across transactions. We need to + * palloc the name space for it because our hash function expects the + * name to be on a longword boundary. CreatePortal copies the name to + * safe storage for us. + */ + pname = pstrdup(VACPNAME); + vc_portal = CreatePortal(pname); + pfree(pname); + + /* + * Set flag to indicate that vc_portal must be removed after an error. + * This global variable is checked in the transaction manager on xact + * abort, and the routine CommonSpecialPortalClose() is called if + * necessary. + */ + CommonSpecialPortalInUse = true; +} + +void CommonSpecialPortalClose(void) +{ + /* Clear flag first, to avoid recursion if PortalDrop elog's */ + CommonSpecialPortalInUse = false; + + /* + * Release our portal for cross-transaction memory. + */ + PortalDrop(&vc_portal); +} + +PortalVariableMemory CommonSpecialPortalGetMemory(void) +{ + return PortalGetVariableMemory(vc_portal); +} +bool CommonSpecialPortalIsOpen(void) +{ + return CommonSpecialPortalInUse; +} + void vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec) { @@ -136,7 +183,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec) strcpy(NameStr(VacRel), vacrel); /* must also copy the column list, if any, to safe storage */ - pmem = PortalGetVariableMemory(vc_portal); + pmem = CommonSpecialPortalGetMemory(); old = MemoryContextSwitchTo((MemoryContext) pmem); foreach(le, va_spec) { @@ -179,24 +226,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec) static void vc_init() { - char *pname; - - /* - * Create a portal for safe memory across transactions. We need to - * palloc the name space for it because our hash function expects the - * name to be on a longword boundary. CreatePortal copies the name to - * safe storage for us. - */ - pname = pstrdup(VACPNAME); - vc_portal = CreatePortal(pname); - pfree(pname); - - /* - * Set flag to indicate that vc_portal must be removed after an error. - * This global variable is checked in the transaction manager on xact - * abort, and the routine vc_abort() is called if necessary. - */ - VacuumRunning = true; + CommonSpecialPortalOpen(); /* matches the StartTransaction in PostgresMain() */ CommitTransactionCommand(); @@ -219,30 +249,12 @@ vc_shutdown() */ unlink(RELCACHE_INIT_FILENAME); - /* - * Release our portal for cross-transaction memory. - */ - PortalDrop(&vc_portal); - - /* okay, we're done */ - VacuumRunning = false; + CommonSpecialPortalClose(); /* matches the CommitTransaction in PostgresMain() */ StartTransactionCommand(); } -void -vc_abort() -{ - /* Clear flag first, to avoid recursion if PortalDrop elog's */ - VacuumRunning = false; - - /* - * Release our portal for cross-transaction memory. - */ - PortalDrop(&vc_portal); -} - /* * vc_vacuum() -- vacuum the database. * @@ -302,7 +314,7 @@ vc_getrels(NameData *VacRelP) F_CHAREQ, CharGetDatum('r')); } - portalmem = PortalGetVariableMemory(vc_portal); + portalmem = CommonSpecialPortalGetMemory(); vrl = cur = (VRelList) NULL; rel = heap_openr(RelationRelationName, AccessShareLock); @@ -379,6 +391,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols) int32 nindices, i; VRelStats *vacrelstats; + bool reindex = false; StartTransactionCommand(); @@ -552,17 +565,31 @@ vc_vacone(Oid relid, bool analyze, List *va_cols) GetXmaxRecent(&XmaxRecent); /* scan it */ + reindex = false; vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0; vc_scanheap(vacrelstats, onerel, &vacuum_pages, &fraged_pages); + if (IsIgnoringSystemIndexes() && IsSystemRelationName(RelationGetRelationName(onerel))) + reindex = true; /* Now open indices */ + nindices = 0; Irel = (Relation *) NULL; vc_getindices(vacrelstats->relid, &nindices, &Irel); - + if (!Irel) + reindex = false; + else if (!RelationGetForm(onerel)->relhasindex) + reindex = true; if (nindices > 0) vacrelstats->hasindex = true; else vacrelstats->hasindex = false; + if (reindex) + { + for (i = 0; i < nindices; i++) + index_close(Irel[i]); + Irel = (Relation *) NULL; + activate_indexes_of_a_table(relid, false); + } /* Clean/scan index relation(s) */ if (Irel != (Relation *) NULL) @@ -590,6 +617,8 @@ vc_vacone(Oid relid, bool analyze, List *va_cols) * vacuum_pages list */ vc_vacheap(vacrelstats, onerel, &vacuum_pages); } + if (reindex) + activate_indexes_of_a_table(relid, true); /* ok - free vacuum_pages list of reaped pages */ if (vacuum_pages.vpl_num_pages > 0) diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 11cde461b4..8f15ac1ed1 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.53 2000/01/26 05:56:22 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.54 2000/02/18 09:29:57 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -48,8 +48,10 @@ #include "catalog/catname.h" #include "catalog/index.h" #include "catalog/pg_index.h" +#include "catalog/catalog.h" #include "executor/execdebug.h" #include "executor/executor.h" +#include "miscadmin.h" static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP, AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP); @@ -770,6 +772,12 @@ ExecOpenIndices(Oid resultRelationOid, PredInfo *predicate; int i; + resultRelationInfo->ri_NumIndices = 0; + if (!RelationGetForm(resultRelationInfo->ri_RelationDesc)->relhasindex) + return; + if (IsIgnoringSystemIndexes() && + IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc))) + return; /* ---------------- * open pg_index * ---------------- diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index e5f7642c85..b1d1c578f3 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.46 2000/02/05 23:19:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.47 2000/02/18 09:29:57 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -1048,6 +1048,10 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent) ¤tRelation, /* return: rel desc */ (Pointer *) ¤tScanDesc); /* return: scan desc */ +if (!RelationGetForm(currentRelation)->relhasindex) +{ + elog(ERROR, "indexes of the relation %u was inactivated", reloid); +} scanstate->css_currentRelation = currentRelation; scanstate->css_currentScanDesc = currentScanDesc; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index e3a60c2c7f..716c31ab0f 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.48 2000/02/17 03:39:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.49 2000/02/18 09:30:09 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,8 @@ #include "optimizer/plancat.h" #include "parser/parsetree.h" #include "utils/syscache.h" +#include "catalog/catalog.h" +#include "miscadmin.h" /* @@ -55,7 +57,10 @@ relation_info(Query *root, Index relid, relationObjectId); relation = (Form_pg_class) GETSTRUCT(relationTuple); - *hasindex = (relation->relhasindex) ? true : false; + if (IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(relation->relname))) + *hasindex = false; + else + *hasindex = (relation->relhasindex) ? true : false; *pages = relation->relpages; *tuples = relation->reltuples; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4babad9524..b6962f8fad 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.143 2000/02/16 17:24:36 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.144 2000/02/18 09:29:40 inoue Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -124,7 +124,7 @@ static Node *doNegate(Node *n); ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropTrigStmt, CreatePLangStmt, DropPLangStmt, IndexStmt, ListenStmt, UnlistenStmt, LockStmt, OptimizableStmt, - ProcedureStmt, RemoveAggrStmt, RemoveOperStmt, + ProcedureStmt, ReindexStmt, RemoveAggrStmt, RemoveOperStmt, RemoveFuncStmt, RemoveStmt, RenameStmt, RevokeStmt, RuleStmt, TransactionStmt, ViewStmt, LoadStmt, CreatedbStmt, DropdbStmt, VacuumStmt, CursorStmt, SubSelect, @@ -141,7 +141,7 @@ static Node *doNegate(Node *n); %type createdb_opt_encoding %type opt_lock, lock_type -%type opt_lmode +%type opt_lmode, opt_force %type user_createdb_clause, user_createuser_clause %type user_passwd_clause @@ -211,7 +211,7 @@ static Node *doNegate(Node *n); opt_with_copy, index_opt_unique, opt_verbose, opt_analyze %type opt_cursor -%type copy_dirn, def_type, direction, remove_type, +%type copy_dirn, def_type, direction, reindex_type, remove_type, opt_column, event, comment_type, comment_cl, comment_ag, comment_fn, comment_op, comment_tg @@ -339,13 +339,13 @@ static Node *doNegate(Node *n); CACHE, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE, DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND, - FORWARD, FUNCTION, HANDLER, + FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL, - RENAME, RESET, RETURNS, ROW, RULE, + REINDEX, RENAME, RESET, RETURNS, ROW, RULE, SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION @@ -440,6 +440,7 @@ stmt : AlterTableStmt | UnlistenStmt | LockStmt | ProcedureStmt + | ReindexStmt | RemoveAggrStmt | RemoveOperStmt | RemoveFuncStmt @@ -2445,6 +2446,35 @@ oper_argtypes: name ; +/***************************************************************************** + * + * QUERY: + * + * REINDEX type [FORCE] [ALL] + * + *****************************************************************************/ + +ReindexStmt: REINDEX reindex_type name opt_force + { + ReindexStmt *n = makeNode(ReindexStmt); + if (IsTransactionBlock()) + elog(ERROR,"REINDEX command could only be used outside begin/end transaction blocks"); + n->reindexType = $2; + n->name = $3; + n->force = $4; + $$ = (Node *)n; + } + ; + +reindex_type: INDEX { $$ = INDEX; } + | TABLE { $$ = TABLE; } + | DATABASE { $$ = DATABASE; } + ; +opt_force: FORCE { $$ = TRUE; } + | /* EMPTY */ { $$ = FALSE; } + ; + + /***************************************************************************** * * QUERY: diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index e1c9424e37..d971e95762 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.66 2000/02/15 03:26:38 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.67 2000/02/18 09:29:40 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -107,6 +107,7 @@ static ScanKeyword ScanKeywords[] = { {"fetch", FETCH}, {"float", FLOAT}, {"for", FOR}, + {"force", FORCE}, {"foreign", FOREIGN}, {"forward", FORWARD}, {"from", FROM}, @@ -196,6 +197,7 @@ static ScanKeyword ScanKeywords[] = { {"public", PUBLIC}, {"read", READ}, {"references", REFERENCES}, + {"reindex", REINDEX}, {"relative", RELATIVE}, {"rename", RENAME}, {"reset", RESET}, diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 3059e8b828..c455d1cbd2 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.135 2000/01/26 05:56:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.136 2000/02/18 09:28:44 inoue Exp $ * * NOTES * @@ -430,6 +430,7 @@ PostmasterMain(int argc, char *argv[]) DataDir = getenv("PGDATA"); /* default value */ opterr = 0; + IgnoreSystemIndexes(false); while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF) { switch (opt) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 123d70af9b..77422deb38 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.141 2000/01/26 05:57:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.142 2000/02/18 09:29:27 inoue Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -963,7 +963,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) optind = 1; /* reset after postmaster's usage */ while ((flag = getopt(argc, argv, - "A:B:CD:d:EeFf:iK:LNOo:p:QS:sT:t:v:W:x:")) + "A:B:CD:d:EeFf:iK:LNOPo:p:QS:sT:t:v:W:x:")) != EOF) switch (flag) { @@ -1116,6 +1116,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) allowSystemTableMods = true; break; + case 'P': + /* -------------------- + * ignore system indexes + * -------------------- + */ + if (secure) /* XXX safe to allow from client??? */ + IgnoreSystemIndexes(true); + break; + case 'o': /* ---------------- * o - send output (stdout and stderr) to the given file @@ -1516,7 +1525,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.141 $ $Date: 2000/01/26 05:57:07 $\n"); + puts("$Revision: 1.142 $ $Date: 2000/02/18 09:29:27 $\n"); } /* diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 66acb230f2..427bf7b4d4 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.82 2000/01/29 16:58:38 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.83 2000/02/18 09:29:31 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -846,6 +846,61 @@ ProcessUtility(Node *parsetree, DropGroup((DropGroupStmt *) parsetree); break; + case T_ReindexStmt: + { + ReindexStmt *stmt = (ReindexStmt *) parsetree; + + PS_SET_STATUS(commandTag = "REINDEX"); + CHECK_IF_ABORTED(); + + switch (stmt->reindexType) + { + case INDEX: + relname = stmt->name; + if (IsSystemRelationName(relname)) + { + if (!allowSystemTableMods && IsSystemRelationName(relname)) + elog(ERROR, "class \"%s\" is a system catalog index", + relname); + if (!IsIgnoringSystemIndexes()) + elog(ERROR, "class \"%s\" is a system catalog index", + relname); + } +#ifndef NO_SECURITY + if (!pg_ownercheck(userName, relname, RELNAME)) + elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]); +#endif + ReindexIndex(relname, stmt->force); + break; + case TABLE: + relname = stmt->name; + if (IsSystemRelationName(relname)) + { + if (!allowSystemTableMods && IsSystemRelationName(relname)) + elog(ERROR, "class \"%s\" is a system catalog index", + relname); + if (!IsIgnoringSystemIndexes()) + elog(ERROR, "class \"%s\" is a system catalog index", + relname); + } +#ifndef NO_SECURITY + if (!pg_ownercheck(userName, relname, RELNAME)) + elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]); +#endif + ReindexTable(relname, stmt->force); + break; + case DATABASE: + relname = stmt->name; + if (!allowSystemTableMods) + elog(ERROR, "-O option is needed"); + if (!IsIgnoringSystemIndexes()) + elog(ERROR, "-P option is needed"); + ReindexDatabase(relname, stmt->force, false); + break; + } + break; + } + break; /* * ******************************** default ******************************** * diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 732569fa8f..8094addc7d 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.51 2000/01/26 05:57:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.52 2000/02/18 09:28:48 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -45,7 +45,7 @@ regprocin(char *pro_name_or_oid) if (pro_name_or_oid[0] == '-' && pro_name_or_oid[1] == '\0') return InvalidOid; - if (!IsBootstrapProcessingMode()) + if (!IsIgnoringSystemIndexes()) { /* diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 1f224e56cf..c6c8763c70 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.60 2000/02/04 03:16:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.61 2000/02/18 09:28:53 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -233,7 +233,7 @@ CatalogCacheInitializeCache(struct catcache * cache, */ if (cache->cc_indname != NULL && cache->indexId == InvalidOid) { - if (RelationGetForm(relation)->relhasindex) + if (!IsIgnoringSystemIndexes() && RelationGetForm(relation)->relhasindex) { /* @@ -817,14 +817,19 @@ SearchSelfReferences(struct catcache * cache) if (!OidIsValid(indexSelfOid)) { + ScanKeyData key; + HeapScanDesc sd; /* Find oid of pg_index_indexrelid_index */ rel = heap_openr(RelationRelationName, AccessShareLock); - ntp = ClassNameIndexScan(rel, IndexRelidIndex); + ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname, + F_NAMEEQ, PointerGetDatum(IndexRelidIndex)); + sd = heap_beginscan(rel, false, SnapshotNow, 1, &key); + ntp = heap_getnext(sd, 0); if (!HeapTupleIsValid(ntp)) elog(ERROR, "SearchSelfReferences: %s not found in %s", IndexRelidIndex, RelationRelationName); indexSelfOid = ntp->t_data->t_oid; - heap_freetuple(ntp); + heap_endscan(sd); heap_close(rel, AccessShareLock); } /* Looking for something other than pg_index_indexrelid_index? */ @@ -1031,7 +1036,7 @@ SearchSysCache(struct catcache * cache, CACHE1_elog(DEBUG, "SearchSysCache: performing scan"); if ((RelationGetForm(relation))->relhasindex - && !IsBootstrapProcessingMode()) + && !IsIgnoringSystemIndexes()) { /* ---------- * Switch back to old memory context so memory not freed diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 7c993d3d73..1615762915 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.89 2000/01/31 04:35:52 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.90 2000/02/18 09:28:55 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -229,6 +229,7 @@ static void IndexedAccessMethodInitialize(Relation relation); static void AttrDefaultFetch(Relation relation); static void RelCheckFetch(Relation relation); +static bool criticalRelcacheBuild = false; /* ---------------------------------------------------------------- * RelationIdGetRelation() and RelationNameGetRelation() * support functions @@ -254,7 +255,7 @@ ScanPgRelation(RelationBuildDescInfo buildinfo) * can, and do. */ - if (IsBootstrapProcessingMode()) + if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild) return scan_pg_rel_seq(buildinfo); else return scan_pg_rel_ind(buildinfo); @@ -424,12 +425,50 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, * can, and do. */ - if (IsBootstrapProcessingMode()) + if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild) build_tupdesc_seq(buildinfo, relation, natts); else build_tupdesc_ind(buildinfo, relation, natts); } +static void +SetConstrOfRelation(Relation relation, TupleConstr *constr, int ndef, AttrDefault *attrdef) +{ + if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks) + { + relation->rd_att->constr = constr; + + if (ndef > 0) /* DEFAULTs */ + { + if (ndef < relation->rd_rel->relnatts) + constr->defval = (AttrDefault *) + repalloc(attrdef, ndef * sizeof(AttrDefault)); + else + constr->defval = attrdef; + constr->num_defval = ndef; + AttrDefaultFetch(relation); + } + else + constr->num_defval = 0; + + if (relation->rd_rel->relchecks > 0) /* CHECKs */ + { + constr->num_check = relation->rd_rel->relchecks; + constr->check = (ConstrCheck *) palloc(constr->num_check * + sizeof(ConstrCheck)); + MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck)); + RelCheckFetch(relation); + } + else + constr->num_check = 0; + } + else + { + pfree(constr); + relation->rd_att->constr = NULL; + } +} + static void build_tupdesc_seq(RelationBuildDescInfo buildinfo, Relation relation, @@ -441,7 +480,11 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, Form_pg_attribute attp; ScanKeyData key; int need; + TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr)); + AttrDefault *attrdef = NULL; + int ndef = 0; + constr->has_not_null = false; /* ---------------- * form a scan key * ---------------- @@ -478,6 +521,23 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, (char *) attp, ATTRIBUTE_TUPLE_SIZE); need--; + /* Update if this attribute have a constraint */ + if (attp->attnotnull) + constr->has_not_null = true; + + if (attp->atthasdef) + { + if (attrdef == NULL) + { + attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts * + sizeof(AttrDefault)); + MemSet(attrdef, 0, + relation->rd_rel->relnatts * sizeof(AttrDefault)); + } + attrdef[ndef].adnum = attp->attnum; + attrdef[ndef].adbin = NULL; + ndef++; + } } pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0); } @@ -492,6 +552,8 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, */ heap_endscan(pg_attribute_scan); heap_close(pg_attribute_desc, AccessShareLock); + + SetConstrOfRelation(relation, constr, ndef, attrdef); } static void @@ -549,39 +611,7 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, heap_close(attrel, AccessShareLock); - if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks) - { - relation->rd_att->constr = constr; - - if (ndef > 0) /* DEFAULTs */ - { - if (ndef < relation->rd_rel->relnatts) - constr->defval = (AttrDefault *) - repalloc(attrdef, ndef * sizeof(AttrDefault)); - else - constr->defval = attrdef; - constr->num_defval = ndef; - AttrDefaultFetch(relation); - } - else - constr->num_defval = 0; - - if (relation->rd_rel->relchecks > 0) /* CHECKs */ - { - constr->num_check = relation->rd_rel->relchecks; - constr->check = (ConstrCheck *) palloc(constr->num_check * - sizeof(ConstrCheck)); - MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck)); - RelCheckFetch(relation); - } - else - constr->num_check = 0; - } - else - { - pfree(constr); - relation->rd_att->constr = NULL; - } + SetConstrOfRelation(relation, constr, ndef, attrdef); } @@ -1806,16 +1836,19 @@ AttrDefaultFetch(Relation relation) AttrDefault *attrdef = relation->rd_att->constr->defval; int ndef = relation->rd_att->constr->num_defval; Relation adrel; - Relation irel; + Relation irel = (Relation) NULL; ScanKeyData skey; HeapTupleData tuple; + HeapTuple htup; Form_pg_attrdef adform; - IndexScanDesc sd; + IndexScanDesc sd = (IndexScanDesc) NULL; + HeapScanDesc adscan = (HeapScanDesc) NULL; RetrieveIndexResult indexRes; struct varlena *val; bool isnull; int found; int i; + bool hasindex; ScanKeyEntryInitialize(&skey, (bits16) 0x0, @@ -1824,8 +1857,14 @@ AttrDefaultFetch(Relation relation) ObjectIdGetDatum(RelationGetRelid(relation))); adrel = heap_openr(AttrDefaultRelationName, AccessShareLock); - irel = index_openr(AttrDefaultIndex); - sd = index_beginscan(irel, false, 1, &skey); + hasindex = (adrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes()); + if (hasindex) + { + irel = index_openr(AttrDefaultIndex); + sd = index_beginscan(irel, false, 1, &skey); + } + else + adscan = heap_beginscan(adrel, false, SnapshotNow, 1, &skey); tuple.t_datamcxt = NULL; tuple.t_data = NULL; @@ -1833,17 +1872,27 @@ AttrDefaultFetch(Relation relation) { Buffer buffer; - indexRes = index_getnext(sd, ForwardScanDirection); - if (!indexRes) - break; + if (hasindex) + { + indexRes = index_getnext(sd, ForwardScanDirection); + if (!indexRes) + break; - tuple.t_self = indexRes->heap_iptr; - heap_fetch(adrel, SnapshotNow, &tuple, &buffer); - pfree(indexRes); - if (tuple.t_data == NULL) - continue; + tuple.t_self = indexRes->heap_iptr; + heap_fetch(adrel, SnapshotNow, &tuple, &buffer); + pfree(indexRes); + if (tuple.t_data == NULL) + continue; + htup = &tuple; + } + else + { + htup = heap_getnext(adscan, 0); + if (!HeapTupleIsValid(htup)) + break; + } found++; - adform = (Form_pg_attrdef) GETSTRUCT(&tuple); + adform = (Form_pg_attrdef) GETSTRUCT(htup); for (i = 0; i < ndef; i++) { if (adform->adnum != attrdef[i].adnum) @@ -1853,7 +1902,7 @@ AttrDefaultFetch(Relation relation) NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname), RelationGetRelationName(relation)); - val = (struct varlena *) fastgetattr(&tuple, + val = (struct varlena *) fastgetattr(htup, Anum_pg_attrdef_adbin, adrel->rd_att, &isnull); if (isnull) @@ -1863,7 +1912,8 @@ AttrDefaultFetch(Relation relation) attrdef[i].adbin = textout(val); break; } - ReleaseBuffer(buffer); + if (hasindex) + ReleaseBuffer(buffer); if (i >= ndef) elog(NOTICE, "AttrDefaultFetch: unexpected record found for attr %d in rel %s", @@ -1875,8 +1925,13 @@ AttrDefaultFetch(Relation relation) elog(NOTICE, "AttrDefaultFetch: %d record not found for rel %s", ndef - found, RelationGetRelationName(relation)); - index_endscan(sd); - index_close(irel); + if (hasindex) + { + index_endscan(sd); + index_close(irel); + } + else + heap_endscan(adscan); heap_close(adrel, AccessShareLock); } @@ -1886,15 +1941,18 @@ RelCheckFetch(Relation relation) ConstrCheck *check = relation->rd_att->constr->check; int ncheck = relation->rd_att->constr->num_check; Relation rcrel; - Relation irel; + Relation irel = (Relation)NULL; ScanKeyData skey; HeapTupleData tuple; - IndexScanDesc sd; + HeapTuple htup; + IndexScanDesc sd = (IndexScanDesc)NULL; + HeapScanDesc rcscan = (HeapScanDesc)NULL; RetrieveIndexResult indexRes; Name rcname; struct varlena *val; bool isnull; int found; + bool hasindex; ScanKeyEntryInitialize(&skey, (bits16) 0x0, @@ -1903,8 +1961,14 @@ RelCheckFetch(Relation relation) ObjectIdGetDatum(RelationGetRelid(relation))); rcrel = heap_openr(RelCheckRelationName, AccessShareLock); - irel = index_openr(RelCheckIndex); - sd = index_beginscan(irel, false, 1, &skey); + hasindex = (rcrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes()); + if (hasindex) + { + irel = index_openr(RelCheckIndex); + sd = index_beginscan(irel, false, 1, &skey); + } + else + rcscan = heap_beginscan(rcrel, false, SnapshotNow, 1, &skey); tuple.t_datamcxt = NULL; tuple.t_data = NULL; @@ -1912,27 +1976,37 @@ RelCheckFetch(Relation relation) { Buffer buffer; - indexRes = index_getnext(sd, ForwardScanDirection); - if (!indexRes) - break; + if (hasindex) + { + indexRes = index_getnext(sd, ForwardScanDirection); + if (!indexRes) + break; - tuple.t_self = indexRes->heap_iptr; - heap_fetch(rcrel, SnapshotNow, &tuple, &buffer); - pfree(indexRes); - if (tuple.t_data == NULL) - continue; + tuple.t_self = indexRes->heap_iptr; + heap_fetch(rcrel, SnapshotNow, &tuple, &buffer); + pfree(indexRes); + if (tuple.t_data == NULL) + continue; + htup = &tuple; + } + else + { + htup = heap_getnext(rcscan, 0); + if (!HeapTupleIsValid(htup)) + break; + } if (found == ncheck) elog(ERROR, "RelCheckFetch: unexpected record found for rel %s", RelationGetRelationName(relation)); - rcname = (Name) fastgetattr(&tuple, + rcname = (Name) fastgetattr(htup, Anum_pg_relcheck_rcname, rcrel->rd_att, &isnull); if (isnull) elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s", RelationGetRelationName(relation)); check[found].ccname = pstrdup(NameStr(*rcname)); - val = (struct varlena *) fastgetattr(&tuple, + val = (struct varlena *) fastgetattr(htup, Anum_pg_relcheck_rcbin, rcrel->rd_att, &isnull); if (isnull) @@ -1940,15 +2014,21 @@ RelCheckFetch(Relation relation) RelationGetRelationName(relation)); check[found].ccbin = textout(val); found++; - ReleaseBuffer(buffer); + if (hasindex) + ReleaseBuffer(buffer); } if (found < ncheck) elog(ERROR, "RelCheckFetch: %d record not found for rel %s", ncheck - found, RelationGetRelationName(relation)); - index_endscan(sd); - index_close(irel); + if (hasindex) + { + index_endscan(sd); + index_close(irel); + } + else + heap_endscan(rcscan); heap_close(rcrel, AccessShareLock); } @@ -2148,6 +2228,7 @@ init_irels(void) RelationCacheInsert(ird); } + criticalRelcacheBuild = true; } static void @@ -2162,7 +2243,6 @@ write_irels(void) Form_pg_class relform; IndexStrategy strat; RegProcedure *support; - ProcessingMode oldmode; int i; int relno; RelationBuildDescInfo bi; @@ -2186,8 +2266,13 @@ write_irels(void) * descriptors, nail them into cache so we never lose them. */ + /* Removed the following ProcessingMode change -- inoue + * At this point + * 1) Catalog Cache isn't initialized + * 2) Relation Cache for the following critical indexes aren't built oldmode = GetProcessingMode(); SetProcessingMode(BootstrapProcessing); + */ bi.infotype = INFO_RELNAME; bi.i.info_name = AttributeRelidNumIndex; @@ -2202,7 +2287,10 @@ write_irels(void) irel[2] = RelationBuildDesc(bi, NULL); irel[2]->rd_isnailed = true; + criticalRelcacheBuild = true; + /* Removed the following ProcessingMode -- inoue SetProcessingMode(oldmode); + */ /* * Write out the index reldescs to the special cache file. diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 3cc7519899..087002ab76 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.48 2000/01/26 05:57:18 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.49 2000/02/18 09:28:56 inoue Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -39,6 +39,7 @@ #include "catalog/pg_type.h" #include "utils/catcache.h" #include "utils/temprel.h" +#include "miscadmin.h" extern bool AMI_OVERRIDE; /* XXX style */ @@ -395,6 +396,11 @@ static struct cachedesc cacheinfo[] = { static struct catcache *SysCache[lengthof(cacheinfo)]; static int32 SysCacheSize = lengthof(cacheinfo); +static bool CacheInitialized = false; +extern bool IsCacheInitialized(void) +{ + return CacheInitialized; +} /* @@ -442,6 +448,7 @@ InitCatalogCache() } } + CacheInitialized = true; } /* diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index d5ce83dc6c..41b4020c71 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.43 2000/01/26 05:57:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.44 2000/02/18 09:28:58 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -38,6 +38,33 @@ unsigned char RecodeBackTable[128]; ProcessingMode Mode = InitProcessing; +/* ---------------------------------------------------------------- + * ignoring system indexes support stuff + * ---------------------------------------------------------------- + */ + +static bool isIgnoringSystemIndexes = false; + +/* + * IsIgnoringSystemIndexes + * True if ignoring system indexes. + */ +bool +IsIgnoringSystemIndexes() +{ + return isIgnoringSystemIndexes; +} + +/* + * IgnoreSystemIndexes + * Set true or false whether PostgreSQL ignores system indexes. + * + */ +void +IgnoreSystemIndexes(bool mode) +{ + isIgnoringSystemIndexes = mode; +} /* ---------------------------------------------------------------- * database path / name support stuff diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index b6d90c3a12..b65e2ad98e 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: index.h,v 1.21 2000/01/26 05:57:56 momjian Exp $ + * $Id: index.h,v 1.22 2000/02/18 09:29:19 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -47,7 +47,11 @@ extern void FormIndexDatum(int numberOfAttributes, TupleDesc heapDescriptor, Datum *datum, char *nullv, FuncIndexInfoPtr fInfo); -extern void UpdateStats(Oid relid, long reltuples, bool hasindex); +extern void UpdateStats(Oid relid, long reltuples, bool inplace); +extern bool IndexesAreActive(Oid relid, bool comfirmCommitted); +extern void setRelhasindexInplace(Oid relid, bool hasindex, bool immediate); +extern bool SetReindexProcessing(bool processing); +extern bool IsReindexProcessing(void); extern void FillDummyExprContext(ExprContext *econtext, TupleTableSlot *slot, TupleDesc tupdesc, Buffer buffer); @@ -60,4 +64,8 @@ extern void index_build(Relation heapRelation, Relation indexRelation, extern bool IndexIsUnique(Oid indexId); extern bool IndexIsUniqueNoCache(Oid indexId); +extern bool activate_index(Oid indexId, bool activate); +extern bool reindex_index(Oid indexId, bool force); +extern bool activate_indexes_of_a_table(Oid relid, bool activate); +extern bool reindex_relation(Oid relid, bool force); #endif /* INDEX_H */ diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index f5d69339e7..f0a1e381e1 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: defrem.h,v 1.18 2000/01/26 05:58:00 momjian Exp $ + * $Id: defrem.h,v 1.19 2000/02/18 09:29:49 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,9 @@ extern void ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable); extern void RemoveIndex(char *name); +extern void ReindexIndex(const char *indexRelationName, bool force); +extern void ReindexTable(const char *relationName, bool force); +extern void ReindexDatabase(const char *databaseName, bool force, bool all); /* * prototypes in define.c diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 7e47b3a360..df3de38611 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: miscadmin.h,v 1.50 2000/01/26 05:57:46 momjian Exp $ + * $Id: miscadmin.h,v 1.51 2000/02/18 09:29:06 inoue Exp $ * * NOTES * some of the information in this file will be moved to @@ -211,6 +211,9 @@ extern ProcessingMode Mode; #define GetProcessingMode() Mode +extern void IgnoreSystemIndexes(bool mode); +extern bool IsIgnoringSystemIndexes(void); +extern bool IsCacheInitialized(void); /* * "postmaster.pid" is a file containing postmaster's pid, being diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 161b53c25a..8dd893e3f1 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nodes.h,v 1.64 2000/02/15 20:49:24 tgl Exp $ + * $Id: nodes.h,v 1.65 2000/02/18 09:29:43 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -146,7 +146,7 @@ typedef enum NodeTag T_DeleteStmt, T_UpdateStmt, T_SelectStmt, - T_AlterTableStmt, + T_AlterTableStmt, T_AggregateStmt, T_ChangeACLStmt, T_ClosePortalStmt, @@ -191,9 +191,10 @@ typedef enum NodeTag T_DropUserStmt, T_LockStmt, T_ConstraintsSetStmt, - T_CreateGroupStmt, - T_AlterGroupStmt, - T_DropGroupStmt, + T_CreateGroupStmt, + T_AlterGroupStmt, + T_DropGroupStmt, + T_ReindexStmt, T_A_Expr = 700, T_Attr, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index df7bec10f0..d98398aade 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.99 2000/02/15 20:49:24 tgl Exp $ + * $Id: parsenodes.h,v 1.100 2000/02/18 09:29:44 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -722,6 +722,19 @@ typedef struct ConstraintsSetStmt bool deferred; } ConstraintsSetStmt; +/* ---------------------- + * REINDEX Statement + * ---------------------- + */ +typedef struct ReindexStmt +{ + NodeTag type; + int reindexType; /* INDEX|TABLE|DATABASE */ + const char *name; /* name to reindex */ + bool force; + bool all; +} ReindexStmt; + /***************************************************************************** * Optimizable Statements diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index 73a53b2a41..d24fd16f1a 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: portal.h,v 1.21 2000/01/26 05:58:38 momjian Exp $ + * $Id: portal.h,v 1.22 2000/02/18 09:30:16 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -80,6 +80,10 @@ extern void EndPortalAllocMode(void); extern void PortalResetHeapMemory(Portal portal); extern PortalVariableMemory PortalGetVariableMemory(Portal portal); extern PortalHeapMemory PortalGetHeapMemory(Portal portal); +extern void CommonSpecialPortalOpen(void); +extern void CommonSpecialPortalClose(void); +extern PortalVariableMemory CommonSpecialPortalGetMemory(void); +extern bool CommonSpecialPortalIsOpen(void); /* estimate of the maximum number of open portals a user would have, * used in initially sizing the PortalHashTable in EnablePortalManager()