Re: Inconsistent behavior on Array & Is Null? - Mailing list pgsql-hackers
| From | Joe Conway |
|---|---|
| Subject | Re: Inconsistent behavior on Array & Is Null? |
| Date | |
| Msg-id | 406CFD7B.5060504@joeconway.com Whole thread Raw |
| In response to | Re: Inconsistent behavior on Array & Is Null? (Greg Stark <gsstark@mit.edu>) |
| Responses |
Re: Inconsistent behavior on Array & Is Null?
|
| List | pgsql-hackers |
Greg Stark wrote:
> length(a) != array_upper(a)-array_lower(a)
[You really meant "array_upper(a) - array_lower(a) + 1" I'd guess]
length(A) is a missing function at the moment; the spec actually calls
it CARDINALITY. Once available, you would use it to determine array
length. SQL2003 says:
The result of <cardinality expression> is the number of elements of the result of the <collection value
expression>.
So, when A is an empty array, CARDINALITY(A) = 0, by definition.
> array_upper(a||b) == array_upper(a)+length(b)
Same here; this would be:
array_upper(a || b) == array_upper(a) + CARDINALITY(b)
and would work just fine. Note that if array-a is NULL, then the spec
defines a || b as NULL. See section 6.35:
2) If <array concatenation> is specified, then let AV1 be the value of <array value expression 1> and let AV2 be
thevalue of <array primary>. Case: a) If either AV1 or AV2 is the null value, then the result of the
<arrayconcatenation> is the null value. b) If the sum of the cardinality of AV1 and the cardinality of AV2
isgreater than IMDC, then an exception condition is raised: data exception — array data, right truncation.
c)Otherwise, the result is the array comprising every element of AV1 followed by every element of AV2.
> If someone implements pop and push it sure makes things weird that push
> doesn't always increment the length pop doesn't decrement the length until 0.
I have no idea what you're trying to say here. Current behavior
certainly increments length by one when you push an element (which is
what "array || element" effectively does). An empty array has length 0
before pushing an element on to it, and length 1 afterward. Pushing an
element onto a NULL array yields NULL, which is not explicitly defined
by the spec (that I can find), but is certainly consistent with the above.
As far as array_pop is concerned, we discussed the fact that it makes no
sense in the context of Postgres arrays -- see the archives from last
year in May.
> Perhaps you're worried that you have pick an arbitrary lower and upper bound
> and, strangely, that the upper bound would actually be one less than the lower
> bound such as [1,0]. However this isn't really any different than the normal
> case. All arrays in postgres have arbitrary lower bounds.
Again, I have no idea what you mean here.
> Fwiw, the int_aggregate function from int_aggregate.c in the contrib section
> makes arrays that don't violate these invariants. For empty arrays the
> dimensions are [0,-1].
Seems rather arbitrary to me. As I said to Josh, an empty array has
undefined bounds, literally.
> This isn't hypothetical for me. Whenever I end up replacing int_aggregate with
> a standard function that constructs your style arrays my app would break. I
> guess I'll have to add a coalesce(...,0) to my array_length() function to work
> around it. Which only seems like strong evidence it's the wrong behaviour.
Sorry, but these are not "my style" arrays, they are "Berkley style" ;-).
Anyway, CARDINALITY is what you really need -- hopefully I'll be able to
find time to address that and some ather array items before the 7.5
freeze. In the meantime, if you have a custom array_length function
already, why not make it return 0 for empty arrays -- then your problems
disappear:
create or replace function array_length(anyarray)
returns int as ' select case when $1 = ''{}'' then 0 else array_upper($1, 1) - array_lower($1, 1) + 1 end
' language sql;
CREATE FUNCTION
regression=# select array_length(array[1,2,3]); array_length
-------------- 3
(1 row)
regression=# select array_length('{}'::int4[]); array_length
-------------- 0
(1 row)
regression=# select array[1,2,3] || '{}'::int4[]; ?column?
---------- {1,2,3}
(1 row)
regression=# select array_upper(array[1,2,3], 1) +
array_length('{}'::int4[]); ?column?
---------- 3
(1 row)
HTH,
Joe
pgsql-hackers by date: