Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit45ae427

Browse files
committed
Fix index-only scan plans when not all index columns can be returned.
If an index has both returnable and non-returnable columns, and one ofthe non-returnable columns is an expression using a Var that is in areturnable column, then a query returning that expression could resultin an index-only scan plan that attempts to read the non-returnablecolumn, instead of recomputing the expression from the returnablecolumn as intended.To fix, redefine the "indextlist" list of an IndexOnlyScan plan nodeas containing null Consts in place of any non-returnable columns.This solves the problem by preventing setrefs.c from falsely matchingto such entries. The executor is happy since it only cares about theexposed types of the entries, and ruleutils.c doesn't care because acorrect plan won't reference those entries. I considered some otherways to prevent setrefs.c from doing the wrong thing, but this wayseems good since (a) it allows a very localized fix, (b) it makesthe indextlist structure more compact in many cases, and (c) theindextlist is now a more faithful representation of what the index AMwill actually produce, viz. nulls for any non-returnable columns.This is easier to hit since we introduced included columns, but it'spossible to construct failing examples without that, as per theadded regression test. Hence, back-patch to all supported branches.Per bug #17350 from Louis Jachiet.Discussion:https://postgr.es/m/17350-b5bdcf476e5badbb@postgresql.org
1 parentcadd98c commit45ae427

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

‎src/backend/optimizer/plan/createplan.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include<math.h>
2121

