Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bug: Driver(8.2dev-500.jdbc3) does not handle boolean->BIT correctly

0 views
Skip to first unread message

j.random.programmer

unread,
Dec 19, 2005, 3:14:51 PM12/19/05
to
Running against postgres 8.1

I have:

create table foo (bit_val bit);

If I now try to insert, via the driver's prepared
statement, a value of java boolean true into
the bit_val column, I get:

---------------------------------
ERROR COULD NOT SAVE.....
org.postgresql.util.PSQLException: ERROR: column
"bit_val" is of type bit but expression is of type
boolean
---------------------------------

This is totally wrong if my reading of the JDBC
spec is correct. Java boolean values should
be converted to bitval(1), possibly as '1' and
then converted back to boolean when read from
the database.

If I go to psql directly, the following works fine:

insert into foo (bit_val) values ('1');

THAT is what the driver should to as well.

This is really hokey since it's breaking my
O/R mapping tool.

Best regards,
--j

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com

---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

Dave Cramer

unread,
Dec 19, 2005, 3:55:35 PM12/19/05
to
The problem is that we don't know in advance if the underlying column
is a bit, or a boolean. Postgresql supports both, the jdbc API
doesn't appear to.

We are now using bound variables and are binding that to a boolean
type, not a bit type. We had to choose one of them, and boolean seems
to be much more "boolean" than bit.

Dave


---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majo...@postgresql.org so that your
message can get through to the mailing list cleanly

j.random.programmer

unread,
Dec 19, 2005, 5:09:37 PM12/19/05
to
Dave:

> The problem is that we don't know in advance if the
> underlying column
> is a bit, or a boolean. Postgresql supports
> both, the jdbc API doesn't appear to.

You can get from the database the actual
type defined in the database for that column
right ? (so if it's BIT your driver can tell it's
BIT in the database, I presume).

So then, as per the JDBC spec
1) while retrieving:
convert that BIT (however long it may be) into a
boolean [true, say, it it's all 1's else false].
2) while saving:
convert java true to a '1' and save that as a BIT
(convert java false to '0').

That's what the spec suggests from what I can
tell. Of course, you could also convert the
BIT into a string if the user wants it as a string).

Oliver Jowett

unread,
Dec 19, 2005, 6:32:00 PM12/19/05
to
j.random.programmer wrote:
> Running against postgres 8.1
>
> I have:
>
> create table foo (bit_val bit);
>
> If I now try to insert, via the driver's prepared
> statement, a value of java boolean true into
> the bit_val column, I get:
>
> ---------------------------------
> ERROR COULD NOT SAVE.....
> org.postgresql.util.PSQLException: ERROR: column
> "bit_val" is of type bit but expression is of type
> boolean
> ---------------------------------

JDBC's "BIT" is actually a boolean type. In JDBC3, BIT and BOOLEAN are
effectively equivalent.

The backend's "bit" type is actually a bitstring that does not have a
direct equivalent in JDBC.

> This is totally wrong if my reading of the JDBC
> spec is correct. Java boolean values should
> be converted to bitval(1), possibly as '1' and
> then converted back to boolean when read from
> the database.

Actually, the spec says nothing about bitstring types AFAIK.

If you want to do this type conversion and still use setBoolean(), you
will need to modify your query to do the type conversion there.

-O

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

http://archives.postgresql.org

j.random.programmer

unread,
Dec 19, 2005, 6:41:36 PM12/19/05
to
> JDBC's "BIT" is actually a boolean type. In
> JDBC3, BIT and BOOLEAN are effectively
> equivalent.

Hmm.

> The backend's "bit" type is actually a bitstring
> that does not have a
> direct equivalent in JDBC.

Aha !

So postgres really has a BITSTRING which is
conceptually different from a BIT type ? (since
BIT is also used instead of BITSTRING, you
can see why there is bound to be confusion).

Anywho, in the JDBC driver, why not convert
java booleans as follows:

true -> '1'
false -> '0'

and store that in the BIT column ?

While retrieving, do the reverse conversion.

Of course, if someone has the following
in the BIT column

'1001010'

then:
a) allow the entire value to be retrieved as a String
(getString...)
b) If there are any 1's present, return true
is retrieving it as boolean, false if all 0's.

