📄 index.c
字号:
* * If we found zero tuples in the scan, do NOT believe it; instead put * a bogus estimate into the statistics fields. Otherwise, the common * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table * with zero size statistics until a VACUUM is done. The optimizer will * generate very bad plans if the stats claim the table is empty when * it is actually sizable. See also CREATE TABLE in heap.c. * ---------------- */ relpages = RelationGetNumberOfBlocks(whichRel); if (reltuples == 0) { if (relpages == 0) { /* Bogus defaults for a virgin table, same as heap.c */ reltuples = 1000; relpages = 10; } else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2) { /* Empty index, leave bogus defaults in place */ reltuples = 1000; } else reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts); } /* * 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; whichRel->rd_rel->relpages = relpages; whichRel->rd_rel->reltuples = reltuples; /* ---------------- * Update statistics in pg_class. * ---------------- */ if (IsBootstrapProcessingMode()) { /* * At bootstrap time, we don't need to worry about concurrency or * visibility of changes, so we cheat. */ rd_rel = (Form_pg_class) GETSTRUCT(tuple); rd_rel->relpages = relpages; rd_rel->reltuples = reltuples; rd_rel->relhasindex = hasindex; WriteBuffer(pg_class_scan->rs_cbuf); } else { /* During normal processing, must work harder. */ for (i = 0; i < Natts_pg_class; i++) { nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' '; replace[i] = ' '; values[i] = (Datum) NULL; } replace[Anum_pg_class_relpages - 1] = 'r'; 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_replace(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); pfree(newtup); } if (!IsBootstrapProcessingMode()) pfree(tuple); else heap_endscan(pg_class_scan); heap_close(pg_class); heap_close(whichRel);}/* ------------------------- * FillDummyExprContext * Sets up dummy ExprContext and TupleTableSlot objects for use * with ExecQual. * ------------------------- */voidFillDummyExprContext(ExprContext *econtext, TupleTableSlot *slot, TupleDesc tupdesc, Buffer buffer){ econtext->ecxt_scantuple = slot; econtext->ecxt_innertuple = NULL; econtext->ecxt_outertuple = NULL; econtext->ecxt_param_list_info = NULL; econtext->ecxt_range_table = NULL; slot->ttc_tupleDescriptor = tupdesc; slot->ttc_buffer = buffer; slot->ttc_shouldFree = false;}/* ---------------- * DefaultBuild * ---------------- */static voidDefaultBuild(Relation heapRelation, Relation indexRelation, int numberOfAttributes, AttrNumber *attributeNumber, IndexStrategy indexStrategy, /* not used */ uint16 parameterCount, /* not used */ Datum *parameter, /* not used */ FuncIndexInfoPtr funcInfo, PredInfo *predInfo){ HeapScanDesc scan; HeapTuple heapTuple; IndexTuple indexTuple; TupleDesc heapDescriptor; TupleDesc indexDescriptor; Datum *datum; char *nullv; long reltuples, indtuples;#ifndef OMIT_PARTIAL_INDEX ExprContext *econtext; TupleTable tupleTable; TupleTableSlot *slot;#endif Node *predicate; Node *oldPred; InsertIndexResult insertResult; /* ---------------- * more & better checking is needed * ---------------- */ Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */ /* ---------------- * get the tuple descriptors from the relations so we know * how to form the index tuples.. * ---------------- */ heapDescriptor = RelationGetDescr(heapRelation); indexDescriptor = RelationGetDescr(indexRelation); /* ---------------- * datum and null are arrays in which we collect the index attributes * when forming a new index tuple. * ---------------- */ datum = (Datum *) palloc(numberOfAttributes * sizeof *datum); nullv = (char *) palloc(numberOfAttributes * sizeof *nullv); /* * If this is a predicate (partial) index, we will need to evaluate * the predicate using ExecQual, which requires the current tuple to * be in a slot of a TupleTable. In addition, ExecQual must have an * ExprContext referring to that slot. Here, we initialize dummy * TupleTable and ExprContext objects for this purpose. --Nels, Feb * '92 */ predicate = predInfo->pred; oldPred = predInfo->oldPred;#ifndef OMIT_PARTIAL_INDEX if (predicate != NULL || oldPred != NULL) { tupleTable = ExecCreateTupleTable(1); slot = ExecAllocTableSlot(tupleTable); econtext = makeNode(ExprContext); /* last parameter was junk being sent bjm 1998/08/17 */ FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer); } else { econtext = NULL; tupleTable = 0; slot = NULL; }#endif /* OMIT_PARTIAL_INDEX */ /* ---------------- * Ok, begin our scan of the base relation. * ---------------- */ scan = heap_beginscan(heapRelation, /* relation */ 0, /* start at end */ SnapshotNow, /* seeself */ 0, /* number of keys */ (ScanKey) NULL); /* scan key */ reltuples = indtuples = 0; /* ---------------- * for each tuple in the base relation, we create an index * tuple and add it to the index relation. We keep a running * count of the number of tuples so that we can update pg_class * with correct statistics when we're done building the index. * ---------------- */ while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0))) { reltuples++;#ifndef OMIT_PARTIAL_INDEX /* * If oldPred != NULL, this is an EXTEND INDEX command, so skip * this tuple if it was already in the existing partial index */ if (oldPred != NULL) { /* SetSlotContents(slot, heapTuple); */ slot->val = heapTuple; if (ExecQual((List *) oldPred, econtext) == true) { indtuples++; continue; } } /* * Skip this tuple if it doesn't satisfy the partial-index * predicate */ if (predicate != NULL) { /* SetSlotContents(slot, heapTuple); */ slot->val = heapTuple; if (ExecQual((List *) predicate, econtext) == false) continue; }#endif /* OMIT_PARTIAL_INDEX */ indtuples++; /* ---------------- * FormIndexDatum fills in its datum and null parameters * with attribute information taken from the given heap tuple. * ---------------- */ FormIndexDatum(numberOfAttributes, /* num attributes */ attributeNumber, /* array of att nums to extract */ heapTuple, /* tuple from base relation */ heapDescriptor, /* heap tuple's descriptor */ datum, /* return: array of attributes */ nullv, /* return: array of char's */ funcInfo); indexTuple = index_formtuple(indexDescriptor, datum, nullv); indexTuple->t_tid = heapTuple->t_self; insertResult = index_insert(indexRelation, datum, nullv, &(heapTuple->t_self), heapRelation); if (insertResult) pfree(insertResult); pfree(indexTuple); } heap_endscan(scan);#ifndef OMIT_PARTIAL_INDEX if (predicate != NULL || oldPred != NULL) { ExecDestroyTupleTable(tupleTable, false); }#endif /* OMIT_PARTIAL_INDEX */ pfree(nullv); pfree(datum); /* * Okay, now update the reltuples and relpages statistics for both the * heap relation and the index. These statistics are used by the * planner to choose a scan type. They are maintained generally by * the vacuum daemon, but we update them here to make the index useful * as soon as possible. */ UpdateStats(RelationGetRelid(heapRelation), reltuples, true); UpdateStats(RelationGetRelid(indexRelation), indtuples, false); if (oldPred != NULL) { if (indtuples == reltuples) predicate = NULL; UpdateIndexPredicate(RelationGetRelid(indexRelation), oldPred, predicate); }}/* ---------------- * index_build * ---------------- */voidindex_build(Relation heapRelation, Relation indexRelation, int numberOfAttributes, AttrNumber *attributeNumber, uint16 parameterCount, Datum *parameter, FuncIndexInfo *funcInfo, PredInfo *predInfo){ RegProcedure procedure; /* ---------------- * sanity checks * ---------------- */ Assert(RelationIsValid(indexRelation)); Assert(PointerIsValid(indexRelation->rd_am)); procedure = indexRelation->rd_am->ambuild; /* ---------------- * use the access method build procedure if supplied.. * ---------------- */ if (RegProcedureIsValid(procedure)) fmgr(procedure, heapRelation, indexRelation, numberOfAttributes, attributeNumber, RelationGetIndexStrategy(indexRelation), parameterCount, parameter, funcInfo, predInfo); else DefaultBuild(heapRelation, indexRelation, numberOfAttributes, attributeNumber, RelationGetIndexStrategy(indexRelation), parameterCount, parameter, funcInfo, predInfo);}/* * IndexIsUnique: given an index's relation OID, see if it * is unique using the system cache. */boolIndexIsUnique(Oid indexId){ HeapTuple tuple; Form_pg_index index; tuple = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(indexId), 0, 0, 0); if (!HeapTupleIsValid(tuple)) { elog(ERROR, "IndexIsUnique: can't find index id %u", indexId); } index = (Form_pg_index) GETSTRUCT(tuple); Assert(index->indexrelid == indexId); return index->indisunique;}/* * IndexIsUniqueNoCache: same as above function, but don't use the * system cache. if we are called from btbuild, the transaction * that is adding the entry to pg_index has not been committed yet. * the system cache functions will do a heap scan, but only with * NowTimeQual, not SelfTimeQual, so it won't find tuples added * by the current transaction (which is good, because if the transaction * is aborted, you don't want the tuples sitting around in the cache). * so anyway, we have to do our own scan with SelfTimeQual. * this is only called when a new index is created, so it's OK * if it's slow. */boolIndexIsUniqueNoCache(Oid indexId){ Relation pg_index; ScanKeyData skey[1]; HeapScanDesc scandesc; HeapTuple tuple; Form_pg_index index; bool isunique; pg_index = heap_openr(IndexRelationName); ScanKeyEntryInitialize(&skey[0], (bits16) 0x0, Anum_pg_index_indexrelid, (RegProcedure) F_OIDEQ, ObjectIdGetDatum(indexId)); scandesc = heap_beginscan(pg_index, 0, SnapshotSelf, 1, skey); /* NO CACHE */ tuple = heap_getnext(scandesc, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "IndexIsUniqueNoCache: can't find index id %u", indexId); index = (Form_pg_index) GETSTRUCT(tuple); Assert(index->indexrelid == indexId); isunique = index->indisunique; heap_endscan(scandesc); heap_close(pg_index); return isunique;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -