本文整理汇总了C++中HeapTupleHeaderGetXmin函数的典型用法代码示例。如果您正苦于以下问题:C++ HeapTupleHeaderGetXmin函数的具体用法?C++ HeapTupleHeaderGetXmin怎么用?C++ HeapTupleHeaderGetXmin使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了HeapTupleHeaderGetXmin函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: PLy_procedure_valid
/*
* Decide whether a cached PLyProcedure struct is still valid
*/
static bool
PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
{
int i;
bool valid;
Assert(proc != NULL);
/* If the pg_proc tuple has changed, it's not valid */
if (!(proc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
return false;
/* Else check the input argument datatypes */
valid = true;
for (i = 0; i < proc->nargs; i++)
{
valid = PLy_procedure_argument_valid(&proc->args[i]);
/* Short-circuit on first changed argument */
if (!valid)
break;
}
/* if the output type is composite, it might have changed */
if (valid)
valid = PLy_procedure_argument_valid(&proc->result);
return valid;
}
示例2: PLy_procedure_argument_valid
/*
* Check if our cached information about a datatype is still valid
*/
static bool
PLy_procedure_argument_valid(PLyTypeInfo *arg)
{
HeapTuple relTup;
bool valid;
/* Nothing to cache unless type is composite */
if (arg->is_rowtype != 1)
return true;
/*
* Zero typ_relid means that we got called on an output argument of a
* function returning a unnamed record type; the info for it can't change.
*/
if (!OidIsValid(arg->typ_relid))
return true;
/* Else we should have some cached data */
Assert(TransactionIdIsValid(arg->typrel_xmin));
Assert(ItemPointerIsValid(&arg->typrel_tid));
/* Get the pg_class tuple for the data type */
relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
if (!HeapTupleIsValid(relTup))
elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
/* If it has changed, the cached data is not valid */
valid = (arg->typrel_xmin == HeapTupleHeaderGetXmin(relTup->t_data) &&
ItemPointerEquals(&arg->typrel_tid, &relTup->t_self));
ReleaseSysCache(relTup);
return valid;
}
示例3: XLogIsValidTuple
/*
* MUST BE CALLED ONLY ON RECOVERY.
*
* Check if exists valid (inserted by not aborted xaction) heap tuple
* for given item pointer
*/
bool
XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr)
{
Relation reln;
Buffer buffer;
Page page;
ItemId lp;
HeapTupleHeader htup;
reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
if (!RelationIsValid(reln))
return (false);
buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
if (!BufferIsValid(buffer))
return (false);
LockBuffer(buffer, BUFFER_LOCK_SHARE);
page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page) ||
ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
{
UnlockAndReleaseBuffer(buffer);
return (false);
}
if (PageGetSUI(page) != ThisStartUpID)
{
Assert(PageGetSUI(page) < ThisStartUpID);
UnlockAndReleaseBuffer(buffer);
return (true);
}
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
{
UnlockAndReleaseBuffer(buffer);
return (false);
}
htup = (HeapTupleHeader) PageGetItem(page, lp);
/* MUST CHECK WASN'T TUPLE INSERTED IN PREV STARTUP */
if (!(htup->t_infomask & HEAP_XMIN_COMMITTED))
{
if (htup->t_infomask & HEAP_XMIN_INVALID ||
(htup->t_infomask & HEAP_MOVED_IN &&
TransactionIdDidAbort(HeapTupleHeaderGetXvac(htup))) ||
TransactionIdDidAbort(HeapTupleHeaderGetXmin(htup)))
{
UnlockAndReleaseBuffer(buffer);
return (false);
}
}
UnlockAndReleaseBuffer(buffer);
return (true);
}
示例4: CrossCheckTuple
/*
* This function performs checks for certain system tables to validate tuple
* fetched from table has the key, using which it was fetched from index.
*/
static void
CrossCheckTuple(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4,
HeapTuple tuple)
{
Form_pg_class rd_rel;
switch (cacheId)
{
case RELOID:
if (HeapTupleGetOid(tuple) != DatumGetObjectId(key1))
{
elog(ERROR, "pg_class_oid_index is broken, oid=%d is pointing to tuple with oid=%d (xmin:%u xmax:%u)",
DatumGetObjectId(key1), HeapTupleGetOid(tuple),
HeapTupleHeaderGetXmin((tuple)->t_data),
HeapTupleHeaderGetXmax((tuple)->t_data));
}
break;
case RELNAMENSP:
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
if (strncmp(rd_rel->relname.data, DatumGetCString(key1), NAMEDATALEN) != 0)
{
elog(ERROR, "pg_class_relname_nsp_index is broken, intended tuple with name \"%s\" fetched \"%s\""
" (xmin:%u xmax:%u)",
DatumGetCString(key1), rd_rel->relname.data,
HeapTupleHeaderGetXmin((tuple)->t_data),
HeapTupleHeaderGetXmax((tuple)->t_data));
}
break;
case TYPEOID:
if (HeapTupleGetOid(tuple) != DatumGetObjectId(key1))
{
elog(ERROR, "pg_type_oid_index is broken, oid=%d is pointing to tuple with oid=%d (xmin:%u xmax:%u)",
DatumGetObjectId(key1), HeapTupleGetOid(tuple),
HeapTupleHeaderGetXmin((tuple)->t_data),
HeapTupleHeaderGetXmax((tuple)->t_data));
}
break;
}
}
示例5: heap_getsysattr
/* ----------------
* heap_getsysattr
*
* Fetch the value of a system attribute for a tuple.
*
* This is a support routine for the heap_getattr macro. The macro
* has already determined that the attnum refers to a system attribute.
* ----------------
*/
Datum
heap_getsysattr(HeapTuple tup, int attnum, bool *isnull)
{
Datum result;
Assert(tup);
Assert(!is_heaptuple_memtuple(tup));
/* Currently, no sys attribute ever reads as NULL. */
if (isnull)
*isnull = false;
switch (attnum)
{
case SelfItemPointerAttributeNumber:
/* pass-by-reference datatype */
result = PointerGetDatum(&(tup->t_self));
break;
case ObjectIdAttributeNumber:
result = ObjectIdGetDatum(HeapTupleGetOid(tup));
break;
case MinTransactionIdAttributeNumber:
result = TransactionIdGetDatum(HeapTupleHeaderGetXmin(tup->t_data));
break;
case MaxTransactionIdAttributeNumber:
result = TransactionIdGetDatum(HeapTupleHeaderGetXmax(tup->t_data));
break;
case MinCommandIdAttributeNumber:
case MaxCommandIdAttributeNumber:
/*
* cmin and cmax are now both aliases for the same field, which
* can in fact also be a combo command id. XXX perhaps we should
* return the "real" cmin or cmax if possible, that is if we are
* inside the originating transaction?
*/
result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
break;
case TableOidAttributeNumber:
/* CDB: Must now use a TupleTableSlot to access the 'tableoid'. */
result = ObjectIdGetDatum(InvalidOid);
elog(ERROR, "Invalid reference to \"tableoid\" system attribute");
break;
case GpSegmentIdAttributeNumber: /*CDB*/
result = Int32GetDatum(Gp_segment);
break;
default:
elog(ERROR, "invalid attnum: %d", attnum);
result = 0; /* keep compiler quiet */
break;
}
return result;
}
示例6: HeapTupleHeaderGetCmin
CommandId
HeapTupleHeaderGetCmin(HeapTupleHeader tup)
{
CommandId cid = HeapTupleHeaderGetRawCommandId(tup);
Assert(!(tup->t_infomask & HEAP_MOVED));
if (tup->t_infomask & HEAP_COMBOCID)
return GetRealCmin(HeapTupleHeaderGetXmin(tup), cid);
else
return cid;
}
示例7: HeapTupleHeaderAdjustCmax
/*
* Given a tuple we are about to delete, determine the correct value to store
* into its t_cid field.
*
* If we don't need a combo CID, *cmax is unchanged and *iscombo is set to
* FALSE. If we do need one, *cmax is replaced by a combo CID and *iscombo
* is set to TRUE.
*
* The reason this is separate from the actual HeapTupleHeaderSetCmax()
* operation is that this could fail due to out-of-memory conditions. Hence
* we need to do this before entering the critical section that actually
* changes the tuple in shared buffers.
*/
void
HeapTupleHeaderAdjustCmax(HeapTupleHeader tup,
CommandId *cmax,
bool *iscombo)
{
/*
* If we're marking a tuple deleted that was inserted by (any
* subtransaction of) our transaction, we need to use a combo command id.
* Test for HEAP_XMIN_COMMITTED first, because it's cheaper than a
* TransactionIdIsCurrentTransactionId call.
*/
if (!(tup->t_infomask & HEAP_XMIN_COMMITTED) &&
TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tup)))
{
CommandId cmin = HeapTupleHeaderGetRawCommandId(tup);
*cmax = GetComboCommandId(HeapTupleHeaderGetXmin(tup), cmin, *cmax);
*iscombo = true;
}
else
{
*iscombo = false;
}
}
示例8: XLogIsOwnerOfTuple
/*
* Check if specified heap tuple was inserted by given
* xaction/command and return
*
* - -1 if not
* - 0 if there is no tuple at all
* - 1 if yes
*/
int
XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
TransactionId xid, CommandId cid)
{
Relation reln;
Buffer buffer;
Page page;
ItemId lp;
HeapTupleHeader htup;
reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
if (!RelationIsValid(reln))
return (0);
buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
if (!BufferIsValid(buffer))
return (0);
LockBuffer(buffer, BUFFER_LOCK_SHARE);
page = (Page) BufferGetPage(buffer);
if (PageIsNew((PageHeader) page) ||
ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
{
UnlockAndReleaseBuffer(buffer);
return (0);
}
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
{
UnlockAndReleaseBuffer(buffer);
return (0);
}
htup = (HeapTupleHeader) PageGetItem(page, lp);
Assert(PageGetSUI(page) == ThisStartUpID);
if (!TransactionIdEquals(HeapTupleHeaderGetXmin(htup), xid) ||
HeapTupleHeaderGetCmin(htup) != cid)
{
UnlockAndReleaseBuffer(buffer);
return (-1);
}
UnlockAndReleaseBuffer(buffer);
return (1);
}
示例9: HeapTupleHeaderGetCmax
CommandId
HeapTupleHeaderGetCmax(HeapTupleHeader tup)
{
CommandId cid = HeapTupleHeaderGetRawCommandId(tup);
/* We do not store cmax when locking a tuple */
Assert(!(tup->t_infomask & (HEAP_MOVED | HEAP_IS_LOCKED)));
/*
* MPP-8317: cursors can't always *tell* that this is the current transaction.
*/
Assert(QEDtxContextInfo.cursorContext || TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tup)));
if (tup->t_infomask & HEAP_COMBOCID)
return GetRealCmax(HeapTupleHeaderGetXmin(tup), cid);
else
return cid;
}
示例10: rewrite_heap_dead_tuple
/*
* Register a dead tuple with an ongoing rewrite. Dead tuples are not
* copied to the new table, but we still make note of them so that we
* can release some resources earlier.
*
* Returns true if a tuple was removed from the unresolved_tups table.
* This indicates that that tuple, previously thought to be "recently dead",
* is now known really dead and won't be written to the output.
*/
bool
rewrite_heap_dead_tuple(RewriteState state, HeapTuple old_tuple)
{
/*
* If we have already seen an earlier tuple in the update chain that
* points to this tuple, let's forget about that earlier tuple. It's in
* fact dead as well, our simple xmax < OldestXmin test in
* HeapTupleSatisfiesVacuum just wasn't enough to detect it. It happens
* when xmin of a tuple is greater than xmax, which sounds
* counter-intuitive but is perfectly valid.
*
* We don't bother to try to detect the situation the other way round,
* when we encounter the dead tuple first and then the recently dead one
* that points to it. If that happens, we'll have some unmatched entries
* in the UnresolvedTups hash table at the end. That can happen anyway,
* because a vacuum might have removed the dead tuple in the chain before
* us.
*/
UnresolvedTup unresolved;
TidHashKey hashkey;
bool found;
memset(&hashkey, 0, sizeof(hashkey));
hashkey.xmin = HeapTupleHeaderGetXmin(old_tuple->t_data);
hashkey.tid = old_tuple->t_self;
unresolved = hash_search(state->rs_unresolved_tups, &hashkey,
HASH_FIND, NULL);
if (unresolved != NULL)
{
/* Need to free the contained tuple as well as the hashtable entry */
heap_freetuple(unresolved->tuple);
hash_search(state->rs_unresolved_tups, &hashkey,
HASH_REMOVE, &found);
Assert(found);
return true;
}
return false;
}
示例11: PyPgFunction_IsCurrent
/*
* PyPgFunction_IsCurrent - determine if the current pg_proc entry is newer than 'func'
*/
bool
PyPgFunction_IsCurrent(PyObj func)
{
HeapTuple ht;
ItemPointerData fn_tid;
TransactionId fn_xmin, last_fn_xmin;
last_fn_xmin = PyPgFunction_GetXMin(func);
if (last_fn_xmin == InvalidTransactionId)
{
/* pseudo-function */
return(true);
}
ht = SearchSysCache(PROCOID, PyPgFunction_GetOid(func), 0, 0, 0);
if (!HeapTupleIsValid(ht))
return(false);
fn_xmin = HeapTupleHeaderGetXmin(ht->t_data);
fn_tid = ht->t_self;
ReleaseSysCache(ht);
if (last_fn_xmin != fn_xmin ||
!ItemPointerEquals(PyPgFunction_GetItemPointer(func), &fn_tid))
{
return(false);
}
if (!PyPgTupleDesc_IsCurrent(PyPgFunction_GetInput(func)))
{
return(false);
}
if (!PyPgType_IsCurrent(PyPgFunction_GetOutput(func)))
return(false);
return(true);
}
示例12: tuple_all_visible
/*
* Check whether a tuple is all-visible relative to a given OldestXmin value.
* The buffer should contain the tuple and should be locked and pinned.
*/
static bool
tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
{
HTSV_Result state;
TransactionId xmin;
state = HeapTupleSatisfiesVacuum(tup, OldestXmin, buffer);
if (state != HEAPTUPLE_LIVE)
return false; /* all-visible implies live */
/*
* Neither lazy_scan_heap nor heap_page_is_all_visible will mark a page
* all-visible unless every tuple is hinted committed. However, those hint
* bits could be lost after a crash, so we can't be certain that they'll
* be set here. So just check the xmin.
*/
xmin = HeapTupleHeaderGetXmin(tup->t_data);
if (!TransactionIdPrecedes(xmin, OldestXmin))
return false; /* xmin not old enough for all to see */
return true;
}
示例13: HeapTupleSatisfiesItself
/*
* HeapTupleSatisfiesItself
* True iff heap tuple is valid "for itself".
*
* Here, we consider the effects of:
* all committed transactions (as of the current instant)
* previous commands of this transaction
* changes made by the current command
*
* Note:
* Assumes heap tuple is valid.
*
* The satisfaction of "itself" requires the following:
*
* ((Xmin == my-transaction && the row was updated by the current transaction, and
* (Xmax is null it was not deleted
* [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
* ||
*
* (Xmin is committed && the row was modified by a committed transaction, and
* (Xmax is null || the row has not been deleted, or
* (Xmax != my-transaction && the row was deleted by another transaction
* Xmax is not committed))) that has not been committed
*/
bool
HeapTupleSatisfiesItself(HeapTupleHeader tuple)
{
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{
if (tuple->t_infomask & HEAP_XMIN_INVALID)
return false;
if (tuple->t_infomask & HEAP_MOVED_OFF)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (TransactionIdIsCurrentTransactionId(xvac))
return false;
if (!TransactionIdIsInProgress(xvac))
{
if (TransactionIdDidCommit(xvac))
{
tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
}
}
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (!TransactionIdIsCurrentTransactionId(xvac))
{
if (TransactionIdIsInProgress(xvac))
return false;
if (TransactionIdDidCommit(xvac))
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
else
{
tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
}
}
else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
{
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));
if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return true;
return false;
}
else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
return false;
else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
tuple->t_infomask |= HEAP_XMIN_COMMITTED;
else
{
/* it must have aborted or crashed */
tuple->t_infomask |= HEAP_XMIN_INVALID;
return false;
}
}
/* by here, the inserting transaction has committed */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return true;
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
return true;
return false; /* updated by other */
}
//.........这里部分代码省略.........
示例14: rewrite_heap_tuple
//.........这里部分代码省略.........
/*
* We can't do anything more now, since we don't know where the
* tuple will be written.
*/
MemoryContextSwitchTo(old_cxt);
return;
}
}
/*
* Now we will write the tuple, and then check to see if it is the B tuple
* in any new or known pair. When we resolve a known pair, we will be
* able to write that pair's A tuple, and then we have to check if it
* resolves some other pair. Hence, we need a loop here.
*/
old_tid = old_tuple->t_self;
free_new = false;
for (;;)
{
ItemPointerData new_tid;
/* Insert the tuple and find out where it's put in new_heap */
raw_heap_insert(state, new_tuple);
new_tid = new_tuple->t_self;
/*
* If the tuple is the updated version of a row, and the prior version
* wouldn't be DEAD yet, then we need to either resolve the prior
* version (if it's waiting in rs_unresolved_tups), or make an entry
* in rs_old_new_tid_map (so we can resolve it when we do see it). The
* previous tuple's xmax would equal this one's xmin, so it's
* RECENTLY_DEAD if and only if the xmin is not before OldestXmin.
*/
if ((new_tuple->t_data->t_infomask & HEAP_UPDATED) &&
!TransactionIdPrecedes(HeapTupleHeaderGetXmin(new_tuple->t_data),
state->rs_oldest_xmin))
{
/*
* Okay, this is B in an update pair. See if we've seen A.
*/
UnresolvedTup unresolved;
memset(&hashkey, 0, sizeof(hashkey));
hashkey.xmin = HeapTupleHeaderGetXmin(new_tuple->t_data);
hashkey.tid = old_tid;
unresolved = hash_search(state->rs_unresolved_tups, &hashkey,
HASH_FIND, NULL);
if (unresolved != NULL)
{
/*
* We have seen and memorized the previous tuple already. Now
* that we know where we inserted the tuple its t_ctid points
* to, fix its t_ctid and insert it to the new heap.
*/
if (free_new)
heap_freetuple(new_tuple);
new_tuple = unresolved->tuple;
free_new = true;
old_tid = unresolved->old_tid;
new_tuple->t_data->t_ctid = new_tid;
/*
* We don't need the hash entry anymore, but don't free its
* tuple just yet.
*/
hash_search(state->rs_unresolved_tups, &hashkey,
HASH_REMOVE, &found);
Assert(found);
/* loop back to insert the previous tuple in the chain */
continue;
}
else
{
/*
* Remember the new tid of this tuple. We'll use it to set the
* ctid when we find the previous tuple in the chain.
*/
OldToNewMapping mapping;
mapping = hash_search(state->rs_old_new_tid_map, &hashkey,
HASH_ENTER, &found);
Assert(!found);
mapping->new_tid = new_tid;
}
}
/* Done with this (chain of) tuples, for now */
if (free_new)
heap_freetuple(new_tuple);
break;
}
MemoryContextSwitchTo(old_cxt);
}
示例15: HeapTupleSatisfiesHistoricMVCC
/*
* See the comments for HeapTupleSatisfiesMVCC for the semantics this function
* obeys.
*
* Only usable on tuples from catalog tables!
*
* We don't need to support HEAP_MOVED_(IN|OFF) for now because we only support
* reading catalog pages which couldn't have been created in an older version.
*
* We don't set any hint bits in here as it seems unlikely to be beneficial as
* those should already be set by normal access and it seems to be too
* dangerous to do so as the semantics of doing so during timetravel are more
* complicated than when dealing "only" with the present.
*/
bool
HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
Buffer buffer)
{
HeapTupleHeader tuple = htup->t_data;
TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
Assert(ItemPointerIsValid(&htup->t_self));
Assert(htup->t_tableOid != InvalidOid);
/* inserting transaction aborted */
if (HeapTupleHeaderXminInvalid(tuple))
{
Assert(!TransactionIdDidCommit(xmin));
return false;
}
/* check if it's one of our txids, toplevel is also in there */
else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
{
bool resolved;
CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
CommandId cmax = InvalidCommandId;
/*
* another transaction might have (tried to) delete this tuple or
* cmin/cmax was stored in a combocid. So we need to lookup the actual
* values externally.
*/
resolved = ResolveCminCmaxDuringDecoding(HistoricSnapshotGetTupleCids(), snapshot,
htup, buffer,
&cmin, &cmax);
if (!resolved)
elog(ERROR, "could not resolve cmin/cmax of catalog tuple");
Assert(cmin != InvalidCommandId);
if (cmin >= snapshot->curcid)
return false; /* inserted after scan started */
/* fall through */
}
/* committed before our xmin horizon. Do a normal visibility check. */
else if (TransactionIdPrecedes(xmin, snapshot->xmin))
{
Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
!TransactionIdDidCommit(xmin)));
/* check for hint bit first, consult clog afterwards */
if (!HeapTupleHeaderXminCommitted(tuple) &&
!TransactionIdDidCommit(xmin))
return false;
/* fall through */
}
/* beyond our xmax horizon, i.e. invisible */
else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
{
return false;
}
/* check if it's a committed transaction in [xmin, xmax) */
else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
{
/* fall through */
}
/*
* none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
* invisible.
*/
else
{
return false;
}
/* at this point we know xmin is visible, go on to check xmax */
/* xid invalid or aborted */
if (tuple->t_infomask & HEAP_XMAX_INVALID)
return true;
/* locked tuples are always visible */
else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
/*
* We can see multis here if we're looking at user tables or if somebody
* SELECT ... FOR SHARE/UPDATE a system table.
//.........这里部分代码省略.........