SQLFunctionCachePtr fcache;
    List       *raw_parsetree_list;
    List       *queryTree_list;
-   List       *flat_query_list;
    List       *resulttlist;
    ListCell   *lc;
    Datum       tmp;
 
    /*
     * Parse and rewrite the queries in the function text.  Use sublists to
-    * keep track of the original query boundaries.  But we also build a
-    * "flat" list of the rewritten queries to pass to check_sql_fn_retval.
-    * This is because the last canSetTag query determines the result type
-    * independently of query boundaries --- and it might not be in the last
-    * sublist, for example if the last query rewrites to DO INSTEAD NOTHING.
-    * (It might not be unreasonable to throw an error in such a case, but
-    * this is the historical behavior and it doesn't seem worth changing.)
+    * keep track of the original query boundaries.
     *
     * Note: since parsing and planning is done in fcontext, we will generate
     * a lot of cruft that lives as long as the fcache does.  This is annoying
    raw_parsetree_list = pg_parse_query(fcache->src);
 
    queryTree_list = NIL;
-   flat_query_list = NIL;
    foreach(lc, raw_parsetree_list)
    {
        RawStmt    *parsetree = lfirst_node(RawStmt, lc);
                                                          fcache->pinfo,
                                                          NULL);
        queryTree_list = lappend(queryTree_list, queryTree_sublist);
-       flat_query_list = list_concat(flat_query_list, queryTree_sublist);
    }
 
-   check_sql_fn_statements(flat_query_list);
+   /*
+    * Check that there are no statements we don't want to allow.
+    */
+   check_sql_fn_statements(queryTree_list);
 
    /*
     * Check that the function returns the type it claims to.  Although in
     * the rowtype column into multiple columns, since we have no way to
     * notify the caller that it should do that.)
     */
-   fcache->returnsTuple = check_sql_fn_retval(flat_query_list,
+   fcache->returnsTuple = check_sql_fn_retval(queryTree_list,
                                               rettype,
                                               rettupdesc,
                                               false,
  * is not acceptable.
  */
 void
-check_sql_fn_statements(List *queryTreeList)
+check_sql_fn_statements(List *queryTreeLists)
 {
    ListCell   *lc;
 
-   foreach(lc, queryTreeList)
+   /* We are given a list of sublists of Queries */
+   foreach(lc, queryTreeLists)
    {
-       Query      *query = lfirst_node(Query, lc);
+       List       *sublist = lfirst_node(List, lc);
+       ListCell   *lc2;
 
-       /*
-        * Disallow procedures with output arguments.  The current
-        * implementation would just throw the output values away, unless the
-        * statement is the last one.  Per SQL standard, we should assign the
-        * output values by name.  By disallowing this here, we preserve an
-        * opportunity for future improvement.
-        */
-       if (query->commandType == CMD_UTILITY &&
-           IsA(query->utilityStmt, CallStmt))
+       foreach(lc2, sublist)
        {
-           CallStmt   *stmt = castNode(CallStmt, query->utilityStmt);
-           HeapTuple   tuple;
-           int         numargs;
-           Oid        *argtypes;
-           char      **argnames;
-           char       *argmodes;
-           int         i;
-
-           tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(stmt->funcexpr->funcid));
-           if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "cache lookup failed for function %u", stmt->funcexpr->funcid);
-           numargs = get_func_arg_info(tuple, &argtypes, &argnames, &argmodes);
-           ReleaseSysCache(tuple);
-
-           for (i = 0; i < numargs; i++)
+           Query      *query = lfirst_node(Query, lc2);
+
+           /*
+            * Disallow procedures with output arguments.  The current
+            * implementation would just throw the output values away, unless
+            * the statement is the last one.  Per SQL standard, we should
+            * assign the output values by name.  By disallowing this here, we
+            * preserve an opportunity for future improvement.
+            */
+           if (query->commandType == CMD_UTILITY &&
+               IsA(query->utilityStmt, CallStmt))
            {
-               if (argmodes && (argmodes[i] == PROARGMODE_INOUT || argmodes[i] == PROARGMODE_OUT))
-                   ereport(ERROR,
-                           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                            errmsg("calling procedures with output arguments is not supported in SQL functions")));
+               CallStmt   *stmt = castNode(CallStmt, query->utilityStmt);
+               HeapTuple   tuple;
+               int         numargs;
+               Oid        *argtypes;
+               char      **argnames;
+               char       *argmodes;
+               int         i;
+
+               tuple = SearchSysCache1(PROCOID,
+                                       ObjectIdGetDatum(stmt->funcexpr->funcid));
+               if (!HeapTupleIsValid(tuple))
+                   elog(ERROR, "cache lookup failed for function %u",
+                        stmt->funcexpr->funcid);
+               numargs = get_func_arg_info(tuple,
+                                           &argtypes, &argnames, &argmodes);
+               ReleaseSysCache(tuple);
+
+               for (i = 0; i < numargs; i++)
+               {
+                   if (argmodes && (argmodes[i] == PROARGMODE_INOUT ||
+                                    argmodes[i] == PROARGMODE_OUT))
+                       ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("calling procedures with output arguments is not supported in SQL functions")));
+               }
            }
        }
    }
 }
 
 /*
- * check_sql_fn_retval() -- check return value of a list of sql parse trees.
+ * check_sql_fn_retval()
+ *     Check return value of a list of lists of sql parse trees.
  *
  * The return value of a sql function is the value returned by the last
  * canSetTag query in the function.  We do some ad-hoc type checking and
  * function is defined to return VOID then *resultTargetList is set to NIL.
  */
 bool
-check_sql_fn_retval(List *queryTreeList,
+check_sql_fn_retval(List *queryTreeLists,
                    Oid rettype, TupleDesc rettupdesc,
                    bool insertDroppedCols,
                    List **resultTargetList)
        return false;
 
    /*
-    * Find the last canSetTag query in the list.  This isn't necessarily the
-    * last parsetree, because rule rewriting can insert queries after what
-    * the user wrote.
+    * Find the last canSetTag query in the function body (which is presented
+    * to us as a list of sublists of Query nodes).  This isn't necessarily
+    * the last parsetree, because rule rewriting can insert queries after
+    * what the user wrote.  Note that it might not even be in the last
+    * sublist, for example if the last query rewrites to DO INSTEAD NOTHING.
+    * (It might not be unreasonable to throw an error in such a case, but
+    * this is the historical behavior and it doesn't seem worth changing.)
     */
    parse = NULL;
    parse_cell = NULL;
-   foreach(lc, queryTreeList)
+   foreach(lc, queryTreeLists)
    {
-       Query      *q = lfirst_node(Query, lc);
+       List       *sublist = lfirst_node(List, lc);
+       ListCell   *lc2;
 
-       if (q->canSetTag)
+       foreach(lc2, sublist)
        {
-           parse = q;
-           parse_cell = lc;
+           Query      *q = lfirst_node(Query, lc2);
+
+           if (q->canSetTag)
+           {
+               parse = q;
+               parse_cell = lc2;
+           }
        }
    }