0003-Subscripting-for-array-v11.patch

text/x-patch

Filename: 0003-Subscripting-for-array-v11.patch
Type: text/x-patch
Part: 2
Message: Re: [HACKERS] [PATCH] Generic type subscripting

Patch

Format: format-patch
Series: patch v11-0003
Subject: Subscripting for array
File+
src/backend/utils/adt/arrayfuncs.c 290 0
src/include/catalog/pg_proc.dat 7 0
src/include/catalog/pg_type.dat 152 81
src/test/regress/expected/arrays.out 6 6
src/test/regress/sql/arrays.sql 2 2
From c9a661978f77b8f79559e42a8cfe32c20df19452 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <dmitrii.dolgov@zalando.de>
Date: Thu, 26 Apr 2018 16:34:27 +0200
Subject: [PATCH 3/5] Subscripting for array

---
 src/backend/utils/adt/arrayfuncs.c   | 290 +++++++++++++++++++++++++++++++++++
 src/include/catalog/pg_proc.dat      |   7 +
 src/include/catalog/pg_type.dat      | 233 ++++++++++++++++++----------
 src/test/regress/expected/arrays.out |  12 +-
 src/test/regress/sql/arrays.sql      |   4 +-
 5 files changed, 457 insertions(+), 89 deletions(-)

diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 0cbdbe5..a4dbcad 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -25,13 +25,20 @@
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
+#include "executor/execExpr.h"
 #include "utils/array.h"
 #include "utils/arrayaccess.h"
 #include "utils/builtins.h"
 #include "utils/datum.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/syscache.h"
 #include "utils/typcache.h"
