📄 exectuples.c
字号:
* Obtain a copy of a slot's physical tuple. The copy is * palloc'd in the current memory context. * * This works even if the slot contains a virtual tuple; * however the "system columns" of the result will not be meaningful. * -------------------------------- */HeapTupleExecCopySlotTuple(TupleTableSlot *slot){ /* * sanity checks */ Assert(slot != NULL); Assert(!slot->tts_isempty); /* * If we have a physical tuple then just copy it. */ if (slot->tts_tuple) return heap_copytuple(slot->tts_tuple); /* * Otherwise we need to build a tuple from the Datum array. */ return heap_form_tuple(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull);}/* -------------------------------- * ExecFetchSlotTuple * Fetch the slot's physical tuple. * * If the slot contains a virtual tuple, we convert it to physical * form. The slot retains ownership of the physical tuple. * * The difference between this and ExecMaterializeSlot() is that this * does not guarantee that the contained tuple is local storage. * Hence, the result must be treated as read-only. * -------------------------------- */HeapTupleExecFetchSlotTuple(TupleTableSlot *slot){ /* * sanity checks */ Assert(slot != NULL); Assert(!slot->tts_isempty); /* * If we have a physical tuple then just return it. */ if (slot->tts_tuple) return slot->tts_tuple; /* * Otherwise materialize the slot... */ return ExecMaterializeSlot(slot);}/* -------------------------------- * 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. * -------------------------------- */HeapTupleExecMaterializeSlot(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;}/* -------------------------------- * 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);}/* ---------------------------------------------------------------- * convenience initialization routines * ---------------------------------------------------------------- *//* -------------------------------- * ExecInit{Result,Scan,Extra}TupleSlot * * These are convenience routines to initialize the specified slot * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot * is used for initializing special-purpose slots. * -------------------------------- *//* ---------------- * ExecInitResultTupleSlot * ---------------- */voidExecInitResultTupleSlot(EState *estate, PlanState *planstate){ planstate->ps_ResultTupleSlot = ExecAllocTableSlot(estate->es_tupleTable);}/* ---------------- * ExecInitScanTupleSlot * ---------------- */voidExecInitScanTupleSlot(EState *estate, ScanState *scanstate){ scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(estate->es_tupleTable);}/* ---------------- * ExecInitExtraTupleSlot * ---------------- */TupleTableSlot *ExecInitExtraTupleSlot(EState *estate){ return ExecAllocTableSlot(estate->es_tupleTable);}/* ---------------- * ExecInitNullTupleSlot * * Build a slot containing an all-nulls tuple of the given type. * This is used as a substitute for an input tuple when performing an * outer join. * ---------------- */TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType){ TupleTableSlot *slot = ExecInitExtraTupleSlot(estate); ExecSetSlotDescriptor(slot, tupType, false); return ExecStoreAllNullTuple(slot);}/* ---------------------------------------------------------------- * ExecTypeFromTL * * Generate a tuple descriptor for the result tuple of a targetlist. * (A parse/plan tlist must be passed, not an ExprState tlist.) * Note that resjunk columns, if any, are included in the result. * * Currently there are about 4 different places where we create * TupleDescriptors. They should all be merged, or perhaps * be rewritten to call BuildDesc(). * ---------------------------------------------------------------- */TupleDescExecTypeFromTL(List *targetList, bool hasoid){ return ExecTypeFromTLInternal(targetList, hasoid, false);}/* ---------------------------------------------------------------- * ExecCleanTypeFromTL * * Same as above, but resjunk columns are omitted from the result. * ---------------------------------------------------------------- */TupleDescExecCleanTypeFromTL(List *targetList, bool hasoid){ return ExecTypeFromTLInternal(targetList, hasoid, true);}static TupleDescExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk){ TupleDesc typeInfo; ListCell *l; int len; int cur_resno = 1; if (skipjunk) len = ExecCleanTargetListLength(targetList); else len = ExecTargetListLength(targetList); typeInfo = CreateTemplateTupleDesc(len, hasoid); foreach(l, targetList) { TargetEntry *tle = lfirst(l); if (skipjunk && tle->resjunk) continue; TupleDescInitEntry(typeInfo, cur_resno++, tle->resname, exprType((Node *) tle->expr), exprTypmod((Node *) tle->expr), 0); } return typeInfo;}/* * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs * * Here we must make up an arbitrary set of field names. */TupleDescExecTypeFromExprList(List *exprList){ TupleDesc typeInfo; ListCell *l; int cur_resno = 1; char fldname[NAMEDATALEN]; typeInfo = CreateTemplateTupleDesc(list_length(exprList), false); foreach(l, exprList) { Node *e = lfirst(l); sprintf(fldname, "f%d", cur_resno); TupleDescInitEntry(typeInfo, cur_resno++, fldname, exprType(e), exprTypmod(e), 0); } return typeInfo;}/* * BlessTupleDesc - make a completed tuple descriptor useful for SRFs * * Rowtype Datums returned by a function must contain valid type information. * This happens "for free" if the tupdesc came from a relcache entry, but * not if we have manufactured a tupdesc for a transient RECORD datatype. * In that case we have to notify typcache.c of the existence of the type. */TupleDescBlessTupleDesc(TupleDesc tupdesc){ if (tupdesc->tdtypeid == RECORDOID && tupdesc->tdtypmod < 0) assign_record_type_typmod(tupdesc); return tupdesc; /* just for notational convenience */}/* * TupleDescGetSlot - Initialize a slot based on the supplied tupledesc * * Note: this is obsolete; it is sufficient to call BlessTupleDesc on * the tupdesc. We keep it around just for backwards compatibility with * existing user-written SRFs. */TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc){ TupleTableSlot *slot; /* The useful work is here */ BlessTupleDesc(tupdesc); /* Make a standalone slot */ slot = MakeSingleTupleTableSlot(tupdesc); /* Return the slot */ return slot;}/* * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings * to produce a properly formed tuple. */AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc){ int natts = tupdesc->natts; int i; Oid atttypeid; Oid attinfuncid; FmgrInfo *attinfuncinfo; Oid *attioparams; int32 *atttypmods; AttInMetadata *attinmeta; attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata)); /* "Bless" the tupledesc so that we can make rowtype datums with it */ attinmeta->tupdesc = BlessTupleDesc(tupdesc); /* * Gather info needed later to call the "in" function for each attribute */ attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo)); attioparams = (Oid *) palloc0(natts * sizeof(Oid)); atttypmods = (int32 *) palloc0(natts * sizeof(int32)); for (i = 0; i < natts; i++) { /* Ignore dropped attributes */ if (!tupdesc->attrs[i]->attisdropped) { atttypeid = tupdesc->attrs[i]->atttypid; getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]); fmgr_info(attinfuncid, &attinfuncinfo[i]); atttypmods[i] = tupdesc->attrs[i]->atttypmod; } } attinmeta->attinfuncs = attinfuncinfo; attinmeta->attioparams = attioparams; attinmeta->atttypmods = atttypmods; return attinmeta;}/* * BuildTupleFromCStrings - build a HeapTuple given user data in C string form. * values is an array of C strings, one for each attribute of the return tuple. */HeapTupleBuildTupleFromCStrings(AttInMetadata *attinmeta, char **values){ TupleDesc tupdesc = attinmeta->tupdesc; int natts = tupdesc->natts; Datum *dvalues; char *nulls; int i; Oid attioparam; int32 atttypmod; HeapTuple tuple; dvalues = (Datum *) palloc(natts * sizeof(Datum)); nulls = (char *) palloc(natts * sizeof(char)); /* Call the "in" function for each non-null, non-dropped attribute */ for (i = 0; i < natts; i++) { if (!tupdesc->attrs[i]->attisdropped) { /* Non-dropped attributes */ if (values[i] != NULL) { attioparam = attinmeta->attioparams[i]; atttypmod = attinmeta->atttypmods[i]; dvalues[i] = FunctionCall3(&attinmeta->attinfuncs[i], CStringGetDatum(values[i]), ObjectIdGetDatum(attioparam), Int32GetDatum(atttypmod)); nulls[i] = ' '; } else { dvalues[i] = (Datum) 0; nulls[i] = 'n'; } } else { /* Handle dropped attributes by setting to NULL */ dvalues[i] = (Datum) 0; nulls[i] = 'n'; } } /* * Form a tuple */ tuple = heap_formtuple(tupdesc, dvalues, nulls); /* * Release locally palloc'd space. XXX would probably be good to pfree * values of pass-by-reference datums, as well. */ pfree(dvalues); pfree(nulls); return tuple;}/* * Functions for sending tuples to the frontend (or other specified destination) * as though it is a SELECT result. These are used by utility commands that * need to project directly to the destination and don't need or want full * Table Function capability. Currently used by EXPLAIN and SHOW ALL */TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc){ TupOutputState *tstate; tstate = (TupOutputState *) palloc(sizeof(TupOutputState)); tstate->metadata = TupleDescGetAttInMetadata(tupdesc); tstate->slot = MakeSingleTupleTableSlot(tupdesc); tstate->dest = dest; (*tstate->dest->rStartup) (tstate->dest, (int) CMD_SELECT, tupdesc); return tstate;}/* * write a single tuple * * values is a list of the external C string representations of the values * to be projected. * * XXX This could be made more efficient, since in reality we probably only * need a virtual tuple. */voiddo_tup_output(TupOutputState *tstate, char **values){ /* build a tuple from the input strings using the tupdesc */ HeapTuple tuple = BuildTupleFromCStrings(tstate->metadata, values); /* put it in a slot */ ExecStoreTuple(tuple, tstate->slot, InvalidBuffer, true); /* send the tuple to the receiver */ (*tstate->dest->receiveSlot) (tstate->slot, tstate->dest); /* clean up */ ExecClearTuple(tstate->slot);}/* * write a chunk of text, breaking at newline characters * * NB: scribbles on its input! * * Should only be used with a single-TEXT-attribute tupdesc. */voiddo_text_output_multiline(TupOutputState *tstate, char *text){ while (*text) { char *eol; eol = strchr(text, '\n'); if (eol) *eol++ = '\0'; else eol = text +strlen(text); do_tup_output(tstate, &text); text = eol; }}voidend_tup_output(TupOutputState *tstate){ (*tstate->dest->rShutdown) (tstate->dest); /* note that destroying the dest is not ours to do */ ExecDropSingleTupleTableSlot(tstate->slot); /* XXX worth cleaning up the attinmetadata? */ pfree(tstate);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -