2010-08-17 8 views
2

J'écris une application Java qui fonctionne avec Apache Derby via JDBC. Je vais avoir des problèmes avec le code dans l'extrait suivant:Derby INSERT SELECT null pointeur exception

byte md5[] = md5sum(file); 

PreparedStatement s = con.prepareStatement("INSERT INTO input_files (job_ID, hash) SELECT job_id, ? FROM job WHERE job_name = ?"); 
s.setBytes(1, md5); 
s.setString(2, jobName); 
s.executeUpdate(); 
s.close(); 

Ceci insère dans les tableaux suivants:

CREATE TABLE input_files 
(
    hash char(16) for bit data, 
    job_id integer REFERENCES job, 
    PRIMARY KEY(job_id, hash) 
); 

CREATE TABLE job 
(
    job_id integer PRIMARY KEY GENERATED ALWAYS as IDENTITY, 
    job_name character varying(50) UNIQUE NOT NULL, 
    #other fields 
); 

L'idée est qu'il existe un entier interne job_id qui est utilisé en interne par le base de données, mais nous voulons le référencer autant que possible avec la chaîne lisible par l'homme job_name

Cela jette systématiquement l'exception suivante.

java.sql.SQLException: Java exception: ': java.lang.NullPointerException'. 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.Util.javaException(Unknown Source) 
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(UnknownSource) 
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(Unknown Source) 
    at org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at [line 3 of snippet above] 

Comme vous pouvez le voir, cela est éjecté de la ligne où est créée la déclaration préparée - il ne fait pas aussi loin que l'exécuter. Qu'est-ce que je fais mal? La même instruction préparée fonctionne très bien avec PostgreSQL.

[modifier] derby.log:

---------------------------------------------------------------- 
2010-08-18 08:47:08.779 GMT: 
Booting Derby version The Apache Software Foundation - Apache Derby - 10.6.1.0 - (938214): instance a816c00e-012a-8461-611c-0000046700d0 
on database directory /path/to/myDatabase with class loader [email protected] 

Database Class Loader started - derby.database.classpath='' 
2010-08-18 08:47:12.067 GMT Thread[SwingWorker-pool-1-thread-1,5,main] (XID = 316), (SESSIONID = 1), (DATABASE = myDatabase), (DRDAID = null), Cleanup action starting 
2010-08-18 08:47:12.067 GMT Thread[SwingWorker-pool-1-thread-1,5,main] (XID = 316), (SESSIONID = 1), (DATABASE = myDatabase), (DRDAID = null), Failed Statement is: INSERT INTO input_files (job_id, hash) SELECT job_id, ? FROM job WHERE job_name = ? 
java.lang.NullPointerException 
    at org.apache.derby.impl.sql.compile.BitTypeCompiler.storable(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumnList.checkStorableExpressions(Unknown Source) 
    at org.apache.derby.impl.sql.compile.InsertNode.bindStatement(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source) 
    at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(Unknown Source) 
    at org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at [line 3 of snippet] 
Cleanup action completed 

2010-08-18 08:47:12.084 GMT: 
Shutting down instance a816c00e-012a-8461-611c-0000046700d0 with class loader [email protected] 
---------------------------------------------------------------- 

et exception déroulée:

java.sql.SQLException: Java exception: ': java.lang.NullPointerException'. 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.Util.javaException(Unknown Source) 
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(Unknown Source) 
    at org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at [line 3 of snippet above] 
Caused by: java.sql.SQLException: Java exception: ': java.lang.NullPointerException'. 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source) 
... 26 more 
Caused by: java.lang.NullPointerException 
    at org.apache.derby.impl.sql.compile.BitTypeCompiler.storable(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumnList.checkStorableExpressions(Unknown Source) 
    at org.apache.derby.impl.sql.compile.InsertNode.bindStatement(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source) 
    at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source) 
