Complain if a function-in-FROM returns a set when it shouldn't.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Mar 2021 23:54:55 +0000 (18:54 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Mar 2021 23:54:55 +0000 (18:54 -0500)
Throw a "function protocol violation" error if a function in FROM
tries to return a set though it wasn't marked proretset.  Although
such cases work at the moment, it doesn't seem like something we
want to guarantee will keep working.  Besides, there are other
negative consequences of not setting the proretset flag, such as
potentially bad plans.

No back-patch, since if there is any third-party code violating
this expectation, people wouldn't appreciate us breaking it in
a minor release.

Discussion: https://postgr.es/m/1636062.1615141782@sss.pgh.pa.us

src/backend/executor/execSRF.c

index 8aec3b549bdea91169ba4ce91fb7ac5a3a7ade3b..545b6c19dac7b8e7332ed3bd9049805cac533d53 100644 (file)
@@ -353,11 +353,21 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
                         */
                        if (rsinfo.isDone != ExprMultipleResult)
                                break;
+
+                       /*
+                        * Check that set-returning functions were properly declared.
+                        * (Note: for historical reasons, we don't complain if a non-SRF
+                        * returns ExprEndResult; that's treated as returning NULL.)
+                        */
+                       if (!returnsSet)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+                                                errmsg("table-function protocol for value-per-call mode was not followed")));
                }
                else if (rsinfo.returnMode == SFRM_Materialize)
                {
                        /* check we're on the same page as the function author */
-                       if (!first_time || rsinfo.isDone != ExprSingleResult)
+                       if (!first_time || rsinfo.isDone != ExprSingleResult || !returnsSet)
                                ereport(ERROR,
                                                (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
                                                 errmsg("table-function protocol for materialize mode was not followed")));