/* * Prepare targetlist SRF function call for execution. * * This is used by nodeProjectSet.c. */ SetExprState * ExecInitFunctionResultSet(Expr *expr, ExprContext *econtext, PlanState *parent) { SetExprState *state = makeNode(SetExprState); state->funcReturnsSet = true; state->expr = expr; state->func.fn_oid = InvalidOid; /* * Initialize metadata. The expression node could be either a FuncExpr or * an OpExpr. */ if (IsA(expr, FuncExpr)) { FuncExpr *func = (FuncExpr *) expr; state->args = ExecInitExprList(func->args, parent); init_sexpr(func->funcid, func->inputcollid, expr, state, parent, econtext->ecxt_per_query_memory, true, true); } else if (IsA(expr, OpExpr)) { OpExpr *op = (OpExpr *) expr; state->args = ExecInitExprList(op->args, parent); init_sexpr(op->opfuncid, op->inputcollid, expr, state, parent, econtext->ecxt_per_query_memory, true, true); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); /* shouldn't get here unless the selected function returns set */ Assert(state->func.fn_retset); return state; }
/* * Prepare function call in FROM (ROWS FROM) for execution. * * This is used by nodeFunctionscan.c. */ SetExprState * ExecInitTableFunctionResult(Expr *expr, ExprContext *econtext, PlanState *parent) { SetExprState *state = makeNode(SetExprState); state->funcReturnsSet = false; state->expr = expr; state->func.fn_oid = InvalidOid; /* * Normally the passed expression tree will be a FuncExpr, since the * grammar only allows a function call at the top level of a table * function reference. However, if the function doesn't return set then * the planner might have replaced the function call via constant-folding * or inlining. So if we see any other kind of expression node, execute * it via the general ExecEvalExpr() code. That code path will not * support set-returning functions buried in the expression, though. */ if (IsA(expr, FuncExpr)) { FuncExpr *func = (FuncExpr *) expr; state->funcReturnsSet = func->funcretset; state->args = ExecInitExprList(func->args, parent); init_sexpr(func->funcid, func->inputcollid, expr, state, parent, econtext->ecxt_per_query_memory, func->funcretset, false); } else { state->elidedFuncState = ExecInitExpr(expr, parent); } return state; }
/* ---------------------------------------------------------------- * ValuesNext * * This is a workhorse for ExecValuesScan * ---------------------------------------------------------------- */ static TupleTableSlot * ValuesNext(ValuesScanState *node) { TupleTableSlot *slot; EState *estate; ExprContext *econtext; ScanDirection direction; List *exprlist; /* * get information from the estate and scan state */ estate = node->ss.ps.state; direction = estate->es_direction; slot = node->ss.ss_ScanTupleSlot; econtext = node->rowcontext; /* * Get the next tuple. Return NULL if no more tuples. */ if (ScanDirectionIsForward(direction)) { if (node->curr_idx < node->array_len) node->curr_idx++; if (node->curr_idx < node->array_len) exprlist = node->exprlists[node->curr_idx]; else exprlist = NIL; } else { if (node->curr_idx >= 0) node->curr_idx--; if (node->curr_idx >= 0) exprlist = node->exprlists[node->curr_idx]; else exprlist = NIL; } /* * Always clear the result slot; this is appropriate if we are at the end * of the data, and if we're not, we still need it as the first step of * the store-virtual-tuple protocol. It seems wise to clear the slot * before we reset the context it might have pointers into. */ ExecClearTuple(slot); if (exprlist) { MemoryContext oldContext; List *exprstatelist; Datum *values; bool *isnull; Form_pg_attribute *att; ListCell *lc; int resind; /* * Get rid of any prior cycle's leftovers. We use ReScanExprContext * not just ResetExprContext because we want any registered shutdown * callbacks to be called. */ ReScanExprContext(econtext); /* * Build the expression eval state in the econtext's per-tuple memory. * This is a tad unusual, but we want to delete the eval state again * when we move to the next row, to avoid growth of memory * requirements over a long values list. */ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); /* * Pass NULL, not my plan node, because we don't want anything in this * transient state linking into permanent state. The only possibility * is a SubPlan, and there shouldn't be any (any subselects in the * VALUES list should be InitPlans). */ exprstatelist = ExecInitExprList(exprlist, NULL); /* parser should have checked all sublists are the same length */ Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts); /* * Compute the expressions and build a virtual result tuple. We * already did ExecClearTuple(slot). */ values = slot->tts_values; isnull = slot->tts_isnull; att = slot->tts_tupleDescriptor->attrs; resind = 0; foreach(lc, exprstatelist) { ExprState *estate = (ExprState *) lfirst(lc); values[resind] = ExecEvalExpr(estate, econtext, &isnull[resind]); /* * We must force any R/W expanded datums to read-only state, in * case they are multiply referenced in the plan node's output * expressions, or in case we skip the output projection and the * output column is multiply referenced in higher plan nodes. */ values[resind] = MakeExpandedObjectReadOnly(values[resind], isnull[resind], att[resind]->attlen); resind++; } MemoryContextSwitchTo(oldContext); /* * And return the virtual tuple. */ ExecStoreVirtualTuple(slot); }
/* ---------------------------------------------------------------- * ValuesNext * * This is a workhorse for ExecValuesScan * ---------------------------------------------------------------- */ static TupleTableSlot * ValuesNext(ValuesScanState *node) { TupleTableSlot *slot; EState *estate; ExprContext *econtext; ScanDirection direction; List *exprlist; /* * get information from the estate and scan state */ estate = node->ss.ps.state; direction = estate->es_direction; slot = node->ss.ss_ScanTupleSlot; econtext = node->rowcontext; /* * Get the next tuple. Return NULL if no more tuples. */ if (ScanDirectionIsForward(direction)) { if (node->curr_idx < node->array_len) node->curr_idx++; if (node->curr_idx < node->array_len) exprlist = node->exprlists[node->curr_idx]; else exprlist = NIL; } else { if (node->curr_idx >= 0) node->curr_idx--; if (node->curr_idx >= 0) exprlist = node->exprlists[node->curr_idx]; else exprlist = NIL; } /* * Always clear the result slot; this is appropriate if we are at the end * of the data, and if we're not, we still need it as the first step of * the store-virtual-tuple protocol. It seems wise to clear the slot * before we reset the context it might have pointers into. */ ExecClearTuple(slot); if (exprlist) { MemoryContext oldContext; List *oldsubplans; List *exprstatelist; Datum *values; bool *isnull; ListCell *lc; int resind; int saved_jit_flags; /* * Get rid of any prior cycle's leftovers. We use ReScanExprContext * not just ResetExprContext because we want any registered shutdown * callbacks to be called. */ ReScanExprContext(econtext); /* * Build the expression eval state in the econtext's per-tuple memory. * This is a tad unusual, but we want to delete the eval state again * when we move to the next row, to avoid growth of memory * requirements over a long values list. */ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); /* * The expressions might contain SubPlans (this is currently only * possible if there's a sub-select containing a LATERAL reference, * otherwise sub-selects in a VALUES list should be InitPlans). Those * subplans will want to hook themselves into our subPlan list, which * would result in a corrupted list after we delete the eval state. We * can work around this by saving and restoring the subPlan list. * (There's no need for the functionality that would be enabled by * having the list entries, since the SubPlans aren't going to be * re-executed anyway.) */ oldsubplans = node->ss.ps.subPlan; node->ss.ps.subPlan = NIL; /* * As the expressions are only ever used once, disable JIT for them. * This is worthwhile because it's common to insert significant * amounts of data via VALUES(). */ saved_jit_flags = econtext->ecxt_estate->es_jit_flags; econtext->ecxt_estate->es_jit_flags = PGJIT_NONE; exprstatelist = ExecInitExprList(exprlist, &node->ss.ps); econtext->ecxt_estate->es_jit_flags = saved_jit_flags; node->ss.ps.subPlan = oldsubplans; /* parser should have checked all sublists are the same length */ Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts); /* * Compute the expressions and build a virtual result tuple. We * already did ExecClearTuple(slot). */ values = slot->tts_values; isnull = slot->tts_isnull; resind = 0; foreach(lc, exprstatelist) { ExprState *estate = (ExprState *) lfirst(lc); Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor, resind); values[resind] = ExecEvalExpr(estate, econtext, &isnull[resind]); /* * We must force any R/W expanded datums to read-only state, in * case they are multiply referenced in the plan node's output * expressions, or in case we skip the output projection and the * output column is multiply referenced in higher plan nodes. */ values[resind] = MakeExpandedObjectReadOnly(values[resind], isnull[resind], attr->attlen); resind++; } MemoryContextSwitchTo(oldContext); /* * And return the virtual tuple. */ ExecStoreVirtualTuple(slot); }