/* *ChooseanOIDtouseasthevalueIDforthistoastvalue. * *NormallywejustchooseanunusedOIDwithinthetoasttable.But *duringtable-rewritingoperationswherewearepreservinganexisting *toasttableOID,wewanttopreservetoastvalueOIDstoo.So,if *rd_toastoidissetandwehadapriorexternalvaluefromthatsame *toasttable,re-useitsvalueID.Ifwedidn'thaveapriorexternal *value(whichisacornercase,butpossibleifthetable'sattstorage *optionshavebeenchanged),wehavetopickavalueIDthatdoesn't *conflictwitheitherneworexistingtoastvalueOIDs.
*/ if (!OidIsValid(rel->rd_toastoid))
{ /* normal case: just choose an unused OID */
toast_pointer.va_valueid =
GetNewOidWithIndex(toastrel,
RelationGetRelid(toastidxs[validIndex]),
(AttrNumber) 1);
} else
{ /* rewrite case: check to see if value was in old toast table */
toast_pointer.va_valueid = InvalidOid; if (oldexternal != NULL)
{ struct varatt_external old_toast_pointer;
Assert(VARATT_IS_EXTERNAL_ONDISK(oldexternal)); /* Must copy to access aligned fields */
VARATT_EXTERNAL_GET_POINTER(old_toast_pointer, oldexternal); if (old_toast_pointer.va_toastrelid == rel->rd_toastoid)
{ /* This value came from the old toast table; reuse its OID */
toast_pointer.va_valueid = old_toast_pointer.va_valueid;
/* *Thereisacornercasehere:thetablerewritemighthave *tocopybothliveandrecently-deadversionsofarow,and *thoseversionscouldeasilyreferencethesametoastvalue. *Whenwecopythesecondorlaterversionofsucharow, *reusingtheOIDwillmeanweselectanOIDthat'salready *inthenewtoasttable.Checkforthat,andifso,just *fallthroughwithoutwritingthedataagain. * *Whileannoyingandugly-looking,thisisagoodthing *becauseitensuresthatwewindupwithonlyonecopyof *thetoastvaluewhenthereisonlyonecopyintheold *toasttable.Beforewedetectedthiscase,we'dhavemade *multiplecopies,wastingspace;andwhat'sworse,the *copiesbelongingtoalready-deletedheaptupleswouldnot *bereclaimedbyVACUUM.
*/ if (toastrel_valueid_exists(toastrel,
toast_pointer.va_valueid))
{ /* Match, so short-circuit the data storage loop below */
data_todo = 0;
}
}
} if (toast_pointer.va_valueid == InvalidOid)
{ /* *newvalue;mustchooseanOIDthatdoesn'tconflictineither *oldornewtoasttable
*/ do
{
toast_pointer.va_valueid =
GetNewOidWithIndex(toastrel,
RelationGetRelid(toastidxs[validIndex]),
(AttrNumber) 1);
} while (toastid_valueid_exists(rel->rd_toastoid,
toast_pointer.va_valueid));
}
}
result = toastrel_valueid_exists(toastrel, valueid);
table_close(toastrel, AccessShareLock);
return result;
}
/* ---------- *toast_get_valid_index * *GetOIDofvalidindexassociatedtogiventoastrelation.Atoast *relationcanhaveonlyonevalidindexatthesametime.
*/
Oid
toast_get_valid_index(Oid toastoid, LOCKMODE lock)
{ int num_indexes; int validIndex;
Oid validIndexOid;
Relation *toastidxs;
Relation toastrel;
/* Open the toast relation */
toastrel = table_open(toastoid, lock);
/* Look for the valid index of the toast relation */
validIndex = toast_open_indexes(toastrel,
lock,
&toastidxs,
&num_indexes);
validIndexOid = RelationGetRelid(toastidxs[validIndex]);
/* Close the toast relation and all its indexes */
toast_close_indexes(toastidxs, num_indexes, NoLock);
table_close(toastrel, NoLock);
return validIndexOid;
}
/* ---------- *toast_open_indexes * *Getanarrayoftheindexesassociatedtothegiventoastrelation *andreturnaswellthepositionofthevalidindexusedbythetoast *relationinthisarray.Itistheresponsibilityofthecallerofthis *functiontoclosetheindexesaswellasfreethem.
*/ int
toast_open_indexes(Relation toastrel,
LOCKMODE lock,
Relation **toastidxs, int *num_indexes)
{ int i = 0; int res = 0; bool found = false;
List *indexlist;
ListCell *lc;
/* Get index list of the toast relation */
indexlist = RelationGetIndexList(toastrel);
Assert(indexlist != NIL);
*num_indexes = list_length(indexlist);
/* Open all the index relations */
*toastidxs = (Relation *) palloc(*num_indexes * sizeof(Relation));
foreach(lc, indexlist)
(*toastidxs)[i++] = index_open(lfirst_oid(lc), lock);
/* Fetch the first valid index in list */ for (i = 0; i < *num_indexes; i++)
{
Relation toastidx = (*toastidxs)[i];
if (toastidx->rd_index->indisvalid)
{
res = i;
found = true; break;
}
}
/* *Thetoastrelationshouldhaveonevalidindex,sosomethingisgoing *wrongifthereisnothing.
*/ if (!found)
elog(ERROR, "no valid index found for toast relation with Oid %u",
RelationGetRelid(toastrel));
return res;
}
/* ---------- *toast_close_indexes * *Closeanarrayofindexesforatoastrelationandfreeit.Thisshould *becalledforasetofindexesopenedpreviouslywithtoast_open_indexes.
*/ void
toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
{ int i;
/* Close relations and clean up things */ for (i = 0; i < num_indexes; i++)
index_close(toastidxs[i], lock);
pfree(toastidxs);
}
/* ---------- *get_toast_snapshot * *ReturntheTOASTsnapshot.Detoasting*must*happeninthesame *transactionthatoriginallyfetchedthetoastpointer.
*/
Snapshot
get_toast_snapshot(void)
{ /* *Wecannotdirectlycheckthatdetoastinghappensinthesame *transactionthatoriginallyfetchedthetoastpointer,butatleast *checkthatthesessionhassomeactivesnapshots.Itmightnotif,for *example,aprocedurefetchesatoastedvalueintoalocalvariable, *commits,andthentriestodetoastthevalue.Suchcodingisunsafe, *becauseoncewecommitthereisnothingtopreventthetoastdatafrom *beingdeleted.(Thisisnotverymuchprotection,becauseinmany *scenariostheprocedurewouldhavealreadycreatedanewtransaction *snapshot,preventingusfromdetectingtheproblem.Butit'sbetter *thannothing.)
*/ if (!HaveRegisteredOrActiveSnapshot())
elog(ERROR, "cannot fetch toast data without an active snapshot");
return &SnapshotToastData;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.