*** a/src/backend/optimizer/path/allpaths.c --- b/src/backend/optimizer/path/allpaths.c *************** *** 1268,1274 **** set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) required_outer = rel->lateral_relids; /* Generate appropriate path */ ! add_path(rel, create_functionscan_path(root, rel, required_outer)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel); --- 1268,1274 ---- required_outer = rel->lateral_relids; /* Generate appropriate path */ ! add_path(rel, create_functionscan_path(root, rel, required_outer, rte->funcordinality)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel); *** a/src/backend/optimizer/path/pathkeys.c --- b/src/backend/optimizer/path/pathkeys.c *************** *** 782,787 **** make_pathkeys_for_sortclauses(PlannerInfo *root, --- 782,820 ---- } /**************************************************************************** + * PATHKEYS AND FUNCTION SCANS + ****************************************************************************/ + + /* + * make_pathkeys_for_functionscan + * Generate a pathkeys list that represents the sort order specified by a + * specific column of a function scan. This is used for WITH ORDINALITY + * + * This is basically exporting make_pathkey_from_sortop for callers that know + * exactly what expression they want to generate a pathkey list for. + */ + List * + make_pathkeys_for_functionscan(PlannerInfo *root, + Expr *expr, + Oid sortop) + + { + List *pathkeys = NIL; + PathKey *pathkey; + pathkey = make_pathkey_from_sortop(root, + expr, + sortop, + false, /* nulls first */ + 0, /* sortref */ + true); + + pathkeys = lappend(pathkeys, pathkey); + return pathkeys; + } + + + + /**************************************************************************** * PATHKEYS AND MERGECLAUSES ****************************************************************************/ *** a/src/backend/optimizer/util/pathnode.c --- b/src/backend/optimizer/util/pathnode.c *************** *** 27,33 **** #include "parser/parsetree.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" ! typedef enum { --- 27,35 ---- #include "parser/parsetree.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" ! #include "catalog/pg_opfamily.h" ! #include "catalog/pg_operator.h" ! #include "catalog/pg_type.h" typedef enum { *************** *** 1623,1629 **** create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, */ Path * create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, ! Relids required_outer) { Path *pathnode = makeNode(Path); --- 1625,1631 ---- */ Path * create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, ! Relids required_outer, bool funcordinality) { Path *pathnode = makeNode(Path); *************** *** 1631,1637 **** create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->parent = rel; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); ! pathnode->pathkeys = NIL; /* for now, assume unordered result */ cost_functionscan(pathnode, root, rel, pathnode->param_info); --- 1633,1647 ---- pathnode->parent = rel; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); ! if (funcordinality) { ! /* ordered by ordinality column */ ! pathnode->pathkeys = ! make_pathkeys_for_functionscan(root, ! llast(rel->reltargetlist), ! INT8GT); ! } else { ! pathnode->pathkeys = NIL; /* No information about ordering */ ! } cost_functionscan(pathnode, root, rel, pathnode->param_info); *** a/src/include/catalog/pg_operator.h --- b/src/include/catalog/pg_operator.h *************** *** 171,182 **** DESCR("greater than or equal"); --- 171,184 ---- DATA(insert OID = 410 ( "=" PGNSP PGUID b t t 20 20 16 410 411 int8eq eqsel eqjoinsel )); DESCR("equal"); + #define INT8EQ 410 DATA(insert OID = 411 ( "<>" PGNSP PGUID b f f 20 20 16 411 410 int8ne neqsel neqjoinsel )); DESCR("not equal"); DATA(insert OID = 412 ( "<" PGNSP PGUID b f f 20 20 16 413 415 int8lt scalarltsel scalarltjoinsel )); DESCR("less than"); DATA(insert OID = 413 ( ">" PGNSP PGUID b f f 20 20 16 412 414 int8gt scalargtsel scalargtjoinsel )); DESCR("greater than"); + #define INT8GT 413 DATA(insert OID = 414 ( "<=" PGNSP PGUID b f f 20 20 16 415 413 int8le scalarltsel scalarltjoinsel )); DESCR("less than or equal"); DATA(insert OID = 415 ( ">=" PGNSP PGUID b f f 20 20 16 414 412 int8ge scalargtsel scalargtjoinsel )); *** a/src/include/optimizer/pathnode.h --- b/src/include/optimizer/pathnode.h *************** *** 70,76 **** extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel, extern Path *create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer); extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, ! Relids required_outer); extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer); extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, --- 70,76 ---- extern Path *create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer); extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, ! Relids required_outer, bool funcordinality); extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer); extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, *** a/src/include/optimizer/paths.h --- b/src/include/optimizer/paths.h *************** *** 174,179 **** extern List *build_join_pathkeys(PlannerInfo *root, --- 174,182 ---- extern List *make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist); + extern List * make_pathkeys_for_functionscan(PlannerInfo *root, + Expr *expr, + Oid sortop); extern void initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo); extern void update_mergeclause_eclasses(PlannerInfo *root,