# Dynamischen String in SQL Statement einbinden



## fnerz (22. Aug 2014)

Hallo zusammen!

Ich möchte eine dynamischen String in ein SQL Statement einbinden, da der Filename variabel sein kann.


```
Connection con = null;
                Statement stmt = null;
                String query = null;
                
                String filen = filename.substring(0, filename.indexOf('.'));
                con = DriverManager.getConnection("jdbc:postgresql_postGIS://localhost:5433" + "user=postgres;password=dominik1;" + "database=geonetwork");
                query = "ALTER TABLE " + filen + " ADD GN_id INTEGER(10) ";
                stmt = con.createStatement();
                stmt.execute(query);
```

Erstmal eine kleine Anmerkung: Die Datenbank-Connectiondetails werden später noch in eine Properties Datei ausgelagert, also nicht gleich an den Kopf fassen

Problem ist nun, dass mir findbugs einen Bug raushaut, genauer gesagt diesen hier: org.fao.geonet.services.resources.UploadAndProcess.exec(Element, ServiceContext) passes a nonconstant String to an execute method on an SQL statement

Ich habe die ganze Sache schon mal mit String.Format versucht, allerdings hat dies an der Bugmeldung nichts geändert. 

Gibt es irgendeine weitere Variante wie ich das Statement korrekt ausführen könnte ohne das findbugs meckert?

Besten Dank schon mal im Voraus!


----------



## Serrano (22. Aug 2014)

Hast du mit prepared statements versucht?

```
PreparedStatement prepStmt = con.prepareStatement("ALTER TABLE " + filen + " ADD GN_id integer (10)");
prepStmt.executeUpdate();
```


----------



## taro (22. Aug 2014)

> Hast du mit prepared statements versucht?


wird das Problem nicht lösen.

entweder query als final deklarieren oder Warnung unterdrücken - leider kann man in diesem Fall kein PreparedStatement.setString() nutzen


----------



## fnerz (23. Aug 2014)

taro hat gesagt.:


> wird das Problem nicht lösen.
> 
> entweder query als final deklarieren oder Warnung unterdrücken - leider kann man in diesem Fall kein PreparedStatement.setString() nutzen



Genau, mit prepared statements hatte es auch nicht hingehauen.

Das mit dem Unterdrücken in findbugs ist mir auch ein Rätsel. Ich habe über die Methode @SuppressWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") angefügt, aber nix tat sich.

Mit final hatte ich es noch nicht versucht. Werde ich dann noch nachholen!


----------



## taro (23. Aug 2014)

Die Warnung solltest du mit folgender Zeile unterdrücken können:

```
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {"SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" }, justification = "Irgend ein Grund")
```

Alternativ ist halt die Frage, ob das von dir genutzte DB-Design sinnig ist - zum einen wirst du bei Dateinamen wie a.b.c.txt unerwartete Ergebnisse bekommen, zum anderen lässt sich eine Datei nicht ohne weiteres umbenennen. Und zu guter letzt käme ich nie auf die Idee, eine Operation vom Dateinamen abhängig zu machen.


----------



## JavaMeister (23. Aug 2014)

Wieso sollte man DDL überhaupt dynmisch machen? 

Hier liegt definitif ein Designfehler vor.


----------



## fnerz (26. Aug 2014)

taro hat gesagt.:


