From 46a0eee3006b11a15b73426c8146ed5ab32e1d62 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 28 Aug 2005 22:47:20 +0000
Subject: [PATCH] Tweak nodeBitmapAnd to stop evaluating sub-plan scans if it
 finds it's got an empty bitmap after any step; the remaining subplans can no
 longer affect the result.  Per a suggestion from Ilia Kantor.

---
 src/backend/executor/nodeBitmapAnd.c  | 12 +++++++++++-
 src/backend/nodes/tidbitmap.c         | 11 ++++++++++-
 src/backend/optimizer/path/indxpath.c |  7 ++++++-
 src/include/nodes/tidbitmap.h         |  4 +++-
 4 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c
index 1d5d94fc3f8..939062d4d6c 100644
--- a/src/backend/executor/nodeBitmapAnd.c
+++ b/src/backend/executor/nodeBitmapAnd.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.2 2005/04/20 15:48:36 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.3 2005/08/28 22:47:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -143,6 +143,16 @@ MultiExecBitmapAnd(BitmapAndState *node)
 			tbm_intersect(result, subresult);
 			tbm_free(subresult);
 		}
+
+		/*
+		 * If at any stage we have a completely empty bitmap, we can fall
+		 * out without evaluating the remaining subplans, since ANDing them
+		 * can no longer change the result.  (Note: the fact that indxpath.c
+		 * orders the subplans by selectivity should make this case more
+		 * likely to occur.)
+		 */
+		if (tbm_is_empty(result))
+			break;
 	}
 
 	if (result == NULL)
diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c
index 777bf6482d2..e36a8d9806a 100644
--- a/src/backend/nodes/tidbitmap.c
+++ b/src/backend/nodes/tidbitmap.c
@@ -23,7 +23,7 @@
  * Copyright (c) 2003-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.5 2005/07/24 02:25:26 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.6 2005/08/28 22:47:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -510,6 +510,15 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
 	}
 }
 
+/*
+ * tbm_is_empty - is a TIDBitmap completely empty?
+ */
+bool
+tbm_is_empty(const TIDBitmap *tbm)
+{
+	return (tbm->nentries == 0);
+}
+
 /*
  * tbm_begin_iterate - prepare to iterate through a TIDBitmap
  *
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index bd0b09fcfe9..c689d1461e9 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.187 2005/07/28 20:26:20 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.188 2005/08/28 22:47:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -538,6 +538,11 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
 	 * cases, the partial index will sort before competing non-partial
 	 * indexes and so it makes the right choice, but perhaps we need to
 	 * work harder.
+	 *
+	 * Note: outputting the selected sub-paths in selectivity order is a good
+	 * thing even if we weren't using that as part of the selection method,
+	 * because it makes the short-circuit case in MultiExecBitmapAnd() more
+	 * likely to apply.
 	 */
 
 	/* Convert list to array so we can apply qsort */
diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h
index 2c90c01d815..ea5673e6f27 100644
--- a/src/include/nodes/tidbitmap.h
+++ b/src/include/nodes/tidbitmap.h
@@ -15,7 +15,7 @@
  *
  * Copyright (c) 2003-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/nodes/tidbitmap.h,v 1.1 2005/04/17 22:24:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/tidbitmap.h,v 1.2 2005/08/28 22:47:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,6 +49,8 @@ extern void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids);
 extern void tbm_union(TIDBitmap *a, const TIDBitmap *b);
 extern void tbm_intersect(TIDBitmap *a, const TIDBitmap *b);
 
+extern bool tbm_is_empty(const TIDBitmap *tbm);
+
 extern void tbm_begin_iterate(TIDBitmap *tbm);
 extern TBMIterateResult *tbm_iterate(TIDBitmap *tbm);
 
-- 
GitLab