*** ./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 <literal>ARRAY</literal>, a left square bracket
!     <literal>[</>, one or more expressions (separated by commas) for the
      array element values, and finally a right square bracket <literal>]</>.
      For example:
  <programlisting>
--- 1497,1503 ----
      array value from values for its member elements.  A simple array
      constructor 
      consists of the key word <literal>ARRAY</literal>, a left square bracket
!     <literal>[</>, a list of expressions (separated by commas) for the
      array element values, and finally a right square bracket <literal>]</>.
      For example:
  <programlisting>
***************
*** 1507,1515 ****
   {1,2,7}
  (1 row)
  </programlisting>
!     The array element type is the common type of the member expressions,
!     determined using the same rules as for <literal>UNION</> or
!     <literal>CASE</> constructs (see <xref linkend="typeconv-union-case">). 
     </para>
  
     <para>
--- 1507,1516 ----
   {1,2,7}
  (1 row)
  </programlisting>
! 	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 <literal>UNION</> or <literal>CASE</> constructs (see
! 	<xref linkend="typeconv-union-case">). 
     </para>
  
     <para>
***************
*** 1554,1559 ****
--- 1555,1573 ----
    </para>
  
    <para>
+    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:
+ <programlisting>
+ SELECT ARRAY[]::int[];
+  int4
+ ------
+  {}
+ (1 row)
+ </programlisting>
+    For more on casting, see <xref linkend="sql-syntax-type-casts">.
+   </para>
+ 
+   <para>
     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 <literal>ARRAY</literal> 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
