Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e4fb8ff

Browse files
committed
Add a new column to pg_am to specify whether an index AM supports backward
scanning; GiST and GIN do not, and it seems like too much trouble to make them do so. By teaching ExecSupportsBackwardScan() about this restriction, we ensure that the planner will protect a scroll cursor from the problem by adding a Materialize node. In passing, fix another longstanding bug in the same area: backwards scan of a plan with set-returning functions in the targetlist did not work either, since the TupFromTlist expansion code pays no attention to direction (and has no way to run a SRF backwards anyway). Again the fix is to make ExecSupportsBackwardScan check this restriction. Also adjust the index AM API specification to note that mark/restore support is unnecessary if the AM can't produce ordered output.
1 parent 2a64931 commit e4fb8ff

File tree

5 files changed

+119
-42
lines changed

5 files changed

+119
-42
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.178 2008/10/06 13:59:37 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.179 2008/10/17 22:10:29 tgl Exp $ -->
22
<!--
33
Documentation of the system catalogs, directed toward PostgreSQL developers
44
-->
@@ -401,6 +401,13 @@
401401
<entry>Does the access method support ordered scans?</entry>
402402
</row>
403403

404+
<row>
405+
<entry><structfield>amcanbackward</structfield></entry>
406+
<entry><type>bool</type></entry>
407+
<entry></entry>
408+
<entry>Does the access method support backward scanning?</entry>
409+
</row>
410+
404411
<row>
405412
<entry><structfield>amcanunique</structfield></entry>
406413
<entry><type>bool</type></entry>

doc/src/sgml/indexam.sgml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.27 2008/08/14 18:47:58 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.28 2008/10/17 22:10:29 tgl Exp $ -->
22

33
<chapter id="indexam">
44
<title>Index Access Method Interface Definition</title>
@@ -474,15 +474,20 @@ amrestrpos (IndexScanDesc scan);
474474
normally would. (This will only occur for access
475475
methods that advertise they support ordered scans.) After the
476476
first call, <function>amgettuple</> must be prepared to advance the scan in
477-
either direction from the most recently returned entry.
477+
either direction from the most recently returned entry. (But if
478+
<structname>pg_am</>.<structfield>amcanbackward</> is false, all subsequent
479+
calls will have the same direction as the first one.)
478480
</para>
479481

480482
<para>
481-
The access method must support <quote>marking</> a position in a scan
482-
and later returning to the marked position. The same position might be
483-
restored multiple times. However, only one position need be remembered
484-
per scan; a new <function>ammarkpos</> call overrides the previously
485-
marked position.
483+
Access methods that support ordered scans must support <quote>marking</> a
484+
position in a scan and later returning to the marked position. The same
485+
position might be restored multiple times. However, only one position need
486+
be remembered per scan; a new <function>ammarkpos</> call overrides the
487+
previously marked position. An access method that does not support
488+
ordered scans should still provide mark and restore functions in
489+
<structname>pg_am</>, but it is sufficient to have them throw errors if
490+
called.
486491
</para>
487492

488493
<para>

src/backend/executor/execAmi.c

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.99 2008/10/04 21:56:53 tgl Exp $
9+
* $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.100 2008/10/17 22:10:29 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -42,6 +42,12 @@
4242
#include "executor/nodeValuesscan.h"
4343
#include "executor/nodeCtescan.h"
4444
#include "executor/nodeWorktablescan.h"
45+
#include "nodes/nodeFuncs.h"
46+
#include "utils/syscache.h"
47+
48+
49+
static bool TargetListSupportsBackwardScan(List *targetlist);
50+
static bool IndexSupportsBackwardScan(Oid indexid);
4551

4652

4753
/*
@@ -390,7 +396,8 @@ ExecSupportsBackwardScan(Plan *node)
390396
{
391397
case T_Result:
392398
if (outerPlan(node) != NULL)
393-
return ExecSupportsBackwardScan(outerPlan(node));
399+
return ExecSupportsBackwardScan(outerPlan(node)) &&
400+
TargetListSupportsBackwardScan(node->targetlist);
394401
else
395402
return false;
396403

@@ -403,29 +410,85 @@ ExecSupportsBackwardScan(Plan *node)
403410
if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
404411
return false;
405412
}
413+
/* need not check tlist because Append doesn't evaluate it */
406414
return true;
407415
}
408416

