diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 71e3058..d113c71 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1985,6 +1985,7 @@ _copyRangeTblEntry(const RangeTblEntry *from)
 	COPY_NODE_FIELD(funccoltypmods);
 	COPY_NODE_FIELD(funccolcollations);
 	COPY_SCALAR_FIELD(funcordinality);
+	COPY_SCALAR_FIELD(funcordinality_attno);
 	COPY_NODE_FIELD(values_lists);
 	COPY_NODE_FIELD(values_collations);
 	COPY_STRING_FIELD(ctename);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3183ccf..8d2ce43 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2236,6 +2236,7 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b)
 	COMPARE_NODE_FIELD(funccoltypmods);
 	COMPARE_NODE_FIELD(funccolcollations);
 	COMPARE_SCALAR_FIELD(funcordinality);
+	COMPARE_SCALAR_FIELD(funcordinality_attno);
 	COMPARE_NODE_FIELD(values_lists);
 	COMPARE_NODE_FIELD(values_collations);
 	COMPARE_STRING_FIELD(ctename);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index bad2239..a2e12ac 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2384,6 +2384,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
 			WRITE_NODE_FIELD(funccoltypmods);
 			WRITE_NODE_FIELD(funccolcollations);
 			WRITE_BOOL_FIELD(funcordinality);
+			WRITE_INT_FIELD(funcordinality_attno);
 			break;
 		case RTE_VALUES:
 			WRITE_NODE_FIELD(values_lists);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index aad63e5..eb36a57 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1224,6 +1224,7 @@ _readRangeTblEntry(void)
 			READ_NODE_FIELD(funccoltypmods);
 			READ_NODE_FIELD(funccolcollations);
 			READ_BOOL_FIELD(funcordinality);
