Esempio n. 1
0
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;
	}

}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 7
0
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;
	}
}
Esempio n. 8
0
/* ----------------
 *		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;
}