*** ./doc/src/sgml/syntax.sgml.orig Fri Nov 30 19:31:29 2007
--- ./doc/src/sgml/syntax.sgml Fri Nov 30 19:32:11 2007
***************
*** 1497,1503 ****
array value from values for its member elements. A simple array
constructor
consists of the key word ARRAY, a left square bracket
! [>, one or more expressions (separated by commas) for the
array element values, and finally a right square bracket ]>.
For example:
--- 1497,1503 ----
array value from values for its member elements. A simple array
constructor
consists of the key word ARRAY, a left square bracket
! [>, a list of expressions (separated by commas) for the
array element values, and finally a right square bracket ]>.
For example:
***************
*** 1507,1515 ****
{1,2,7}
(1 row)
! The array element type is the common type of the member expressions,
! determined using the same rules as for UNION> or
! CASE> constructs (see ).
--- 1507,1516 ----
{1,2,7}
(1 row)
! If the array is not explictly cast to a particular type, the array element
! type is the common type of the member expressions, determined using the
! same rules as for UNION> or CASE> constructs (see
! ).
***************
*** 1554,1559 ****
--- 1555,1573 ----
+ You can construct an empty array, but since it's impossible to have an array
+ with no type, you must explictly cast your empty array to the desired type. For example:
+
+ SELECT ARRAY[]::int[];
+ int4
+ ------
+ {}
+ (1 row)
+
+ For more on casting, see .
+
+
+
It is also possible to construct an array from the results of a
subquery. In this form, the array constructor is written with the
key word ARRAY followed by a parenthesized (not
*** ./src/backend/nodes/copyfuncs.c.orig Fri Nov 30 19:29:16 2007
--- ./src/backend/nodes/copyfuncs.c Fri Nov 30 19:32:11 2007
***************
*** 1704,1709 ****
--- 1704,1719 ----
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)
{
***************
*** 3538,3543 ****
--- 3548,3556 ----
case T_A_ArrayExpr:
retval = _copyA_ArrayExpr(from);
break;
+ case T_A_ArrayExpr:
+ retval = _copyA_ArrayExpr(from);
+ break;
case T_ResTarget:
retval = _copyResTarget(from);
break;
*** ./src/backend/nodes/outfuncs.c.orig Fri Nov 30 19:29:16 2007
--- ./src/backend/nodes/outfuncs.c Fri Nov 30 19:32:11 2007
***************
*** 1978,1983 ****
--- 1978,1991 ----
}
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");
*** ./src/backend/parser/gram.y.orig Fri Nov 30 19:31:29 2007
--- ./src/backend/parser/gram.y Fri Nov 30 19:32:11 2007
***************
*** 108,113 ****
--- 108,114 ----
static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
+ static Node *makeAArrayExpr(List *elements);
%}
***************
*** 8439,8457 ****
{ $$ = list_make1($1); }
| array_expr_list ',' array_expr
{ $$ = lappend($1, $3); }
;
array_expr: '[' expr_list ']'
{
! ArrayExpr *n = makeNode(ArrayExpr);
! n->elements = $2;
! $$ = (Node *)n;
}
| '[' array_expr_list ']'
{
! ArrayExpr *n = makeNode(ArrayExpr);
! n->elements = $2;
! $$ = (Node *)n;
}
;
--- 8440,8456 ----
{ $$ = list_make1($1); }
| array_expr_list ',' array_expr
{ $$ = lappend($1, $3); }
+ | /* EMPTY */
+ { $$ = NIL; }
;
array_expr: '[' expr_list ']'
{
! $$ = makeAArrayExpr($2);
}
| '[' array_expr_list ']'
{
! $$ = makeAArrayExpr($2);
}
;
***************
*** 9820,9825 ****
--- 9819,9833 ----
return (Node *) x;
}
+ static Node *
+ makeAArrayExpr(List *elements)
+ {
+ A_ArrayExpr *n = makeNode(A_ArrayExpr);
+
+ n->elements = elements;
+ return (Node *) n;
+ }
+
/*
* Must undefine base_yylex before including scan.c, since we want it
* to create the function base_yylex not filtered_base_yylex.
*** ./src/backend/parser/parse_expr.c.orig Fri Nov 30 19:31:29 2007
--- ./src/backend/parser/parse_expr.c Fri Nov 30 19:32:11 2007
***************
*** 52,58 ****
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 *transformRowExpr(ParseState *pstate, RowExpr *r);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
--- 52,58 ----
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, A_ArrayExpr *a, Oid typeid, int32 typmod);
static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
***************
*** 145,153 ****
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
! Node *arg = transformExpr(pstate, tc->arg);
! result = typecast_expression(pstate, arg, tc->typename);
break;
}
--- 145,174 ----
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
! int32 typmod;
! Oid typeid = typenameTypeId(pstate, tc->typename, &typmod);
! /*
! * If the subject of the typecast is an array expression, we
! * check whether the target type is an array type. If so, we
! * skip the creation of a typecast expression and instead pass
! * the type down to transformArrayExpr. This allows us to know
! * the type of the array without having to examine the types of
! * all its elements. This in turn allows us to construct
! * viable empty arrays.
! */
! if (nodeTag(tc->arg) == T_A_ArrayExpr && type_is_array(typeid))
! {
! result = transformArrayExpr(pstate,
! (A_ArrayExpr *) tc->arg,
! typeid,
! typmod);
! }
! else
! {
! Node *arg = transformExpr(pstate, tc->arg);
! result = typecast_expression(pstate, arg, tc->typename);
! }
break;
}
***************
*** 205,212 ****
result = transformCaseExpr(pstate, (CaseExpr *) expr);
break;
! case T_ArrayExpr:
! result = transformArrayExpr(pstate, (ArrayExpr *) expr);
break;
case T_RowExpr:
--- 226,233 ----
result = transformCaseExpr(pstate, (CaseExpr *) expr);
break;
! case T_A_ArrayExpr:
! result = transformArrayExpr(pstate, (A_ArrayExpr *) expr, InvalidOid, -1);
break;
case T_RowExpr:
***************
*** 1255,1262 ****
return result;
}
static Node *
! transformArrayExpr(ParseState *pstate, ArrayExpr *a)
{
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
--- 1276,1292 ----
return result;
}
+ /*
+ * transformArrayExpr
+ *
+ * If the array is the subject of an explicit cast to an array type, the target
+ * type should be passed in via the typeid argument.
+ *
+ * When typeid is present, rather than examining the elements to determine the
+ * overall array type, the elements will be coerced to the appropriate type.
+ */
static Node *
! transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, Oid typeid, int32 typmod)
{
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
***************
*** 1265,1318 ****
ListCell *element;
Oid array_type;
Oid element_type;
! /* Transform the element expressions */
foreach(element, a->elements)
{
Node *e = (Node *) lfirst(element);
Node *newe;
newe = transformExpr(pstate, e);
newelems = lappend(newelems, newe);
- typeids = lappend_oid(typeids, exprType(newe));
- }
-
- /* Select a common type for the elements */
- element_type = select_common_type(typeids, "ARRAY");
! /* Coerce arguments to common type if necessary */
! foreach(element, newelems)
! {
! Node *e = (Node *) lfirst(element);
! Node *newe;
! newe = coerce_to_common_type(pstate, e,
! element_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;
--- 1295,1400 ----
ListCell *element;
Oid array_type;
Oid element_type;
+ Oid coerce_type;
! /*
! * Transform the element expressions
! *
! * Assume that the array is one-dimensional until we discover otherwise.
! */
! newa->multidims = false;
foreach(element, a->elements)
{
Node *e = (Node *) lfirst(element);
Node *newe;
+ Oid newe_type;
newe = transformExpr(pstate, e);
newelems = lappend(newelems, newe);
! newe_type = exprType(newe);
! if (!newa->multidims && OidIsValid(get_element_type(newe_type)))
! /*
! * This element appears to be an array, so presume that we have a
! * multi-dimensional array.
! */
! newa->multidims = true;
! typeids = lappend_oid(typeids, newe_type);
}
! /*
! * Select a target type for the elements.
! *
! * If we haven't been given an array type via the typeid argument, we must
! * try to deduce a common type based on the types of the individual
! * elements present.
! */
! if (OidIsValid(typeid))
{
! array_type = typeid;
! element_type = get_element_type(array_type);
! coerce_type = (newa->multidims ? array_type : element_type);
!
! if (!OidIsValid(element_type))
! /* The caller screwed up by passing us a non-array type */
! ereport(ERROR,
! (errcode(ERRCODE_INTERNAL_ERROR),
! errmsg("invalid target type for array expression"),
! errdetail("%s is not an array type.",
! format_type_be(typeid))));
}
else
{
! if (newelems == NIL)
! /* Can't have an empty array without a target type */
! ereport(ERROR,
! (errcode(ERRCODE_INDETERMINATE_DATATYPE),
! errmsg("no target type for empty array"),
! errhint("Empty arrays must be explictly cast to the "
! "desired array type, e.g. ARRAY[]::int[]")));
!
! coerce_type = select_common_type(typeids, "ARRAY");
! array_type = (newa->multidims ?
! coerce_type :
! get_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))));
}
+ /*
+ * Coerce elements to target type
+ *
+ * If the array has been explictly type cast, then the elements are in turn
+ * explictly coerced.
+ *
+ * If the array's type was merely derived from the common type of its
+ * elements, then the elements are implictly coerced to the common type.
+ */
+ foreach(element, newelems)
+ {
+ Node *e = (Node *) lfirst(element);
+ Node *newe;
+
+ if (OidIsValid(typeid))
+ newe = coerce_to_target_type(pstate, e,
+ exprType(e),
+ coerce_type,
+ typmod,
+ COERCION_EXPLICIT,
+ COERCE_EXPLICIT_CAST);
+ else
+ newe = coerce_to_common_type(pstate, e,
+ coerce_type,
+ "ARRAY");
+ newcoercedelems = lappend(newcoercedelems, newe);
+ }
+
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
*** ./src/backend/parser/parse_target.c.orig Fri Nov 30 19:31:30 2007
--- ./src/backend/parser/parse_target.c Fri Nov 30 19:32:11 2007
***************
*** 1294,1299 ****
--- 1294,1300 ----
return 1;
}
break;
+ case T_A_ArrayExpr:
case T_ArrayExpr:
/* make ARRAY[] act like a function */
*name = "array";
*** ./src/include/nodes/nodes.h.orig Fri Nov 30 19:31:30 2007
--- ./src/include/nodes/nodes.h Fri Nov 30 19:32:11 2007
***************
*** 347,352 ****
--- 347,353 ----
T_LockingClause,
T_RowMarkClause,
T_XmlSerialize,
+ T_A_ArrayExpr,
/*
* TAGS FOR RANDOM OTHER STUFF
*** ./src/include/nodes/parsenodes.h.orig Fri Nov 30 19:31:30 2007
--- ./src/include/nodes/parsenodes.h Fri Nov 30 19:32:11 2007
***************
*** 305,310 ****
--- 305,319 ----
} A_Indirection;
/*
+ * A_ArrayExpr - an ARRAY[] construction
+ */
+ typedef struct A_ArrayExpr
+ {
+ NodeTag type;
+ List *elements; /* array elements, or NIL if none */
+ } A_ArrayExpr;
+
+ /*
* ResTarget -
* result target (used in target list of pre-transformed parse trees)
*
*** ./src/test/regress/expected/arrays.out.orig Fri Nov 30 19:31:30 2007
--- ./src/test/regress/expected/arrays.out Fri Nov 30 19:32:11 2007
***************
*** 785,790 ****
--- 785,793 ----
ERROR: malformed array literal: "{}}"
select '{ }}'::text[];
ERROR: malformed array literal: "{ }}"
+ select array[];
+ ERROR: no target type for empty array
+ HINT: Empty arrays must be explictly cast to the desired array type, e.g. ARRAY[]::int[]
-- none of the above should be accepted
-- all of the following should be accepted
select '{}'::text[];
***************
*** 826,831 ****
--- 829,840 ----
{"@ 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[]);
*** ./src/test/regress/sql/arrays.sql.orig Fri Nov 30 19:31:30 2007
--- ./src/test/regress/sql/arrays.sql Fri Nov 30 19:32:11 2007
***************
*** 280,285 ****
--- 280,286 ----
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,297 ****
--- 293,299 ----
0 second,
@ 1 hour @ 42 minutes @ 20 seconds
}'::interval[];
+ select array[]::text[];
-- all of the above should be accepted
-- tests for array aggregates