Validator für einen SQL-Befehl

NicoRyl

Mitglied
Hallo zusammen.
Was ich hier versuche ist ein Validator für gewisse(!) SQL-Befehle. Am Ende soll der Validator einen Befehl wie "SELECT spalte FROM tabelle WHERE spalte = wert;" validieren können. Leider stehe ich gerade ein wenig auf dem Schlauch und komme nicht weiter.
Ich hoffe jemand kann mich wieder in die Spur bringen. 🙂

Vielen Dank schonmal im Voraus!

Java:
public class SQLValidator {

  public static final char[] ALLOWED_CHARACTERS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', ',', '*', ';'};

  public static final String[] ALLOWED_CHARACTERS_FOR_WHERE = {"<", ">", "=", "LIKE"};


  public boolean isValidSQL(String sql) {

    String[] sqlInParts = sql.split("\\s");
    for (String a:sqlInParts)
      System.out.println(a);

    if(sqlInParts[0] != "SELECT"){
      return false;
    }

    if(sqlInParts[1] != ALLOWED_CHARACTERS.toString()){
      return false;
    }

    if(sqlInParts[2] != "FROM"){
      return false;
    }

    if(sqlInParts[3] != ALLOWED_CHARACTERS.toString()){
      return false;
    }

    if(!sql.endsWith(";")){
      return false;
    }

    return true;
  }
}
 
Also erst einmal ist er Ansatz mit dem Split auch interessant...

Aber es ändert nichts daran, dass dies:
Java:
    if(sqlInParts[1] != ALLOWED_CHARACTERS.toString()){
      return false;
    }
absoluter Müll ist.

a) Lass Dir doch einmal ALLOWED_CHARACTERS.toString() ausgeben. Was ist das?
b) Strings werden nicht mit == und != verglichen!
c) Formuliere erst einmal genau, was da geprüft werden soll. Und prinzipiell hattest Du im anderen Thread sogar schon einen Code bekommen, der prinzipiell sowas in der Art gemacht hat.
 
Hier noch die Main-Methode dazu, ganz vergessen.

Java:
public static void main(String[] args) {
    SQLValidator SQLValidator = new SQLValidator();

    Scanner scanner = new Scanner(System.in);
    System.out.println("Enter SQL-Code: ");
    String sql = scanner.nextLine();

    if (SQLValidator.isValidSQL(sql)) {
      System.out.printf("%s is a valid SQL-Code.\n", sql);
    } else {
      System.out.printf("%s is not a valid SQL-Code.\n", sql);
    }
  }

  private static String prompt(Scanner scanner, String text) {
    System.out.printf("%s: ", text);
    return scanner.next();
  }
 
Also erst einmal ist er Ansatz mit dem Split auch interessant...

Aber es ändert nichts daran, dass dies:
Java:
    if(sqlInParts[1] != ALLOWED_CHARACTERS.toString()){
      return false;
    }
absoluter Müll ist.

a) Lass Dir doch einmal ALLOWED_CHARACTERS.toString() ausgeben. Was ist das?
b) Strings werden nicht mit == und != verglichen!
c) Formuliere erst einmal genau, was da geprüft werden soll. Und prinzipiell hattest Du im anderen Thread sogar schon einen Code bekommen, der prinzipiell sowas in der Art gemacht hat.
Ich weiß deine Hilfe wirklich sehr zu schätzen, aber leider verstehe ich nicht was du mir sagen willst, bzw. was dein vorgeschlagener Code bedeutet. Ich hab's mir angeschaut, verstehe es aber nicht wirklich. Ich will doch einfach nur das eingegebene mit den erlaubten Zeichen abgleichen. Gibt es dafür keine 'einfache' Lösung?
 
Ja, vergleichen von Instanzen bitte immer mit equals. Das == würde nur die Instanzen vergleichen.

Und hast Du mal ein
System.out.println(ALLOWED_CHARACTERS.toString());
gemacht?
Womit würdest Du den String hier vergleichen?

Ich will doch einfach nur das eingegebene mit den erlaubten Zeichen abgleichen.
Kannst Du das näher erläutern? Stell Dir vor, du willst jemandem erklären, was er genau machen soll... Er hat da einen String und so eine Liste mit Zeichen. Was genau soll die Person machen? "abgleichen" sagt ihm nichts ...
 
Bezüglich dem abgleichen vielleicht ein einfaches Beispiel:

Du hast das Alphabet 'a', 'b', 'c'

