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.
This commit is contained in:
parent
8759b79d0f
commit
6b0706ac33
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.121 2008/01/23 19:51:29 tgl Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.122 2008/03/20 21:42:47 tgl Exp $ -->
|
||||
|
||||
<chapter id="sql-syntax">
|
||||
<title>SQL Syntax</title>
|
||||
@ -1305,7 +1305,7 @@ sqrt(2)
|
||||
|
||||
where <replaceable>aggregate_name</replaceable> is a previously
|
||||
defined aggregate (possibly qualified with a schema name), and
|
||||
<replaceable>expression</replaceable> is
|
||||
<replaceable>expression</replaceable> is
|
||||
any value expression that does not itself contain an aggregate
|
||||
expression.
|
||||
</para>
|
||||
@ -1335,7 +1335,7 @@ sqrt(2)
|
||||
<para>
|
||||
The predefined aggregate functions are described in <xref
|
||||
linkend="functions-aggregate">. Other aggregate functions can be added
|
||||
by the user.
|
||||
by the user.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -1495,9 +1495,9 @@ SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
|
||||
<para>
|
||||
An array constructor is an expression that builds an
|
||||
array value from values for its member elements. A simple array
|
||||
constructor
|
||||
constructor
|
||||
consists of the key word <literal>ARRAY</literal>, a left square bracket
|
||||
<literal>[</>, one or more expressions (separated by commas) for the
|
||||
<literal>[</>, a list of expressions (separated by commas) for the
|
||||
array element values, and finally a right square bracket <literal>]</>.
|
||||
For example:
|
||||
<programlisting>
|
||||
@ -1507,9 +1507,22 @@ SELECT ARRAY[1,2,3+4];
|
||||
{1,2,7}
|
||||
(1 row)
|
||||
</programlisting>
|
||||
The array element type is the common type of the member expressions,
|
||||
By default,
|
||||
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">).
|
||||
<literal>CASE</> constructs (see <xref linkend="typeconv-union-case">).
|
||||
You can override this by explicitly casting the array constructor to the
|
||||
desired type, for example:
|
||||
<programlisting>
|
||||
SELECT ARRAY[1,2,22.7]::integer[];
|
||||
array
|
||||
----------
|
||||
{1,2,23}
|
||||
(1 row)
|
||||
</programlisting>
|
||||
This has the same effect as casting each expression to the array
|
||||
element type individually.
|
||||
For more on casting, see <xref linkend="sql-syntax-type-casts">.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -1534,6 +1547,8 @@ SELECT ARRAY[[1,2],[3,4]];
|
||||
|
||||
Since multidimensional arrays must be rectangular, inner constructors
|
||||
at the same level must produce sub-arrays of identical dimensions.
|
||||
Any cast applied to the outer <literal>ARRAY</> constructor propagates
|
||||
automatically to all the inner constructors.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -1553,6 +1568,19 @@ SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You can construct an empty array, but since it's impossible to have an
|
||||
array with no type, you must explicitly cast your empty array to the
|
||||
desired type. For example:
|
||||
<programlisting>
|
||||
SELECT ARRAY[]::integer[];
|
||||
array
|
||||
-------
|
||||
{}
|
||||
(1 row)
|
||||
</programlisting>
|
||||
</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
|
||||
|
@ -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;
|
||||
|
@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1729,6 +1729,14 @@ _equalA_Indirection(A_Indirection *a, A_Indirection *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalA_ArrayExpr(A_ArrayExpr *a, A_ArrayExpr *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(elements);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalResTarget(ResTarget *a, ResTarget *b)
|
||||
{
|
||||
@ -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;
|
||||
|
@ -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*
|
||||
@ -1971,6 +1971,14 @@ _outA_Indirection(StringInfo str, A_Indirection *node)
|
||||
WRITE_NODE_FIELD(indirection);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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;
|
||||
|
@ -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,6 +8430,29 @@ expr_list: a_expr
|
||||
}
|
||||
;
|
||||
|
||||
type_list: Typename { $$ = list_make1($1); }
|
||||
| type_list ',' Typename { $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
array_expr: '[' expr_list ']'
|
||||
{
|
||||
$$ = makeAArrayExpr($2);
|
||||
}
|
||||
| '[' array_expr_list ']'
|
||||
{
|
||||
$$ = 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
|
||||
{
|
||||
@ -8440,34 +8464,9 @@ extract_list:
|
||||
| /*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;
|
||||
}
|
||||
| '[' array_expr_list ']'
|
||||
{
|
||||
ArrayExpr *n = makeNode(ArrayExpr);
|
||||
n->elements = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
/* 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.
|
||||
*
|
||||
@ -9827,6 +9810,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)
|
||||
{
|
||||
@ -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.
|
||||
|
@ -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[].")));
|
||||
|
||||
/* Coerce arguments to common type if necessary */
|
||||
/* 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 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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
@ -304,6 +304,15 @@ typedef struct A_Indirection
|
||||
List *indirection; /* subscripts and/or field names */
|
||||
} 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)
|
||||
|
@ -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[]);
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user