409417
case T_SeqScan:
410-
case T_IndexScan:
411418
case T_TidScan:
412419
case T_FunctionScan:
413420
case T_ValuesScan:
414421
case T_CteScan:
415422
case T_WorkTableScan:
416-
return true;
423+
return TargetListSupportsBackwardScan(node->targetlist);
424+
425+
case T_IndexScan:
426+
return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) &&
427+
TargetListSupportsBackwardScan(node->targetlist);
417428

418429
case T_SubqueryScan:
419-
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
430+
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
431+
TargetListSupportsBackwardScan(node->targetlist);
420432

421433
case T_Material:
422434
case T_Sort:
435+
/* these don't evaluate tlist */
423436
return true;
424437

425438
case T_Limit:
439+
/* doesn't evaluate tlist */
426440
return ExecSupportsBackwardScan(outerPlan(node));
427441

428442
default:
429443
return false;
430444
}
431445
}
446+
447+
/*
448+
* If the tlist contains set-returning functions, we can't support backward
449+
* scan, because the TupFromTlist code is direction-ignorant.
450+
*/
451+
static bool
452+
TargetListSupportsBackwardScan(List *targetlist)
453+
{
454+
if (expression_returns_set((Node *) targetlist))
455+
return false;
456+
return true;
457+
}
458+
459+
/*
460+
* An IndexScan node supports backward scan only if the index's AM does.
461+
*/
462+
static bool
463+
IndexSupportsBackwardScan(Oid indexid)
464+
{
465+
bool result;
466+
HeapTuple ht_idxrel;
467+
HeapTuple ht_am;
468+
Form_pg_class idxrelrec;
469+
Form_pg_am amrec;
470+
471+
/* Fetch the pg_class tuple of the index relation */
472+
ht_idxrel = SearchSysCache(RELOID,
473+
ObjectIdGetDatum(indexid),
474+
0, 0, 0);
475+
if (!HeapTupleIsValid(ht_idxrel))
476+
elog(ERROR, "cache lookup failed for relation %u", indexid);
477+
idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
478+
479+
/* Fetch the pg_am tuple of the index' access method */
480+
ht_am = SearchSysCache(AMOID,
481+
ObjectIdGetDatum(idxrelrec->relam),
482+
0, 0, 0);
483+
if (!HeapTupleIsValid(ht_am))
484+
elog(ERROR, "cache lookup failed for access method %u",
485+
idxrelrec->relam);
486+
amrec = (Form_pg_am) GETSTRUCT(ht_am);
487+
488+
result = amrec->amcanbackward;
489+
490+
ReleaseSysCache(ht_idxrel);
491+
ReleaseSysCache(ht_am);
492+
493+
return result;
494+
}

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.498 2008/10/14 17:12:33 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.499 2008/10/17 22:10:30 tgl Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 200810141
56+
#define CATALOG_VERSION_NO 200810171
5757

5858
#endif

src/include/catalog/pg_am.h

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.58 2008/09/15 18:43:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.59 2008/10/17 22:10:30 tgl Exp $
1212
*
1313
* NOTES
1414
* the genbki.sh script reads this file and generates .bki
@@ -41,6 +41,7 @@ CATALOG(pg_am,2601)
4141
int2 amsupport; /* total number of support functions that this
4242
* AM uses */
4343
bool amcanorder; /* does AM support ordered scan results? */
44+
bool amcanbackward; /* does AM support backward scan? */
4445
bool amcanunique; /* does AM support UNIQUE indexes? */
4546
bool amcanmulticol; /* does AM support multi-column indexes? */
4647
bool amoptionalkey; /* can query omit key for the first column? */
@@ -75,48 +76,49 @@ typedef FormData_pg_am *Form_pg_am;
7576
* compiler constants for pg_am
7677
* ----------------
7778
*/
78-
#define Natts_pg_am 25
79+
#define Natts_pg_am 26
7980
#define Anum_pg_am_amname 1
8081
#define Anum_pg_am_amstrategies 2
8182
#define Anum_pg_am_amsupport 3
8283
#define Anum_pg_am_amcanorder 4
83-
#define Anum_pg_am_amcanunique 5
84-
#define Anum_pg_am_amcanmulticol 6
85-
#define Anum_pg_am_amoptionalkey 7
86-
#define Anum_pg_am_amindexnulls 8
87-
#define Anum_pg_am_amsearchnulls 9
88-
#define Anum_pg_am_amstorage 10
89-
#define Anum_pg_am_amclusterable 11
90-
#define Anum_pg_am_amkeytype 12
91-
#define Anum_pg_am_aminsert 13
92-
#define Anum_pg_am_ambeginscan 14
93-
#define Anum_pg_am_amgettuple 15
94-
#define Anum_pg_am_amgetbitmap 16
95-
#define Anum_pg_am_amrescan 17
96-
#define Anum_pg_am_amendscan 18
97-
#define Anum_pg_am_ammarkpos 19
98-
#define Anum_pg_am_amrestrpos 20
99-
#define Anum_pg_am_ambuild 21
100-
#define Anum_pg_am_ambulkdelete 22
101-
#define Anum_pg_am_amvacuumcleanup 23
102-
#define Anum_pg_am_amcostestimate 24
103-
#define Anum_pg_am_amoptions 25
84+
#define Anum_pg_am_amcanbackward 5
85+
#define Anum_pg_am_amcanunique 6
86+
#define Anum_pg_am_amcanmulticol 7
87+
#define Anum_pg_am_amoptionalkey 8
88+
#define Anum_pg_am_amindexnulls 9
89+
#define Anum_pg_am_amsearchnulls 10
90+
#define Anum_pg_am_amstorage 11
91+
#define Anum_pg_am_amclusterable 12
92+
#define Anum_pg_am_amkeytype 13
93+
#define Anum_pg_am_aminsert 14
94+
#define Anum_pg_am_ambeginscan 15
95+
#define Anum_pg_am_amgettuple 16
96+
#define Anum_pg_am_amgetbitmap 17
97+
#define Anum_pg_am_amrescan 18
98+
#define Anum_pg_am_amendscan 19
99+
#define Anum_pg_am_ammarkpos 20
100+
#define Anum_pg_am_amrestrpos 21
101+
#define Anum_pg_am_ambuild 22
102+
#define Anum_pg_am_ambulkdelete 23
103+
#define Anum_pg_am_amvacuumcleanup 24
104+
#define Anum_pg_am_amcostestimate 25
105+
#define Anum_pg_am_amoptions 26
104106

105107
/* ----------------
106108
* initial contents of pg_am
107109
* ----------------
108110
*/
109111

110-
DATA(insert OID = 403 ( btree 5 1 t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
112+
DATA(insert OID = 403 ( btree 5 1 t t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
111113
DESCR("b-tree index access method");
112114
#define BTREE_AM_OID 403
113-
DATA(insert OID = 405 ( hash 1 1 f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
115+
DATA(insert OID = 405 ( hash 1 1 f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
114116
DESCR("hash index access method");
115117
#define HASH_AM_OID 405
116-
DATA(insert OID = 783 ( gist 0 7 f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
118+
DATA(insert OID = 783 ( gist 0 7 f f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
117119
DESCR("GiST index access method");
118120
#define GIST_AM_OID 783
119-
DATA(insert OID = 2742 ( gin 0 5 f f t t f f t f 0 gininsert ginbeginscan gingettuple gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
121+
DATA(insert OID = 2742 ( gin 0 5 f f f t t f f t f 0 gininsert ginbeginscan gingettuple gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
120122
DESCR("GIN index access method");
121123
#define GIN_AM_OID 2742
122124

0 commit comments

Comments
 (0)