Re: Bug in intarray? - Mailing list pgsql-hackers

From Tom Lane
Subject Re: Bug in intarray?
Date
Msg-id 6294.1329438477@sss.pgh.pa.us
Whole thread Raw
In response to Bug in intarray?  (Guillaume Lelarge <guillaume@lelarge.info>)
Responses Re: Bug in intarray?
List pgsql-hackers
Guillaume Lelarge <guillaume@lelarge.info> writes:
> This query:
>   SELECT ARRAY[-1,3,1] & ARRAY[1, 2];
> should give {1} as a result.

> But, on HEAD (and according to his tests, on 9.0.6 and 9.1.2), it
> appears to give en empty array.

Definitely a bug, and I'll bet it goes all the way back.

> Digging on this issue, another user (Julien Rouhaud) made an interesting
> comment on this line of code:

> if (i + j == 0 || (i + j > 0 && *(dr - 1) != db[j]))

> (line 159 of contrib/intarray/_int_tool.c, current HEAD)

> Apparently, the code tries to check the current value of the right side
> array with the previous value of the resulting array. Which clearly
> cannot work if there is no previous value in the resulting array.

> So I worked on a patch to fix this, as I think it is a bug (but I may be
> wrong). Patch is attached and fixes the issue AFAICT.

Yeah, this code is bogus, but it's also pretty unreadable.  I think
it's better to get rid of the inconsistently-used pointer arithmetic
and the fundamentally wrong/irrelevant test on i+j, along the lines
of the attached.

            regards, tom lane


diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c
index 79f018d333b1d6810aa7fd2996c158b41b0263fb..132d15316054d842593468f191eca9053846f706 100644
*** a/contrib/intarray/_int_tool.c
--- b/contrib/intarray/_int_tool.c
*************** inner_int_inter(ArrayType *a, ArrayType
*** 140,146 ****
                 *db,
                 *dr;
      int            i,
!                 j;

      if (ARRISEMPTY(a) || ARRISEMPTY(b))
          return new_intArrayType(0);
--- 140,147 ----
                 *db,
                 *dr;
      int            i,
!                 j,
!                 k;

      if (ARRISEMPTY(a) || ARRISEMPTY(b))
          return new_intArrayType(0);
*************** inner_int_inter(ArrayType *a, ArrayType
*** 152,166 ****
      r = new_intArrayType(Min(na, nb));
      dr = ARRPTR(r);

!     i = j = 0;
      while (i < na && j < nb)
      {
          if (da[i] < db[j])
              i++;
          else if (da[i] == db[j])
          {
!             if (i + j == 0 || (i + j > 0 && *(dr - 1) != db[j]))
!                 *dr++ = db[j];
              i++;
              j++;
          }
--- 153,167 ----
      r = new_intArrayType(Min(na, nb));
      dr = ARRPTR(r);

!     i = j = k = 0;
      while (i < na && j < nb)
      {
          if (da[i] < db[j])
              i++;
          else if (da[i] == db[j])
          {
!             if (k == 0 || dr[k - 1] != db[j])
!                 dr[k++] = db[j];
              i++;
              j++;
          }
*************** inner_int_inter(ArrayType *a, ArrayType
*** 168,180 ****
              j++;
      }

!     if ((dr - ARRPTR(r)) == 0)
      {
          pfree(r);
          return new_intArrayType(0);
      }
      else
!         return resize_intArrayType(r, dr - ARRPTR(r));
  }

  void
--- 169,181 ----
              j++;
      }

!     if (k == 0)
      {
          pfree(r);
          return new_intArrayType(0);
      }
      else
!         return resize_intArrayType(r, k);
  }

  void
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index 6ed3cc6ced096e2e97665e76ceba7fc139415029..4080b9633fe98a91861684e0d82f1297c21b91af 100644
*** a/contrib/intarray/expected/_int.out
--- b/contrib/intarray/expected/_int.out
*************** SELECT '{123,623,445}'::int[] & '{1623,6
*** 137,142 ****
--- 137,148 ----
   {623}
  (1 row)

+ SELECT '{-1,3,1}'::int[] & '{1,2}';
+  ?column?
+ ----------
+  {1}
+ (1 row)
+
  --test query_int
  SELECT '1'::query_int;
   query_int
diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql
index b60e936dc520d8308bd16e50681f061dc86e2dfe..216c5c58d615a7cd1a5fe3714c9a5c91fb255138 100644
*** a/contrib/intarray/sql/_int.sql
--- b/contrib/intarray/sql/_int.sql
*************** SELECT '{123,623,445}'::int[] | 623;
*** 24,29 ****
--- 24,30 ----
  SELECT '{123,623,445}'::int[] | 1623;
  SELECT '{123,623,445}'::int[] | '{1623,623}';
  SELECT '{123,623,445}'::int[] & '{1623,623}';
+ SELECT '{-1,3,1}'::int[] & '{1,2}';


  --test query_int

pgsql-hackers by date:

Previous
From: Dan Scales
Date:
Subject: Re: possible new option for wal_sync_method
Next
From: Shigeru Hanada
Date:
Subject: Re: pgsql_fdw, FDW for PostgreSQL server