Thread: BUG #7730: intarray representation of empty arrays

BUG #7730: intarray representation of empty arrays

From
elein@varlena.com
Date:
The following bug has been logged on the website:

Bug reference:      7730
Logged by:          elein
Email address:      elein@varlena.com
PostgreSQL version: 9.2.1
Operating system:   Linux
Description:        =


select NULLIF('{1,2,3}'::integer[] - '{3,2,1}'::integer[], '{}'::integer[]);
This returns an empty array.  It should return NULL. =


Per RhodiumToad: the core code represents '{}' as an array with 0
dimensions, whereas intarray represents it as an array with 1 dimension but
0 elements

intarray should use the same standards as the core code if possible.  I
peered at the code and don't see anything untoward but did not have time to
spend on it.

Re: BUG #7730: intarray representation of empty arrays

From
Bruce Momjian
Date:
On Wed, Dec  5, 2012 at 12:44:39AM +0000, elein@varlena.com wrote:
> The following bug has been logged on the website:
>
> Bug reference:      7730
> Logged by:          elein
> Email address:      elein@varlena.com
> PostgreSQL version: 9.2.1
> Operating system:   Linux
> Description:
>
> select NULLIF('{1,2,3}'::integer[] - '{3,2,1}'::integer[], '{}'::integer[]);
> This returns an empty array.  It should return NULL.
>
> Per RhodiumToad: the core code represents '{}' as an array with 0
> dimensions, whereas intarray represents it as an array with 1 dimension but
> 0 elements
>
> intarray should use the same standards as the core code if possible.  I
> peered at the code and don't see anything untoward but did not have time to
> spend on it.

I just got time to look at this, and it is certainly easier to see when
you use array_dims():

    SELECT '{1,2,3}'::integer[] - '{3,2,1}'::integer[];
     ?column?
    ----------
     {}

    SELECT array_dims('{1,2,3}'::integer[] - '{3,2,1}'::integer[]);
     array_dims
    ------------
     [1:0]

    SELECT array_dims('{}'::integer[]);
     array_dims
    ------------
     (null)

This is part of the larger TODO item of how to handle empty
>=1-dimensional empty arrays vs. zero-dimensional empty arrays, which is
discussed here:

    https://wiki.postgresql.org/wiki/Todo#Arrays
    Improve handling of empty arrays

In that thread, no one could find a way to create a 1-dimensional empty
array at the SQL level, but thanks to intarray, you found a way.  It is
natural that intarray, being mostly used for one-dimensional arrays,
would return a 1-dimensional empty array.  However, besides being
inconsistent, as you mentioned, there is also no way to dump/restore
one-dimensional empty arrays, which is a larger concern.

I have developed the attached patch to force empty intarray results to
be zero-dimensional empty arrays, rather than 1-dimensional empty
arrays.  With this patch, a zero-dimensional empty array is returned:

    SELECT array_dims('{1,2,3}'::integer[] - '{3,2,1}'::integer[]);
     array_dims
    ------------
     (null)

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + It's impossible for everything to be true. +

Attachment

Re: BUG #7730: intarray representation of empty arrays

From
Bruce Momjian
Date:
Applied.

---------------------------------------------------------------------------

