mirror of
https://github.com/postgres/postgres.git
synced 2025-05-05 09:19:17 +03:00
Allow domains over arrays to match ANYARRAY parameters again.
This use-case was broken in commit 529cb267a6843a6a8190c86b75d091771d99d6a9 of 2010-10-21, in which I commented "For the moment, we just forbid such matching. We might later wish to insert an automatic downcast to the underlying array type, but such a change should also change matching of domains to ANYELEMENT for consistency". We still lack consensus about what to do with ANYELEMENT; but not matching ANYARRAY is a clear loss of functionality compared to prior releases, so let's go ahead and make that happen. Per complaint from Regina Obe and extensive subsequent discussion.
This commit is contained in:
parent
8f9622bbb3
commit
b7e8feb33e
@ -143,9 +143,7 @@ coerce_type(ParseState *pstate, Node *node,
|
|||||||
}
|
}
|
||||||
if (targetTypeId == ANYOID ||
|
if (targetTypeId == ANYOID ||
|
||||||
targetTypeId == ANYELEMENTOID ||
|
targetTypeId == ANYELEMENTOID ||
|
||||||
targetTypeId == ANYNONARRAYOID ||
|
targetTypeId == ANYNONARRAYOID)
|
||||||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
|
|
||||||
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Assume can_coerce_type verified that implicit coercion is okay.
|
* Assume can_coerce_type verified that implicit coercion is okay.
|
||||||
@ -154,15 +152,48 @@ coerce_type(ParseState *pstate, Node *node,
|
|||||||
* it's OK to treat an UNKNOWN constant as a valid input for a
|
* it's OK to treat an UNKNOWN constant as a valid input for a
|
||||||
* function accepting ANY, ANYELEMENT, or ANYNONARRAY. This should be
|
* function accepting ANY, ANYELEMENT, or ANYNONARRAY. This should be
|
||||||
* all right, since an UNKNOWN value is still a perfectly valid Datum.
|
* all right, since an UNKNOWN value is still a perfectly valid Datum.
|
||||||
* However an UNKNOWN value is definitely *not* an array, and so we
|
|
||||||
* mustn't accept it for ANYARRAY. (Instead, we will call anyarray_in
|
|
||||||
* below, which will produce an error.) Likewise, UNKNOWN input is no
|
|
||||||
* good for ANYENUM.
|
|
||||||
*
|
*
|
||||||
* NB: we do NOT want a RelabelType here.
|
* NB: we do NOT want a RelabelType here: the exposed type of the
|
||||||
|
* function argument must be its actual type, not the polymorphic
|
||||||
|
* pseudotype.
|
||||||
*/
|
*/
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
if (targetTypeId == ANYARRAYOID ||
|
||||||
|
targetTypeId == ANYENUMOID)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Assume can_coerce_type verified that implicit coercion is okay.
|
||||||
|
*
|
||||||
|
* These cases are unlike the ones above because the exposed type of
|
||||||
|
* the argument must be an actual array or enum type. In particular
|
||||||
|
* the argument must *not* be an UNKNOWN constant. If it is, we just
|
||||||
|
* fall through; below, we'll call anyarray_in or anyenum_in, which
|
||||||
|
* will produce an error. Also, if what we have is a domain over
|
||||||
|
* array or enum, we have to relabel it to its base type.
|
||||||
|
*
|
||||||
|
* Note: currently, we can't actually see a domain-over-enum here,
|
||||||
|
* since the other functions in this file will not match such a
|
||||||
|
* parameter to ANYENUM. But that should get changed eventually.
|
||||||
|
*/
|
||||||
|
if (inputTypeId != UNKNOWNOID)
|
||||||
|
{
|
||||||
|
Oid baseTypeId = getBaseType(inputTypeId);
|
||||||
|
|
||||||
|
if (baseTypeId != inputTypeId)
|
||||||
|
{
|
||||||
|
RelabelType *r = makeRelabelType((Expr *) node,
|
||||||
|
baseTypeId, -1,
|
||||||
|
InvalidOid,
|
||||||
|
cformat);
|
||||||
|
|
||||||
|
r->location = location;
|
||||||
|
return (Node *) r;
|
||||||
|
}
|
||||||
|
/* Not a domain type, so return it as-is */
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (inputTypeId == UNKNOWNOID && IsA(node, Const))
|
if (inputTypeId == UNKNOWNOID && IsA(node, Const))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -1257,6 +1288,11 @@ coerce_to_common_type(ParseState *pstate, Node *node,
|
|||||||
* (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
|
* (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
|
||||||
* is an extra restriction if not.)
|
* is an extra restriction if not.)
|
||||||
*
|
*
|
||||||
|
* Domains over arrays match ANYARRAY, and are immediately flattened to their
|
||||||
|
* base type. (Thus, for example, we will consider it a match if one ANYARRAY
|
||||||
|
* argument is a domain over int4[] while another one is just int4[].) Also
|
||||||
|
* notice that such a domain does *not* match ANYNONARRAY.
|
||||||
|
*
|
||||||
* If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
|
* If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
|
||||||
* argument, assume it is okay.
|
* argument, assume it is okay.
|
||||||
*
|
*
|
||||||
@ -1309,6 +1345,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
|||||||
{
|
{
|
||||||
if (actual_type == UNKNOWNOID)
|
if (actual_type == UNKNOWNOID)
|
||||||
continue;
|
continue;
|
||||||
|
actual_type = getBaseType(actual_type); /* flatten domains */
|
||||||
if (OidIsValid(array_typeid) && actual_type != array_typeid)
|
if (OidIsValid(array_typeid) && actual_type != array_typeid)
|
||||||
return false;
|
return false;
|
||||||
array_typeid = actual_type;
|
array_typeid = actual_type;
|
||||||
@ -1346,8 +1383,8 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
|||||||
|
|
||||||
if (have_anynonarray)
|
if (have_anynonarray)
|
||||||
{
|
{
|
||||||
/* require the element type to not be an array */
|
/* require the element type to not be an array or domain over array */
|
||||||
if (type_is_array(elem_typeid))
|
if (type_is_array_domain(elem_typeid))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,6 +1443,10 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
|||||||
* (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
|
* (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
|
||||||
* is an extra restriction if not.)
|
* is an extra restriction if not.)
|
||||||
*
|
*
|
||||||
|
* Domains over arrays match ANYARRAY arguments, and are immediately flattened
|
||||||
|
* to their base type. (In particular, if the return type is also ANYARRAY,
|
||||||
|
* we'll set it to the base type not the domain type.)
|
||||||
|
*
|
||||||
* When allow_poly is false, we are not expecting any of the actual_arg_types
|
* When allow_poly is false, we are not expecting any of the actual_arg_types
|
||||||
* to be polymorphic, and we should not return a polymorphic result type
|
* to be polymorphic, and we should not return a polymorphic result type
|
||||||
* either. When allow_poly is true, it is okay to have polymorphic "actual"
|
* either. When allow_poly is true, it is okay to have polymorphic "actual"
|
||||||
@ -1485,6 +1526,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
|||||||
}
|
}
|
||||||
if (allow_poly && decl_type == actual_type)
|
if (allow_poly && decl_type == actual_type)
|
||||||
continue; /* no new information here */
|
continue; /* no new information here */
|
||||||
|
actual_type = getBaseType(actual_type); /* flatten domains */
|
||||||
if (OidIsValid(array_typeid) && actual_type != array_typeid)
|
if (OidIsValid(array_typeid) && actual_type != array_typeid)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
@ -1557,8 +1599,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
|||||||
|
|
||||||
if (have_anynonarray && elem_typeid != ANYELEMENTOID)
|
if (have_anynonarray && elem_typeid != ANYELEMENTOID)
|
||||||
{
|
{
|
||||||
/* require the element type to not be an array */
|
/* require the element type to not be an array or domain over array */
|
||||||
if (type_is_array(elem_typeid))
|
if (type_is_array_domain(elem_typeid))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("type matched to anynonarray is an array type: %s",
|
errmsg("type matched to anynonarray is an array type: %s",
|
||||||
@ -1655,15 +1697,19 @@ resolve_generic_type(Oid declared_type,
|
|||||||
{
|
{
|
||||||
if (context_declared_type == ANYARRAYOID)
|
if (context_declared_type == ANYARRAYOID)
|
||||||
{
|
{
|
||||||
/* Use actual type, but it must be an array */
|
/*
|
||||||
Oid array_typelem = get_element_type(context_actual_type);
|
* Use actual type, but it must be an array; or if it's a domain
|
||||||
|
* over array, use the base array type.
|
||||||
|
*/
|
||||||
|
Oid context_base_type = getBaseType(context_actual_type);
|
||||||
|
Oid array_typelem = get_element_type(context_base_type);
|
||||||
|
|
||||||
if (!OidIsValid(array_typelem))
|
if (!OidIsValid(array_typelem))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("argument declared \"anyarray\" is not an array but type %s",
|
errmsg("argument declared \"anyarray\" is not an array but type %s",
|
||||||
format_type_be(context_actual_type))));
|
format_type_be(context_base_type))));
|
||||||
return context_actual_type;
|
return context_base_type;
|
||||||
}
|
}
|
||||||
else if (context_declared_type == ANYELEMENTOID ||
|
else if (context_declared_type == ANYELEMENTOID ||
|
||||||
context_declared_type == ANYNONARRAYOID ||
|
context_declared_type == ANYNONARRAYOID ||
|
||||||
@ -1687,13 +1733,14 @@ resolve_generic_type(Oid declared_type,
|
|||||||
if (context_declared_type == ANYARRAYOID)
|
if (context_declared_type == ANYARRAYOID)
|
||||||
{
|
{
|
||||||
/* Use the element type corresponding to actual type */
|
/* Use the element type corresponding to actual type */
|
||||||
Oid array_typelem = get_element_type(context_actual_type);
|
Oid context_base_type = getBaseType(context_actual_type);
|
||||||
|
Oid array_typelem = get_element_type(context_base_type);
|
||||||
|
|
||||||
if (!OidIsValid(array_typelem))
|
if (!OidIsValid(array_typelem))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("argument declared \"anyarray\" is not an array but type %s",
|
errmsg("argument declared \"anyarray\" is not an array but type %s",
|
||||||
format_type_be(context_actual_type))));
|
format_type_be(context_base_type))));
|
||||||
return array_typelem;
|
return array_typelem;
|
||||||
}
|
}
|
||||||
else if (context_declared_type == ANYELEMENTOID ||
|
else if (context_declared_type == ANYELEMENTOID ||
|
||||||
@ -1796,12 +1843,12 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
|
|||||||
|
|
||||||
/* Also accept any array type as coercible to ANYARRAY */
|
/* Also accept any array type as coercible to ANYARRAY */
|
||||||
if (targettype == ANYARRAYOID)
|
if (targettype == ANYARRAYOID)
|
||||||
if (type_is_array(srctype))
|
if (type_is_array_domain(srctype))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Also accept any non-array type as coercible to ANYNONARRAY */
|
/* Also accept any non-array type as coercible to ANYNONARRAY */
|
||||||
if (targettype == ANYNONARRAYOID)
|
if (targettype == ANYNONARRAYOID)
|
||||||
if (!type_is_array(srctype))
|
if (!type_is_array_domain(srctype))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Also accept any enum type as coercible to ANYENUM */
|
/* Also accept any enum type as coercible to ANYENUM */
|
||||||
|
@ -127,6 +127,16 @@ select testint4arr[1], testchar4arr[2:2] from domarrtest;
|
|||||||
| {{d,e,f}}
|
| {{d,e,f}}
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
select array_dims(testint4arr), array_dims(testchar4arr) from domarrtest;
|
||||||
|
array_dims | array_dims
|
||||||
|
------------+------------
|
||||||
|
[1:2] | [1:2][1:2]
|
||||||
|
[1:2][1:2] | [1:1][1:2]
|
||||||
|
[1:2] | [1:3][1:2]
|
||||||
|
[1:2] | [1:2][1:1]
|
||||||
|
| [1:2][1:3]
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
COPY domarrtest FROM stdin;
|
COPY domarrtest FROM stdin;
|
||||||
COPY domarrtest FROM stdin; -- fail
|
COPY domarrtest FROM stdin; -- fail
|
||||||
ERROR: value too long for type character varying(4)
|
ERROR: value too long for type character varying(4)
|
||||||
@ -146,6 +156,32 @@ select * from domarrtest;
|
|||||||
drop table domarrtest;
|
drop table domarrtest;
|
||||||
drop domain domainint4arr restrict;
|
drop domain domainint4arr restrict;
|
||||||
drop domain domainchar4arr restrict;
|
drop domain domainchar4arr restrict;
|
||||||
|
create domain dia as int[];
|
||||||
|
select '{1,2,3}'::dia;
|
||||||
|
dia
|
||||||
|
---------
|
||||||
|
{1,2,3}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select array_dims('{1,2,3}'::dia);
|
||||||
|
array_dims
|
||||||
|
------------
|
||||||
|
[1:3]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select pg_typeof('{1,2,3}'::dia);
|
||||||
|
pg_typeof
|
||||||
|
-----------
|
||||||
|
dia
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select pg_typeof('{1,2,3}'::dia || 42); -- should be int[] not dia
|
||||||
|
pg_typeof
|
||||||
|
-----------
|
||||||
|
integer[]
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
drop domain dia;
|
||||||
create domain dnotnull varchar(15) NOT NULL;
|
create domain dnotnull varchar(15) NOT NULL;
|
||||||
create domain dnull varchar(15);
|
create domain dnull varchar(15);
|
||||||
create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
|
create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
|
||||||
|
@ -87,6 +87,7 @@ INSERT INTO domarrtest values (NULL, '{{"a","b","c"},{"d","e","f"}}');
|
|||||||
INSERT INTO domarrtest values (NULL, '{{"toolong","b","c"},{"d","e","f"}}');
|
INSERT INTO domarrtest values (NULL, '{{"toolong","b","c"},{"d","e","f"}}');
|
||||||
select * from domarrtest;
|
select * from domarrtest;
|
||||||
select testint4arr[1], testchar4arr[2:2] from domarrtest;
|
select testint4arr[1], testchar4arr[2:2] from domarrtest;
|
||||||
|
select array_dims(testint4arr), array_dims(testchar4arr) from domarrtest;
|
||||||
|
|
||||||
COPY domarrtest FROM stdin;
|
COPY domarrtest FROM stdin;
|
||||||
{3,4} {q,w,e}
|
{3,4} {q,w,e}
|
||||||
@ -103,6 +104,12 @@ drop table domarrtest;
|
|||||||
drop domain domainint4arr restrict;
|
drop domain domainint4arr restrict;
|
||||||
drop domain domainchar4arr restrict;
|
drop domain domainchar4arr restrict;
|
||||||
|
|
||||||
|
create domain dia as int[];
|
||||||
|
select '{1,2,3}'::dia;
|
||||||
|
select array_dims('{1,2,3}'::dia);
|
||||||
|
select pg_typeof('{1,2,3}'::dia);
|
||||||
|
select pg_typeof('{1,2,3}'::dia || 42); -- should be int[] not dia
|
||||||
|
drop domain dia;
|
||||||
|
|
||||||
create domain dnotnull varchar(15) NOT NULL;
|
create domain dnotnull varchar(15) NOT NULL;
|
||||||
create domain dnull varchar(15);
|
create domain dnull varchar(15);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user