Обсуждение: PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

Поиск
Список
Период
Сортировка

PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

От
"Dawid Kuroczko"
Дата:
VmVyc2lvbnMgOC4wLCA4LjEgd29yayBmaW5lLCB3aGlsZSB2ZXJzaW9uIDgu
Mi41IChhbmQgZWFybGllciBwcm9iYWJseSB0b28pOgoKcG9zdGdyZXM9PiBD
UkVBVEUgVEVNUCBUQUJMRSB0ZXN0IChpZCB2YXJjaGFyKDMyKSk7CkNSRUFU
RSBUQUJMRQpwb3N0Z3Jlcz0+IElOU0VSVCBJTlRPIHRlc3QgU0VMRUNUICog
RlJPTSBnZW5lcmF0ZV9zZXJpZXMoMSwxMDApOwpJTlNFUlQgMCAxMDAKcG9z
dGdyZXM9PiBTRUxFQ1QgKiBGUk9NIHRlc3QgV0hFUkUgaWQgSU4gKDUwKTsK
IGlkCi0tLS0KIDUwCigxIHJvdykKCnBvc3RncmVzPT4gU0VMRUNUICogRlJP
TSB0ZXN0IFdIRVJFIGlkIElOICg1NSw1MCk7CkVSUk9SOiAgSU4gdHlwZXMg
Y2hhcmFjdGVyIHZhcnlpbmcgYW5kIGludGVnZXIgY2Fubm90IGJlIG1hdGNo
ZWQKClRoaXMgd29ya3MgZmluZSBpbiB2ZXJzaW9uIDguMCBhbmQgOC4xLgoK
VGhlIGJ1ZyB3YXMgZm91bmQgYnkgTWljaGGzIFdvamFzLgoKICBSZWdhcmRz
LAogICAgIERhd2lkIEt1cm9jemtvCg==

Re: PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

От
"Heikki Linnakangas"
Дата:
Dawid Kuroczko wrote:
> Versions 8.0, 8.1 work fine, while version 8.2.5 (and earlier probably too):
>
> postgres=> CREATE TEMP TABLE test (id varchar(32));
> CREATE TABLE
> postgres=> INSERT INTO test SELECT * FROM generate_series(1,100);
> INSERT 0 100
> postgres=> SELECT * FROM test WHERE id IN (50);
>  id
> ----
>  50
> (1 row)
>
> postgres=> SELECT * FROM test WHERE id IN (55,50);
> ERROR:  IN types character varying and integer cannot be matched
>
> This works fine in version 8.0 and 8.1.

Note that neither SELECT will work on 8.3, because we no longer have an
implicit cast from integer to text. I suppose the above is an oversight
in how we handle IN-clauses (starting with 8.2 an IN-clause is
transformed into an "x = ANY (...)" expression), but I don't think it's
worth changing.

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

От
Tom Lane
Дата:
"Heikki Linnakangas" <heikki@enterprisedb.com> writes:
> Note that neither SELECT will work on 8.3, because we no longer have an
> implicit cast from integer to text. I suppose the above is an oversight
> in how we handle IN-clauses (starting with 8.2 an IN-clause is
> transformed into an "x = ANY (...)" expression), but I don't think it's
> worth changing.

Yeah, the reason for the difference in behavior is that when there's
just one IN-list item, the parser reduces the thing to a plain "x = y"
expression, which succeeds in the same cases where writing it out that
way would work.  If there's more than one item then it wants to find a
common data type for all the expressions involved.  The implementation
details have changed (repeatedly) over time, but given that we're moving
to stricter behavior for implicit casting, I don't think there's really
anything to fix here.

You need to either cast the varchar to int, or quote the list items to
make them look like varchars, depending on which comparison semantics
you're really after.

            regards, tom lane

Re: PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