On Wed, Sep  4, 2013 at 03:01:50PM -0400, Bruce Momjian wrote:
> On Wed, Dec  5, 2012 at 12:44:39AM +0000, elein@varlena.com wrote:
> > The following bug has been logged on the website:
> >
> > Bug reference:      7730
> > Logged by:          elein
> > Email address:      elein@varlena.com
> > PostgreSQL version: 9.2.1
> > Operating system:   Linux
> > Description:
> >
> > select NULLIF('{1,2,3}'::integer[] - '{3,2,1}'::integer[], '{}'::integer[]);
> > This returns an empty array.  It should return NULL.
> >
> > Per RhodiumToad: the core code represents '{}' as an array with 0
> > dimensions, whereas intarray represents it as an array with 1 dimension but
> > 0 elements
> >
> > intarray should use the same standards as the core code if possible.  I
> > peered at the code and don't see anything untoward but did not have time to
> > spend on it.
>
> I just got time to look at this, and it is certainly easier to see when
> you use array_dims():
>
>     SELECT '{1,2,3}'::integer[] - '{3,2,1}'::integer[];
>      ?column?
>     ----------
>      {}
>
>     SELECT array_dims('{1,2,3}'::integer[] - '{3,2,1}'::integer[]);
>      array_dims
>     ------------
>      [1:0]
>
>     SELECT array_dims('{}'::integer[]);
>      array_dims
>     ------------
>      (null)
>
> This is part of the larger TODO item of how to handle empty
> >=1-dimensional empty arrays vs. zero-dimensional empty arrays, which is
> discussed here:
>
>     https://wiki.postgresql.org/wiki/Todo#Arrays
>     Improve handling of empty arrays
>
> In that thread, no one could find a way to create a 1-dimensional empty
> array at the SQL level, but thanks to intarray, you found a way.  It is
> natural that intarray, being mostly used for one-dimensional arrays,
> would return a 1-dimensional empty array.  However, besides being
> inconsistent, as you mentioned, there is also no way to dump/restore
> one-dimensional empty arrays, which is a larger concern.
>
> I have developed the attached patch to force empty intarray results to
> be zero-dimensional empty arrays, rather than 1-dimensional empty
> arrays.  With this patch, a zero-dimensional empty array is returned:
>
>     SELECT array_dims('{1,2,3}'::integer[] - '{3,2,1}'::integer[]);
>      array_dims
>     ------------
>      (null)
>
> --
>   Bruce Momjian  <bruce@momjian.us>        http://momjian.us
>   EnterpriseDB                             http://enterprisedb.com
>
>   + It's impossible for everything to be true. +

> diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c
> new file mode 100644
> index 8635576..fc462b2
> *** a/contrib/intarray/_int_tool.c
> --- b/contrib/intarray/_int_tool.c
> *************** resize_intArrayType(ArrayType *a, int nu
> *** 246,251 ****
> --- 246,258 ----
>       int            nbytes = ARR_DATA_OFFSET(a) + sizeof(int) * num;
>       int            i;
>
> +     /* if no elements, return a zero-dimensional array */
> +     if (num == 0)
> +     {
> +         ARR_NDIM(a) = 0;
> +         return a;
> +     }
> +
>       if (num == ARRNELEMS(a))
>           return a;
>

>
> --
> Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-bugs


--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + It's impossible for everything to be true. +

Re: BUG #7730: intarray representation of empty arrays

From
Elein
Date:
Thanks for looking into this. Finally I'll get to test  existing columns fil=
led with a variety of array[0], '{}' and array[0]-array[0] or Null. Sorry it=
 took so long.=20

What is the target production release?

A. Elein Mustain
Elein@varlena.com
510-637-9106

> On Sep 7, 2013, at 8:44 AM, Bruce Momjian <bruce@momjian.us> wrote:
>=20
>=20
> Applied.
>=20
> --------------------------------------------------------------------------=
-
>=20
>> On Wed, Sep  4, 2013 at 03:01:50PM -0400, Bruce Momjian wrote:
>>> On Wed, Dec  5, 2012 at 12:44:39AM +0000, elein@varlena.com wrote:
>>> The following bug has been logged on the website:
>>>=20
>>> Bug reference:      7730
>>> Logged by:          elein
>>> Email address:      elein@varlena.com
>>> PostgreSQL version: 9.2.1
>>> Operating system:   Linux
>>> Description:       =20
>>>=20
>>> select NULLIF('{1,2,3}'::integer[] - '{3,2,1}'::integer[], '{}'::integer=
[]);
>>> This returns an empty array.  It should return NULL.=20
>>>=20
>>> Per RhodiumToad: the core code represents '{}' as an array with 0
>>> dimensions, whereas intarray represents it as an array with 1 dimension b=
ut
>>> 0 elements
>>>=20
>>> intarray should use the same standards as the core code if possible.  I
>>> peered at the code and don't see anything untoward but did not have time=
 to
>>> spend on it.
>>=20
>> I just got time to look at this, and it is certainly easier to see when
>> you use array_dims():
>>=20
>>    SELECT '{1,2,3}'::integer[] - '{3,2,1}'::integer[];
>>     ?column?
>>    ----------
>>     {}
>>   =20
>>    SELECT array_dims('{1,2,3}'::integer[] - '{3,2,1}'::integer[]);
>>     array_dims
>>    ------------
>>     [1:0]
>>   =20
>>    SELECT array_dims('{}'::integer[]);
>>     array_dims
>>    ------------
>>     (null)
>>=20
>> This is part of the larger TODO item of how to handle empty
>>> =3D1-dimensional empty arrays vs. zero-dimensional empty arrays, which i=
s
>> discussed here:
>>=20
>>    https://wiki.postgresql.org/wiki/Todo#Arrays
>>    Improve handling of empty arrays
>>=20
>> In that thread, no one could find a way to create a 1-dimensional empty
>> array at the SQL level, but thanks to intarray, you found a way.  It is
>> natural that intarray, being mostly used for one-dimensional arrays,
>> would return a 1-dimensional empty array.  However, besides being
>> inconsistent, as you mentioned, there is also no way to dump/restore
>> one-dimensional empty arrays, which is a larger concern.
>>=20
>> I have developed the attached patch to force empty intarray results to
>> be zero-dimensional empty arrays, rather than 1-dimensional empty
>> arrays.  With this patch, a zero-dimensional empty array is returned:
>>=20
>>    SELECT array_dims('{1,2,3}'::integer[] - '{3,2,1}'::integer[]);
>>     array_dims
>>    ------------
>>     (null)
>>=20
>> --=20
>>  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
>>  EnterpriseDB                             http://enterprisedb.com
>>=20
>>  + It's impossible for everything to be true. +
>=20
>> diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c
>> new file mode 100644
>> index 8635576..fc462b2
>> *** a/contrib/intarray/_int_tool.c
>> --- b/contrib/intarray/_int_tool.c
>> *************** resize_intArrayType(ArrayType *a, int nu
>> *** 246,251 ****
>> --- 246,258 ----
>>      int            nbytes =3D ARR_DATA_OFFSET(a) + sizeof(int) * num;
>>      int            i;
>>=20
>> +    /* if no elements, return a zero-dimensional array */
>> +    if (num =3D=3D 0)
>> +    {
>> +        ARR_NDIM(a) =3D 0;
>> +        return a;
>> +    }
>> +=20
>>      if (num =3D=3D ARRNELEMS(a))
>>          return a;
>=20
>>=20
>> --=20
>> Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
>> To make changes to your subscription:
>> http://www.postgresql.org/mailpref/pgsql-bugs
>=20
>=20
> --=20
>  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
>  EnterpriseDB                             http://enterprisedb.com
>=20
>  + It's impossible for everything to be true. +
>=20

Re: BUG #7730: intarray representation of empty arrays

From
Bruce Momjian
Date:
On Sun, Jan 19, 2014 at 04:21:42PM -0800, Elein wrote:
> Thanks for looking into this. Finally I'll get to test  existing columns filled with a variety of array[0], '{}' and
array[0]-array[0]or Null. Sorry it took so long.  
>
> What is the target production release?

Well, I think we are going to close patching for 9.4 beta in about 1-2
months.

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + Everyone has their own god. +

Re: BUG #7730: intarray representation of empty arrays

From
Bruce Momjian
Date:
On Sun, Jan 19, 2014 at 04:21:42PM -0800, Elein wrote:
> Thanks for looking into this. Finally I'll get to test  existing columns filled with a variety of array[0], '{}' and
array[0]-array[0]or Null. Sorry it took so long.  
>
> What is the target production release?

FYI, it has been committed;  I just need testing help:

    commit c155f654b4f755b4111bd9adb60559fe22526a10
    Author: Bruce Momjian <bruce@momjian.us>
    Date:   Sat Sep 7 11:44:33 2013 -0400

        intarray:  return empty zero-dimensional array for an empty array

        Previously a one-dimensional empty array was returned, but its text
        representation matched a zero-dimensional array, and there is no way to
        dump/reload a one-dimensional empty array.

        BACKWARD INCOMPATIBILITY

        Per report from elein

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + Everyone has their own god. +