static void transform_receive(TupleTableSlot *slot, DestReceiver *self) { TransformState *t = (TransformState *) self; MemoryContext old = MemoryContextSwitchTo(ContQueryBatchContext); if (t->tg_rel == NULL) t->tg_rel = heap_open(t->cont_query->matrelid, AccessShareLock); if (t->cont_query->tgfn != PIPELINE_STREAM_INSERT_OID) { TriggerData *cxt = (TriggerData *) t->trig_fcinfo->context; Assert(t->trig_fcinfo); cxt->tg_relation = t->tg_rel; cxt->tg_trigtuple = ExecCopySlotTuple(slot); FunctionCallInvoke(t->trig_fcinfo); heap_freetuple(cxt->tg_trigtuple); cxt->tg_trigtuple = NULL; } else { if (t->tups == NULL) { Assert(t->nmaxtups == 0); Assert(t->ntups == 0); t->nmaxtups = continuous_query_batch_size / 8; t->tups = palloc(sizeof(HeapTuple) * t->nmaxtups); } if (t->ntups == t->nmaxtups) { t->nmaxtups *= 2; t->tups = repalloc(t->tups, sizeof(HeapTuple) * t->nmaxtups); } t->tups[t->ntups] = ExecCopySlotTuple(slot); t->ntups++; if (synchronous_stream_insert && t->acks == NULL) t->acks = InsertBatchAckCreate(t->cont_exec->yielded_msgs, &t->nacks); } MemoryContextSwitchTo(old); }
jobject TupleTable_createFromSlot(TupleTableSlot* tts) { HeapTuple tuple; jobject tupdesc; jobjectArray tuples; MemoryContext curr; if(tts == 0) return 0; curr = MemoryContextSwitchTo(JavaMemoryContext); #if (PGSQL_MAJOR_VER == 8 && PGSQL_MINOR_VER == 0) tupdesc = TupleDesc_internalCreate(tts->ttc_tupleDescriptor); tuple = heap_copytuple(tts->val); #else tupdesc = TupleDesc_internalCreate(tts->tts_tupleDescriptor); tuple = ExecCopySlotTuple(tts); #endif tuples = Tuple_createArray(&tuple, 1, false); MemoryContextSwitchTo(curr); return JNI_newObject(s_TupleTable_class, s_TupleTable_init, tupdesc, tuples); }
/* -------------------------------- * 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) { HeapTuple newTuple; MemoryContext oldContext; /* * There might be ways to optimize this when the source is virtual, but * for now just always build a physical copy. Make sure it is in the * right context. */ oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt); newTuple = ExecCopySlotTuple(srcslot); MemoryContextSwitchTo(oldContext); return ExecStoreTuple(newTuple, dstslot, InvalidBuffer, true); }
static void combiner_receive(TupleTableSlot *slot, DestReceiver *self) { CombinerState *c = (CombinerState *) self; MemoryContext old = MemoryContextSwitchTo(ContQueryBatchContext); tagged_ref_t *ref; uint32 shard_hash; bool received = false; if (!c->cont_query) c->cont_query = c->cont_exec->curr_query->query; Assert(c->cont_query->type == CONT_VIEW); ref = palloc(sizeof(tagged_ref_t)); ref->ptr = ExecCopySlotTuple(slot); /* Shard by groups or name if no grouping. */ if (c->hash_fcinfo) { ref->tag = slot_hash_group(slot, c->hashfn, c->hash_fcinfo); shard_hash = slot_hash_group_skip_attr(slot, c->cont_query->sw_attno, c->hashfn, c->hash_fcinfo); } else { ref->tag = c->name_hash; shard_hash = c->name_hash; } if (CombinerReceiveHook) received = CombinerReceiveHook(c->cont_query, shard_hash, ref->tag, ref->ptr); if (!received) { int i = get_combiner_for_shard_hash(shard_hash); c->tups_per_combiner[i] = lappend(c->tups_per_combiner[i], ref); } MemoryContextSwitchTo(old); }
/* -------------------------------- * ExecMaterializeSlot * Force a slot into the "materialized" state. * * This causes the slot's tuple to be a local copy not dependent on * any external storage. A pointer to the contained tuple is returned. * * A typical use for this operation is to prepare a computed tuple * for being stored on disk. The original data may or may not be * virtual, but in any case we need a private copy for heap_insert * to scribble on. * -------------------------------- */ HeapTuple ExecMaterializeSlot(TupleTableSlot *slot) { HeapTuple newTuple; MemoryContext oldContext; /* * sanity checks */ Assert(slot != NULL); Assert(!slot->tts_isempty); /* * If we have a physical tuple, and it's locally palloc'd, we have nothing * to do. */ if (slot->tts_tuple && slot->tts_shouldFree) return slot->tts_tuple; /* * Otherwise, copy or build a tuple, and then store it as the new slot * value. (Note: tts_nvalid will be reset to zero here. There are cases * in which this could be optimized but it's probably not worth worrying * about.) * * We may be called in a context that is shorter-lived than the tuple * slot, but we have to ensure that the materialized tuple will survive * anyway. */ oldContext = MemoryContextSwitchTo(slot->tts_mcxt); newTuple = ExecCopySlotTuple(slot); MemoryContextSwitchTo(oldContext); ExecStoreTuple(newTuple, slot, InvalidBuffer, true); return slot->tts_tuple; }
/* * ExecSetOp for non-hashed case */ static TupleTableSlot * setop_retrieve_direct(SetOpState *setopstate) { SetOp *node = (SetOp *) setopstate->ps.plan; PlanState *outerPlan; SetOpStatePerGroup pergroup; TupleTableSlot *outerslot; TupleTableSlot *resultTupleSlot; /* * get state info from node */ outerPlan = outerPlanState(setopstate); pergroup = setopstate->pergroup; resultTupleSlot = setopstate->ps.ps_ResultTupleSlot; /* * We loop retrieving groups until we find one we should return */ while (!setopstate->setop_done) { /* * If we don't already have the first tuple of the new group, fetch it * from the outer plan. */ if (setopstate->grp_firstTuple == NULL) { outerslot = ExecProcNode(outerPlan); if (!TupIsNull(outerslot)) { /* Make a copy of the first input tuple */ setopstate->grp_firstTuple = ExecCopySlotTuple(outerslot); } else { /* outer plan produced no tuples at all */ setopstate->setop_done = true; return NULL; } } /* * Store the copied first input tuple in the tuple table slot reserved * for it. The tuple will be deleted when it is cleared from the * slot. */ ExecStoreTuple(setopstate->grp_firstTuple, resultTupleSlot, InvalidBuffer, true); setopstate->grp_firstTuple = NULL; /* don't keep two pointers */ /* Initialize working state for a new input tuple group */ initialize_counts(pergroup); /* Count the first input tuple */ advance_counts(pergroup, fetch_tuple_flag(setopstate, resultTupleSlot)); /* * Scan the outer plan until we exhaust it or cross a group boundary. */ for (;;) { outerslot = ExecProcNode(outerPlan); if (TupIsNull(outerslot)) { /* no more outer-plan tuples available */ setopstate->setop_done = true; break; } /* * Check whether we've crossed a group boundary. */ if (!execTuplesMatch(resultTupleSlot, outerslot, node->numCols, node->dupColIdx, setopstate->eqfunctions, setopstate->tempContext)) { /* * Save the first input tuple of the next group. */ setopstate->grp_firstTuple = ExecCopySlotTuple(outerslot); break; } /* Still in same group, so count this tuple */ advance_counts(pergroup, fetch_tuple_flag(setopstate, outerslot)); } /* * Done scanning input tuple group. See if we should emit any copies * of result tuple, and if so return the first copy. */ set_output_count(setopstate, pergroup); if (setopstate->numOutput > 0) { setopstate->numOutput--; return resultTupleSlot; } } /* No more groups */ ExecClearTuple(resultTupleSlot); return NULL; }