Und nun sollst Du prüfen:
"aabcbabca"
"abcZbbbab"

Das Alphabet zu einem String zu machen und dann das zu prüfen, dürfte nicht das gewünschte Ergebnis sein, den beides ist nicht "abc". (Aber mach bitte die Ausgabe von dem toString() - der Punkt ist immer noch offen!)
 
Ja, vergleichen von Instanzen bitte immer mit equals. Das == würde nur die Instanzen vergleichen.

Und hast Du mal ein
System.out.println(ALLOWED_CHARACTERS.toString());
gemacht?
Womit würdest Du den String hier vergleichen?


Kannst Du das näher erläutern? Stell Dir vor, du willst jemandem erklären, was er genau machen soll... Er hat da einen String und so eine Liste mit Zeichen. Was genau soll die Person machen? "abgleichen" sagt ihm nichts ...
Ja, du hast Recht das macht keinen Sinn was da raus kommt.

Okey, ich versuche es so verständlich wie Möglich zu erklären:
In der Main-Methode ist ja ein Scanner, in den man dann seinen SQL-Befehl eingeben kann (z.B. SELECT splate1 FROM tabelle1; ). Diese Eingabe zersetze ich dann mit dem Split in die einzelnen Wörter, die dann in dem StringArray gespeichert werden. Anschließend möchte ich die einzelnen Wörter, sprich das 'SELECT', das 'spalte1', usw. , überprüfen, ob diese richtig geschrieben sind oder irgendwelche, nicht erlaubten Zeichen enthalten sind. Außerdem muss am Ende ein Semikolon stehen, was natürlich auch überprüft werden soll.

In dem CharArray 'ALLOWED_CHARACTERS' habe ich alle erlaubten Zeichen eingetragen und habe gedacht, dass das eingegebene Wort mit diesen Zeichen vergleichen kann. Wenn das Wort ein Zeichen enthält, was nicht in dem CharArray enthalten ist, dann soll es natürlich 'false' sein.
 
@MoxxiManagarm @kneitzel

Ich habe das jetzt mal so gemacht:

Java:
public boolean isValidTableColumn(){
      return (StringUtils.isBlank(sqlInParts[1]) || StringUtils.containsAny(sqlInParts[1], ALLOWED_CHARACTERS));
    }

Dann könnte ich das 'ALLOWED_CHARACTERS' ja auch in ein 'DISALLOWED_CHARACTERS' umwandeln, oder? Und dann muss da noch irgendwas in die Klammern hinter 'isValidTableColumn', ich weiß nur nicht was.
 
@MoxxiManagarm @kneitzel
Ich habe jetzt folgendes:
Java:
public class SQLValidator {

  public static final char[] ALLOWED_CHARACTERS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', ',', '*', ';'};

  public static final String[] ALLOWED_CHARACTERS_FOR_WHERE = {"<", ">", "=", "LIKE"};

  public boolean isValidSQL(String sql) {

    String[] sqlInParts = sql.split("\\s");
    for (String a:sqlInParts)
      System.out.println(a);

    if(!sqlInParts[0].equals("SELECT")){
      return false;
    }

    public boolean isValidTableColumnName(){
      return (StringUtils.isBlank(sqlInParts[1]) || StringUtils.containsOnly(sqlInParts[1], ALLOWED_CHARACTERS));
    }

    if(!sqlInParts[2].equals("FROM")){
      return false;
    }

    public boolean isValidTableName(){
      return (StringUtils.isBlank(sqlInParts[3]) || StringUtils.containsOnly(sqlInParts[4], ALLOWED_CHARACTERS));
    }

    if(!sql.endsWith(";")){
      return false;
    }

    return true;
  }
}

Allerdings habe ich immer noch das Problem, dass ich mir nicht sicher bin, was hinter 'isValidTableColumn' und 'isValidTableName' in die Klammern kommt.
 
Also ich würde bei sowas auch - alleine schon aus Übungsgründen - erst einmal selbst lösen. Irgendwelche Libraries mit StringUtils einzubinden, halte ich für nicht gut, wenn es darum geht, diese Grundlagen zu begreifen.

Du willst also über alle Zeichen des Strings gehen und schauen, ob dies in dem Array mit chars enthalten ist.