+#include "parser/parse_node.h"
+#include "parser/parse_coerce.h"
 
 
 /*
@@ -158,7 +165,14 @@ static int width_bucket_array_variable(Datum operand,
 							ArrayType *thresholds,
 							Oid collation,
 							TypeCacheEntry *typentry);
+static SubscriptingRef *array_subscript_prepare(bool isAssignment, SubscriptingRef *sbsref);
+static SubscriptingRef *array_subscript_validate(bool isAssignment, SubscriptingRef *sbsref,
+												 ParseState *pstate);
 
+static Datum array_subscript_fetch(Datum containerSource,
+								   SubscriptingRefState *sbstate);
+static Datum array_subscript_assign(Datum containerSource,
+									SubscriptingRefState *sbstate);
 
 /*
  * array_in :
@@ -6558,3 +6572,279 @@ width_bucket_array_variable(Datum operand,
 
 	return left;
 }
+
+/*
+ * Perform an actual data extraction or modification for the array
+ * subscripting. As a result the extracted Datum or the modified containers
+ * value will be returned.
+ */
+Datum
+array_subscript_assign(Datum containerSource, SubscriptingRefState *sbstate)
+{
+	bool						is_slice = (sbstate->numlower != 0);
+	IntArray					u_index, l_index;
+	bool						eisnull = sbstate->resnull;
+	int							i = 0;
+
+	if (sbstate->refelemlength == 0)
+	{
+		/* do one-time catalog lookups for type info */
+		get_typlenbyvalalign(sbstate->refelemtype,
+							 &sbstate->refelemlength,
+							 &sbstate->refelembyval,
+							 &sbstate->refelemalign);
+	}
+
+	for(i = 0; i < sbstate->numupper; i++)
+		u_index.indx[i] = DatumGetInt32(sbstate->upperindex[i]);
+
+	if (is_slice)
+	{
+		for(i = 0; i < sbstate->numlower; i++)
+			l_index.indx[i] = DatumGetInt32(sbstate->lowerindex[i]);
+	}
+
+	/*
+	 * For assignment to varlena arrays, we handle a NULL original array
+	 * by substituting an empty (zero-dimensional) array; insertion of the
+	 * new element will result in a singleton array value.  It does not
+	 * matter whether the new element is NULL.
+	 */
+	if (eisnull)
+	{
+		containerSource = PointerGetDatum(construct_empty_array(sbstate->refelemtype));
+		sbstate->resnull = false;
+		eisnull = false;
+	}
+
+	if (!is_slice)
+		return array_set_element(containerSource, sbstate->numupper,
+								 u_index.indx,
+								 sbstate->replacevalue,
+								 sbstate->replacenull,
+								 sbstate->refattrlength,
+								 sbstate->refelemlength,
+								 sbstate->refelembyval,
+								 sbstate->refelemalign);
+	else
+		return array_set_slice(containerSource, sbstate->numupper,
+							   u_index.indx, l_index.indx,
+							   sbstate->upperprovided,
+							   sbstate->lowerprovided,
+							   sbstate->replacevalue,
+							   sbstate->replacenull,
+							   sbstate->refattrlength,
+							   sbstate->refelemlength,
+							   sbstate->refelembyval,
+							   sbstate->refelemalign);
+}
+
+Datum
+array_subscript_fetch(Datum containerSource, SubscriptingRefState *sbstate)
+{
+	bool							is_slice = (sbstate->numlower != 0);
+	IntArray						u_index, l_index;
+	int								i = 0;
+
+	if (sbstate->refelemlength == 0)
+	{
+		/* do one-time catalog lookups for type info */
+		get_typlenbyvalalign(sbstate->refelemtype,
+							 &sbstate->refelemlength,
+							 &sbstate->refelembyval,
+							 &sbstate->refelemalign);
+	}
+
+	for(i = 0; i < sbstate->numupper; i++)
+		u_index.indx[i] = DatumGetInt32(sbstate->upperindex[i]);
+
+	if (is_slice)
+	{
+		for(i = 0; i < sbstate->numlower; i++)
+			l_index.indx[i] = DatumGetInt32(sbstate->lowerindex[i]);
+	}
+
+	if (!is_slice)
+		return array_get_element(containerSource, sbstate->numupper,
+								 u_index.indx,
+								 sbstate->refattrlength,
+								 sbstate->refelemlength,
+								 sbstate->refelembyval,
+								 sbstate->refelemalign,
+								 &sbstate->resnull);
+	else
+		return array_get_slice(containerSource, sbstate->numupper,
+							   u_index.indx, l_index.indx,
+							   sbstate->upperprovided,
+							   sbstate->lowerprovided,
+							   sbstate->refattrlength,
+							   sbstate->refelemlength,
+							   sbstate->refelembyval,
+							   sbstate->refelemalign);
+}
+
+/*
+ * Handle array-type subscripting logic.
+ */
+Datum
+array_subscript_handler(PG_FUNCTION_ARGS)
+{
+	SubscriptRoutines *sbsroutines = (SubscriptRoutines *)
+									 palloc(sizeof(SubscriptRoutines));
+
+	sbsroutines->prepare = array_subscript_prepare;
+	sbsroutines->validate = array_subscript_validate;
+	sbsroutines->fetch = array_subscript_fetch;
+	sbsroutines->assign = array_subscript_assign;
+
+	PG_RETURN_POINTER(sbsroutines);
+}
+
+SubscriptingRef *
+array_subscript_prepare(bool isAssignment, SubscriptingRef *sbsref)
+{
+	Oid					array_type = sbsref->refcontainertype;
+	HeapTuple			type_tuple_container;
+	Form_pg_type		type_struct_container;
+	bool				is_slice = sbsref->reflowerindexpr != NIL;
+
+	/* Get the type tuple for the container */
+	type_tuple_container = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_type));
+	if (!HeapTupleIsValid(type_tuple_container))
+		elog(ERROR, "cache lookup failed for type %u", array_type);
+	type_struct_container = (Form_pg_type) GETSTRUCT(type_tuple_container);
+
+	/* needn't check typisdefined since this will fail anyway */
+	sbsref->refelemtype = type_struct_container->typelem;
+
+	/* Identify type that RHS must provide */
+	if (isAssignment)
+		sbsref->refassgntype = is_slice ? sbsref->refcontainertype : sbsref->refelemtype;
+
+	ReleaseSysCache(type_tuple_container);
+
+	return sbsref;
+}
+
+SubscriptingRef *
+array_subscript_validate(bool isAssignment, SubscriptingRef *sbsref,
+					  ParseState *pstate)
+{
+	bool				is_slice = sbsref->reflowerindexpr != NIL;
+	Oid					typeneeded = InvalidOid,
+						typesource = InvalidOid;
+	Node				*new_from;
+	Node				*subexpr;
+	List				*upperIndexpr = NIL;
+	List				*lowerIndexpr = NIL;
+	ListCell			*u, *l, *s;
+
+	foreach(u, sbsref->refupperindexpr)
+	{
+		subexpr = (Node *) lfirst(u);
+
+		if (subexpr == NULL)
+		{
+			upperIndexpr = lappend(upperIndexpr, subexpr);
+			continue;
+		}
+
+		subexpr = coerce_to_target_type(pstate,
+										subexpr, exprType(subexpr),
+										INT4OID, -1,
+										COERCION_ASSIGNMENT,
+										COERCE_IMPLICIT_CAST,
+										-1);
+		if (subexpr == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("array subscript must have type integer"),
+					 parser_errposition(pstate, exprLocation(subexpr))));
+
+		upperIndexpr = lappend(upperIndexpr, subexpr);
+	}
+
+	sbsref->refupperindexpr = upperIndexpr;
+
+	forboth(l, sbsref->reflowerindexpr, s, sbsref->refindexprslice)
+	{
+		A_Indices *ai = (A_Indices *) lfirst(s);
+		subexpr = (Node *) lfirst(l);
+
+		if (subexpr == NULL && !ai->is_slice)
+		{
+			/* Make a constant 1 */
+			subexpr = (Node *) makeConst(INT4OID,
+										 -1,
+										 InvalidOid,
+										 sizeof(int32),
+										 Int32GetDatum(1),
+										 false,
+										 true);		/* pass by value */
+		}
+
+		if (subexpr == NULL)
+		{
+			lowerIndexpr = lappend(lowerIndexpr, subexpr);
+			continue;
+		}
+
+		subexpr = coerce_to_target_type(pstate,
+										subexpr, exprType(subexpr),
+										INT4OID, -1,
+										COERCION_ASSIGNMENT,
+										COERCE_IMPLICIT_CAST,
+										-1);
+		if (subexpr == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("array subscript must have type integer"),
+					 parser_errposition(pstate, exprLocation(subexpr))));
+
+		lowerIndexpr = lappend(lowerIndexpr, subexpr);
+	}
+
+	sbsref->reflowerindexpr = lowerIndexpr;
+
+	if (isAssignment)
+	{
+		SubscriptingRef *assignRef = (SubscriptingRef *) sbsref;
+		Node *assignExpr = (Node *) assignRef->refassgnexpr;
+
+		typesource = exprType(assignExpr);
+		typeneeded = is_slice ? sbsref->refcontainertype : sbsref->refelemtype;
+		new_from = coerce_to_target_type(pstate,
+										assignExpr, typesource,
+										typeneeded, sbsref->reftypmod,
+										COERCION_ASSIGNMENT,
+										COERCE_IMPLICIT_CAST,
+										-1);
+		if (new_from == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("array assignment requires type %s"
+							" but expression is of type %s",
+							format_type_be(sbsref->refelemtype),
+							format_type_be(typesource)),
+				 errhint("You will need to rewrite or cast the expression."),
+					 parser_errposition(pstate, exprLocation(assignExpr))));
+		assignRef->refassgnexpr = (Expr *) new_from;
+	}
+
+	sbsref->refnestedfunc = F_ARRAY_SUBSCRIPT_HANDLER;
+
+	/* Verify subscript list lengths are within limit */
+	if (list_length(sbsref->refupperindexpr) > MAXDIM)
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
+						list_length(sbsref->refupperindexpr), MAXDIM)));
+
+	if (list_length(sbsref->reflowerindexpr) > MAXDIM)
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
+						list_length(sbsref->reflowerindexpr), MAXDIM)));
+
+	return sbsref;
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f643f56..81f82f3 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -10169,6 +10169,13 @@
   proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}',
   prosrc => 'pg_control_init' },
 
