+static int
+exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
+ Portal portal, bool prefetch_ok)
+{
+ PLpgSQL_rec *rec = NULL;
+ PLpgSQL_row *row = NULL;
+ SPITupleTable *tuptab;
+ bool found = false;
+ int rc = PLPGSQL_RC_OK;
+ int n;
+
+ /*
+ * Determine if we assign to a record or a row
+ */
+ if (stmt->rec != NULL)
+ rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->dno]);
+ else if (stmt->row != NULL)
+ row = (PLpgSQL_row *) (estate->datums[stmt->row->dno]);
+ else
+ elog(ERROR, "unsupported target");
+
+ /*
+ * Fetch the initial tuple(s). If prefetching is allowed then we grab
+ * a few more rows to avoid multiple trips through executor startup
+ * overhead.
+ */
+ SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
+ tuptab = SPI_tuptable;
+ n = SPI_processed;
+
+ /*
+ * If the query didn't return any rows, set the target to NULL and
+ * fall through with found = false.
+ */
+ if (n <= 0)
+ exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
+ else
+ found = true; /* processed at least one tuple */
+
+ /*
+ * Now do the loop
+ */
+ while (n > 0)
+ {
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ /*
+ * Assign the tuple to the target
+ */
+ exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc);
+
+ /*
+ * Execute the statements
+ */
+ rc = exec_stmts(estate, stmt->body);
+
+ if (rc != PLPGSQL_RC_OK)
+ {
+ if (rc == PLPGSQL_RC_EXIT)
+ {
+ if (estate->exitlabel == NULL)
+ {
+ /* unlabelled exit, so exit the current loop */
+ rc = PLPGSQL_RC_OK;
+ }
+ else if (stmt->label != NULL &&
+ strcmp(stmt->label, estate->exitlabel) == 0)
+ {
+ /* label matches this loop, so exit loop */
+ estate->exitlabel = NULL;
+ rc = PLPGSQL_RC_OK;
+ }
+
+ /*
+ * otherwise, we processed a labelled exit that does not
+ * match the current statement's label, if any; return
+ * RC_EXIT so that the EXIT continues to recurse upward.
+ */
+ }
+ else if (rc == PLPGSQL_RC_CONTINUE)
+ {
+ if (estate->exitlabel == NULL)
+ {
+ /* unlabelled continue, so re-run the current loop */
+ rc = PLPGSQL_RC_OK;
+ continue;
+ }
+ else if (stmt->label != NULL &&
+ strcmp(stmt->label, estate->exitlabel) == 0)
+ {
+ /* label matches this loop, so re-run loop */
+ estate->exitlabel = NULL;
+ rc = PLPGSQL_RC_OK;
+ continue;
+ }
+
+ /*
+ * otherwise, we process a labelled continue that does not
+ * match the current statement's label, if any; return
+ * RC_CONTINUE so that the CONTINUE will propagate up the
+ * stack.
+ */
+ }
+
+ /*
+ * We're aborting the loop. Need a goto to get out of two
+ * levels of loop...
+ */
+ goto loop_exit;
+ }
+ }
+
+ SPI_freetuptable(tuptab);
+
+ /*
+ * Fetch more tuples. If prefetching is allowed, grab 50 at a time.
+ */
+ SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
+ tuptab = SPI_tuptable;
+ n = SPI_processed;
+ }
+
+loop_exit:
+
+ /*
+ * Release last group of tuples (if any)
+ */
+ SPI_freetuptable(tuptab);
+
+ /*
+ * Set the FOUND variable to indicate the result of executing the loop
+ * (namely, whether we looped one or more times). This must be set last so
+ * that it does not interfere with the value of the FOUND variable inside
+ * the loop processing itself.
+ */
+ exec_set_found(estate, found);
+
+ return rc;
+}
+
+
+/* ----------
+ * exec_eval_simple_expr - Evaluate a simple expression returning
+ * a Datum by directly calling ExecEvalExpr().
+ *
+ * If successful, store results into *result, *isNull, *rettype and return
+ * TRUE. If the expression is not simple (any more), return FALSE.
+ *
+ * It is possible though unlikely for a simple expression to become non-simple
+ * (consider for example redefining a trivial view). We must handle that for
+ * correctness; fortunately it's normally inexpensive to do
+ * RevalidateCachedPlan on a simple expression. We do not consider the other
+ * direction (non-simple expression becoming simple) because we'll still give
+ * correct results if that happens, and it's unlikely to be worth the cycles
+ * to check.
+ *
+ * Note: if pass-by-reference, the result is in the eval_econtext's
+ * temporary memory context. It will be freed when exec_eval_cleanup
+ * is done.
+ * ----------
+ */
+static bool
+exec_eval_simple_expr(PLpgSQL_execstate *estate,
+ PLpgSQL_expr *expr,
+ Datum *result,
+ bool *isNull,