Das Zeichen eines Strings an eine Position bekommst Du über charAt(index), wobei index von 0 bis length() -1 geht:
Das wäre also etwas wie der folgende Code (der false / true zurück geben würde, also für eine Methode gedacht ist:
Java:
for (int index=0; index < stringValue.length(); index++) {
    if (!arrayContains(ALLOWED_CHARACTERS, stringValue.charAt(index))) return false;
}
return true;

Was uns aber dann noch fehlt, ist so eine arrayContains Methode... Di sieht ähnlich aus: Wir gehen durch alle Elemente durch und wenn wir es finden geben wir true zurück, sonst false:
Java:
  public static boolean arrayContains(final char[] array, final char value) {
    for (char ch: array) {
      if (ch == value) return true;
    }
    return false;
  }

Diese Dinge sind Basics, die Du beherrschen solltest, denn solche Dinge kommen ständig vor. Wobei man später sowas auch mit Streams kürzer und eleganter schreiben würde. Aber das wäre ein Schritt, der später kommen kann, wenn diese Basics sitzen ....
 
Allerdings habe ich immer noch das Problem, dass ich mir nicht sicher bin, was hinter 'isValidTableColumn' und 'isValidTableName' in die Klammern kommt.
Diese Methoden brauchen dann erst einmal Parameter. Was soll denn geprüft werden? Da muss also der String übergeben werden, der geprüft werden soll.

Dann kann eine Methode natürlich nicht innerhalb einer anderen Methode geschrieben werden. Da wo Du die Methode geschrieben hast, müsste der Aufruf rein.
 
Also ich würde bei sowas auch - alleine schon aus Übungsgründen - erst einmal selbst lösen. Irgendwelche Libraries mit StringUtils einzubinden, halte ich für nicht gut, wenn es darum geht, diese Grundlagen zu begreifen.

Du willst also über alle Zeichen des Strings gehen und schauen, ob dies in dem Array mit chars enthalten ist.

Das Zeichen eines Strings an eine Position bekommst Du über charAt(index), wobei index von 0 bis length() -1 geht:
Das wäre also etwas wie der folgende Code (der false / true zurück geben würde, also für eine Methode gedacht ist:
Java:
for (int index=0; index < stringValue.length(); index++) {
    if (!arrayContains(ALLOWED_CHARACTERS, stringValue.charAt(index))) return false;
}
return true;

Was uns aber dann noch fehlt, ist so eine arrayContains Methode... Di sieht ähnlich aus: Wir gehen durch alle Elemente durch und wenn wir es finden geben wir true zurück, sonst false:
Java:
  public static boolean arrayContains(final char[] array, final char value) {
    for (char ch: array) {
      if (ch == value) return true;
    }
    return false;
  }

Diese Dinge sind Basics, die Du beherrschen solltest, denn solche Dinge kommen ständig vor. Wobei man später sowas auch mit Streams kürzer und eleganter schreiben würde. Aber das wäre ein Schritt, der später kommen kann, wenn diese Basics sitzen ....
Ich verstehe was du meinst. Ersetze ich damit dann 'isValidTableColumn', oder wo genau wird dies eingesetzt?
 
Ich verstehe was du meinst. Ersetze ich damit dann 'isValidTableColumn', oder wo genau wird dies eingesetzt?
Das ersetzt StringUtils Aufrufe. Die Apache Commons Library solltest Du am Anfang für solche Dinge nicht nutzen. Das ist nur meine bescheidene Meinung und ich möchte Dir nicht vorgeben, was Du wie machst, aber deine Priorität sollte aus meiner Sicht sein, mit diesem selbstausgesuchten Projekt deine Java Kenntnisse zu vertiefen. Und dazu gehört, dass Du Dir die gezeigten Grundlagen aneignest:
- Wo und wie kannst Du weitere Methoden schreiben um diese dann zu nutzen?
- Wie kannst Du selbst einfache Algorithmen schreiben / Basistypen des Java Frameworks nutzen/verstehen?
 
Das ersetzt StringUtils Aufrufe. Die Apache Commons Library solltest Du am Anfang für solche Dinge nicht nutzen. Das ist nur meine bescheidene Meinung und ich möchte Dir nicht vorgeben, was Du wie machst, aber deine Priorität sollte aus meiner Sicht sein, mit diesem selbstausgesuchten Projekt deine Java Kenntnisse zu vertiefen. Und dazu gehört, dass Du Dir die gezeigten Grundlagen aneignest:
- Wo und wie kannst Du weitere Methoden schreiben um diese dann zu nutzen?
- Wie kannst Du selbst einfache Algorithmen schreiben / Basistypen des Java Frameworks nutzen/verstehen?
Alles klar. Ich habe es jetzt folgendermaßen:

Java:
public class SQLValidator {

  public static final char[] ALLOWED_CHARACTERS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', ',', '*', ';'};

  public static final String[] ALLOWED_CHARACTERS_FOR_WHERE = {"<", ">", "=", "LIKE"};

  public static boolean arrayContains(final char[] array, final char value) {
    for (char ch: array) {
      if (ch == value) return true;
    }
    return false;
  }

  public boolean isValidSQL(String sql) {

    String [] sqlInParts = sql.split("\\s");
    for (String a:sqlInParts)
      System.out.println(a);

    if(!sqlInParts[0].equals("SELECT")){
      return false;
    }

    for (int index=0; index < sqlInParts[1].length(); index++) {
      if (!arrayContains(ALLOWED_CHARACTERS, sqlInParts[1].charAt(index)))
        return false;
    }

   // public boolean isValidTableColumnName(sqlInParts[1]){
   //   return (StringUtils.isBlank(sqlInParts[1]) || StringUtils.containsOnly(sqlInParts[1], ALLOWED_CHARACTERS));
   // }

    if(!sqlInParts[2].equals("FROM")){
      return false;
    }

    for (int index=0; index < sqlInParts[3].length(); index++) {
      if (!arrayContains(ALLOWED_CHARACTERS, sqlInParts[3].charAt(index)))
        return false;
    }

    if(!sql.endsWith(";")){
      return false;
    }

    return true;
  }
 
}

Mir werden zumindest mal keine Fehler mehr vom Programm (IntelliJ IDEA) angezeigt.
 
Alles klar. Ich habe es jetzt folgendermaßen:

Java:
public class SQLValidator {

  public static final char[] ALLOWED_CHARACTERS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', ',', '*', ';'};

  public static final String[] ALLOWED_CHARACTERS_FOR_WHERE = {"<", ">", "=", "LIKE"};

  public static boolean arrayContains(final char[] array, final char value) {
    for (char ch: array) {
      if (ch == value) return true;
    }
    return false;
  }

  public boolean isValidSQL(String sql) {

    String [] sqlInParts = sql.split("\\s");
    for (String a:sqlInParts)
      System.out.println(a);

    if(!sqlInParts[0].equals("SELECT")){
      return false;
    }

    for (int index=0; index < sqlInParts[1].length(); index++) {
      if (!arrayContains(ALLOWED_CHARACTERS, sqlInParts[1].charAt(index)))
        return false;
    }

   // public boolean isValidTableColumnName(sqlInParts[1]){
   //   return (StringUtils.isBlank(sqlInParts[1]) || StringUtils.containsOnly(sqlInParts[1], ALLOWED_CHARACTERS));
   // }

    if(!sqlInParts[2].equals("FROM")){
      return false;
    }

    for (int index=0; index < sqlInParts[3].length(); index++) {
      if (!arrayContains(ALLOWED_CHARACTERS, sqlInParts[3].charAt(index)))
        return false;
    }

    if(!sql.endsWith(";")){
      return false;
    }

    return true;
  }

}

Mir werden zumindest mal keine Fehler mehr vom Programm (IntelliJ IDEA) angezeigt.
Es funktioniert jetzt! Vielen Dank für die Hilfe! Ich habe nun auch verstanden, warum es vorher nicht geklappt hat und wie es nun funktioniert! Darauf kann ich jetzt aufbauen.
 
Jetzt an der Stelle nur noch eine kleine Anregung:

Du hast da zwei Mal fast identischen Code, der sich lediglich durch den Index im sqlParts unterscheidet. Das könnte (sollte) man in eine eigenständige Methode stecken. Vielleicht willst Du das als Übung einfach einmal ausprobieren.
 
Je nach Datenbanksystem unterscheidet sich der SQL-Syntax.
Wie wäre es, wenn du die aus dem SQL-String über die Connection ein PreparedStatement erstellen lässt? Falls das nicht klappt, kriegst du eine Exception mit der Fehlermeldung.
Hier ein Beispiel mit UCanAccess:
Java:
connection.prepareStatement("this is a bad sql string")
[CODE lang="java" title="Meldugn der Exception:"]"UCAExc:::5.0.0-SNAPSHOT unexpected token: THIS in statement [this is a bad sql string]"[/CODE]
 

Zurück
Oben