+{ oid => '4004',
+  descr => 'Array subscripting logic',
+  proname => 'array_subscript_handler',
+  prorettype => 'internal',
+  proargtypes => 'internal',
+  prosrc => 'array_subscript_handler' },
+
 # collation management functions
 { oid => '3445', descr => 'import collations from operating system',
   proname => 'pg_import_system_collations', procost => '100',
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 48e01cd..68f6d79 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -48,7 +48,8 @@
   typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f',
   typcategory => 'S', typelem => 'char', typarray => '_name',
   typinput => 'namein', typoutput => 'nameout', typreceive => 'namerecv',
-  typsend => 'namesend', typalign => 'c' },
+  typsend => 'namesend', typalign => 'c',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '20', descr => '~18 digit integer, 8-byte storage',
   typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
   typcategory => 'N', typarray => '_int8', typinput => 'int8in',
@@ -62,7 +63,8 @@
   typname => 'int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int2', typarray => '_int2vector', typinput => 'int2vectorin',
   typoutput => 'int2vectorout', typreceive => 'int2vectorrecv',
-  typsend => 'int2vectorsend', typalign => 'i' },
+  typsend => 'int2vectorsend', typalign => 'i',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '23', descr => '-2 billion to 2 billion integer, 4-byte storage',
   typname => 'int4', typlen => '4', typbyval => 't', typcategory => 'N',
   typarray => '_int4', typinput => 'int4in', typoutput => 'int4out',
