#include <math.h>
#include "access/sysattr.h"
+#include "catalog/pg_am.h"
#include "catalog/pg_class.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
List *indexqual, List *indexorderby,
List *indextlist,
ScanDirection indexscandir);
+static List *make_indexonly_tlist(IndexOptInfo *indexinfo);
static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
List *indexqual,
List *indexqualorig);
if (best_path->pathtype == T_IndexOnlyScan)
{
/* For index-only scan, the preferred tlist is the index's */
- tlist = copyObject(((IndexPath *) best_path)->indexinfo->indextlist);
+ tlist = copyObject(make_indexonly_tlist(((IndexPath *) best_path)->indexinfo));
/*
* Transfer sortgroupref data to the replacement tlist, if
indexoid,
fixed_indexquals,
fixed_indexorderbys,
- best_path->indexinfo->indextlist,
+ make_indexonly_tlist(best_path->indexinfo),
best_path->indexscandir);
else
scan_plan = (Scan *) make_indexscan(tlist,
return node;
}
+/*
+ * make_indexonly_tlist
+ *
+ * Construct the indextlist for an IndexOnlyScan plan node.
+ * We must replace any column that can't be returned by the index AM
+ * with a null Const of the appropriate datatype. This is necessary
+ * to prevent setrefs.c from trying to use the value of such a column,
+ * and anyway it makes the indextlist a better representative of what
+ * the indexscan will really return. (We do this here, not where the
+ * IndexOptInfo is originally constructed, because earlier planner
+ * steps need to know what is in such columns.)
+ */
+static List *
+make_indexonly_tlist(IndexOptInfo *indexinfo)
+{
+ List *result;
+ int i;
+ ListCell *lc;
+
+ /* We needn't work hard for the common case of btrees. */
+ if (indexinfo->relam == BTREE_AM_OID)
+ return indexinfo->indextlist;
+
+ result = NIL;
+ i = 0;
+ foreach(lc, indexinfo->indextlist)
+ {
+ TargetEntry *indextle = (TargetEntry *) lfirst(lc);
+
+ if (indexinfo->canreturn[i])
+ result = lappend(result, indextle);
+ else
+ {
+ TargetEntry *newtle = makeNode(TargetEntry);
+ Node *texpr = (Node *) indextle->expr;
+
+ memcpy(newtle, indextle, sizeof(TargetEntry));
+ newtle->expr = (Expr *) makeNullConst(exprType(texpr),
+ exprTypmod(texpr),
+ exprCollation(texpr));
+ result = lappend(result, newtle);
+ }
+ i++;
+ }
+ return result;
+}
+
static BitmapIndexScan *
make_bitmap_indexscan(Index scanrelid,
Oid indexid,
(11 rows)
drop index gist_tbl_multi_index;
+-- Test that we don't try to return the value of a non-returnable
+-- column in an index-only scan. (This isn't GIST-specific, but
+-- it only applies to index AMs that can return some columns and not
+-- others, so GIST with appropriate opclasses is a convenient test case.)
+create index gist_tbl_multi_index on gist_tbl using gist (circle(p,1), p);
+explain (verbose, costs off)
+select circle(p,1) from gist_tbl
+where p <@ box(point(5, 5), point(5.3, 5.3));
+ QUERY PLAN
+---------------------------------------------------------------
+ Index Only Scan using gist_tbl_multi_index on public.gist_tbl
+ Output: circle(p, '1'::double precision)
+ Index Cond: (gist_tbl.p <@ '(5.3,5.3),(5,5)'::box)
+(3 rows)
+
+select circle(p,1) from gist_tbl
+where p <@ box(point(5, 5), point(5.3, 5.3));
+ circle
+-----------------
+ <(5,5),1>
+ <(5.05,5.05),1>
+ <(5.1,5.1),1>
+ <(5.15,5.15),1>
+ <(5.2,5.2),1>
+ <(5.25,5.25),1>
+ <(5.3,5.3),1>
+(7 rows)
+
-- Clean up
reset enable_seqscan;
reset enable_bitmapscan;
drop index gist_tbl_multi_index;
+-- Test that we don't try to return the value of a non-returnable
+-- column in an index-only scan. (This isn't GIST-specific, but
+-- it only applies to index AMs that can return some columns and not
+-- others, so GIST with appropriate opclasses is a convenient test case.)
+create index gist_tbl_multi_index on gist_tbl using gist (circle(p,1), p);
+explain (verbose, costs off)
+select circle(p,1) from gist_tbl
+where p <@ box(point(5, 5), point(5.3, 5.3));
+select circle(p,1) from gist_tbl
+where p <@ box(point(5, 5), point(5.3, 5.3));
+
-- Clean up
reset enable_seqscan;
reset enable_bitmapscan;