Best,
-j


__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com

---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Dave Cramer

unread,
Dec 19, 2005, 7:14:16 PM12/19/05
to
This isn't the problem. The problem is that was bind the parameter to
the type. So setBoolean binds the parameter to a boolean type.

putting ' quotes around it will not help matters.

Dave


---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

Oliver Jowett

unread,
Dec 20, 2005, 2:03:40 AM12/20/05
to
j.random.programmer wrote:

> Anywho, in the JDBC driver, why not convert
> java booleans as follows:
>
> true -> '1'
> false -> '0'
>
> and store that in the BIT column ?

That wouldn't help you as the parameter is typed as boolean at the
protocol level, as is reflected in your error message -- it is a type
issue, not a representation issue.

If you really want to do a conversion, make it explicit in your query.

> Of course, if someone has the following
> in the BIT column
>
> '1001010'
>
> then:
> a) allow the entire value to be retrieved as a String
> (getString...)

We do that already.

> b) If there are any 1's present, return true
> is retrieving it as boolean, false if all 0's.

That seems very error-prone.

-O

---------------------------(end of broadcast)---------------------------

j.random.programmer

unread,
Dec 20, 2005, 11:41:29 PM12/20/05
to
Ok. This while BIT thing is very non-intuitive from my
perspective.

First consider this:
In PSQL:
--------------------------------------
test=# create table foo (bit_val bit(5));
CREATE TABLE
test=# insert into foo (bit_val) values ('B10101');
INSERT 0 1
test=# insert into foo (bit_val) values ('11111');
INSERT 0 1
test=# select * from foo;
bit_val
---------
10101
11111
(2 rows)
------------------------------------

Value 'B11110' IS 100% valid according to
the postgresql manual. (for a BIT(5) column
type).

Now, from JDBC this is impossible.

BOTH of the following give exceptions and
error out.

With val = '11111'
------------------------------------
PreparedStatement pstmt =
con.prepareStatement(
"insert into foo (bit_val) values (?)"
);
pstmt.setString(1, val);
pstmt.executeUpdate();
-----------------------------------

The same with val = 'B11111'
The same with val = true
...etc...

SQLException: SQLState(42804)
Exception in thread "main"


org.postgresql.util.PSQLException: ERROR: column
"bit_val" is of type bit but expression is of type

character varying
at
org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1514)
at
org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1299)

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

As far as I can tell, this is a big problem. Or
am I missing something ? [Is there *ANY* way
to get a value into a BIT column from JDBC
via preparedstatements ?]

Best regards,
--j

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

Oliver Jowett

unread,
Dec 21, 2005, 2:22:52 AM12/21/05
to
j.random.programmer wrote:
> Ok. This while BIT thing is very non-intuitive from my
> perspective.

It sure is. You're trying to deal with a type that's not directly
supported by the JDBC spec, using only spec-provided mechanisms. Having
a JDBC type called "BIT" which actually maps to a single boolean type is
very confusing. If you assume that JDBC's BIT has *nothing* to do with
the server type called "bit", and that it's just a coincidence that they
have the same name, then things should be clearer.

> In PSQL:
> --------------------------------------
> test=# create table foo (bit_val bit(5));
> CREATE TABLE
> test=# insert into foo (bit_val) values ('B10101');
> INSERT 0 1
> test=# insert into foo (bit_val) values ('11111');
> INSERT 0 1

The equivalent queries if you are using the JDBC driver and
PreparedStatement.setString() look like this:

>> test=# create table foo (bit_val bit(5));
>> CREATE TABLE

>> test=# insert into foo (bit_val) values ('B10101'::varchar);


>> ERROR: column "bit_val" is of type bit but expression is of type character varying

>> HINT: You will need to rewrite or cast the expression.
>> test=# insert into foo (bit_val) values ('11111'::varchar);


>> ERROR: column "bit_val" is of type bit but expression is of type character varying

>> HINT: You will need to rewrite or cast the expression.

Does that error look familiar? :)

