/* -------------------------------- * ExecCopySlotHeadTupleTo * Copy heapTuple to a preallocated buffer. Code adapted from ExecCopySlotTuple * * return the copied heaptule if there is enough space, or, if the memorycontext is * not null, which the function will alloc enough space from the context. One can * test if the tuple is alloced (ret == dest) * * return NULL and set *len to space need if there is not enough space and the mem context is null. * return NULL if heap tuple is not valid, and set *len = 0. See slot->tts_tuple case below. * ------------------------------- */ HeapTuple ExecCopySlotHeapTupleTo(TupleTableSlot *slot, MemoryContext pctxt, char* dest, unsigned int *len) { uint32 dumlen; HeapTuple tup = NULL; Assert(!TupIsNull(slot)); Assert(slot->tts_tupleDescriptor); if(!len) len = &dumlen; if (slot->PRIVATE_tts_heaptuple) { tup = heaptuple_copy_to(slot->PRIVATE_tts_heaptuple, (HeapTuple) dest, len); if(tup || !pctxt) return tup; tup = (HeapTuple) ctxt_alloc(pctxt, *len); tup = heaptuple_copy_to(slot->PRIVATE_tts_heaptuple, tup, len); Assert(tup); return tup; } slot_getallattrs(slot); tup = heaptuple_form_to(slot->tts_tupleDescriptor, slot_get_values(slot), slot_get_isnull(slot), (HeapTuple) dest, len); if(tup || !pctxt) return tup; tup = (HeapTuple) ctxt_alloc(pctxt, *len); tup = heaptuple_form_to(slot->tts_tupleDescriptor, slot_get_values(slot), slot_get_isnull(slot), tup, len); Assert(tup); return tup; }
/* -------------------------------- * ExecCopySlot * Copy the source slot's contents into the destination slot. * * The destination acquires a private copy that will not go away * if the source is cleared. * * The caller must ensure the slots have compatible tupdescs. * -------------------------------- */ TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) { Assert(!TupIsNull(srcslot)); ExecClearTuple(dstslot); TupClearIsEmpty(dstslot); /* heap tuple stuff */ if(srcslot->PRIVATE_tts_heaptuple && !srcslot->PRIVATE_tts_memtuple) { uint32 tuplen = dstslot->PRIVATE_tts_htup_buf_len; HeapTuple htup = heaptuple_copy_to(srcslot->PRIVATE_tts_heaptuple, dstslot->PRIVATE_tts_htup_buf, &tuplen); if(!htup) { dstslot->PRIVATE_tts_htup_buf = MemoryContextAlloc(dstslot->tts_mcxt, tuplen); dstslot->PRIVATE_tts_htup_buf_len = tuplen; htup = heaptuple_copy_to(srcslot->PRIVATE_tts_heaptuple, dstslot->PRIVATE_tts_htup_buf, &tuplen); } Assert(htup); dstslot->PRIVATE_tts_heaptuple = htup; dstslot->PRIVATE_tts_nvalid = 0; } else { uint32 tuplen = dstslot->PRIVATE_tts_mtup_buf_len; MemTuple mtup; Assert(srcslot->tts_mt_bind != NULL && dstslot->tts_mt_bind != NULL); mtup = ExecCopySlotMemTupleTo(srcslot, NULL, dstslot->PRIVATE_tts_mtup_buf, &tuplen); if(!mtup) { dstslot->PRIVATE_tts_mtup_buf = MemoryContextAlloc(dstslot->tts_mcxt, tuplen); dstslot->PRIVATE_tts_mtup_buf_len = tuplen; mtup = ExecCopySlotMemTupleTo(srcslot, NULL, dstslot->PRIVATE_tts_mtup_buf, &tuplen); } Assert(mtup); dstslot->PRIVATE_tts_memtuple = mtup; dstslot->PRIVATE_tts_nvalid = 0; } return dstslot; }
static void * copytup_heap(Tuplestorestate *state, TuplestorePos *pos, void *tup) { if(!is_heaptuple_memtuple((HeapTuple) tup)) return heaptuple_copy_to((HeapTuple) tup, NULL, NULL); return memtuple_copy_to((MemTuple) tup, NULL, NULL, NULL); }
static void * copytup_heap(Tuplestorestate *state, void *tup) { if (!is_memtuple((GenericTuple) tup)) return heaptuple_copy_to((HeapTuple) tup, NULL, NULL); else return memtuple_copy_to((MemTuple) tup, NULL, NULL); }
/* * insert a tuple into in-memory heap table. */ void InMemHeap_Insert(InMemHeapRelation relation, HeapTuple tup, int contentid) { InMemHeapTuple inmemtup; MemoryContext oldmem = CurrentMemoryContext; Assert(NULL != relation && NULL != tup); Assert(GP_ROLE_EXECUTE == Gp_role || -1 == contentid); Assert(NULL != relation && NULL != tup); CurrentMemoryContext = relation->memcxt; if (relation->tupsize >= relation->tupmaxsize) { Assert(NULL != relation->tuples); relation->tuples = repalloc(relation->tuples, sizeof(InMemHeapTupleData) * relation->tupmaxsize * 2); relation->tupmaxsize *= 2; } inmemtup = &relation->tuples[relation->tupsize]; inmemtup->contentid = contentid; inmemtup->flags = INMEM_HEAP_TUPLE_DISPATCHED; inmemtup->tuple = heaptuple_copy_to(tup, NULL, NULL); Assert(inmemtup->tuple != NULL); if (relation->hashIndex) { Oid key; bool isNull, found; key = DatumGetObjectId( heap_getattr(tup, relation->keyAttrno, RelationGetDescr(relation->rel), &isNull)); Insist(!isNull && "index key cannot be null"); MemHeapHashIndexEntry *entry; entry = (MemHeapHashIndexEntry *) hash_search(relation->hashIndex, &key, HASH_ENTER, &found); if (!found) { entry->key = key; entry->values = NIL; } entry->values = lappend_int(entry->values, relation->tupsize); elog(DEBUG1, "add index %d key %d relation %s", relation->tupsize, key, relation->relname); } ++relation->tupsize; CurrentMemoryContext = oldmem; }
/* * update a tuple in in-memory heap table. * * if the target tuple already in the memory, * update it in-place with flag INMEM_HEAP_TUPLE_UPDATED. * else report an error. * * update should not change the otid of the old tuple, * since updated tuple should write back to the master and update there. */ void InMemHeap_Update(InMemHeapRelation relation, ItemPointer otid, HeapTuple tup) { int pos; HeapTuple target; MemoryContext oldmem = CurrentMemoryContext; Assert(ItemPointerIsValid(otid)); pos = InMemHeap_Find(relation, otid); CurrentMemoryContext = relation->memcxt; /* * not found, report error */ if (pos >= relation->tupsize) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("update a tuple which does not exist," " relname = %s, relid = %u", relation->rel->rd_rel->relname.data, relation->relid))); } Insist(relation->hashIndex == NULL && "cannot handle index in in-memory heap when update"); /* * already in table */ Assert(relation->tuples[pos].flags == INMEM_HEAP_TUPLE_DISPATCHED || relation->tuples[pos].flags == INMEM_HEAP_TUPLE_UPDATED); relation->tuples[pos].flags = INMEM_HEAP_TUPLE_UPDATED; target = heaptuple_copy_to(tup, NULL, NULL ); /* * do not modify original tuple header */ ItemPointerCopy(&target->t_self, &relation->tuples[pos].tuple->t_self); Assert(ItemPointerEquals(&target->t_self, otid)); memcpy(target->t_data, relation->tuples[pos].tuple->t_data, sizeof(HeapTupleHeaderData)); CurrentMemoryContext = oldmem; pfree(relation->tuples[pos].tuple); relation->tuples[pos].tuple = target; }
Datum caql_copy_to_in_memory_pg_class(PG_FUNCTION_ARGS) { text *inText = PG_GETARG_TEXT_P(0);; char *inStr = text_to_cstring(inText); char kind = PG_GETARG_CHAR(1); StringInfoData buf; initStringInfo(&buf); /* create tuples for pg_class table */ HeapTuple reltup = NULL; HeapTuple copytup = NULL; Form_pg_class relform; cqContext *pcqCtx; cqContext *pcqCtxInsert; pcqCtx = caql_beginscan( NULL, cql("SELECT * FROM pg_class " " WHERE relname = :1", CStringGetDatum((char *) inStr))); reltup = caql_getnext(pcqCtx); if (NULL == reltup) { appendStringInfo(&buf, "no tuples with relname=%s found!", inStr); } else { copytup = heaptuple_copy_to(reltup, NULL, NULL); relform = (Form_pg_class) GETSTRUCT(copytup); relform->relkind = kind; appendStringInfo(&buf, "table pg_class, insert 1 line (relname %s, relkind %c)", NameStr(relform->relname), kind); /* insert */ pcqCtxInsert = caql_beginscan( NULL, cql("INSERT INTO pg_class", NULL)); caql_insert_inmem(pcqCtxInsert, copytup); caql_endscan(pcqCtxInsert); heap_freetuple(copytup); } caql_endscan(pcqCtx); PG_RETURN_TEXT_P(cstring_to_text(buf.data)); }
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; }
HeapTuple PersistentStore_GetScanTupleCopy( PersistentStoreScan *storeScan) { return heaptuple_copy_to(storeScan->tuple, NULL, NULL); }
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; } }