От
"Dawid Kuroczko"
Дата:
On 10/19/07, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> "Heikki Linnakangas" <heikki@enterprisedb.com> writes:
> > Note that neither SELECT will work on 8.3, because we no longer have an
> > implicit cast from integer to text. I suppose the above is an oversight
> > in how we handle IN-clauses (starting with 8.2 an IN-clause is
> > transformed into an "x = ANY (...)" expression), but I don't think it's
> > worth changing.
>
> Yeah, the reason for the difference in behavior is that when there's
> just one IN-list item, the parser reduces the thing to a plain "x = y"
> expression, which succeeds in the same cases where writing it out that
> way would work.  If there's more than one item then it wants to find a
> common data type for all the expressions involved.  The implementation
> details have changed (repeatedly) over time, but given that we're moving

I thought so.  Interestingly if you do transformation into ANY "manually",
you get a work around. ;-)

postgres=> SELECT * FROM test WHERE id IN (5,10);
ERROR:  IN types character varying and integer cannot be matched
postgres=> SELECT * FROM test WHERE id = ANY (ARRAY[5,10]);
 id
----
 5
 10
(2 rows)
postgres=> EXPLAIN SELECT * FROM test WHERE id = ANY (ARRAY[5,10]);
                          QUERY PLAN
--------------------------------------------------------------
 Seq Scan on test  (cost=0.00..13.26 rows=59 width=34)
   Filter: ((id)::text = ANY (('{5,10}'::integer[])::text[]))

> to stricter behavior for implicit casting, I don't think there's really
> anything to fix here.
>
> You need to either cast the varchar to int, or quote the list items to
> make them look like varchars, depending on which comparison semantics
> you're really after.

Well, what I'm after is helping port application from another RDBMS,
and this is one problem developers stumbled upon.

What troubles me here is that surprise factor is unusally high here.
While I understand mechanics why IN (1) works while IN (1,2) does not,
I think random developers are going to be confused.  I think it would
be better from surprise-factor point of view if <text> IN (<int>) would
also cause error.

   Regards,
      Dawid

PS: I wonder why explicitly using IN (ARRAY[...]) works.

Re: PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

От
Tom Lane
Дата:
"Dawid Kuroczko" <qnex42@gmail.com> writes:
> What troubles me here is that surprise factor is unusally high here.
> While I understand mechanics why IN (1) works while IN (1,2) does not,
> I think random developers are going to be confused.

If you're not testing against 8.3 then this argument doesn't carry much
weight.  8.3 will reject *both* cases in the examples you've mentioned.

> PS: I wonder why explicitly using IN (ARRAY[...]) works.

Um, it does not work AFAICS:

regression=# select 'foo'::varchar in (array[1,2,3]);
ERROR:  operator does not exist: character varying = integer[]
LINE 1: select 'foo'::varchar in (array[1,2,3]);
                              ^
HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.

            regards, tom lane

Re: PostgreSQL 8.2 Bug in casting varchar to int in SELECT ... WHERE IN ( ... )

От
"Dawid Kuroczko"
Дата:
On 10/20/07, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> "Dawid Kuroczko" <qnex42@gmail.com> writes:
> > What troubles me here is that surprise factor is unusally high here.
> > While I understand mechanics why IN (1) works while IN (1,2) does not,
> > I think random developers are going to be confused.
>
> If you're not testing against 8.3 then this argument doesn't carry much
> weight.  8.3 will reject *both* cases in the examples you've mentioned.

Fair enough.  I have checked that both cases are rejected in 8.3 beta1

> > PS: I wonder why explicitly using IN (ARRAY[...]) works.
>
> Um, it does not work AFAICS:
>
> regression=# select 'foo'::varchar in (array[1,2,3]);
> ERROR:  operator does not exist: character varying = integer[]
> LINE 1: select 'foo'::varchar in (array[1,2,3]);
>                               ^
> HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.

A thinko on my side, what I inteded to write was, that explicit = ANY
(ARRAY[...]) works
fine under 8.2.5 while IN (...) does not.

postgres=> SELECT 'foo'::varchar = ANY (array[1,2,3]), version();
 ?column? |                                        version
----------+----------------------------------------------------------------------------------------
 f        | PostgreSQL 8.2.5 on i486-pc-linux-gnu, compiled by GCC cc
(GCC) 4.2.1 (Debian 4.2.1-5)
(1 row)

postgres=> SELECT 'foo'::varchar = ANY (array[1,2,3]);
 ?column?
----------
 f
(1 row)