> Die Warnung solltest du mit folgender Zeile unterdrücken können:
> 
> ```
> @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {"SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" }, justification = "Irgend ein Grund")
> ...



Ich würde das ganze gerne über eine ID machen, allerdings sind die IDs des Datensätze in der Datenbank abweichend von den IDs im Metadatenkatalog Geonetwork. Nur die Namen sind gleich. Deshalb muss die Operation zu Anfang wohl von dem Dateinamen abhängig sein. Ich möchte aber darauf eine ID-Spalte hinzufügen und die Zellen jeweils auf den Wert der ID vom Metadatenkatalog setzen, damit ich danach immer über IDs handeln kann.
Im Moment fällt mir als Anfänger da nur ein, mit einem dynamischen String zu arbeiten? Gibt es da schlauerer Methoden?

Ich habe die query nun auch mal als final deklariert, was jedoch nicht zur Beseitigung des Problems führte.

Hinsichtlich der Zeile, welche die Warnung unterdrücken soll: Sind da noch irgendwelche Anpassungen notwendig? 
Derzeitige Meldungen: edu cannot be resolved to a type, the attribut value is undefined for the annotation type SupressWarning, the attribut justification is undefined for the annotation type SupressWarning

Nochmals besten Dank für jeden Tipp!


----------



## taro (26. Aug 2014)

zur Annotation zitiere ich mal die Dokumentation von findbugs


> FindBugs supports several annotations to express the developer's intent so that FindBugs can issue warnings more appropriately. You need to use Java 5 to use annotations, and must place the annotations.jar and jsr305.jar files in the classpath while compiling your program.
> 
> Quelle: Chapter 10. Annotations






> Ich würde das ganze gerne über eine ID machen, allerdings sind die IDs des Datensätze in der Datenbank abweichend von den IDs im Metadatenkatalog Geonetwork. Nur die Namen sind gleich. Deshalb muss die Operation zu Anfang wohl von dem Dateinamen abhängig sein. Ich möchte aber darauf eine ID-Spalte hinzufügen und die Zellen jeweils auf den Wert der ID vom Metadatenkatalog setzen, damit ich danach immer über IDs handeln kann.
> Im Moment fällt mir als Anfänger da nur ein, mit einem dynamischen String zu arbeiten? Gibt es da schlauerer Methoden?



Ich kenne Geonetwork nicht, deswegen:

Zeige doch bitte einmal "anschaulich", was du vorliegen hast und was du erreichen willst.

So wie ich es lese, hast du mehrere Dateien mit Datensätzen, welche du 1 zu 1 in eine DB überführen möchtest. Dabei hast du für jede Datei eine eigene Tabelle - die Frage die sich mir hier stellt: Warum?


----------



## fnerz (27. Aug 2014)

taro hat gesagt.:


> zur Annotation zitiere ich mal die Dokumentation von findbugs
> 
> 
> 
> ...



Hallo Taro!

Die Dateien sind bereits in die PostGIS Datenbank überführt worden. Dies hat ein Student zuvor gemacht. Hier ist aber bereits das genannte Problem, da der Student nicht diesselben IDs genutzt hat. Beispiel: ID der Datei1 im Geonetwork: 50, ID der Datei in der Datenbank: 2.
Mein Betreuer hat mir nun die Aufgabe zugeteilt, dass ich alle Tabellen mit einer weiteren ID-Spalte versehen soll, dessen Wert der ID im Geonetwork entspricht.

Zum groben Ablauf was erreicht werden soll:
-Ein User lädt eine eine Shapefile-Datei in Geonetwork hoch (Shapefile ist eine Datei, die Geometriedaten beinhaltet und weitere Informationen enthält, also X und Y Koordinaten, Höhe, Name des Ortes usw). Die Datei wird gleichzeitig in eine postGIS Datenbank als Tabelle hochgeladen.
- Die Tabelle kann direkt aus der postGIS Datenbank heraus in QuantumGIS (ein Geoinformationssystem zum Bearbeiten von räumlichen Daten) geladen und aktualisiert werden (Bsp: Einfügen von neuen Straßen als Liniendaten, Bäumen als Punktddaten etc.)
Die ganzen räumliche Tabellen werden somit immer aktuell geladen.
- Die aktuellen Tabelle der jeweiligen Datei soll im Geonetwork bei Interesse wieder runtergeladen werden können. Dazu wird die postGIS Tabelle wieder in eine Shapefile umgewandelt, sodass der Nutzer die Karte in einer der gängigen Geoinformationssystem-Softwareprodukte anschauen kann (nicht bearbeiten). 
Hier tritt das Problem auf, da wie bereits erwähnt die IDs nicht übereinstimmen.
Im Geonetwork wird nach dem Klicken auf dem Download-Button gesagt: "Lade die postGIS-Tabelle mit der ID xx runter und wandle sie zuvor in eine ShapeFile um." Geonetwork geht dabei von der ID aus, unter dem die Datei damals nach dem Hochladen im Katalog gespeichert wurde. Das haut natürlich nicht korrekt hin, da die ID in der Datenbank nicht gefunden wird bzw. eine andere Tabelle angefragt wird, die garnicht interessiert.

Da ich die IDs in der Datenbank nicht manuell anpassen kann, möchte ich nun wie beschrieben die Tabellen vor dem Download editieren und mit einer weiteren ID Spalte ausstatten, welche den Wert besitzt, unter der die Datei im Geonetwork gespeichert ist. 
Und diese in meinen Augen eigentlich einfache Aufgabe haut nicht hin, weil mir entweder findbugs einen Strich durch die Rechnung macht oder anderer Probleme auftreten.

Ich hoffe, dass es anschaulich genug war. 

Viele Grüße


----------



## fnerz (27. Aug 2014)

taro hat gesagt.:


> Die Warnung solltest du mit folgender Zeile unterdrücken können:
> 
> ```
> @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {"SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" }, justification = "Irgend ein Grund")
> ```



Das hat nun hingehauen. 
Es hatte nur noch gefehlt, die annotations.jar in den classpath hinzufügen. Besten Dank für die Zeile!


----------

