aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-03-20 21:42:48 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-03-20 21:42:48 +0000
commit6b0706ac33ab5da815980c642a9cde9a4cd86b6b (patch)
tree511ad4743ad55a095cbacea0713b437af36ba9ce /src
parent8759b79d0fe8b9937b7cbebfed78480b3e6a94b2 (diff)
downloadpostgresql-6b0706ac33ab5da815980c642a9cde9a4cd86b6b.tar.gz
postgresql-6b0706ac33ab5da815980c642a9cde9a4cd86b6b.zip
Arrange for an explicit cast applied to an ARRAY[] constructor to be applied
directly to all the member expressions, instead of the previous implementation where the ARRAY[] constructor would infer a common element type and then we'd coerce the finished array after the fact. This has a number of benefits, one being that we can allow an empty ARRAY[] construct so long as its element type is specified by such a cast. Brendan Jurd, minor fixes by me.
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/copyfuncs.c15
-rw-r--r--src/backend/nodes/equalfuncs.c13
-rw-r--r--src/backend/nodes/outfuncs.c13
-rw-r--r--src/backend/parser/gram.y85
-rw-r--r--src/backend/parser/parse_expr.c207
-rw-r--r--src/backend/parser/parse_target.c4
-rw-r--r--src/include/nodes/nodes.h3
-rw-r--r--src/include/nodes/parsenodes.h17
-rw-r--r--src/test/regress/expected/arrays.out9
-rw-r--r--src/test/regress/sql/arrays.sql2
10 files changed, 276 insertions, 92 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e9df49bab9c..d9432532666 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.388 2008/02/07 20:19:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.389 2008/03/20 21:42:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1684,6 +1684,16 @@ _copyA_Indirection(A_Indirection *from)
return newnode;
}
+static A_ArrayExpr *
+_copyA_ArrayExpr(A_ArrayExpr *from)
+{
+ A_ArrayExpr *newnode = makeNode(A_ArrayExpr);
+
+ COPY_NODE_FIELD(elements);
+
+ return newnode;
+}
+
static ResTarget *
_copyResTarget(ResTarget *from)
{
@@ -3543,6 +3553,9 @@ copyObject(void *from)
case T_A_Indirection:
retval = _copyA_Indirection(from);
break;
+ case T_A_ArrayExpr:
+ retval = _copyA_ArrayExpr(from);
+ break;
case T_ResTarget:
retval = _copyResTarget(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 57c51b2c73f..a92911dc27e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.318 2008/02/07 20:19:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.319 2008/03/20 21:42:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1730,6 +1730,14 @@ _equalA_Indirection(A_Indirection *a, A_Indirection *b)
}
static bool
+_equalA_ArrayExpr(A_ArrayExpr *a, A_ArrayExpr *b)
+{
+ COMPARE_NODE_FIELD(elements);
+
+ return true;
+}
+
+static bool
_equalResTarget(ResTarget *a, ResTarget *b)
{
COMPARE_STRING_FIELD(name);
@@ -2469,6 +2477,9 @@ equal(void *a, void *b)
case T_A_Indirection:
retval = _equalA_Indirection(a, b);
break;
+ case T_A_ArrayExpr:
+ retval = _equalA_ArrayExpr(a, b);
+ break;
case T_ResTarget:
retval = _equalResTarget(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c54cbc9d024..ceb0eb607b7 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.322 2008/01/09 08:46:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.323 2008/03/20 21:42:48 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1972,6 +1972,14 @@ _outA_Indirection(StringInfo str, A_Indirection *node)
}
static void
+_outA_ArrayExpr(StringInfo str, A_ArrayExpr *node)
+{
+ WRITE_NODE_TYPE("A_ARRAYEXPR");
+
+ WRITE_NODE_FIELD(elements);
+}
+
+static void
_outResTarget(StringInfo str, ResTarget *node)
{
WRITE_NODE_TYPE("RESTARGET");
@@ -2417,6 +2425,9 @@ _outNode(StringInfo str, void *obj)
case T_A_Indirection:
_outA_Indirection(str, obj);
break;
+ case T_A_ArrayExpr:
+ _outA_ArrayExpr(str, obj);
+ break;
case T_ResTarget:
_outResTarget(str, obj);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6d4df81a8a3..01cc50428ba 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.608 2008/03/19 18:38:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.609 2008/03/20 21:42:48 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -107,6 +107,7 @@ static void insertSelectOptions(SelectStmt *stmt,
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
+static Node *makeAArrayExpr(List *elements);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
%}
@@ -8429,45 +8430,43 @@ expr_list: a_expr
}
;
-extract_list:
- extract_arg FROM a_expr
- {
- A_Const *n = makeNode(A_Const);
- n->val.type = T_String;
- n->val.val.str = $1;
- $$ = list_make2((Node *) n, $3);
- }
- | /*EMPTY*/ { $$ = NIL; }
- ;
-
type_list: Typename { $$ = list_make1($1); }
| type_list ',' Typename { $$ = lappend($1, $3); }
;
-array_expr_list: array_expr
- { $$ = list_make1($1); }
- | array_expr_list ',' array_expr
- { $$ = lappend($1, $3); }
- ;
-
array_expr: '[' expr_list ']'
{
- ArrayExpr *n = makeNode(ArrayExpr);
- n->elements = $2;
- $$ = (Node *)n;
+ $$ = makeAArrayExpr($2);
}
| '[' array_expr_list ']'
{
- ArrayExpr *n = makeNode(ArrayExpr);
- n->elements = $2;
- $$ = (Node *)n;
+ $$ = makeAArrayExpr($2);
+ }
+ | '[' ']'
+ {
+ $$ = makeAArrayExpr(NIL);
+ }
+ ;
+
+array_expr_list: array_expr { $$ = list_make1($1); }
+ | array_expr_list ',' array_expr { $$ = lappend($1, $3); }
+ ;
+
+
+extract_list:
+ extract_arg FROM a_expr
+ {
+ A_Const *n = makeNode(A_Const);
+ n->val.type = T_String;
+ n->val.val.str = $1;
+ $$ = list_make2((Node *) n, $3);
}
+ | /*EMPTY*/ { $$ = NIL; }
;
/* Allow delimited string SCONST in extract_arg as an SQL extension.
* - thomas 2001-04-12
*/
-
extract_arg:
IDENT { $$ = $1; }
| YEAR_P { $$ = "year"; }
@@ -9502,13 +9501,6 @@ makeColumnRef(char *relname, List *indirection, int location)
static Node *
makeTypeCast(Node *arg, TypeName *typename)
{
- /*
- * Simply generate a TypeCast node.
- *
- * Earlier we would determine whether an A_Const would
- * be acceptable, however Domains require coerce_type()
- * to process them -- applying constraints as required.
- */
TypeCast *n = makeNode(TypeCast);
n->arg = arg;
n->typename = typename;
@@ -9582,7 +9574,7 @@ makeBoolAConst(bool state)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
- n->val.val.str = (state? "t": "f");
+ n->val.val.str = (state ? "t" : "f");
n->typename = SystemTypeName("bool");
return n;
}
@@ -9763,15 +9755,6 @@ SystemTypeName(char *name)
makeString(name)));
}
-/* parser_init()
- * Initialize to parse one query string
- */
-void
-parser_init(void)
-{
- QueryIsRule = FALSE;
-}
-
/* doNegate()
* Handle negation of a numeric constant.
*
@@ -9828,6 +9811,15 @@ doNegateFloat(Value *v)
}
static Node *
+makeAArrayExpr(List *elements)
+{
+ A_ArrayExpr *n = makeNode(A_ArrayExpr);
+
+ n->elements = elements;
+ return (Node *) n;
+}
+
+static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
{
XmlExpr *x = makeNode(XmlExpr);
@@ -9844,6 +9836,15 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
return (Node *) x;
}
+/* parser_init()
+ * Initialize to parse one query string
+ */
+void
+parser_init(void)
+{
+ QueryIsRule = FALSE;
+}
+
/*
* Must undefine base_yylex before including scan.c, since we want it
* to create the function base_yylex not filtered_base_yylex.
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index d43d38c494d..29c058aa40b 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.226 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.227 2008/03/20 21:42:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -52,7 +52,8 @@ static Node *transformAExprIn(ParseState *pstate, A_Expr *a);
static Node *transformFuncCall(ParseState *pstate, FuncCall *fn);
static Node *transformCaseExpr(ParseState *pstate, CaseExpr *c);
static Node *transformSubLink(ParseState *pstate, SubLink *sublink);
-static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a);
+static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
+ Oid array_type, Oid element_type, int32 typmod);
static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
@@ -142,11 +143,49 @@ transformExpr(ParseState *pstate, Node *expr)
break;
}
+ case T_A_ArrayExpr:
+ result = transformArrayExpr(pstate, (A_ArrayExpr *) expr,
+ InvalidOid, InvalidOid, -1);
+ break;
+
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
- Node *arg = transformExpr(pstate, tc->arg);
+ Node *arg;
+
+ /*
+ * If the subject of the typecast is an ARRAY[] construct
+ * and the target type is an array type, we invoke
+ * transformArrayExpr() directly so that we can pass down
+ * the type information. This avoids some cases where
+ * transformArrayExpr() might not infer the correct type.
+ */
+ if (IsA(tc->arg, A_ArrayExpr))
+ {
+ Oid targetType;
+ Oid elementType;
+ int32 targetTypmod;
+
+ targetType = typenameTypeId(pstate, tc->typename,
+ &targetTypmod);
+ elementType = get_element_type(targetType);
+ if (OidIsValid(elementType))
+ {
+ result = transformArrayExpr(pstate,
+ (A_ArrayExpr *) tc->arg,
+ targetType,
+ elementType,
+ targetTypmod);
+ break;
+ }
+ /*
+ * Corner case: ARRAY[] cast to a non-array type.
+ * Fall through to do it the standard way.
+ */
+ }
+
+ arg = transformExpr(pstate, tc->arg);
result = typecast_expression(pstate, arg, tc->typename);
break;
}
@@ -205,10 +244,6 @@ transformExpr(ParseState *pstate, Node *expr)
result = transformCaseExpr(pstate, (CaseExpr *) expr);
break;
- case T_ArrayExpr:
- result = transformArrayExpr(pstate, (ArrayExpr *) expr);
- break;
-
case T_RowExpr:
result = transformRowExpr(pstate, (RowExpr *) expr);
break;
@@ -1255,64 +1290,156 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
return result;
}
+/*
+ * transformArrayExpr
+ *
+ * If the caller specifies the target type, the resulting array will
+ * be of exactly that type. Otherwise we try to infer a common type
+ * for the elements using select_common_type().
+ */
static Node *
-transformArrayExpr(ParseState *pstate, ArrayExpr *a)
+transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
+ Oid array_type, Oid element_type, int32 typmod)
{
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
List *newcoercedelems = NIL;
List *typeids = NIL;
ListCell *element;
- Oid array_type;
- Oid element_type;
+ Oid coerce_type;
+ bool coerce_hard;
- /* Transform the element expressions */
+ /*
+ * Transform the element expressions
+ *
+ * Assume that the array is one-dimensional unless we find an
+ * array-type element expression.
+ */
+ newa->multidims = false;
foreach(element, a->elements)
{
Node *e = (Node *) lfirst(element);
Node *newe;
+ Oid newe_type;
+
+ /*
+ * If an element is itself an A_ArrayExpr, recurse directly so that
+ * we can pass down any target type we were given.
+ */
+ if (IsA(e, A_ArrayExpr))
+ {
+ newe = transformArrayExpr(pstate,
+ (A_ArrayExpr *) e,
+ array_type,
+ element_type,
+ typmod);
+ newe_type = exprType(newe);
+ /* we certainly have an array here */
+ Assert(array_type == InvalidOid || array_type == newe_type);
+ newa->multidims = true;
+ }
+ else
+ {
+ newe = transformExpr(pstate, e);
+ newe_type = exprType(newe);
+ /*
+ * Check for sub-array expressions, if we haven't already
+ * found one.
+ */
+ if (!newa->multidims && type_is_array(newe_type))
+ newa->multidims = true;
+ }
- newe = transformExpr(pstate, e);
newelems = lappend(newelems, newe);
- typeids = lappend_oid(typeids, exprType(newe));
+ typeids = lappend_oid(typeids, newe_type);
}
- /* Select a common type for the elements */
- element_type = select_common_type(typeids, "ARRAY");
+ /*
+ * Select a target type for the elements.
+ *
+ * If we haven't been given a target array type, we must try to deduce a
+ * common type based on the types of the individual elements present.
+ */
+ if (OidIsValid(array_type))
+ {
+ /* Caller must ensure array_type matches element_type */
+ Assert(OidIsValid(element_type));
+ coerce_type = (newa->multidims ? array_type : element_type);
+ coerce_hard = true;
+ }
+ else
+ {
+ /* Can't handle an empty array without a target type */
+ if (typeids == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INDETERMINATE_DATATYPE),
+ errmsg("cannot determine type of empty array"),
+ errhint("Explicitly cast to the desired type, "
+ "for example ARRAY[]::integer[].")));
+
+ /* Select a common type for the elements */
+ coerce_type = select_common_type(typeids, "ARRAY");
+
+ if (newa->multidims)
+ {
+ array_type = coerce_type;
+ element_type = get_element_type(array_type);
+ if (!OidIsValid(element_type))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find element type for data type %s",
+ format_type_be(array_type))));
+ }
+ else
+ {
+ element_type = coerce_type;
+ array_type = get_array_type(element_type);
+ if (!OidIsValid(array_type))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(element_type))));
+ }
+ coerce_hard = false;
+ }
- /* Coerce arguments to common type if necessary */
+ /*
+ * Coerce elements to target type
+ *
+ * If the array has been explicitly cast, then the elements are in turn
+ * explicitly coerced.
+ *
+ * If the array's type was merely derived from the common type of its
+ * elements, then the elements are implicitly coerced to the common type.
+ * This is consistent with other uses of select_common_type().
+ */
foreach(element, newelems)
{
Node *e = (Node *) lfirst(element);
Node *newe;
- newe = coerce_to_common_type(pstate, e,
- element_type,
- "ARRAY");
+ if (coerce_hard)
+ {
+ newe = coerce_to_target_type(pstate, e,
+ exprType(e),
+ coerce_type,
+ typmod,
+ COERCION_EXPLICIT,
+ COERCE_EXPLICIT_CAST);
+ if (newe == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_CANNOT_COERCE),
+ errmsg("cannot cast type %s to %s",
+ format_type_be(exprType(e)),
+ format_type_be(coerce_type))));
+ }
+ else
+ newe = coerce_to_common_type(pstate, e,
+ coerce_type,
+ "ARRAY");
newcoercedelems = lappend(newcoercedelems, newe);
}
- /* Do we have an array type to use? */
- array_type = get_array_type(element_type);
- if (array_type != InvalidOid)
- {
- /* Elements are presumably of scalar type */
- newa->multidims = false;
- }
- else
- {
- /* Must be nested array expressions */
- newa->multidims = true;
-
- array_type = element_type;
- element_type = get_element_type(array_type);
- if (!OidIsValid(element_type))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("could not find array type for data type %s",
- format_type_be(array_type))));
- }
-
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index bd3153548a5..e1d69fec421 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.158 2008/01/01 19:45:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.159 2008/03/20 21:42:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1294,7 +1294,7 @@ FigureColnameInternal(Node *node, char **name)
return 1;
}
break;
- case T_ArrayExpr:
+ case T_A_ArrayExpr:
/* make ARRAY[] act like a function */
*name = "array";
return 2;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 5a6745a2141..79d679b5be4 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.205 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.206 2008/03/20 21:42:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -324,6 +324,7 @@ typedef enum NodeTag
T_FuncCall,
T_A_Indices,
T_A_Indirection,
+ T_A_ArrayExpr,
T_ResTarget,
T_TypeCast,
T_SortBy,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index c973eea729d..ff014383313 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.359 2008/02/07 17:09:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.360 2008/03/20 21:42:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -242,9 +242,9 @@ typedef struct A_Const
* TypeCast - a CAST expression
*
* NOTE: for mostly historical reasons, A_Const parsenodes contain
- * room for a TypeName; we only generate a separate TypeCast node if the
- * argument to be casted is not a constant. In theory either representation
- * would work, but the combined representation saves a bit of code in many
+ * room for a TypeName, allowing a constant to be marked as being of a given
+ * type without a separate TypeCast node. Either representation will work,
+ * but the combined representation saves a bit of code in many
* productions in gram.y.
*/
typedef struct TypeCast
@@ -305,6 +305,15 @@ typedef struct A_Indirection
} A_Indirection;
/*
+ * A_ArrayExpr - an ARRAY[] construct
+ */
+typedef struct A_ArrayExpr
+{
+ NodeTag type;
+ List *elements; /* array element expressions */
+} A_ArrayExpr;
+
+/*
* ResTarget -
* result target (used in target list of pre-transformed parse trees)
*
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 0f611bf7d78..c82cd3919b9 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -785,6 +785,9 @@ select '{}}'::text[];
ERROR: malformed array literal: "{}}"
select '{ }}'::text[];
ERROR: malformed array literal: "{ }}"
+select array[];
+ERROR: cannot determine type of empty array
+HINT: Explicitly cast to the desired type, for example ARRAY[]::integer[].
-- none of the above should be accepted
-- all of the following should be accepted
select '{}'::text[];
@@ -826,6 +829,12 @@ select '{
{"@ 0","@ 1 hour 42 mins 20 secs"}
(1 row)
+select array[]::text[];
+ array
+-------
+ {}
+(1 row)
+
-- all of the above should be accepted
-- tests for array aggregates
CREATE TEMP TABLE arraggtest ( f1 INT[], f2 TEXT[][], f3 FLOAT[]);
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index a60bf560fa8..192648a39b6 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -280,6 +280,7 @@ select E'{{1,2},\\{2,3}}'::text[];
select '{{"1 2" x},{3}}'::text[];
select '{}}'::text[];
select '{ }}'::text[];
+select array[];
-- none of the above should be accepted
-- all of the following should be accepted
@@ -292,6 +293,7 @@ select '{
0 second,
@ 1 hour @ 42 minutes @ 20 seconds
}'::interval[];
+select array[]::text[];
-- all of the above should be accepted
-- tests for array aggregates