From 48c348f86ce09c668af7cf271757c3f156f28344 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 18 Nov 2010 11:53:49 -0500
Subject: [PATCH] Dept of second thoughts: don't try to push LIMIT below a SRF.

If we have Limit->Result->Sort, the Result might be projecting a tlist
that contains a set-returning function.  If so, it's possible for the
SRF to sometimes return zero rows, which means we could need to fetch
more than N rows from the Sort in order to satisfy LIMIT N.
So top-N sorting cannot be used in this scenario.
---
 src/backend/executor/nodeLimit.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 5ed8664f66f..c939752f37a 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -23,6 +23,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeLimit.h"
+#include "nodes/nodeFuncs.h"
 
 static void recompute_limits(LimitState *node);
 static void pass_down_bound(LimitState *node, PlanState *child_node);
@@ -344,7 +345,19 @@ pass_down_bound(LimitState *node, PlanState *child_node)
 	}
 	else if (IsA(child_node, ResultState))
 	{
-		if (outerPlanState(child_node))
+		/*
+		 * An extra consideration here is that if the Result is projecting
+		 * a targetlist that contains any SRFs, we can't assume that every
+		 * input tuple generates an output tuple, so a Sort underneath
+		 * might need to return more than N tuples to satisfy LIMIT N.
+		 * So we cannot use bounded sort.
+		 *
+		 * If Result supported qual checking, we'd have to punt on seeing
+		 * a qual, too.  Note that having a resconstantqual is not a
+		 * showstopper: if that fails we're not getting any rows at all.
+		 */
+		if (outerPlanState(child_node) &&
+			!expression_returns_set((Node *) child_node->plan->targetlist))
 			pass_down_bound(node, outerPlanState(child_node));
 	}
 }
-- 
GitLab