+			READ_INT_FIELD(funcordinality_attno);
 			break;
 		case RTE_VALUES:
 			READ_NODE_FIELD(values_lists);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 4b8a73d..63d53bf 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1259,6 +1259,7 @@ static void
 set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 {
 	Relids		required_outer;
+	List	   *pathkeys;
 
 	/*
 	 * We don't support pushing join clauses into the quals of a function
@@ -1267,8 +1268,11 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 	 */
 	required_outer = rel->lateral_relids;
 
+	/* Generate pathkeys for a function scan */
+	pathkeys = build_function_pathkeys(root, rel, rte);
+
 	/* Generate appropriate path */
-	add_path(rel, create_functionscan_path(root, rel, required_outer));
+	add_path(rel, create_functionscan_path(root, rel, pathkeys, required_outer));
 
 	/* Select cheapest path (pretty easy in this case...) */
 	set_cheapest(rel);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 6724996..9f3f261 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -18,6 +18,7 @@
 #include "postgres.h"
 
 #include "access/skey.h"
+#include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/plannodes.h"
@@ -26,6 +27,7 @@
 #include "optimizer/paths.h"
 #include "optimizer/tlist.h"
 #include "utils/lsyscache.h"
+#include "utils/typcache.h"
 
 
 static PathKey *make_canonical_pathkey(PlannerInfo *root,
@@ -699,6 +701,64 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
 }
 
 /*
+ * build_function_pathkeys
+ *	  Generate a single-PathKey list that represents the sort order specified
+ *	  by a specific column of a function scan.
+ */
+List *
+build_function_pathkeys(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
+{
+	TypeCacheEntry *typentry;
+	Oid			sortop;
+	Oid			opfamily;
+	Oid			opcintype;
+	int16		strategy;
+	Expr	   *expr;
+	PathKey    *cpathkey = NULL;
+
+	if (rte->funcordinality == false ||
+		has_useful_pathkeys(root, rel) == false)
+		return NIL;
+
+	Assert(rte->funcordinality_attno > 0);
+
+	/* Find the sort operator using the type cache */
+	typentry = lookup_type_cache(INT8OID, TYPECACHE_LT_OPR);
+	sortop = typentry->lt_opr;
+
+	/* Find the operator in pg_amop --- failure shouldn't happen */
+	if (!get_ordering_op_properties(sortop,
+									&opfamily, &opcintype, &strategy))
+		elog(ERROR, "operator %u is not a valid ordering operator",
+			 sortop);
+
+	/* Build a representation for ordinality column */
+	expr = (Expr *) makeVar(rel->relid,
+							rte->funcordinality_attno,
+							INT8OID,
+							-1,
+							InvalidOid,
+							0);
+
+	/* OK, Try to make a canonical pathkey for ordinality column */
+	cpathkey = make_pathkey_from_sortinfo(root,
+										  expr,
+										  opfamily,
+										  opcintype,
+										  InvalidOid,
+										  false,
+										  false,
+										  0,
+										  rel->relids,
+										  false);
+
+	if (cpathkey != NULL)
+		return truncate_useless_pathkeys(root, rel, list_make1(cpathkey));
+	else
+		return NIL;
+}
+
+/*
  * build_join_pathkeys
  *	  Build the path keys for a join relation constructed by mergejoin or
  *	  nestloop join.  This is normally the same as the outer path's keys.
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 64b1705..a7169ef 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1623,7 +1623,7 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
  */
 Path *
 create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
-						 Relids required_outer)
+						 List *pathkeys, Relids required_outer)
 {
 	Path	   *pathnode = makeNode(Path);
 
@@ -1631,7 +1631,7 @@ 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 */
+	pathnode->pathkeys = pathkeys;
 
 	cost_functionscan(pathnode, root, rel, pathnode->param_info);
 
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 39922d3..dd53c7a 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1228,6 +1228,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
 	Alias	   *alias = rangefunc->alias;
 	List	   *coldeflist = rangefunc->coldeflist;
 	Alias	   *eref;
+	AttrNumber	ordinality_attno = 0;
 
 	rte->rtekind = RTE_FUNCTION;
 	rte->relid = InvalidOid;
@@ -1275,11 +1276,15 @@ addRangeTableEntryForFunction(ParseState *pstate,
 		Assert(tupdesc);
 		/* Build the column alias list */
 		buildRelationAliases(tupdesc, alias, eref, rangefunc->ordinality);
+
+		ordinality_attno = tupdesc->natts + 1;
 	}
 	else if (functypclass == TYPEFUNC_SCALAR)
 	{
 		/* Base data type, i.e. scalar */
 		buildScalarFunctionAlias(funcexpr, funcname, alias, eref, rangefunc->ordinality);
+
+		ordinality_attno = 2;
 	}
 	else if (functypclass == TYPEFUNC_RECORD)
 	{
@@ -1334,6 +1339,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
 	 */
 	rte->lateral = lateral;
 	rte->funcordinality = rangefunc->ordinality;
+	rte->funcordinality_attno = ordinality_attno;
 	rte->inh = false;			/* never true for functions */
 	rte->inFromCl = inFromCl;
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 51fef68..49a7017 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -772,6 +772,7 @@ typedef struct RangeTblEntry
 	List	   *funccoltypmods; /* integer list of column typmods */
 	List	   *funccolcollations;		/* OID list of column collation OIDs */
 	bool		funcordinality;	/* is this called WITH ORDINALITY? */
+	AttrNumber	funcordinality_attno;	/* attno of ordinality column */
 
 	/*
 	 * Fields valid for a values RTE (else NIL):
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index bc68789..bc9bc34 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -70,7 +70,7 @@ 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);
+						 List *pathkeys, Relids required_outer);
 extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
 					   Relids required_outer);
 extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel,
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 9ef93c7..3a2ace8 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -167,6 +167,8 @@ extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index,
 					 ScanDirection scandir);
 extern List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
 						  List *subquery_pathkeys);
+extern List *build_function_pathkeys(PlannerInfo *root, RelOptInfo *rel,
+									 RangeTblEntry *rte);
 extern List *build_join_pathkeys(PlannerInfo *root,
 					RelOptInfo *joinrel,
 					JoinType jointype,
