Hi Trejkaz,

I can reproduce your results if my UserAuthenticator throws a SQLException whose SQLState is 08004, one of the SQLStates reserved for use by Derby. If my UserAuthenticator throws a SQLException whose SQLState is ZZZZZ, a state not reserved by Derby, then the exception traverses the network correctly and is seen by the client application. Here is a sample program showing the success case:

import java.sql.*;

public class ZZ
{
    public static void main( String... args ) throws Exception
    {
        try {
            Connection  conn = DriverManager.getConnection
( "jdbc:derby://localhost:8246/memory:db;create=true;user=foo;password=bar" );
        }
        catch (Throwable t) { printThrowable( t ); }
    }

    private static  void    printThrowable( Throwable t )
    {
        if ( t == null ) { return; }

        println( "\nThrowable is a " + t.getClass().getName() );
        println( "    message = " + t.getMessage() );

        if ( t instanceof SQLException )
        {
            SQLException    se = (SQLException) t;

            println( "    SQLState = " + se.getSQLState() );
            printThrowable( se.getNextException() );
        }

        printThrowable( t.getCause() );
    }

private static void println( String text ) { System.out.println( text ); }
}

...and here is the UserAuthenticator I used:

import java.sql.SQLException;
import java.util.Properties;

import org.apache.derby.authentication.UserAuthenticator;

public class Z implements UserAuthenticator
{
    public Z() {}

    public boolean authenticateUser
        (
         String userName,
         String userPassword,
         String databaseName,
         Properties info
         )
       throws SQLException
    {
        throw new SQLException( "I can't do that, Dave.", "ZZZZZ" );
    }
}

Hope this helps,
-Rick

On 4/26/12 10:09 PM, Trejkaz wrote:
On Mon, Apr 23, 2012 at 10:50 PM, Rick Hillegas
<[email protected]>  wrote:
UserAuthenticator.authenticateUser() can throw a SQLException which explains
that the user doesn't have access to the given database. I find that
SQLExceptions raised by the following code reach the application:
[snip]

I just gave this a shot, but it doesn't appear to work, at least not
over the client-server connection.

I tried it using a mock authenticator:

     mockery.checking(new Expectations() {{
         oneOf(authenticator).authenticateUser("bob", "bob",
dbDir.getAbsolutePath(), new Properties());
         will(throwException(new
SQLNonTransientConnectionException("Database access denied for user
bob", "08004.C.3")));
     }});

Then when I connect to the database, I do get back SQLState "08004",
but it's "08004.C.1" with a different error message to the one I
returned. My initial guess would be that Derby swallows the
authentication exception on the server side, sends some kind of error
code over the wire and then the client driver propagates a brand new
exception to the application.

TX


Reply via email to