diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index b56d0e3..60510c3 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -673,7 +673,7 @@ BuildDescForRelation(List *schema)
  * BuildDescFromLists
  *
  * Build a TupleDesc given lists of column names (as String nodes),
- * column type OIDs, typmods, and collation OIDs.
+ * column type OIDs, typmods, collation OIDs and ndims.
  *
  * No constraints are generated.
  *
@@ -681,7 +681,8 @@ BuildDescForRelation(List *schema)
  * with functions returning RECORD.
  */
 TupleDesc
-BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
+BuildDescFromLists(List *names, List *types, List *typmods, List *collations,
+				   List *ndims)
 {
 	int			natts;
 	AttrNumber	attnum;
@@ -689,12 +690,14 @@ BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
 	ListCell   *l2;
 	ListCell   *l3;
 	ListCell   *l4;
+	ListCell   *l5;
 	TupleDesc	desc;
 
 	natts = list_length(names);
 	Assert(natts == list_length(types));
 	Assert(natts == list_length(typmods));
 	Assert(natts == list_length(collations));
+	Assert(natts == list_length(ndims));
 
 	/*
 	 * allocate a new tuple descriptor
@@ -706,12 +709,15 @@ BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
 	l2 = list_head(types);
 	l3 = list_head(typmods);
 	l4 = list_head(collations);
+	l5 = list_head(ndims);
+
 	foreach(l1, names)
 	{
 		char	   *attname = strVal(lfirst(l1));
 		Oid			atttypid;
 		int32		atttypmod;
 		Oid			attcollation;
+		int32		attndims;
 
 		atttypid = lfirst_oid(l2);
 		l2 = lnext(l2);
@@ -719,10 +725,12 @@ BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
 		l3 = lnext(l3);
 		attcollation = lfirst_oid(l4);
 		l4 = lnext(l4);
+		attndims = lfirst_oid(l5);
+		l5 = lnext(l5);
 
 		attnum++;
 
-		TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
+		TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, attndims);
 		TupleDescInitEntryCollation(desc, attnum, attcollation);
 	}
 
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 5a0f324..6d93cb3 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -410,7 +410,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
 			tupdesc = BuildDescFromLists(rtfunc->funccolnames,
 										 rtfunc->funccoltypes,
 										 rtfunc->funccoltypmods,
-										 rtfunc->funccolcollations);
+										 rtfunc->funccolcollations,
+										 rtfunc->funccolndims);
 
 			/*
 			 * For RECORD results, make sure a typmod has been assigned.  (The
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 6955298..6ca0c91 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2181,6 +2181,7 @@ _copyRangeTblFunction(const RangeTblFunction *from)
 	COPY_NODE_FIELD(funccoltypes);
 	COPY_NODE_FIELD(funccoltypmods);
 	COPY_NODE_FIELD(funccolcollations);
+	COPY_NODE_FIELD(funccolndims);
 	COPY_BITMAPSET_FIELD(funcparams);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 548a2aa..b0e0851 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2490,6 +2490,7 @@ _equalRangeTblFunction(const RangeTblFunction *a, const RangeTblFunction *b)
 	COMPARE_NODE_FIELD(funccoltypes);
 	COMPARE_NODE_FIELD(funccoltypmods);
 	COMPARE_NODE_FIELD(funccolcollations);
+	COMPARE_NODE_FIELD(funccolndims);
 	COMPARE_BITMAPSET_FIELD(funcparams);
 
 	return true;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 9fe9873..3b9439c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2880,6 +2880,7 @@ _outRangeTblFunction(StringInfo str, const RangeTblFunction *node)
 	WRITE_NODE_FIELD(funccoltypes);
 	WRITE_NODE_FIELD(funccoltypmods);
 	WRITE_NODE_FIELD(funccolcollations);
+	WRITE_NODE_FIELD(funccolndims);
 	WRITE_BITMAPSET_FIELD(funcparams);
 }
 
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 63f6336..4525298 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1359,6 +1359,7 @@ _readRangeTblFunction(void)
 	READ_NODE_FIELD(funccoltypes);
 	READ_NODE_FIELD(funccoltypmods);
 	READ_NODE_FIELD(funccolcollations);
+	READ_NODE_FIELD(funccolndims);
 	READ_BITMAPSET_FIELD(funcparams);
 
 	READ_DONE();
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 58f7050..19f5fe2 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1444,6 +1444,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
 		rtfunc->funccoltypes = NIL;
 		rtfunc->funccoltypmods = NIL;
 		rtfunc->funccolcollations = NIL;
+		rtfunc->funccolndims = NIL;
 		rtfunc->funcparams = NULL;		/* not set until planning */
 
 		/*
@@ -1509,6 +1510,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
 				Oid			attrtype;
 				int32		attrtypmod;
 				Oid			attrcollation;
+				int32		attrndims;
 
 				attrname = n->colname;
 				if (n->typeName->setof)
@@ -1520,12 +1522,13 @@ addRangeTableEntryForFunction(ParseState *pstate,
 				typenameTypeIdAndMod(pstate, n->typeName,
 									 &attrtype, &attrtypmod);
 				attrcollation = GetColumnDefCollation(pstate, n, attrtype);
+				attrndims = list_length(n->typeName->arrayBounds);
 				TupleDescInitEntry(tupdesc,
 								   (AttrNumber) i,
 								   attrname,
 								   attrtype,
 								   attrtypmod,
-								   0);
+								   attrndims);
 				TupleDescInitEntryCollation(tupdesc,
 											(AttrNumber) i,
 											attrcollation);
@@ -1537,6 +1540,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
 													 attrtypmod);
 				rtfunc->funccolcollations = lappend_oid(rtfunc->funccolcollations,
 														attrcollation);
+				rtfunc->funccolndims = lappend_int(rtfunc->funccolndims,
+												   attrndims);
 
 				i++;
 			}
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h
index de18f74..9ed44fd 100644
--- a/src/include/access/tupdesc.h
+++ b/src/include/access/tupdesc.h
@@ -125,6 +125,7 @@ extern void TupleDescInitEntryCollation(TupleDesc desc,
 
 extern TupleDesc BuildDescForRelation(List *schema);
 
-extern TupleDesc BuildDescFromLists(List *names, List *types, List *typmods, List *collations);
+extern TupleDesc BuildDescFromLists(List *names, List *types, List *typmods,
+									List *collations, List *ndims);
 
 #endif   /* TUPDESC_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index fc532fb..d27db6e 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -969,7 +969,8 @@ typedef struct RangeTblEntry
  * If the function had a column definition list (required for an
  * otherwise-unspecified RECORD result), funccolnames lists the names given
  * in the definition list, funccoltypes lists their declared column types,
- * funccoltypmods lists their typmods, funccolcollations their collations.
+ * funccoltypmods lists their typmods, funccolcollations their collations,
+ * funccolndims lists their numbers of array dimensions.
  * Otherwise, those fields are NIL.
  *
  * Notice we don't attempt to store info about the results of functions
@@ -989,6 +990,7 @@ typedef struct RangeTblFunction
 	List	   *funccoltypes;	/* OID list of column type OIDs */
 	List	   *funccoltypmods; /* integer list of column typmods */
 	List	   *funccolcollations;		/* OID list of column collation OIDs */
+	List	   *funccolndims;	/* integer list of column array ndims */
 	/* This is set during planning for use by the executor: */
 	Bitmapset  *funcparams;		/* PARAM_EXEC Param IDs affecting this func */
 } RangeTblFunction;