> With val = '11111'
> ------------------------------------
> PreparedStatement pstmt =
> con.prepareStatement(
> "insert into foo (bit_val) values (?)"
> );
> pstmt.setString(1, val);
> pstmt.executeUpdate();
> -----------------------------------
>
> The same with val = 'B11111'
> The same with val = true
> ...etc...
>
> SQLException: SQLState(42804)
> Exception in thread "main"
> org.postgresql.util.PSQLException: ERROR: column
> "bit_val" is of type bit but expression is of type
> character varying

It is a *type* issue, not a representation issue. That error is
occurring before the server even looks at the parameter value you've
passed -- the problem is that you're passing a varchar parameter
(courtesy of using setString()) in a context where the server is
expecting something that can be implicitly cast to a bit(n) value, and
there is no such implicit conversion from varchar.

Use something like this to get an explicit type conversion from varchar
to bit(5):

INSERT INTO foo(bit_val) VALUES (CAST (? AS bit(5)))

or (nonstandard):

INSERT INTO foo(bit_val) VALUES (?::bit(5))

Or turn on autocasting for string parameters (see the development driver
docs).

If you want to support bit(n) directly, you could write an extension
type (subclass of PGobject). AFAIK noone has written this yet.

Another possible mapping would be to/from a Java boolean array. This has
the problem that a Java array of booleans passed to setObject() should
probably be mapped to an array of booleans on the server side, not to a
bit(n) type.

-O

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Oliver Jowett

unread,
Dec 21, 2005, 2:24:57 AM12/21/05
to
Oliver Jowett wrote:

> or (nonstandard):
>
> INSERT INTO foo(bit_val) VALUES (?::bit(5))

Actually, this doesn't appear to work. The CAST variant works fine, use
that instead.

-O

---------------------------(end of broadcast)---------------------------

Oliver Jowett

unread,
Dec 21, 2005, 2:26:54 AM12/21/05
to
Oliver Jowett wrote:
> Oliver Jowett wrote:
>
>> or (nonstandard):
>>
>> INSERT INTO foo(bit_val) VALUES (?::bit(5))
>
>
> Actually, this doesn't appear to work. The CAST variant works fine, use
> that instead.

Bah, I'm really not having much luck with sending email before I've
completely checked things today, sorry about all the individual
corrections :/

CAST doesn't work either -- it seems there is no explicit cast from
varchar to bit(n) at all.

So you can either mess with input functions directly, or write a custom
PGobject type, or turn on string autocasting.

Csaba Nagy

unread,
Dec 21, 2005, 4:32:29 AM12/21/05
to
[snip]

> Another possible mapping would be to/from a Java boolean array. This has
> the problem that a Java array of booleans passed to setObject() should
> probably be mapped to an array of booleans on the server side, not to a
> bit(n) type.

What about a java.util.BitSet ? Or does it have to extend PGObject ?

Cheers,
Csaba.

Markus Schaber

unread,
Dec 21, 2005, 4:59:06 AM12/21/05
to
Hi, Csaba,

Csaba Nagy wrote:

>>Another possible mapping would be to/from a Java boolean array. This has
>>the problem that a Java array of booleans passed to setObject() should
>>probably be mapped to an array of booleans on the server side, not to a
>>bit(n) type.
>
> What about a java.util.BitSet ? Or does it have to extend PGObject ?

Currently, all Objects have either to be special cased inside the
driver, or extend PGObject (which does not allow binary transfer).

There were several ideas to change this, but AFAIR none of them was
implemented.

Markus

--
Markus Schaber | Logical Tracking&Tracing International AG
Dipl. Inf. | Software Development GIS

Fight against software patents in EU! www.ffii.org www.nosoftwarepatents.org

Oliver Jowett

unread,
Dec 21, 2005, 7:41:30 AM12/21/05
to
Csaba Nagy wrote:
> [snip]
>
>>Another possible mapping would be to/from a Java boolean array. This has
>>the problem that a Java array of booleans passed to setObject() should
>>probably be mapped to an array of booleans on the server side, not to a
>>bit(n) type.
>
>
> What about a java.util.BitSet ? Or does it have to extend PGObject ?

BitSet would work. The only real reason to extend PGobject is so you can
implement support for extra types without modifying the driver itself.

-O

---------------------------(end of broadcast)---------------------------

0 new messages