/******************************************************************************* * Copyright (c) 2012-2015 INRIA. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Generoso Pagano - initial API and implementation ******************************************************************************/ package fr.inria.soctrace.lib.storage.dbmanager; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Date; import fr.inria.soctrace.lib.model.utils.SoCTraceException; import fr.inria.soctrace.lib.storage.utils.SQLConstants.FramesocTable; import fr.inria.soctrace.lib.utils.Configuration; import fr.inria.soctrace.lib.utils.Configuration.SoCTraceProperty; import fr.inria.soctrace.lib.utils.Portability; /** * DB Manager class for SQLite DBMS (see {@link DBManager}). * * Note that for SQLite the default table creators are OK. * * @author "Generoso Pagano <generoso.pagano@inria.fr>" */ public class SQLiteDBManager extends DBManager { /** * Enable/disable connection tuning through PRAGMAs */ private final static boolean CONNECTION_TUNING = false; /** * Index of the column containing the names of column of table when returning * from a query of type "PRAGMA table_info(TABLE)" */ private static final int NAME_COLUMN_INDEX = 2; public SQLiteDBManager(String dbName) throws SoCTraceException { super(dbName); } @Override protected void createConnection() throws SoCTraceException { try { // clean existing connection, if any if (connection != null) { if (!connection.isClosed()) { connection.close(); decOpen(dbName); } connection = null; } // create the connection Class.forName("org.sqlite.JDBC"); connection = DriverManager.getConnection("jdbc:sqlite:"+getDBPath()); // Connection tuning if (CONNECTION_TUNING) { Statement stm = connection.createStatement(); stm.executeUpdate("PRAGMA synchronous = OFF;"); stm.executeUpdate("PRAGMA default_synchronous=OFF;"); stm.executeUpdate("PRAGMA default_cache_size=80000;"); stm.executeUpdate("PRAGMA cache_size=80000;"); stm.executeUpdate("PRAGMA temp_store=memory;"); stm.close(); } connection.setAutoCommit(false); incOpen(dbName); } catch (Exception e) { throw new SoCTraceException(e); } } @Override public boolean isDBExisting() throws SoCTraceException { File f = new File(getDBPath()); if (f.exists()) { return true; } return false; } @Override public boolean checkSettings() throws SoCTraceException { File f = new File(Configuration.getInstance().get( SoCTraceProperty.sqlite_db_directory)); if (f.canWrite()) { return true; } else { throw new SoCTraceException( "The current directory does not have the write permission."); } } @Override public Connection createDB() throws SoCTraceException { // nothing to do: connection creation already creates the DB file return getConnection(); } @Override public Connection openConnection() throws SoCTraceException { if (!isDBExisting()) throw new SoCTraceException("SQLite database '" + dbName + "' does not exist."); return getConnection(); } @Override public void dropDB() throws SoCTraceException { closeConnection(); File f = new File(getDBPath()); if (f.exists()) if (!f.delete()) throw new SoCTraceException("Error deleting DB file: " + getDBPath()); } @Override public void exportDB(String path) throws SoCTraceException { File sf = new File(getDBPath()); File sd = new File(path); try { Files.copy(sf.toPath(), sd.toPath(), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { System.err.println(e); throw new SoCTraceException("Error copying DB file: " + getDBPath()); } } @Override public void importDB(String path) throws SoCTraceException { File sf = new File(path); File sd = new File(getDBPath()); try { Files.copy(sf.toPath(), sd.toPath()); } catch (IOException e) { System.err.println(e); throw new SoCTraceException("Error copying DB file: " + getDBPath()); } } /** * @return the path of the file containing the SQLite DB * @throws SoCTraceException */ private String getDBPath() throws SoCTraceException { String sqlitePath = Configuration.getInstance().get( SoCTraceProperty.sqlite_db_directory); File dir = new File(sqlitePath); if (!dir.exists()) throw new SoCTraceException( "Directory " + sqlitePath + " does not exists. \n" + "Create it or write the correct path in the configuration file " + "("+Configuration.SoCTraceProperty.sqlite_db_directory+" property)."); return Portability.normalize(sqlitePath + "/" + dbName); } @Override public void createIndex(String table, String column, String name) throws SoCTraceException { try { Statement stm = getConnection().createStatement(); stm.execute("CREATE INDEX IF NOT EXISTS " + name + " ON " + table + "(" + column + ");"); stm.close(); } catch (SQLException e) { throw new SoCTraceException(e); } } @Override public void dropIndex(String table, String name) throws SoCTraceException { try { Statement stm = getConnection().createStatement(); stm.execute("DROP INDEX IF EXISTS " + name + ";"); stm.close(); } catch (SQLException e) { throw new SoCTraceException(e); } } /* * Default table creators are OK. */ @Override public String getTableInfoQuery(FramesocTable framesocTable) { return "PRAGMA table_info(" + framesocTable.name() + ");"; } @Override public void setDBVersion(int userVersion) throws SoCTraceException { try { tableStatement.execute("PRAGMA user_version = " + userVersion + ";"); } catch (SQLException e) { throw new SoCTraceException(e); } } @Override public int getDBVersion() throws SoCTraceException { try { Statement stm = getConnection().createStatement(); ResultSet rs = stm.executeQuery("PRAGMA user_version;"); return rs.getInt(1); } catch (SQLException e) { throw new SoCTraceException(e); } } @Override public void replaceDB(String oldBDName, String newDBName) throws SoCTraceException { // Old DB File oldDBFile = new File(Configuration.getInstance().get( SoCTraceProperty.sqlite_db_directory) + oldBDName); // New DB File newDBFile = new File(Configuration.getInstance().get( SoCTraceProperty.sqlite_db_directory) + newDBName); // Back up file for the old DB File bakDBFile = new File(Configuration.getInstance().get( SoCTraceProperty.sqlite_db_directory) + oldBDName + ".bak_" + new Date().getTime()); // Check that both files exist if (oldDBFile.exists() && newDBFile.exists()) { // Back up the old DB boolean success = oldDBFile.renameTo(bakDBFile); if (!success) throw new SoCTraceException("Failed to save SQLite DB from " + oldDBFile.getName() + " to" + bakDBFile.getName()); // Switch DB newDBFile.renameTo(oldDBFile); if (!success) throw new SoCTraceException("Failed to replace SQLite DB from " + oldDBFile.getName() + " to" + newDBFile.getName()); } } @Override public int getColumnNameIndex() { return NAME_COLUMN_INDEX; } }