Re: citext data type does not work with JDBC PreparedStatement?

From: Anton Moiseev <benderamp(at)gmail(dot)com>
To: Craig Ringer <ringerc(at)ringerc(dot)id(dot)au>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: citext data type does not work with JDBC PreparedStatement?
Date: 2011-08-06 10:38:12
Message-ID: CAJFs0QC_nn5WxhrgMuXsK=WCc5JHvMmGk+zHoiwLz-EG7W2a4A@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On Sat, Aug 6, 2011 at 1:49 PM, Craig Ringer wrote:

> On 6/08/2011 5:28 PM, Anton Moiseev wrote:
>
>> Hi,
>>
>> I wanted to have case-insensitive user names in my db and found that
>> citext postgresql data type
>> (http://www.postgresql.org/**docs/8.4/interactive/citext.**html<http://www.postgresql.org/docs/8.4/interactive/citext.html>)
>> is exactly
>> what I need.
>>
>> So I have added to my db and it seemed to work fine when query db from
>> command line interface, but when I run it from java prepared statement,
>> things do not work as expected.
>>
>> For example, I have user name 'Leon' stored in the db and want to get
>> password for him.
>>
>> If I execute query in sql console:
>> SELECT password FROM users WHERE name = 'leon';
>>
>
> I hope that's not an example from your code... because storing passwords in
> clear text is almost always an *INCREDIBLY* bad idea.
>
> If at all possible, hash the password using a salted hash function, and
> compare the hashes when checking passwords.
>
>
This is stripped test case, password column would return hashed password,
and actually the authentication code is located in JDBCRealm in apache
tomcat which also uses PreparedStatement mostly in the same way as above.

>
> final String query = "SELECT password FROM users WHERE name = ?";
>> final PreparedStatement stmt =
>> dbConnection.prepareStatement(**query);
>> stmt.setString(1, "leon");
>>
>
>
> password won't be found.
>>
>
>
> What's the query sent to the backend? Enable query and parameter logging in
> postgresql.conf, re-run your test, and see what the server receives.
>

Yes, the problem was in how jdbc sends the final query to server. I have
tried to look at the postgres JDBC source code and found the following place
in AbstractJdbc2Statement:

public void setString(int parameterIndex, String x) throws SQLException
{
checkClosed();
setString(parameterIndex, x, (connection.getStringVarcharFlag() ?
Oid.VARCHAR : Oid.UNSPECIFIED));
}

So it seems that it might do some kind of casting strings to varchar if
connection.getStringVarcharFlag() is true (and citext docs say that casting
column to text during comparison would result case-sensitive operation).

So, in AbstractJdbc2Connection I have found that "stringtype" connection
property value affects this flag - "unspecified" would result
bindStringAsVarchar = false;

So I have tried to create connection in this way:

final Properties props = new Properties();
props.put("user", "db_user");
props.put("password", "db_pass");
props.put("stringtype", "unspecified");

Class.forName("org.postgresql.Driver");
Connection dbConnection =
DriverManager.getConnection("jdbc:postgresql://db_host/db_name", props);

and case-insensitive comparison started to work even with jdbc statement
setString(xxx).

And also just for the record - tomcat JDBCRealm would work in
case-insensitive way the the following connectionURL param provided in
context.xml:

connectionURL="jdbc:postgresql://db_host/db_name?user=db_user&amp;password=db_password&amp;stringtype=unspecified"

thank's

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Antonio Goméz Soto 2011-08-06 13:28:03 Re: FREE hosting platforms with PostgreSQL, Java SDK, Tomcat, ecc.?
Previous Message Fernando Pianegiani 2011-08-06 10:12:15 Re: FREE hosting platforms with PostgreSQL, Java SDK, Tomcat, ecc.?