Derby/JavaDB SQLException wenn die Datenbank in eine Jar gepackt wurde.

hansmueller

Bekanntes Mitglied
Hallo,

ich habe ein Programm geschrieben, das auf eine Derby-Datenbank (Embedded) zugreift.
Das Programm liest nur. Beim Verbindungsaufbau wird die Datenbank auf "read-only" gesetzt.
Es werden keine Daten geschrieben. Es erfolgt kein gleichzeitiger Zugriff von mehreren Anwendungen auf die Datenbank.

In meiner Entwicklungsumgebung (Eclipse) greife ich auf die ungepackte Datenbank zu, da ich in dieser infolge der Programmierung immer wieder kleinere Datensätze hinzufügen muß.
Es funktioniert auch alles. Der Verbindungsaufbau, die Abfragen und der Verbindungsabbau bei Programmbeendigung.

Jetzt wollte ich das Programm auf einen anderen Rechner zu Vorführungszwecken installieren (wenn man das so sagen kann).
Ich habe die Datenbank in eine Jar-Datei gepackt. Habe das Programm kompiliert und ebenfalls in eine Jar gepackt. (Den Verbindungsaufbau zur DB habe ich natürlich angepaßt. Ein entsprechendes Manifest habe ich auch erstellt.) Die derby.jar ist auch vorhanden.
(Später soll das Programm mit der Datenbank und Derby über WebStart verteilt werden.)

