There are two places where we currently set CURSOR_OPT_PARALLEL_OK in PL/pgsql: exec_stmt_return_query() sets it when calling exec_dynquery_with_params(), and exec_run_select() calls it when calling exec_prepare_plan() if parallelOK is set. The latter is OK, because exec_run_select() runs the plan via SPI_execute_plan_with_paramlist(), which calls _SPI_execute_plan(), which calls _SPI_pquery(). But the former is broken, because exec_stmt_return_query() executes the query by calling SPI_cursor_fetch() with a fetch count of 50, and that calls _SPI_cursor_operation() which calls PortalRunFetch() -- and of course each call to PortalRunFetch() is going to cause a separate call to PortalRunSelect(), resulting in a separate call to ExecutorRun(). Oops.
Fixed. The attached patch is over execute_once.patch [1].
I haven't addressed the issue regarding the confusion I raised upthread about incorrect value of !es->lazyeval that is restricting parallelism for simple queries coming from sql functions, as I am not sure if it is the concern of this patch or not.