valid casts to anyarray

Started by Philip Carlsenover 2 years ago4 messagesgeneral
Jump to latest
#1Philip Carlsen
plcplc@gmail.com

Hi list

I've been down a rabbit hole today trying to understand what exactly makes
a type a valid candidate for an ANYARRAY function argument (e.g., something
you can 'unnest()').

My reading has led me across such functions as 'get_promoted_array_type',
'IsTrueArrayType', 'can_coerce_type', and 'check_generic_type_consistency',
and this has led me to believe that any type which has a valid (i.e.,
non-zero?) pg_type.typelem defined should be applicable.

However, I cannot seem to be able to call 'unnest' on a 'point':

postgres=# select unnest(point(1,2));
ERROR: function unnest(point) does not exist

... even though according to 'pg_catalog.pg_type' the type 'point' does
indeed look very array-like (it should be equivalent to an float8 array).
The only difference I can spot is that it has
'typsubscript=raw_array_subscript_handler', as opposed to
typsubscript=array_subscript_handler' which is what 'IsTrueArrayType'
checks for.

Can anyone here perhaps enlighten me as to how I can tell if a type is a
valid ANYARRAY (and bonus points to point out the check I must have missed
in the (parser?) source code)?

-Philip

#2Laurenz Albe
laurenz.albe@cybertec.at
In reply to: Philip Carlsen (#1)
Re: valid casts to anyarray

On Tue, 2023-09-26 at 21:39 +0200, Philip Carlsen wrote:

I've been down a rabbit hole today trying to understand what exactly makes a type
a valid candidate for an ANYARRAY function argument (e.g., something you can 'unnest()').

My reading has led me across such functions as 'get_promoted_array_type',  'IsTrueArrayType',
'can_coerce_type', and 'check_generic_type_consistency', and this has led me to believe
that any type which has a valid (i.e., non-zero?) pg_type.typelem defined should be applicable.

However, I cannot seem to be able to call 'unnest' on a 'point':

postgres=# select unnest(point(1,2));
ERROR:  function unnest(point) does not exist

... even though according to 'pg_catalog.pg_type' the type 'point' does indeed look
very array-like (it should be equivalent to an float8 array). The only difference I
can spot is that it has 'typsubscript=raw_array_subscript_handler', as opposed to
typsubscript=array_subscript_handler' which is what 'IsTrueArrayType' checks for.

Can anyone here perhaps enlighten me as to how I can tell if a type is a valid ANYARRAY
(and bonus points to point out the check I must have missed in the (parser?) source code)?

I'd say that the type has to be an array type...

For example, here is the definition of "cardinality()", which takes "anyarray"
as argument:

Datum
array_cardinality(PG_FUNCTION_ARGS)
{
AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);

PG_RETURN_INT32(ArrayGetNItems(AARR_NDIM(v), AARR_DIMS(v)));
}

Yours,
Laurenz Albe

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Philip Carlsen (#1)
Re: valid casts to anyarray

Philip Carlsen <plcplc@gmail.com> writes:

I've been down a rabbit hole today trying to understand what exactly makes
a type a valid candidate for an ANYARRAY function argument (e.g., something
you can 'unnest()').

Per the comments for check_generic_type_consistency:

* 2) All arguments declared ANYARRAY must have the same datatype,
* which must be a varlena array type.

If you follow that code down you eventually find that it expects
get_element_type() to succeed, and that says

* NB: this only succeeds for "true" arrays having array_subscript_handler
* as typsubscript. For other types, InvalidOid is returned independently
* of whether they have typelem or typsubscript set.

which is mechanized as an IsTrueArrayType() check.

My reading has led me across such functions as 'get_promoted_array_type',
'IsTrueArrayType', 'can_coerce_type', and 'check_generic_type_consistency',
and this has led me to believe that any type which has a valid (i.e.,
non-zero?) pg_type.typelem defined should be applicable.

It has to not only have an element type, but have a standard array
header, else we don't know how to do a lot of operations on it.

Type "point" and related animals are sort of a poor man's array,
which is supported for basic subscripting operations, but it's not
generic enough to be reasonable to consider as an ANYARRAY.

regards, tom lane

#4Philip Carlsen
plcplc@gmail.com
In reply to: Tom Lane (#3)
Re: valid casts to anyarray

Per the comments for check_generic_type_consistency:

* 2) All arguments declared ANYARRAY must have the same datatype,
* which must be a varlena array type.

This must be exactly the bit that I missed during my reading - thanks!

It has to not only have an element type, but have a standard array
header, else we don't know how to do a lot of operations on it.

Type "point" and related animals are sort of a poor man's array,
which is supported for basic subscripting operations, but it's not
generic enough to be reasonable to consider as an ANYARRAY.

This is what I had started to suspect.

I also found the source commentary in c.h (via
https://doxygen.postgresql.org/c_8h_source.html, though apparently the
comments do not make it to the generated doxygen docs) was helpful in
understanding just what exactly the term 'varlena' refers to.
The docs also refer to this term at times, but it never makes concrete
what it actually means (IIRC).

This was a very enlightening answer - Thanks!

-Philip