Ich kann das Programm ohne Probleme starten, der Verbindungsaufbau zur Datenbank in der Jar funktioniert auch, ABER bei manchen Abfragen kommen folgende Fehlermeldungen:
java.sql.SQLException: Ein Feature ist nicht implementiert.
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(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.EmbedStatement.executeStatement(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.executeQuery(Unknown Source)
at Datenbankanbindung.mAbfrageElementSonstiges(Datenbankanbindung.java:8758)
...
Caused by: java.sql.SQLException: Ein Feature ist nicht implementiert.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
... 14 more
Caused by: ERROR XSAI3: Ein Feature ist nicht implementiert.
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
at org.apache.derby.impl.store.raw.log.ReadOnly.checkVersion(Unknown Source)
at org.apache.derby.impl.store.raw.RawStore.checkVersion(Unknown Source)
at org.apache.derby.impl.store.access.RAMTransaction.checkVersion(Unknown Source)
at org.apache.derby.impl.store.access.heap.HeapConglomerateFactory.createConglomerate(Unknown Source)
at org.apache.derby.impl.store.access.RAMTransaction.createConglomerate(Unknown Source)
at org.apache.derby.iapi.store.access.DiskHashtable.<init>(Unknown Source)
at org.apache.derby.iapi.store.access.BackingStoreHashtable.spillToDisk(Unknown Source)
at org.apache.derby.iapi.store.access.BackingStoreHashtable.add_row_to_hash_table(Unknown Source)
at org.apache.derby.iapi.store.access.BackingStoreHashtable.putRow(Unknown Source)
at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(Unknown Source)
at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchSet(Unknown Source)
at org.apache.derby.impl.store.access.BackingStoreHashTableFromScan.<init>(Unknown Source)
at org.apache.derby.impl.store.access.RAMTransaction.createBackingStoreHashtableFromScan(Unknown Source)
at org.apache.derby.impl.sql.execute.HashScanResultSet.openCore(Unknown Source)
at org.apache.derby.impl.sql.execute.JoinResultSet.openRight(Unknown Source)
at org.apache.derby.impl.sql.execute.JoinResultSet.openCore(Unknown Source)
at org.apache.derby.impl.sql.execute.JoinResultSet.openCore(Unknown Source)
at org.apache.derby.impl.sql.execute.ProjectRestrictResultSet.openCore(Unknown Source)
at org.apache.derby.impl.sql.execute.UnionResultSet.openCore(Unknown Source)
at org.apache.derby.impl.sql.execute.SortResultSet.openCore(Unknown Source)
at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.open(Unknown Source)
at org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(Unknown Source)
at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
... 8 more

Die Verbindung zur Datenbank in der Jar funktioniert. Ein Großteil der Abfragen funktioniert ebenfalls. Der Verbindungsabbau klappt auch. Im log-File steht nichts über diese geworfenen Fehler. (Nur, daß die Verbindung aufgebaut wurde, mehr nicht.)

Und deshalb meine Frage: Warum funktioniert alles, wenn die Datenbank nicht in eine Jar gepackt ist, und warum funktionieren auf einmal bestimmte Abfragen nicht mehr, sobald die Datenbank in eine Jar gepackt wurde? ???:L

Der Umstand, daß die DB in einer Jar ist, sollte sich doch nicht auf Ihre Funktion auswirken. Zumal die DB ja im "read-only"-Modus betrieben wird.

Hat irgendjemand von euch schon so was ähnliches erlebt und weiß, wie man dieses Problem lösen kann?

Ich werde mir mal die Abfragen genauer anschauen (sind teilweise ziemlich komplizierte und aufwendige SQL-Abfragen) um herauszufinden, ob es da eine Gemeinsamkeit gibt.

Ich hoffe, irgendjemand von euch hat hierzu eine Idee.

MfG
hansmueller
 
Hallo,

ich benutze auch keine besonderen Methoden. Meine Abfragen gehen eigendlich alle nach dem Muster:
Java:
public void mAbfrage()
    {
    	try
    	{   		
    		st = con.createStatement();
    		   		
    		rs = null;
    		
    		rs = st.executeQuery("SELECT");
    		
    		String x = null;
    		
    		while(rs.next())
    		{
    			x = rs.getString(1);
    		}
    		
    		System.out.println(x);    		    		
    	}
    	catch(Exception e)
    	{
    		e.printStackTrace();    	
    	}
    	finally
    	{
    		mAufraeumenAbfrage();
    	}
    }

Ich benutze teilweise auch noch PreparedStatements. Da gehe ich aber vom Prinzip her genauso vor, wie im obrigen Muster.

Die SQL-Abfragen, die nicht funktionieren weisen auf den ersten Blick auch keine besonderen Abnormitäten oder extravagante SQL-Konstrukte auf im Vergleich zu den funktionierenden Abfragen auf.

Bin für jeden Tipp dankbar - auch wenn es noch so unwahrscheinlich erscheint oder an den Haaren herbeigezogen ist.

MfG
hansmueller
 
Hallo,

ich habe mit
Java:
System.setProperty("derby.language.logStatementText", "true");
//und    		
System.setProperty("derby.stream.error.logSeverityLevel", "0");
in der derby.log nun ein paar Infos mehr. Aber leider keine, die mir weiterhelfen.

Ich habe ein kleines Testprogramm geschrieben, welches ein Prepared Statement ausführt. (War die kürzeste Abfrage von allen Abfragen.)

Zuerst bereitet die Datenbank mit
Code:
Begin compiling prepared statement:
das Prepared-Statment vor.
Diese Vorbereitung wird auch beendet
Code:
End compiling prepared statement:
.
Anschließend wird das Statement ausgeführt
Code:
Executing prepared statement:
.
Bei der nicht in eine Jar gepackten Datenbank wird jetzt das entsprechende Ergebnis von meinen Programm ausgelesen.
Bei einer in eine Jar gepackten Datenbank kommen jetzt noch folgende Log-Einträge:
Zuerst ein
Code:
Cleanup action starting
, dann ein
Code:
Failed Statement is:
und schließlich folgt die Fehlermeldung
Code:
ERROR XSAI3: Ein Feature ist nicht implementiert.
	at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
	at org.apache.derby.impl.store.raw.log.ReadOnly.checkVersion(Unknown Source)
	at org.apache.derby.impl.store.raw.RawStore.checkVersion(Unknown Source)
	at org.apache.derby.impl.store.access.RAMTransaction.checkVersion(Unknown Source)
	at org.apache.derby.impl.store.access.heap.HeapConglomerateFactory.createConglomerate(Unknown Source)
	at org.apache.derby.impl.store.access.RAMTransaction.createConglomerate(Unknown Source)
	at org.apache.derby.iapi.store.access.DiskHashtable.<init>(Unknown Source)
	at org.apache.derby.iapi.store.access.BackingStoreHashtable.spillToDisk(Unknown Source)
	at org.apache.derby.iapi.store.access.BackingStoreHashtable.add_row_to_hash_table(Unknown Source)
	at org.apache.derby.iapi.store.access.BackingStoreHashtable.putRow(Unknown Source)
	at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(Unknown Source)
	at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchSet(Unknown Source)
	at org.apache.derby.impl.store.access.BackingStoreHashTableFromScan.<init>(Unknown Source)
	at org.apache.derby.impl.store.access.RAMTransaction.createBackingStoreHashtableFromScan(Unknown Source)
	at org.apache.derby.impl.sql.execute.HashScanResultSet.openCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.JoinResultSet.openRight(Unknown Source)
	at org.apache.derby.impl.sql.execute.JoinResultSet.openCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.ProjectRestrictResultSet.openCore(Unknown Source)
	at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.open(Unknown Source)
	at org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(Unknown Source)
	at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeQuery(Unknown Source)
	at Datenbankanbindung.mTest01(Datenbankanbindung.java:400)
	at MainProg.main(MainProg.java:12)

Es ist egal, ob ich es als Prepared Statement oder nur als normales Statement mache. Die Log-Datei ändert sich nur darin, daß beim Letzteren kein Parameter für das ? angegeben wird.

Mit dem Codeschnipsel:
Java:
catch (SQLException e)
		{
			do
			{
				System.out.println("SQLState:" + e.getSQLState());
				System.out.println("Error Code:" + e.getErrorCode());
				System.out.println("Message:" + e.getMessage());
				Throwable t = e.getCause();
				while (t != null)
				{
					System.out.println("Cause:" + t);
					t = t.getCause();
				}
				e = e.getNextException();
			}
			while (e != null);
		}
bekomme ich noch folgende Meldung:
Code:
SQLState:XSAI3
Error Code:30000
Message:Ein Feature ist nicht implementiert.
Cause:java.sql.SQLException: Ein Feature ist nicht implementiert.
Cause:ERROR XSAI3: Ein Feature ist nicht implementiert.

Kann mit diesen Informationen irgendwer was anfangen?

MfG
hansmueller
 
Hallo,

mit Hilfe eines Kollegen konnte ich die SQL-Abfrage so umändern, daß sie mit einer in eine Jar gepackten Datenbank wieder funktioniert.

Der ursprüngliche SQL-Befehl lautete:
SQL:
SELECT ArtikelTab.ArtikelNr, SpracheTab.Text1, ArtikelTab.Sortiment 
FROM ArtikelTab INNER JOIN SpracheTab ON ArtikelTab.ArtikelNr = SpracheTab.IdentifikationsNr INNER JOIN FassadenartenGruppeTab ON ArtikelTab.ArtikelNr = FassadenartenGruppeTab.ArtikelNr 
WHERE SpracheTab.Sprache = 'de' 
AND ArtikelTab.Baugruppe = 'asdf' 
AND (ArtikelTab.Systembreite = ? OR ArtikelTab.Systembreite IS NULL) 
AND ArtikelTab.Lage LIKE '%Vertikal%' 
AND FassadenartenGruppeTab.Fassadenart = 'xyz' 
AND ArtikelTab.Sortiment = 's' 
ORDER BY ArtikelNr

Wie schon geschrieben, in einer ungepackten Datenbank funktioniert diese Abfrage.
Damit diese Abfrage auch in einer in eine Jar gepackten Datenbank funktioniert muß man sie wie folgt umändern:
SQL:
SELECT ArtikelTab.ArtikelNr, SpracheTab.Text1, ArtikelTab.Sortiment 
FROM ArtikelTab INNER JOIN SpracheTab ON ArtikelTab.ArtikelNr = SpracheTab.IdentifikationsNr INNER JOIN FassadenartenGruppeTab ON ArtikelTab.ArtikelNr = FassadenartenGruppeTab.ArtikelNr 
WHERE SpracheTab.Sprache = 'de' 
AND ArtikelTab.Baugruppe = 'asdf' 
AND (ArtikelTab.Systembreite = ? OR ArtikelTab.Systembreite IS NULL) 
AND ArtikelTab.Lage LIKE '%Vertikal%' 
AND FassadenartenGruppeTab.Fassadenart = 'xyz' 
AND ArtikelTab.Sortiment = 's' 
ORDER BY IdentifikationsNr
Es funktioniert auch, wenn man die Zeile mit dem "ORDER BY" ganz wegläßt.

Man könnte jetzt sagen, daß es an dem "ORDER BY" liegt, aber seltsamerweise liefert folgende Abfrage auch ein Ergebnis, trotz "ORDER BY":
SQL:
SELECT ArtikelTab.ArtikelNr, SpracheTab.Text1, ArtikelTab.Sortiment 
FROM ArtikelTab INNER JOIN SpracheTab ON ArtikelTab.ArtikelNr = SpracheTab.IdentifikationsNr INNER JOIN FassadenartenGruppeTab ON ArtikelTab.ArtikelNr = FassadenartenGruppeTab.ArtikelNr 
WHERE SpracheTab.Sprache = 'de' 
AND (ArtikelTab.Systembreite = ? OR ArtikelTab.Systembreite IS NULL) 
AND FassadenartenGruppeTab.Fassadenart = 'xyz' 
ORDER BY ArtikelNr

Das ist schon ein sehr merkwürdiges Verhalten? ???:L

Es ist allerdings sehr mühsam durch herumprobieren zu versuchen die nicht funktionierenden Abfragen wieder zum Laufen zu bringen. Zumal ich bei einigen kein "ORDER BY" verwendet habe.

Hat von euch wirklich keiner eine Idee, wie dieses Problem zu lösen ist?

Ach ja, ich habe natürlich auch daran gedacht ein derby.storage.tempDirectory zu setzten - daran kann es also nicht liegen.

MfG
hansmueller
 
"ERROR XSAI3" kann man suchen, führt z.B. zu
Old Nabble - Apache Derby Users - ResultSet.next() throws ERROR XSAI3: Feature not implemented.
und dann
https://issues.apache.org/jira/browse/DERBY-2354

anscheinend muss die Datenbank für JOINs oder andere Spezialitäten auf der Festplatte zwischenspeichern,
das ist halt Pech, anscheinend nicht nicht für Verpackung ausgelegt?

> Ach ja, ich habe natürlich auch daran gedacht ein derby.storage.tempDirectory zu setzten - daran kann es also nicht liegen.

ok, vielleicht dann nix neues von mir
 
Hallo,

habe mal bei Derby direkt nachgefragt.

Wenn man mit sehr langen Listen in der Datenbank hantiert, dann will Derby anscheinend etwas auf die Platte zwischenspeichern. Bei einer Read-only Datenbank funktioniert das aber trotz angegebenen TempDirectory anscheinend nicht.

Wenn man bei den SQL-Abfragen ein
Code:
--DERBY-PROPERTIES joinStrategy = NESTEDLOOP
bei jeder Tabelle nach dem FROM setzt, kann man das Problem umgehen.
Dieser Workaround scheint ganz gut zu funktionieren - muß ihn allerdings noch etwas austesten.

Nähere Infos siehe: Re: Problems with SQL-Queries if the database is stored in a jar

Ach ja, man muß nach dem
Code:
--DERBY-PROPERTIES joinStrategy = NESTEDLOOP
auch noch einen Zeilenumbruch setzten, damit der nachfolgende Teil der SQL-Abfrage nicht als Kommentar behandelt wird.

MfG
hansmueller
 
Hallo,

der Fehler wurde mit der neuen Derby-Version 10.8.1.2 behoben.

(Der Workaround funktionierte zwar, hat sich aber extrem negativ auf die Geschwindigkeit ausgewirkt.)

MfG
hansmueller
 

Neue Themen


Zurück
Oben