Hi hackers!

Experimenting with the new pluggable storage API, I found that amcanbackward
flag is not checked in build_index_paths() before
build_index_pathkeys(... BackwardScanDirection) call when we are building
paths for ORDER BY.  And this flag is even not copied into IndexOptInfo struct.
Obviously, this can lead to misuse of Backward Index [Only] Scan plans.

Attached patch with the corresponding fix.

There are no test cases because now only btree supports ordered scans but it
supports backward scans too.

--
Nikita Glukhov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

>From 2bb9a17a8efb166339bcd5618157728a4b596430 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.glu...@postgrespro.ru>
Date: Sun, 13 May 2018 16:37:00 +0300
Subject: [PATCH] Disable backward scans on indices that do not support it

---
 src/backend/optimizer/path/indxpath.c | 2 +-
 src/backend/optimizer/util/plancat.c  | 1 +
 src/include/nodes/relation.h          | 1 +
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index f295558..caa688c 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1084,7 +1084,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 	/*
 	 * 5. If the index is ordered, a backwards scan might be interesting.
 	 */
-	if (index_is_ordered && pathkeys_possibly_useful)
+	if (index_is_ordered && pathkeys_possibly_useful && index->amcanbackward)
 	{
 		index_pathkeys = build_index_pathkeys(root, index,
 											  BackwardScanDirection);
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 8369e3a..470d38e 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -271,6 +271,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 			info->amsearcharray = amroutine->amsearcharray;
 			info->amsearchnulls = amroutine->amsearchnulls;
 			info->amcanparallel = amroutine->amcanparallel;
+			info->amcanbackward = amroutine->amcanbackward;
 			info->amhasgettuple = (amroutine->amgettuple != NULL);
 			info->amhasgetbitmap = (amroutine->amgetbitmap != NULL);
 			info->amcostestimate = amroutine->amcostestimate;
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 3b28d19..593ee48 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -798,6 +798,7 @@ typedef struct IndexOptInfo
 	bool		amhasgettuple;	/* does AM have amgettuple interface? */
 	bool		amhasgetbitmap; /* does AM have amgetbitmap interface? */
 	bool		amcanparallel;	/* does AM support parallel scan? */
+	bool		amcanbackward;	/* does AM support backward scan? */
 	/* Rather than include amapi.h here, we declare amcostestimate like this */
 	void		(*amcostestimate) ();	/* AM's cost estimator */
 } IndexOptInfo;
-- 
2.7.4

Reply via email to