static void readindextuple(readindexinfo *info, Relation irel, Relation hrel, Datum *values, bool *nulls) { BlockNumber blkno; Page page; OffsetNumber offnum; IndexTuple itup; HeapTupleData htup; Buffer hbuf; AttrNumber attno; TupleDesc tupdesc = RelationGetDescr(irel); blkno = info->blkno; page = info->page; offnum = info->offnum; itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); htup.t_self = itup->t_tid; values[1] = ItemPointerGetDatum(&itup->t_tid); if (hrel == NULL) values[2] = PointerGetDatum(cstring_to_text(AOTupleIdToString((AOTupleId *)&itup->t_tid))); else values[2] = PointerGetDatum(cstring_to_text("N/A")); values[3] = PointerGetDatum(istatus_text(PageGetItemId(page, offnum))); if (hrel != NULL) { if (heap_fetch(hrel, SnapshotAny, &htup, &hbuf, true, NULL)) values[4] = PointerGetDatum(hstatus_text(htup.t_data, true)); else if (htup.t_data) values[4] = PointerGetDatum(hstatus_text(htup.t_data, false)); else values[4] = PointerGetDatum(cstring_to_text("NOT_FOUND")); ReleaseBuffer(hbuf); } else values[4] = PointerGetDatum(cstring_to_text("N/A")); for (attno = 1; attno <= tupdesc->natts; attno++) { bool isnull; values[FIXED_COLUMN+attno-1] = index_getattr(itup, attno, tupdesc, &isnull); nulls[FIXED_COLUMN+attno-1] = isnull; } }
uint64 lookup_pkey(Oid heapRelOid, char *pkeyFieldname, ItemPointer ctid) { Relation heapRel; HeapTupleData tuple; Buffer buffer; Datum pkey; bool isnull; heapRel = RelationIdGetRelation(heapRelOid); tuple.t_self = *ctid; if (!heap_fetch(heapRel, SnapshotAny, &tuple, &buffer, false, NULL)) elog(ERROR, "Unable to fetch heap page from index"); pkey = heap_getattr(&tuple, get_attnum(heapRelOid, pkeyFieldname), RelationGetDescr(heapRel), &isnull); if (isnull) elog(ERROR, "detected NULL key value. Cannot update row"); ReleaseBuffer(buffer); RelationClose(heapRel); return DatumGetInt64(pkey); }
static void GlobalSequence_ReadTuple( GpGlobalSequence gpGlobalSequence, int64 *currentSequenceNum) { Relation gpGlobalSequenceRel; bool nulls[Anum_gp_global_sequence_sequence_num]; Datum values[Anum_gp_global_sequence_sequence_num]; HeapTupleData globalSequenceTuple; Buffer buffer; gpGlobalSequenceRel = DirectOpen_GpGlobalSequenceOpenShared(); GlobalSequence_MakeTid( gpGlobalSequence, &globalSequenceTuple.t_self); if (!heap_fetch(gpGlobalSequenceRel, SnapshotAny, &globalSequenceTuple, &buffer, false, NULL)) elog(ERROR, "Failed to fetch global sequence tuple at %s", ItemPointerToString(&globalSequenceTuple.t_self)); heap_deform_tuple( &globalSequenceTuple, gpGlobalSequenceRel->rd_att, values, nulls); GpGlobalSequence_GetValues( values, currentSequenceNum); ReleaseBuffer(buffer); DirectOpen_GpGlobalSequenceClose(gpGlobalSequenceRel); }
void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex) { Relation LocalNewHeap, LocalOldHeap, LocalOldIndex; IndexScanDesc ScanDesc; RetrieveIndexResult ScanResult; ItemPointer HeapTid; HeapTuple LocalHeapTuple; Buffer LocalBuffer; Oid OIDNewHeapInsert; /* * Open the relations I need. Scan through the OldHeap on the OldIndex and * insert each tuple into the NewHeap. */ LocalNewHeap=(Relation)heap_open(OIDNewHeap); LocalOldHeap=(Relation)heap_open(OIDOldHeap); LocalOldIndex=(Relation)index_open(OIDOldIndex); ScanDesc=index_beginscan(LocalOldIndex, false, 0, (ScanKey) NULL); while ((ScanResult = index_getnext(ScanDesc, ForwardScanDirection)) != NULL) { HeapTid = &ScanResult->heap_iptr; LocalHeapTuple = heap_fetch(LocalOldHeap, 0, HeapTid, &LocalBuffer); OIDNewHeapInsert = heap_insert(LocalNewHeap, LocalHeapTuple); pfree(ScanResult); ReleaseBuffer(LocalBuffer); } index_close(LocalOldIndex); heap_close(LocalOldHeap); heap_close(LocalNewHeap); }
void PersistentStore_ReplaceTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer persistentTid, /* TID of the stored tuple. */ HeapTuple tuple, Datum *newValues, bool *replaces, bool flushToXLog) /* When true, the XLOG record for this change will be flushed to disk. */ { Relation persistentRel; bool *nulls; HeapTuple replacementTuple = NULL; XLogRecPtr xlogUpdateEndLoc; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReplaceTuple: Going to replace set of columns in tuple at TID %s ('%s', shared data %p)", ItemPointerToString(persistentTid), storeData->tableName, storeSharedData); persistentRel = (*storeData->openRel)(); /* * In order to keep the tuples the exact same size to enable direct reuse of * free tuples, we do not use NULLs. */ nulls = (bool*)palloc0(storeData->numAttributes * sizeof(bool)); /* * Modify the tuple. */ replacementTuple = heap_modify_tuple(tuple, persistentRel->rd_att, newValues, nulls, replaces); replacementTuple->t_self = *persistentTid; frozen_heap_inplace_update(persistentRel, replacementTuple); /* * Return the XLOG location of the UPDATE tuple's XLOG record. */ xlogUpdateEndLoc = XLogLastInsertEndLoc(); heap_freetuple(replacementTuple); pfree(nulls); if (Debug_persistent_store_print) { Datum *readValues; bool *readNulls; HeapTupleData readTuple; Buffer buffer; HeapTuple readTupleCopy; elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReplaceTuple: Replaced set of columns in tuple at TID %s ('%s')", ItemPointerToString(persistentTid), storeData->tableName); readValues = (Datum*)palloc(storeData->numAttributes * sizeof(Datum)); readNulls = (bool*)palloc(storeData->numAttributes * sizeof(bool)); readTuple.t_self = *persistentTid; if (!heap_fetch(persistentRel, SnapshotAny, &readTuple, &buffer, false, NULL)) { elog(ERROR, "Failed to fetch persistent tuple at %s ('%s')", ItemPointerToString(&readTuple.t_self), storeData->tableName); } readTupleCopy = heaptuple_copy_to(&readTuple, NULL, NULL); ReleaseBuffer(buffer); heap_deform_tuple(readTupleCopy, persistentRel->rd_att, readValues, readNulls); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE REPLACED TUPLE", persistentTid, readValues); heap_freetuple(readTupleCopy); pfree(readValues); pfree(readNulls); } (*storeData->closeRel)(persistentRel); if (flushToXLog) { XLogFlush(xlogUpdateEndLoc); XLogRecPtr_Zero(&nowaitXLogEndLoc); } else nowaitXLogEndLoc = xlogUpdateEndLoc; }
void PersistentStore_ReadTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer readTid, Datum *values, HeapTuple *tupleCopy) { Relation persistentRel; HeapTupleData tuple; Buffer buffer; bool *nulls; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReadTuple: Going to read tuple at TID %s ('%s', shared data %p)", ItemPointerToString(readTid), storeData->tableName, storeSharedData); if (PersistentStore_IsZeroTid(readTid)) elog(ERROR, "TID for fetch persistent tuple is invalid (0,0) ('%s')", storeData->tableName); // UNDONE: I think the InRecovery test only applies to physical Master Mirroring on Standby. /* Only test this outside of recovery scenarios */ if (!InRecovery && (PersistentStore_IsZeroTid(&storeSharedData->maxTid) || ItemPointerCompare( readTid, &storeSharedData->maxTid) == 1 // Greater-than. )) { elog(ERROR, "TID %s for fetch persistent tuple is greater than the last known TID %s ('%s')", ItemPointerToString(readTid), ItemPointerToString2(&storeSharedData->maxTid), storeData->tableName); } persistentRel = (*storeData->openRel)(); tuple.t_self = *readTid; if (!heap_fetch(persistentRel, SnapshotAny, &tuple, &buffer, false, NULL)) { elog(ERROR, "Failed to fetch persistent tuple at %s (maximum known TID %s, '%s')", ItemPointerToString(&tuple.t_self), ItemPointerToString2(&storeSharedData->maxTid), storeData->tableName); } *tupleCopy = heaptuple_copy_to(&tuple, NULL, NULL); ReleaseBuffer(buffer); /* * In order to keep the tuples the exact same size to enable direct reuse of * free tuples, we do not use NULLs. */ nulls = (bool*)palloc(storeData->numAttributes * sizeof(bool)); heap_deform_tuple(*tupleCopy, persistentRel->rd_att, values, nulls); (*storeData->closeRel)(persistentRel); if (Debug_persistent_store_print) { elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReadTuple: Successfully read tuple at TID %s ('%s')", ItemPointerToString(readTid), storeData->tableName); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE READ TUPLE", readTid, values); } pfree(nulls); }
void PersistentStore_ReadTuple( PersistentStoreData *storeData, PersistentStoreSharedData *storeSharedData, ItemPointer readTid, Datum *values, HeapTuple *tupleCopy) { Relation persistentRel; HeapTupleData tuple; Buffer buffer; bool *nulls; #ifdef USE_ASSERT_CHECKING if (storeSharedData == NULL || !PersistentStoreSharedData_EyecatcherIsValid(storeSharedData)) elog(ERROR, "Persistent store shared-memory not valid"); #endif if (Debug_persistent_store_print) elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReadTuple: Going to read tuple at TID %s ('%s', shared data %p)", ItemPointerToString(readTid), storeData->tableName, storeSharedData); if (PersistentStore_IsZeroTid(readTid)) elog(ERROR, "TID for fetch persistent tuple is invalid (0,0) ('%s')", storeData->tableName); persistentRel = (*storeData->openRel)(); tuple.t_self = *readTid; if (heap_fetch(persistentRel, SnapshotAny, &tuple, &buffer, false, NULL)) { *tupleCopy = heaptuple_copy_to(&tuple, NULL, NULL); ReleaseBuffer(buffer); /* * In order to keep the tuples the exact same size to enable direct reuse of * free tuples, we do not use NULLs. */ nulls = (bool*)palloc(storeData->numAttributes * sizeof(bool)); heap_deform_tuple(*tupleCopy, persistentRel->rd_att, values, nulls); (*storeData->closeRel)(persistentRel); if (Debug_persistent_store_print) { elog(PersistentStore_DebugPrintLevel(), "PersistentStore_ReadTuple: Successfully read tuple at TID %s ('%s')", ItemPointerToString(readTid), storeData->tableName); (*storeData->printTupleCallback)( PersistentStore_DebugPrintLevel(), "STORE READ TUPLE", readTid, values); } pfree(nulls); } else { *tupleCopy = NULL; } }
/* ---------------- * index_getnext - get the next heap tuple from a scan * * The result is the next heap tuple satisfying the scan keys and the * snapshot, or NULL if no more matching tuples exist. On success, * the buffer containing the heap tuple is pinned (the pin will be dropped * at the next index_getnext or index_endscan). The index TID corresponding * to the heap tuple can be obtained if needed from scan->currentItemData. * ---------------- */ HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction) { HeapTuple heapTuple = &scan->xs_ctup; SCAN_CHECKS; /* Release any previously held pin */ if (BufferIsValid(scan->xs_cbuf)) { ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } /* * If we already got a tuple and it must be unique, there's no need to * make the index AM look through any additional tuples. (This can * save a useful amount of work in scenarios where there are many dead * tuples due to heavy update activity.) * * To do this we must keep track of the logical scan position * (before/on/after tuple). Also, we have to be sure to release scan * resources before returning NULL; if we fail to do so then a * multi-index scan can easily run the system out of free buffers. We * can release index-level resources fairly cheaply by calling * index_rescan. This means there are two persistent states as far as * the index AM is concerned: on-tuple and rescanned. If we are * actually asked to re-fetch the single tuple, we have to go through * a fresh indexscan startup, which penalizes that (infrequent) case. */ if (scan->keys_are_unique && scan->got_tuple) { int new_tuple_pos = scan->unique_tuple_pos; if (ScanDirectionIsForward(direction)) { if (new_tuple_pos <= 0) new_tuple_pos++; } else { if (new_tuple_pos >= 0) new_tuple_pos--; } if (new_tuple_pos == 0) { /* * We are moving onto the unique tuple from having been off * it. We just fall through and let the index AM do the work. * Note we should get the right answer regardless of scan * direction. */ scan->unique_tuple_pos = 0; /* need to update position */ } else { /* * Moving off the tuple; must do amrescan to release * index-level pins before we return NULL. Since index_rescan * will reset my state, must save and restore... */ int unique_tuple_mark = scan->unique_tuple_mark; index_rescan(scan, NULL /* no change to key */ ); scan->keys_are_unique = true; scan->got_tuple = true; scan->unique_tuple_pos = new_tuple_pos; scan->unique_tuple_mark = unique_tuple_mark; return NULL; } } /* just make sure this is false... */ scan->kill_prior_tuple = false; for (;;) { bool found; uint16 sv_infomask; pgstat_count_index_scan(&scan->xs_pgstat_info); /* * The AM's gettuple proc finds the next tuple matching the scan * keys. index_beginscan already set up fn_getnext. */ found = DatumGetBool(FunctionCall2(&scan->fn_getnext, PointerGetDatum(scan), Int32GetDatum(direction))); /* Reset kill flag immediately for safety */ scan->kill_prior_tuple = false; if (!found) return NULL; /* failure exit */ /* * Fetch the heap tuple and see if it matches the snapshot. */ if (heap_fetch(scan->heapRelation, scan->xs_snapshot, heapTuple, &scan->xs_cbuf, true, &scan->xs_pgstat_info)) break; /* Skip if no tuple at this location */ if (heapTuple->t_data == NULL) continue; /* should we raise an error instead? */ /* * If we can't see it, maybe no one else can either. Check to see * if the tuple is dead to all transactions. If so, signal the * index AM to not return it on future indexscans. * * We told heap_fetch to keep a pin on the buffer, so we can * re-access the tuple here. But we must re-lock the buffer * first. Also, it's just barely possible for an update of hint * bits to occur here. */ LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE); sv_infomask = heapTuple->t_data->t_infomask; if (HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin) == HEAPTUPLE_DEAD) scan->kill_prior_tuple = true; if (sv_infomask != heapTuple->t_data->t_infomask) SetBufferCommitInfoNeedsSave(scan->xs_cbuf); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); ReleaseBuffer(scan->xs_cbuf); scan->xs_cbuf = InvalidBuffer; } /* Success exit */ scan->got_tuple = true; /* * If we just fetched a known-unique tuple, then subsequent calls will * go through the short-circuit code above. unique_tuple_pos has been * initialized to 0, which is the correct state ("on row"). */ pgstat_count_index_getnext(&scan->xs_pgstat_info); return heapTuple; }