/* * Open pg_largeobject and its index, if not already done in current xact */ static void open_lo_relation(void) { ResourceOwner currentOwner; if (lo_heap_r && lo_index_r) return; /* already open in current xact */ /* Arrange for the top xact to own these relation references */ currentOwner = CurrentResourceOwner; PG_TRY(); { CurrentResourceOwner = TopTransactionResourceOwner; /* Use RowExclusiveLock since we might either read or write */ if (lo_heap_r == NULL) lo_heap_r = heap_openr(LargeObjectRelationName, RowExclusiveLock); if (lo_index_r == NULL) lo_index_r = index_openr(LargeObjectLOidPNIndex); } PG_CATCH(); { /* Ensure CurrentResourceOwner is restored on error */ CurrentResourceOwner = currentOwner; PG_RE_THROW(); } PG_END_TRY(); CurrentResourceOwner = currentOwner; }
/* * systable_beginscan --- set up for heap-or-index scan * * rel: catalog to scan, already opened and suitably locked * indexRelname: name of index to conditionally use * indexOK: if false, forces a heap scan (see notes below) * snapshot: time qual to use (usually should be SnapshotNow) * nkeys, key: scan keys * * The attribute numbers in the scan key should be set for the heap case. * If we choose to index, we reset them to 1..n to reference the index * columns. Note this means there must be one scankey qualification per * index column! This is checked by the Asserts in the normal, index-using * case, but won't be checked if the heapscan path is taken. * * The routine checks the normal cases for whether an indexscan is safe, * but caller can make additional checks and pass indexOK=false if needed. * In standard case indexOK can simply be constant TRUE. */ SysScanDesc systable_beginscan(Relation heapRelation, const char *indexRelname, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key) { SysScanDesc sysscan; Relation irel; if (indexOK && !IsIgnoringSystemIndexes()) { /* We assume it's a system index, so index_openr is OK */ irel = index_openr(indexRelname); if (ReindexIsProcessingIndex(RelationGetRelid(irel))) { /* oops, can't use index that's being rebuilt */ index_close(irel); irel = NULL; } } else irel = NULL; sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData)); sysscan->heap_rel = heapRelation; sysscan->irel = irel; if (irel) { int i; /* * Change attribute numbers to be index column numbers. * * This code could be generalized to search for the index key numbers * to substitute, but for now there's no need. */ for (i = 0; i < nkeys; i++) { Assert(key[i].sk_attno == irel->rd_index->indkey[i]); key[i].sk_attno = i + 1; } sysscan->iscan = index_beginscan(heapRelation, irel, snapshot, nkeys, key); sysscan->scan = NULL; } else { sysscan->scan = heap_beginscan(heapRelation, snapshot, nkeys, key); sysscan->iscan = NULL; } return sysscan; }
/* * InitCatCachePhase2 -- external interface for CatalogCacheInitializeCache * * The only reason to call this routine is to ensure that the relcache * has created entries for all the catalogs and indexes referenced by * catcaches. Therefore, open the index too. An exception is the indexes * on pg_am, which we don't use (cf. IndexScanOK). */ void InitCatCachePhase2(CatCache *cache) { if (cache->cc_tupdesc == NULL) CatalogCacheInitializeCache(cache); if (cache->id != AMOID && cache->id != AMNAME) { Relation idesc; idesc = index_openr(cache->cc_indname); index_close(idesc); } }
/* * cluster * * Check that the relation is a relation in the appropriate user * ACL. I will use the same security that limits users on the * renamerel() function. * * Check that the index specified is appropriate for the task * ( ie it's an index over this relation ). This is trickier. * * Create a list of all the other indicies on this relation. Because * the cluster will wreck all the tids, I'll need to destroy bogus * indicies. The user will have to re-create them. Not nice, but * I'm not a nice guy. The alternative is to try some kind of post * destroy re-build. This may be possible. I'll check out what the * index create functiond want in the way of paramaters. On the other * hand, re-creating n indicies may blow out the space. * * Create new (temporary) relations for the base heap and the new * index. * * Exclusively lock the relations. * * Create new clustered index and base heap relation. * */ void cluster(char oldrelname[], char oldindexname[]) { Oid OIDOldHeap, OIDOldIndex, OIDNewHeap; Relation OldHeap, OldIndex; Relation NewHeap; char *NewIndexName; char *szNewHeapName; /* * * I'm going to force all checking back into the commands.c function. * * Get the list if indicies for this relation. If the index we want * is among them, do not add it to the 'kill' list, as it will be * handled by the 'clean up' code which commits this transaction. * * I'm not using the SysCache, because this will happen but * once, and the slow way is the sure way in this case. * */ /* * Like vacuum, cluster spans transactions, so I'm going to handle it in * the same way. */ /* matches the StartTransaction in PostgresMain() */ OldHeap = heap_openr(oldrelname); if (!RelationIsValid(OldHeap)) { elog(WARN, "cluster: unknown relation: \"%-.*s\"", NAMEDATALEN, oldrelname); } OIDOldHeap = OldHeap->rd_id; /* Get OID for the index scan */ OldIndex=index_openr(oldindexname);/* Open old index relation */ if (!RelationIsValid(OldIndex)) { elog(WARN, "cluster: unknown index: \"%-.*s\"", NAMEDATALEN, oldindexname); } OIDOldIndex = OldIndex->rd_id; /* OID for the index scan */ heap_close(OldHeap); index_close(OldIndex); /* * I need to build the copies of the heap and the index. The Commit() * between here is *very* bogus. If someone is appending stuff, they will * get the lock after being blocked and add rows which won't be present in * the new table. Bleagh! I'd be best to try and ensure that no-one's * in the tables for the entire duration of this process with a pg_vlock. */ NewHeap = copy_heap(OIDOldHeap); OIDNewHeap = NewHeap->rd_id; szNewHeapName = pstrdup(NewHeap->rd_rel->relname.data); /* Need to do this to make the new heap visible. */ CommandCounterIncrement(); rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex); /* Need to do this to make the new heap visible. */ CommandCounterIncrement(); /* can't be found in the SysCache. */ copy_index(OIDOldIndex, OIDNewHeap); /* No contention with the old */ /* * make this really happen. Flush all the buffers. */ CommitTransactionCommand(); StartTransactionCommand(); /* * Questionable bit here. Because the renamerel destroys all trace of the * pre-existing relation, I'm going to Destroy old, and then rename new * to old. If this fails, it fails, and you lose your old. Tough - say * I. Have good backups! */ /* Here lies the bogosity. The RelationNameGetRelation returns a bad list of TupleDescriptors. Damn. Can't work out why this is. */ heap_destroy(oldrelname); /* AAAAAAAAGH!! */ CommandCounterIncrement(); /* * The Commit flushes all palloced memory, so I have to grab the * New stuff again. This is annoying, but oh heck! */ /* renamerel(szNewHeapName.data, oldrelname); TypeRename(&szNewHeapName, &szOldRelName); sprintf(NewIndexName.data, "temp_%x", OIDOldIndex); renamerel(NewIndexName.data, szOldIndexName.data); */ NewIndexName = palloc(NAMEDATALEN+1); /* XXX */ sprintf(NewIndexName, "temp_%x", OIDOldIndex); renamerel(NewIndexName, oldindexname); }