Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/backend/access/heap/heapam_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -2964,6 +2964,7 @@ heapam_reloptions(char relkind, Datum reloptions, bool validate)

static const TableAmRoutine heapam_methods = {
.type = T_TableAmRoutine,
.amcanbackward = true,

.slot_callbacks = heapam_slot_callbacks,
.get_row_ref_type = heapam_get_row_ref_type,
Expand Down
2 changes: 1 addition & 1 deletion src/backend/commands/portalcmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
{
if (plan->rowMarks == NIL &&
ExecSupportsBackwardScan(plan->planTree))
ExecSupportsBackwardScan(plan->planTree, plan->rtable))
portal->cursorOptions |= CURSOR_OPT_SCROLL;
else
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
Expand Down
52 changes: 47 additions & 5 deletions src/backend/executor/execAmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "access/amapi.h"
#include "access/htup_details.h"
#include "access/tableam.h"
#include "catalog/pg_am_d.h"
#include "catalog/pg_class.h"
#include "executor/nodeAgg.h"
#include "executor/nodeAppend.h"
Expand Down Expand Up @@ -60,9 +62,11 @@
#include "executor/nodeWorktablescan.h"
#include "nodes/extensible.h"
#include "nodes/pathnodes.h"
#include "parser/parsetree.h"
#include "utils/syscache.h"

static bool IndexSupportsBackwardScan(Oid indexid);
static bool TableSupportsBackwardScan(Oid tableid);


/*
Expand Down Expand Up @@ -507,7 +511,7 @@ ExecSupportsMarkRestore(Path *pathnode)
* children do. Therefore, this routine must be passed a complete plan tree.
*/
bool
ExecSupportsBackwardScan(Plan *node)
ExecSupportsBackwardScan(Plan *node, List *rtable)
{
if (node == NULL)
return false;
Expand All @@ -524,7 +528,7 @@ ExecSupportsBackwardScan(Plan *node)
{
case T_Result:
if (outerPlan(node) != NULL)
return ExecSupportsBackwardScan(outerPlan(node));
return ExecSupportsBackwardScan(outerPlan(node), rtable);
else
return false;

Expand All @@ -538,7 +542,7 @@ ExecSupportsBackwardScan(Plan *node)

foreach(l, ((Append *) node)->appendplans)
{
if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
if (!ExecSupportsBackwardScan((Plan *) lfirst(l), rtable))
return false;
}
/* need not check tlist because Append doesn't evaluate it */
Expand All @@ -559,7 +563,7 @@ ExecSupportsBackwardScan(Plan *node)
return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);

case T_SubqueryScan:
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan, rtable);

case T_CustomScan:
if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
Expand All @@ -569,6 +573,16 @@ ExecSupportsBackwardScan(Plan *node)
case T_SeqScan:
case T_TidScan:
case T_TidRangeScan:
{
RangeTblEntry *rte;

Assert(((Scan *) node)->scanrelid > 0 &&
((Scan *) node)->scanrelid <= list_length(rtable));

rte = rt_fetch(((Scan *) node)->scanrelid, rtable);
return TableSupportsBackwardScan(rte->relid);
}

case T_FunctionScan:
case T_ValuesScan:
case T_CteScan:
Expand All @@ -587,7 +601,7 @@ ExecSupportsBackwardScan(Plan *node)

case T_LockRows:
case T_Limit:
return ExecSupportsBackwardScan(outerPlan(node));
return ExecSupportsBackwardScan(outerPlan(node), rtable);

default:
return false;
Expand Down Expand Up @@ -623,6 +637,34 @@ IndexSupportsBackwardScan(Oid indexid)
return result;
}

/*
* An SeqScan, TidScan or TidRangeScan node supports backward scan only if the
* table's AM does.
*/
static bool
TableSupportsBackwardScan(Oid tableid)
{
bool result;
HeapTuple ht_tabrel;
Form_pg_class tabrelrec;
const TableAmRoutine *amroutine;

/* Fetch the pg_class tuple of the index relation */
ht_tabrel = SearchSysCache1(RELOID, ObjectIdGetDatum(tableid));
if (!HeapTupleIsValid(ht_tabrel))
elog(ERROR, "cache lookup failed for relation %u", tableid);
tabrelrec = (Form_pg_class) GETSTRUCT(ht_tabrel);

/* Fetch the table AM's API struct */
amroutine = GetTableAmRoutineByAmOid(tabrelrec->relam);

result = amroutine->amcanbackward;

ReleaseSysCache(ht_tabrel);

return result;
}

/*
* ExecMaterializesOutput - does a plan type materialize its output?
*
Expand Down
3 changes: 2 additions & 1 deletion src/backend/executor/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,8 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
if (list_length(stmt_list) == 1 &&
linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL &&
ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree))
ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree,
linitial_node(PlannedStmt, stmt_list)->rtable))
portal->cursorOptions |= CURSOR_OPT_SCROLL;
else
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
Expand Down
2 changes: 1 addition & 1 deletion src/backend/optimizer/plan/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
*/
if (cursorOptions & CURSOR_OPT_SCROLL)
{
if (!ExecSupportsBackwardScan(top_plan))
if (!ExecSupportsBackwardScan(top_plan, root->parse->rtable))
top_plan = materialize_finished_plan(top_plan);
}

Expand Down
2 changes: 2 additions & 0 deletions src/include/access/tableam.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ typedef struct TableAmRoutine
/* this must be set to T_TableAmRoutine */
NodeTag type;

/* does AM support backward scanning? */
bool amcanbackward;

/* ------------------------------------------------------------------------
* Slot related callbacks.
Expand Down
2 changes: 1 addition & 1 deletion src/include/executor/executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ extern void ExecReScan(PlanState *node);
extern void ExecMarkPos(PlanState *node);
extern void ExecRestrPos(PlanState *node);
extern bool ExecSupportsMarkRestore(struct Path *pathnode);
extern bool ExecSupportsBackwardScan(Plan *node);
extern bool ExecSupportsBackwardScan(Plan *node, List *rtable);
extern bool ExecMaterializesOutput(NodeTag plantype);

/*
Expand Down