/*
* 03/01/2004 - 12:27:08
*
* SQLCommand.java -
* Copyright (C) 2004 Dreux Loic
* dreuxl@free.fr
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.analyse.merise.sql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.StringTokenizer;
/**
* Cette classe fait le lien avec une base de donnée. Elle contient permet
* d'exécuter les requêtes avec la base de données.
*/
public class SQLCommand {
public static final int DECONNECTED = 0;
public static final int CONNECTED = 1;
private int state;
private String driver, url, user, password;
private Connection con;
private Statement stmt;
private String error;
private int errorCode;
private ObservableSQL observableSQL;
private List<String> requests;
private List<String> keywords;
private List<String> types;
private List<String> typesWithoutSize;
// Syntaxes SQL disponibles
public enum SQLsyntax { MySQL, PostgreSQL, OracleDB}
public SQLCommand() {
observableSQL = new ObservableSQL();
state = DECONNECTED;
requests = new ArrayList<String>();
initKeywords();
initTypes();
}
/**
* Initialise le Vector contenant les différents mots clé.
*/
private void initKeywords() {
keywords = new ArrayList<String>();
keywords.add("CREATE");
keywords.add("ALTER");
keywords.add("SELECT");
keywords.add("INSERT");
keywords.add("TABLE");
keywords.add("VIEW");
keywords.add("ADD");
keywords.add("NOT");
keywords.add("IN");
keywords.add("AS");
keywords.add("NULL");
keywords.add("PRIMARY");
keywords.add("CONSTRAINT");
keywords.add("REFERENCES");
keywords.add("FOREIGN");
keywords.add("KEY");
/*
* Edité par B. Bouffet le 20/05/2016
* Mots-clés spécifiques Oracle Database
* Permettent de définir l'équivalent du type MySQL AUTO_INCREMENT
* ainsi que de la requête MySQL DROP TABLE IF EXISTS
* Génération de code compatible avec Oracle : à venir...
*/
keywords.add("TRIGGER");
keywords.add("SEQUENCE");
keywords.add("BEFORE");
keywords.add("ON");
keywords.add("FOR");
keywords.add("EACH");
keywords.add("ROW");
keywords.add("BEGIN");
keywords.add("INTO");
keywords.add("FROM");
keywords.add("END");
keywords.add("DECLARE");
keywords.add("WHERE");
keywords.add("IF");
keywords.add("THEN");
keywords.add("EXECUTE");
keywords.add("IMMEDIATE");
keywords.add("DROP");
}
/**
* Initialise le Vector contenant les différents types SQL.
*/
public void initTypes() {
types = new ArrayList<String>();
types.add("TINYINT") ;
types.add("SMALLINT") ;
types.add("MEDIUMINT") ;
types.add("INT") ;
types.add("INT_AUTO_INCREMENT") ; // oups, légère entorse (pour faire plaisir)
types.add("BIGINT_AUTO_INCREMENT") ; // oups, légère entorse (pour faire plaisir)
types.add("INTEGER") ;
types.add("BIGINT") ;
types.add("TIMESTAMP") ;
types.add("CHAR") ;
types.add("VARCHAR") ;
types.add("TINYBLOB") ;
types.add("FLOAT") ;
types.add("DOUBLE PRECISION") ;
types.add("DOUBLE") ;
types.add("REAL") ;
types.add("DECIMAL") ;
types.add("NUMERIC") ;
types.add("DATE") ;
types.add("DATETIME") ;
types.add("TIME") ;
types.add("YEAR") ;
types.add("BIT") ;
types.add("BOOL") ;
types.add("TINYTEXT") ;
types.add("BLOB") ;
types.add("TEXT") ;
types.add("MEDIUMBLOB") ;
types.add("MEDIUMTEXT") ;
types.add("LONGBLOB") ;
types.add("LONGTEXT") ;
types.add("ENUM") ;
types.add("SET") ;
// PostgreSQL specific types.
types.add("SERIAL");
types.add("BIGSERIAL");
types.add("TIMESTAMP");
/*
* Edité par B. Bouffet le 12/05/2016
* Types spécifiques Oracle Database
*/
types.add("BOOLEAN");
types.add("VARCHAR2");
types.add("BINARY_FLOAT");
types.add("BINARY_DOUBLE");
// les types sans taille
typesWithoutSize = new ArrayList<String>();
typesWithoutSize.add("BIT") ;
typesWithoutSize.add("BOOL") ;
typesWithoutSize.add("BOOLEAN") ;
typesWithoutSize.add("BLOB") ;
typesWithoutSize.add("DATE") ;
typesWithoutSize.add("DATETIME") ;
typesWithoutSize.add("ENUM") ;
typesWithoutSize.add("LONGBLOB") ;
typesWithoutSize.add("LONGTEXT") ;
typesWithoutSize.add("MEDIUMBLOB") ;
typesWithoutSize.add("MEDIUMTEXT") ;
typesWithoutSize.add("SET") ;
typesWithoutSize.add("TEXT") ;
typesWithoutSize.add("TIME") ;
typesWithoutSize.add("TINYTEXT") ;
typesWithoutSize.add("YEAR") ;
// tri des données pour affichage ultérieur
Collections.sort(types);
Collections.sort(typesWithoutSize);
}
/**
* Ajoute un observer qui permet d'avertir les autres classes d'un ajout ou
* d'une suppression d'une requete.
*/
public void addObserver(Observer obs) {
observableSQL.addObserver(obs);
}
/**
* Supprime toutes les requetes.
*/
public void clear() {
requests.clear();
observableSQL.notifyObservers();
}
public String getRequests() {
String res = "";
for (Iterator<String> e = requests.iterator(); e.hasNext();) {
res += e.next();
}
return res;
}
public void addRequest(String request) {
requests.add(request);
observableSQL.notifyObservers();
}
public boolean execRequest() {
return execRequest(false);
}
/**
* Exécute les différentes requêtes.
*/
public boolean execRequest(boolean deleteTable) {
String line;
boolean returnTemp = true;
error = null;
if (stmt == null) {
error = "Non connecté à la base ...";
return false;
}
if (!deleteTable) {
try {
for (Iterator<String> e = requests.iterator(); e.hasNext();) {
stmt.executeUpdate(e.next());
}
} catch (SQLException e) {
//e.printStackTrace();
error = e.getMessage();
errorCode = e.getErrorCode();
return false;
}
} else {
Iterator<String> e = requests.iterator();
line = e.next();
while (e.hasNext()) {
try {
stmt.executeUpdate(line);
line = e.next();
} catch (SQLException e2) {
//e2.printStackTrace();
if (e2.getErrorCode() == 0 && !deleteTable(e2.getMessage())) {
return false;
}
}
}
}
return true;
}
public boolean deleteTable(String errorMessage) {
String table;
StringTokenizer tk = new StringTokenizer(errorMessage, "\"");
tk.nextToken();
table = tk.nextToken();
try {
stmt.executeUpdate("DROP TABLE " + table + " CASCADE;");
} catch (SQLException e) {
//e.printStackTrace();
error = e.getMessage();
errorCode = e.getErrorCode();
return false;
}
return true;
}
/**
* Effectue la connection avec la base de donnée.
*
* @return Indique si la connection a réussi
*/
public boolean connection(String driver, String url, String user,
String password) {
this.driver = driver;
this.url = url;
this.user = user;
this.password = password;
error = null;
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
error = "Impossible de charger le driver : "
+ driver
+ ", vérifiez que le driver JDBC se trouve bien dans le classpath";
//e.printStackTrace();
error += e.getMessage() ;
return false;
}
try {
con = DriverManager.getConnection(url, user, password);
stmt = con.createStatement();
} catch (SQLException e) {
error = "Impossible de se connecter à la base de donnée, vérifier l'URL, le login et le password\net que votre database existe !";
error += e.getMessage() ;
//e.printStackTrace();
return false;
}
state = CONNECTED;
observableSQL.notifyObservers();
return true;
}
/**
* Deconnecte.
*/
public void deconnection() {
this.driver = null;
this.url = null;
this.user = null;
this.password = null;
state = DECONNECTED;
observableSQL.notifyObservers();
}
/**
* Permet de récupérer l'erreur lors de la connection ou de l'éxécution des requetes SQL.
*/
public String getError() {
return error;
}
/**
* Permet de récupérer le code d'erreur.
*/
public int getErrorCode() {
return errorCode;
}
/**
* Retourne l'état de la connection sous forme de chaine de caractères.
*/
public String getLabelState() {
if (state == DECONNECTED)
return "Déconnecté";
return "Connecté";
}
/**
* Retourne l'état de la connection.
*/
public int getState() {
return state;
}
/**
* Retourne les différents mots clés SQL.
*/
public List<String> getKeywords() {
return keywords;
}
/**
* Retourne les différents types SQL.
*/
public List<String> getTypes() {
return types;
}
/**
* Retourne les types SQL ne nécessitant pas de tailles
*
* @author dreuxl
*
*/
public List<String> getTypesWithoutSize() {
return typesWithoutSize;
}
private class ObservableSQL extends Observable {
public void notifyObservers() {
setChanged();
super.notifyObservers();
}
}
}