... 19 more 
SQLState: XJ001 
Error code: 0 
Message: Java exception: ': java.lang.NullPointerException'. 
Cause: java.sql.SQLException: Java exception: ': java.lang.NullPointerException'. 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source) 
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.Util.javaException(Unknown Source) 
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source) 
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(Unknown Source) 
    at org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at [line 3 of snippet above] 
Caused by: java.lang.NullPointerException 
    at org.apache.derby.impl.sql.compile.BitTypeCompiler.storable(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumnList.checkStorableExpressions(Unknown Source) 
    at org.apache.derby.impl.sql.compile.InsertNode.bindStatement(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source) 
    at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source) 
... 19 more 
Cause: java.lang.NullPointerException 
    at org.apache.derby.impl.sql.compile.BitTypeCompiler.storable(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumn.checkStorableExpression(Unknown Source) 
    at org.apache.derby.impl.sql.compile.ResultColumnList.checkStorableExpressions(Unknown Source) 
    at org.apache.derby.impl.sql.compile.InsertNode.bindStatement(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source) 
    at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source) 
    at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(Unknown Source) 
    at org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) 
    at [line 3 of snippet above] 

Répondre

2

Une exception de pointeur NULL dans ce contexte - surtout si le même code JDBC fonctionne avec un autre SGBD - regards comme si vous aviez rencontré un bug dans le pilote Derby JDBC. Même si vous avez fait une erreur et transmis des données erronées ou un pointeur nul, le pilote devrait détecter cela et signaler une erreur, sans se bloquer.

+0

Je suis d'accord, cela ressemble à un bug dans Derby. Vous pouvez probablement obtenir plus d'informations (c'est-à-dire, une trace de pile plus complète), en déroulant la chaîne d'exception: http://wiki.apache.org/db-derby/UnwindExceptionChain Aussi, jetez un coup d'œil sur derby.log pour Plus d'information. –

+0

Bug déposé: https://issues.apache.org/jira/browse/DERBY-4780 – Scott

+0

Pour l'enregistrement, apparemment c'était un bug connu, et a été corrigé dans la source de Derby. Le travail consiste à ajouter un cast autour du paramètre - c'est-à-dire 'INSERT INTO input_files (ID_travail, hash) SELECT ID_travail, CAST (? En CHAR (16) POUR BIT DATA) FROM travail WHERE nom_travail =?' – Scott

0
PreparedStatement s = con.prepareStatement("INSERT INTO input_files (job_ID, hash) SELECT job_id, ? FROM job WHERE job_name = ?"); 

"JOB_ID" vs "job_id" la casse et voir si cela corrige le problème.

+0

Aucune joie. Je pensais que SQL était insensible à la casse, de toute façon. – Scott

+0

@Scott: SQL n'est pas sensible à la casse sauf si vous utilisez des identifiants délimités (guillemets dans la norme, crochets dans MS SQL Server, coches de retour dans MySQL, etc.). –

1

Je suppose que vous ne serez pas en mesure de bloquer le code de hachage littéral directement dans la liste des colonnes de sélection, car Derby ne comprend pas que vous voulez y mettre une valeur littérale plutôt qu'un nom de colonne.

Une solution de contournement raisonnable pourrait être de re-code votre application pour exécuter l'instruction INSERT à partir d'une boucle qui lit les valeurs du SELECT. Quelque chose dans le style de:

updateStatement = prepareStatement("insert into input_files (job_id, hash) values (?,?)") 
ResultSet rs = executeQuery("select job_id from job where job_name = ?") 
while (rs.next()) 
    updateStatement.setString(1, rs.getString(1)) 
    updateStatement.setBytes(2, md5sum) 
    updateStatement.executeUpdate() 
+0

Pour contourner le problème, je pense que c'est ce que nous finirons par faire. En fait, nous effectuons des requêtes similaires à quelques endroits, donc si nous mettons en cache la valeur de job_id, nous pouvons améliorer nos performances de base de données. – Scott