@@ -97,7 +99,8 @@
   typname => 'oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'oid', typarray => '_oidvector', typinput => 'oidvectorin',
   typoutput => 'oidvectorout', typreceive => 'oidvectorrecv',
-  typsend => 'oidvectorsend', typalign => 'i' },
+  typsend => 'oidvectorsend', typalign => 'i',
+  typsubshandler => 'array_subscript_handler' },
 
 # hand-built rowtype entries for bootstrapped catalogs
 # NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations
@@ -138,12 +141,14 @@
   typname => '_xml', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'xml', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '199',
   typname => '_json', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'json', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '194', oid_symbol => 'PGNODETREEOID',
   descr => 'string representing an internal node tree',
   typname => 'pg_node_tree', typlen => '-1', typbyval => 'f',
@@ -185,37 +190,38 @@
   typname => 'point', typlen => '16', typbyval => 'f', typcategory => 'G',
   typelem => 'float8', typarray => '_point', typinput => 'point_in',
   typoutput => 'point_out', typreceive => 'point_recv', typsend => 'point_send',
-  typalign => 'd' },
+  typalign => 'd', typsubshandler => 'array_subscript_handler' },
 { oid => '601', descr => 'geometric line segment \'(pt1,pt2)\'',
   typname => 'lseg', typlen => '32', typbyval => 'f', typcategory => 'G',
   typelem => 'point', typarray => '_lseg', typinput => 'lseg_in',
   typoutput => 'lseg_out', typreceive => 'lseg_recv', typsend => 'lseg_send',
-  typalign => 'd' },
+  typalign => 'd', typsubshandler => 'array_subscript_handler' },
 { oid => '602', descr => 'geometric path \'(pt1,...)\'',
   typname => 'path', typlen => '-1', typbyval => 'f', typcategory => 'G',
   typarray => '_path', typinput => 'path_in', typoutput => 'path_out',
   typreceive => 'path_recv', typsend => 'path_send', typalign => 'd',
-  typstorage => 'x' },
+  typstorage => 'x', typsubshandler => 'array_subscript_handler' },
 { oid => '603', descr => 'geometric box \'(lower left,upper right)\'',
   typname => 'box', typlen => '32', typbyval => 'f', typcategory => 'G',
   typdelim => ';', typelem => 'point', typarray => '_box', typinput => 'box_in',
   typoutput => 'box_out', typreceive => 'box_recv', typsend => 'box_send',
-  typalign => 'd' },
+  typalign => 'd', typsubshandler => 'array_subscript_handler' },
 { oid => '604', descr => 'geometric polygon \'(pt1,...)\'',
   typname => 'polygon', typlen => '-1', typbyval => 'f', typcategory => 'G',
   typarray => '_polygon', typinput => 'poly_in', typoutput => 'poly_out',
   typreceive => 'poly_recv', typsend => 'poly_send', typalign => 'd',
-  typstorage => 'x' },
+  typstorage => 'x', typsubshandler => 'array_subscript_handler' },
 { oid => '628', descr => 'geometric line',
   typname => 'line', typlen => '24', typbyval => 'f', typcategory => 'G',
   typelem => 'float8', typarray => '_line', typinput => 'line_in',
   typoutput => 'line_out', typreceive => 'line_recv', typsend => 'line_send',
-  typalign => 'd' },
+  typalign => 'd', typsubshandler => 'array_subscript_handler' },
 { oid => '629',
   typname => '_line', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'line', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # OIDS 700 - 799
 
@@ -258,7 +264,8 @@
   typname => '_circle', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'circle', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '790', oid_symbol => 'CASHOID',
   descr => 'monetary amounts, $d,ddd.cc',
   typname => 'money', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
@@ -269,7 +276,8 @@
   typname => '_money', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'money', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # OIDS 800 - 899
 
@@ -299,142 +307,166 @@
   typname => '_bool', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'bool', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1001',
   typname => '_bytea', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'bytea', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1002',
   typname => '_char', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'char', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1003',
   typname => '_name', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'name', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1005',
   typname => '_int2', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int2', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1006',
   typname => '_int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int2vector', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1007',
   typname => '_int4', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int4', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1008',
   typname => '_regproc', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'regproc', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1009',
   typname => '_text', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'text', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
-  typcollation => '100' },
+  typcollation => '100', typsubshandler => 'array_subscript_handler' },
 { oid => '1028',
   typname => '_oid', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'oid', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1010',
   typname => '_tid', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'tid', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1011',
   typname => '_xid', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'xid', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1012',
   typname => '_cid', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'cid', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1013',
   typname => '_oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'oidvector', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1014',
   typname => '_bpchar', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'bpchar', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'bpchartypmodin', typmodout => 'bpchartypmodout',
   typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
-  typcollation => '100' },
+  typcollation => '100', typsubshandler => 'array_subscript_handler' },
 { oid => '1015',
   typname => '_varchar', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'varchar', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'varchartypmodin', typmodout => 'varchartypmodout',
   typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
-  typcollation => '100' },
+  typcollation => '100', typsubshandler => 'array_subscript_handler' },
 { oid => '1016',
   typname => '_int8', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int8', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1017',
   typname => '_point', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'point', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1018',
   typname => '_lseg', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'lseg', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1019',
   typname => '_path', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'path', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1020',
   typname => '_box', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typdelim => ';', typelem => 'box', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1021',
   typname => '_float4', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'float4', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1022',
   typname => '_float8', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'float8', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1023',
   typname => '_abstime', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'abstime', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1024',
   typname => '_reltime', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'reltime', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1025',
   typname => '_tinterval', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'tinterval', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1027',
   typname => '_polygon', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'polygon', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1033', descr => 'access control list',
   typname => 'aclitem', typlen => '12', typbyval => 'f', typcategory => 'U',
   typarray => '_aclitem', typinput => 'aclitemin', typoutput => 'aclitemout',
@@ -443,32 +475,38 @@
   typname => '_aclitem', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'aclitem', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1040',
   typname => '_macaddr', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'macaddr', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '775',
   typname => '_macaddr8', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'macaddr8', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1041',
   typname => '_inet', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'inet', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '651',
   typname => '_cidr', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'cidr', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1263',
   typname => '_cstring', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'cstring', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1042',
   descr => 'char(length), blank-padded string, fixed storage length',
   typname => 'bpchar', typlen => '-1', typbyval => 'f', typcategory => 'S',
@@ -506,18 +544,21 @@
   typelem => 'timestamp', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'timestamptypmodin', typmodout => 'timestamptypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1182',
   typname => '_date', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'date', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1183',
   typname => '_time', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'time', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'timetypmodin', typmodout => 'timetypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1184', descr => 'date and time with time zone',
   typname => 'timestamptz', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
   typcategory => 'D', typispreferred => 't', typarray => '_timestamptz',
@@ -530,7 +571,8 @@
   typcategory => 'A', typelem => 'timestamptz', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'timestamptztypmodin', typmodout => 'timestamptztypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1186', descr => '@ <number> <units>, time interval',
   typname => 'interval', typlen => '16', typbyval => 'f', typcategory => 'T',
   typispreferred => 't', typarray => '_interval', typinput => 'interval_in',
@@ -542,7 +584,8 @@
   typelem => 'interval', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'intervaltypmodin', typmodout => 'intervaltypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # OIDS 1200 - 1299
 
@@ -551,7 +594,8 @@
   typelem => 'numeric', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'numerictypmodin', typmodout => 'numerictypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1266', descr => 'time of day with time zone',
   typname => 'timetz', typlen => '12', typbyval => 'f', typcategory => 'D',
   typarray => '_timetz', typinput => 'timetz_in', typoutput => 'timetz_out',
@@ -563,7 +607,8 @@
   typelem => 'timetz', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'timetztypmodin', typmodout => 'timetztypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # OIDS 1500 - 1599
 
@@ -577,7 +622,8 @@
   typelem => 'bit', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'bittypmodin', typmodout => 'bittypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '1562', descr => 'variable-length bit string',
   typname => 'varbit', typlen => '-1', typbyval => 'f', typcategory => 'V',
   typispreferred => 't', typarray => '_varbit', typinput => 'varbit_in',
@@ -589,7 +635,8 @@
   typelem => 'varbit', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
   typmodin => 'varbittypmodin', typmodout => 'varbittypmodout',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # OIDS 1700 - 1799
 
@@ -613,7 +660,8 @@
   typname => '_refcursor', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'refcursor', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 { oid => '2202', descr => 'registered procedure (with args)',
   typname => 'regprocedure', typlen => '4', typbyval => 't', typcategory => 'N',
@@ -650,37 +698,44 @@
   typname => '_regprocedure', typlen => '-1', typbyval => 'f',
   typcategory => 'A', typelem => 'regprocedure', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '2208',
   typname => '_regoper', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'regoper', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '2209',
   typname => '_regoperator', typlen => '-1', typbyval => 'f',
   typcategory => 'A', typelem => 'regoperator', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '2210',
   typname => '_regclass', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'regclass', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '2211',
   typname => '_regtype', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'regtype', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '4097',
   typname => '_regrole', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'regrole', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '4090',
   typname => '_regnamespace', typlen => '-1', typbyval => 'f',
   typcategory => 'A', typelem => 'regnamespace', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # uuid
 { oid => '2950', descr => 'UUID datatype',
@@ -691,7 +746,8 @@
   typname => '_uuid', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'uuid', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # pg_lsn
 { oid => '3220', oid_symbol => 'LSNOID', descr => 'PostgreSQL LSN datatype',
@@ -703,7 +759,8 @@
   typname => '_pg_lsn', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'pg_lsn', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # text search
 { oid => '3614', descr => 'text representation for text search',
@@ -737,39 +794,45 @@
   typname => '_tsvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'tsvector', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3644',
   typname => '_gtsvector', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'gtsvector', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3645',
   typname => '_tsquery', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'tsquery', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3735',
   typname => '_regconfig', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'regconfig', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3770',
   typname => '_regdictionary', typlen => '-1', typbyval => 'f',
   typcategory => 'A', typelem => 'regdictionary', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # jsonb
 { oid => '3802', descr => 'Binary JSON',
   typname => 'jsonb', typlen => '-1', typbyval => 'f', typcategory => 'U',
   typarray => '_jsonb', typinput => 'jsonb_in', typoutput => 'jsonb_out',
   typreceive => 'jsonb_recv', typsend => 'jsonb_send', typalign => 'i',
-  typstorage => 'x' },
+  typstorage => 'x', typsubshandler => 'jsonb_subscript_handler' },
 { oid => '3807',
   typname => '_jsonb', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'jsonb', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 { oid => '2970', descr => 'txid snapshot',
   typname => 'txid_snapshot', typlen => '-1', typbyval => 'f',
@@ -781,7 +844,8 @@
   typname => '_txid_snapshot', typlen => '-1', typbyval => 'f',
   typcategory => 'A', typelem => 'txid_snapshot', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # range types
 { oid => '3904', descr => 'range of integers',
@@ -793,7 +857,8 @@
   typname => '_int4range', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int4range', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3906', descr => 'range of numerics',
   typname => 'numrange', typlen => '-1', typbyval => 'f', typtype => 'r',
   typcategory => 'R', typarray => '_numrange', typinput => 'range_in',
@@ -803,7 +868,8 @@
   typname => '_numrange', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'numrange', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3908', descr => 'range of timestamps without time zone',
   typname => 'tsrange', typlen => '-1', typbyval => 'f', typtype => 'r',
   typcategory => 'R', typarray => '_tsrange', typinput => 'range_in',
@@ -813,7 +879,8 @@
   typname => '_tsrange', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'tsrange', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3910', descr => 'range of timestamps with time zone',
   typname => 'tstzrange', typlen => '-1', typbyval => 'f', typtype => 'r',
   typcategory => 'R', typarray => '_tstzrange', typinput => 'range_in',
@@ -823,7 +890,8 @@
   typname => '_tstzrange', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'tstzrange', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3912', descr => 'range of dates',
   typname => 'daterange', typlen => '-1', typbyval => 'f', typtype => 'r',
   typcategory => 'R', typarray => '_daterange', typinput => 'range_in',
@@ -833,7 +901,8 @@
   typname => '_daterange', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'daterange', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '3926', descr => 'range of bigints',
   typname => 'int8range', typlen => '-1', typbyval => 'f', typtype => 'r',
   typcategory => 'R', typarray => '_int8range', typinput => 'range_in',
@@ -843,7 +912,8 @@
   typname => '_int8range', typlen => '-1', typbyval => 'f', typcategory => 'A',
   typelem => 'int8range', typinput => 'array_in', typoutput => 'array_out',
   typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 
 # pseudo-types
 # types with typtype='p' represent various special cases in the type system.
@@ -863,7 +933,8 @@
   typname => '_record', typlen => '-1', typbyval => 'f', typtype => 'p',
   typcategory => 'P', typelem => 'record', typinput => 'array_in',
   typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send',
-  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+  typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x',
+  typsubshandler => 'array_subscript_handler' },
 { oid => '2275',
   typname => 'cstring', typlen => '-2', typbyval => 'f', typtype => 'p',
   typcategory => 'P', typarray => '_cstring', typinput => 'cstring_in',
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index c730563..f54b73c 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -190,9 +190,9 @@ select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2];
 --
 -- check subscription corner cases
 --
--- More subscripts than MAXDIMS(6)
-SELECT ('{}'::int[])[1][2][3][4][5][6][7];
-ERROR:  number of array dimensions (7) exceeds the maximum allowed (6)
+-- More subscripts than MAXDIMS(12)
+SELECT ('{}'::int[])[1][2][3][4][5][6][7][8][9][10][11][12][13];
+ERROR:  number of array dimensions (13) exceeds the maximum allowed (6)
 -- NULL index yields NULL when selecting
 SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL][1];
  int4 
@@ -216,15 +216,15 @@ SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][1:NULL][1];
 UPDATE arrtest
   SET c[NULL] = '{"can''t assign"}'
   WHERE array_dims(c) is not null;
-ERROR:  array subscript in assignment must not be null
+ERROR:  subscript in assignment must not be null
 UPDATE arrtest
   SET c[NULL:1] = '{"can''t assign"}'
   WHERE array_dims(c) is not null;
-ERROR:  array subscript in assignment must not be null
+ERROR:  subscript in assignment must not be null
 UPDATE arrtest
   SET c[1:NULL] = '{"can''t assign"}'
   WHERE array_dims(c) is not null;
-ERROR:  array subscript in assignment must not be null
+ERROR:  subscript in assignment must not be null
 -- test slices with empty lower and/or upper index
 CREATE TEMP TABLE arrtest_s (
   a       int2[],
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 25dd4e2..fb7a319 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -106,8 +106,8 @@ select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2];
 --
 -- check subscription corner cases
 --
--- More subscripts than MAXDIMS(6)
-SELECT ('{}'::int[])[1][2][3][4][5][6][7];
+-- More subscripts than MAXDIMS(12)
+SELECT ('{}'::int[])[1][2][3][4][5][6][7][8][9][10][11][12][13];
 -- NULL index yields NULL when selecting
 SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL][1];
 SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL:1][1];
-- 
2.7.4