2222
#include"access/sysattr.h"
23+
#include"catalog/pg_am.h"
2324
#include"catalog/pg_class.h"
2425
#include"foreign/fdwapi.h"
2526
#include"miscadmin.h"
@@ -183,6 +184,7 @@ static IndexOnlyScan *make_indexonlyscan(List *qptlist, List *qpqual,
183184
List*indexqual,List*indexorderby,
184185
List*indextlist,
185186
ScanDirectionindexscandir);
187+
staticList*make_indexonly_tlist(IndexOptInfo*indexinfo);
186188
staticBitmapIndexScan*make_bitmap_indexscan(Indexscanrelid,Oidindexid,
187189
List*indexqual,
188190
List*indexqualorig);
@@ -600,7 +602,7 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
600602
if (best_path->pathtype==T_IndexOnlyScan)
601603
{
602604
/* For index-only scan, the preferred tlist is the index's */
603-
tlist=copyObject(((IndexPath*)best_path)->indexinfo->indextlist);
605+
tlist=copyObject(make_indexonly_tlist(((IndexPath*)best_path)->indexinfo));
604606

605607
/*
606608
* Transfer sortgroupref data to the replacement tlist, if
@@ -2982,7 +2984,7 @@ create_indexscan_plan(PlannerInfo *root,
29822984
indexoid,
29832985
fixed_indexquals,
29842986
fixed_indexorderbys,
2985-
best_path->indexinfo->indextlist,
2987+
make_indexonly_tlist(best_path->indexinfo),
29862988
best_path->indexscandir);
29872989
else
29882990
scan_plan= (Scan*)make_indexscan(tlist,
@@ -5309,6 +5311,53 @@ make_indexonlyscan(List *qptlist,
53095311
returnnode;
53105312
}
53115313

5314+
/*
5315+
* make_indexonly_tlist
5316+
*
5317+
* Construct the indextlist for an IndexOnlyScan plan node.
5318+
* We must replace any column that can't be returned by the index AM
5319+
* with a null Const of the appropriate datatype. This is necessary
5320+
* to prevent setrefs.c from trying to use the value of such a column,
5321+
* and anyway it makes the indextlist a better representative of what
5322+
* the indexscan will really return. (We do this here, not where the
5323+
* IndexOptInfo is originally constructed, because earlier planner
5324+
* steps need to know what is in such columns.)
5325+
*/
5326+
staticList*
5327+
make_indexonly_tlist(IndexOptInfo*indexinfo)
5328+
{
5329+
List*result;
5330+
inti;
5331+
ListCell*lc;
5332+
5333+
/* We needn't work hard for the common case of btrees. */
5334+
if (indexinfo->relam==BTREE_AM_OID)
5335+
returnindexinfo->indextlist;
5336+
5337+
result=NIL;
5338+
i=0;
5339+
foreach(lc,indexinfo->indextlist)
5340+
{
5341+
TargetEntry*indextle= (TargetEntry*)lfirst(lc);
5342+
5343+
if (indexinfo->canreturn[i])
5344+
result=lappend(result,indextle);
5345+
else
5346+
{
5347+
TargetEntry*newtle=makeNode(TargetEntry);
5348+
Node*texpr= (Node*)indextle->expr;
5349+
5350+
memcpy(newtle,indextle,sizeof(TargetEntry));
5351+
newtle->expr= (Expr*)makeNullConst(exprType(texpr),
5352+
exprTypmod(texpr),
5353+
exprCollation(texpr));
5354+
result=lappend(result,newtle);
5355+
}
5356+
i++;
5357+
}
5358+
returnresult;
5359+
}
5360+
53125361
staticBitmapIndexScan*
53135362
make_bitmap_indexscan(Indexscanrelid,
53145363
Oidindexid,

‎src/include/nodes/plannodes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,8 @@ typedef struct IndexScan
425425
* indextlist, which represents the contents of the index as a targetlist
426426
* with one TLE per index column. Vars appearing in this list reference
427427
* the base table, and this is the only field in the plan node that may
428-
* contain such Vars.
428+
* contain such Vars. Note however that index columns that the AM can't
429+
* reconstruct are replaced by null Consts in indextlist.
429430
* ----------------
430431
*/
431432
typedefstructIndexOnlyScan

‎src/test/regress/expected/gist.out

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,34 @@ and p <@ box(point(5,5), point(6, 6));
312312
(11 rows)
313313

314314
drop index gist_tbl_multi_index;
315+
-- Test that we don't try to return the value of a non-returnable
316+
-- column in an index-only scan. (This isn't GIST-specific, but
317+
-- it only applies to index AMs that can return some columns and not
318+
-- others, so GIST with appropriate opclasses is a convenient test case.)
319+
create index gist_tbl_multi_index on gist_tbl using gist (circle(p,1), p);
320+
explain (verbose, costs off)
321+
select circle(p,1) from gist_tbl
322+
where p <@ box(point(5, 5), point(5.3, 5.3));
323+
QUERY PLAN
324+
---------------------------------------------------------------
325+
Index Only Scan using gist_tbl_multi_index on public.gist_tbl
326+
Output: circle(p, '1'::double precision)
327+
Index Cond: (gist_tbl.p <@ '(5.3,5.3),(5,5)'::box)
328+
(3 rows)
329+
330+
select circle(p,1) from gist_tbl
331+
where p <@ box(point(5, 5), point(5.3, 5.3));
332+
circle
333+
-----------------
334+
<(5,5),1>
335+
<(5.05,5.05),1>
336+
<(5.1,5.1),1>
337+
<(5.15,5.15),1>
338+
<(5.2,5.2),1>
339+
<(5.25,5.25),1>
340+
<(5.3,5.3),1>
341+
(7 rows)
342+
315343
-- Clean up
316344
reset enable_seqscan;
317345
reset enable_bitmapscan;

‎src/test/regress/sql/gist.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ and p <@ box(point(5,5), point(6, 6));
142142

143143
dropindex gist_tbl_multi_index;
144144

145+
-- Test that we don't try to return the value of a non-returnable
146+
-- column in an index-only scan. (This isn't GIST-specific, but
147+
-- it only applies to index AMs that can return some columns and not
148+
-- others, so GIST with appropriate opclasses is a convenient test case.)
149+
createindexgist_tbl_multi_indexon gist_tbl using gist (circle(p,1), p);
150+
explain (verbose, costs off)
151+
selectcircle(p,1)from gist_tbl
152+
where p<@box(point(5,5),point(5.3,5.3));
153+
selectcircle(p,1)from gist_tbl
154+
where p<@box(point(5,5),point(5.3,5.3));
155+
145156
-- Clean up
146157
reset enable_seqscan;
147158
reset enable_bitmapscan;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp