Skip to content

Commit bc16f95

Browse files
za-arthurpashkinelfe
authored andcommitted
Issue #487: Add TableSupportsBackwardScan() and TableAmRoutine->amcanbackward
OrioleDB table AM doesn't support BACKWARD SCAN in all cases. A user needs to declare a cursor with SCROLL option.
1 parent 70723c3 commit bc16f95

File tree

7 files changed

+55
-9
lines changed

7 files changed

+55
-9
lines changed

src/backend/access/heap/heapam_handler.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,6 +2917,7 @@ heapam_reloptions(char relkind, Datum reloptions, bool validate)
29172917

29182918
static const TableAmRoutine heapam_methods = {
29192919
.type = T_TableAmRoutine,
2920+
.amcanbackward = true,
29202921

29212922
.slot_callbacks = heapam_slot_callbacks,
29222923
.get_row_ref_type = heapam_get_row_ref_type,

src/backend/commands/portalcmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
134134
if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
135135
{
136136
if (plan->rowMarks == NIL &&
137-
ExecSupportsBackwardScan(plan->planTree))
137+
ExecSupportsBackwardScan(plan->planTree, plan->rtable))
138138
portal->cursorOptions |= CURSOR_OPT_SCROLL;
139139
else
140140
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;

src/backend/executor/execAmi.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
#include "access/amapi.h"
1616
#include "access/htup_details.h"
17+
#include "access/tableam.h"
1718
#include "executor/execdebug.h"
19+
#include "catalog/pg_class.h"
1820
#include "executor/nodeAgg.h"
1921
#include "executor/nodeAppend.h"
2022
#include "executor/nodeBitmapAnd.h"
@@ -61,10 +63,12 @@
6163
#include "nodes/extensible.h"
6264
#include "nodes/nodeFuncs.h"
6365
#include "nodes/pathnodes.h"
66+
#include "parser/parsetree.h"
6467
#include "utils/rel.h"
6568
#include "utils/syscache.h"
6669

6770
static bool IndexSupportsBackwardScan(Oid indexid);
71+
static bool TableSupportsBackwardScan(Oid tableid);
6872

6973

7074
/*
@@ -509,7 +513,7 @@ ExecSupportsMarkRestore(Path *pathnode)
509513
* children do. Therefore, this routine must be passed a complete plan tree.
510514
*/
511515
bool
512-
ExecSupportsBackwardScan(Plan *node)
516+
ExecSupportsBackwardScan(Plan *node, List *rtable)
513517
{
514518
if (node == NULL)
515519
return false;
@@ -526,7 +530,7 @@ ExecSupportsBackwardScan(Plan *node)
526530
{
527531
case T_Result:
528532
if (outerPlan(node) != NULL)
529-
return ExecSupportsBackwardScan(outerPlan(node));
533+
return ExecSupportsBackwardScan(outerPlan(node), rtable);
530534
else
531535
return false;
532536

@@ -540,7 +544,7 @@ ExecSupportsBackwardScan(Plan *node)
540544

541545
foreach(l, ((Append *) node)->appendplans)
542546
{
543-
if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
547+
if (!ExecSupportsBackwardScan((Plan *) lfirst(l), rtable))
544548
return false;
545549
}
546550
/* need not check tlist because Append doesn't evaluate it */
@@ -561,7 +565,7 @@ ExecSupportsBackwardScan(Plan *node)
561565
return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
562566

563567
case T_SubqueryScan:
564-
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
568+
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan, rtable);
565569

566570
case T_CustomScan:
567571
if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
@@ -571,6 +575,16 @@ ExecSupportsBackwardScan(Plan *node)
571575
case T_SeqScan:
572576
case T_TidScan:
573577
case T_TidRangeScan:
578+
{
579+
RangeTblEntry *rte;
580+
581+
Assert(((Scan *) node)->scanrelid > 0 &&
582+
((Scan *) node)->scanrelid <= list_length(rtable));
583+
584+
rte = rt_fetch(((Scan *) node)->scanrelid, rtable);
585+
return TableSupportsBackwardScan(rte->relid);
586+
}
587+
574588
case T_FunctionScan:
575589
case T_ValuesScan:
576590
case T_CteScan:
@@ -589,7 +603,7 @@ ExecSupportsBackwardScan(Plan *node)
589603

590604
case T_LockRows:
591605
case T_Limit:
592-
return ExecSupportsBackwardScan(outerPlan(node));
606+
return ExecSupportsBackwardScan(outerPlan(node), rtable);
593607

594608
default:
595609
return false;
@@ -625,6 +639,34 @@ IndexSupportsBackwardScan(Oid indexid)
625639
return result;
626640
}
627641

642+
/*
643+
* An SeqScan, TidScan or TidRangeScan node supports backward scan only if the
644+
* table's AM does.
645+
*/
646+
static bool
647+
TableSupportsBackwardScan(Oid tableid)
648+
{
649+
bool result;
650+
HeapTuple ht_tabrel;
651+
Form_pg_class tabrelrec;
652+
const TableAmRoutine *amroutine;
653+
654+
/* Fetch the pg_class tuple of the index relation */
655+
ht_tabrel = SearchSysCache1(RELOID, ObjectIdGetDatum(tableid));
656+
if (!HeapTupleIsValid(ht_tabrel))
657+
elog(ERROR, "cache lookup failed for relation %u", tableid);
658+
tabrelrec = (Form_pg_class) GETSTRUCT(ht_tabrel);
659+
660+
/* Fetch the table AM's API struct */
661+
amroutine = GetTableAmRoutineByAmOid(tabrelrec->relam);
662+
663+
result = amroutine->amcanbackward;
664+
665+
ReleaseSysCache(ht_tabrel);
666+
667+
return result;
668+
}
669+
628670
/*
629671
* ExecMaterializesOutput - does a plan type materialize its output?
630672
*

src/backend/executor/spi.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1698,7 +1698,8 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
16981698
if (list_length(stmt_list) == 1 &&
16991699
linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
17001700
linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL &&
1701-
ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree))
1701+
ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree,
1702+
linitial_node(PlannedStmt, stmt_list)->rtable))
17021703
portal->cursorOptions |= CURSOR_OPT_SCROLL;
17031704
else
17041705
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;

src/backend/optimizer/plan/planner.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
426426
*/
427427
if (cursorOptions & CURSOR_OPT_SCROLL)
428428
{
429-
if (!ExecSupportsBackwardScan(top_plan))
429+
if (!ExecSupportsBackwardScan(top_plan, root->parse->rtable))
430430
top_plan = materialize_finished_plan(top_plan);
431431
}
432432

src/include/access/tableam.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ typedef struct TableAmRoutine
304304
/* this must be set to T_TableAmRoutine */
305305
NodeTag type;
306306

307+
/* does AM support backward scanning? */
308+
bool amcanbackward;
307309

308310
/* ------------------------------------------------------------------------
309311
* Slot related callbacks.

src/include/executor/executor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ extern void ExecReScan(PlanState *node);
106106
extern void ExecMarkPos(PlanState *node);
107107
extern void ExecRestrPos(PlanState *node);
108108
extern bool ExecSupportsMarkRestore(struct Path *pathnode);
109-
extern bool ExecSupportsBackwardScan(Plan *node);
109+
extern bool ExecSupportsBackwardScan(Plan *node, List *rtable);
110110
extern bool ExecMaterializesOutput(NodeTag plantype);
111111

112112
/*

0 commit comments

Comments
 (0)