package edu.washington.escience.myria.util; import java.io.File; import java.io.IOException; import com.almworks.sqlite4java.SQLiteConnection; import com.almworks.sqlite4java.SQLiteException; import com.almworks.sqlite4java.SQLiteStatement; import edu.washington.escience.myria.MyriaConstants; import edu.washington.escience.myria.RelationKey; import edu.washington.escience.myria.Type; /** * Util methods for SQLite. * * */ public final class SQLiteUtils { /** * Helper utility for creating SQLite CREATE TABLE statements. * * @param type a Myria column type. * @return the name of the SQLite type that matches the given Myria type. */ public static String typeToSQLiteType(final Type type) { switch (type) { case BOOLEAN_TYPE: return "BOOLEAN"; case DOUBLE_TYPE: return "DOUBLE"; case FLOAT_TYPE: return "DOUBLE"; case INT_TYPE: return "INTEGER"; case LONG_TYPE: return "INTEGER"; case STRING_TYPE: return "TEXT"; case DATETIME_TYPE: return "INTEGER"; // SQLLite does not support date type. use long to store the difference, measured in // milliseconds, between the date time and // midnight, January 1, 1970 UTC. default: throw new UnsupportedOperationException("Type " + type + " is not supported"); } } /** * util classes are not instantiable. * */ private SQLiteUtils() {} /** * Create a SQLite table. This method always creates an empty table, so if the table already exists, all its contents * will be removed. * * @throws SQLiteException if SQLite error occur * @throws IOException if any IO error occur * @param dbFileAbsolutePath the SQLite file absolute path * @param relationKey the relation key to create * @param sqlSchemaString schema as a string * @param replaceExisting replace existing table with a new empty table * @param swipeData swipe existing data in the table. * */ public static void createTable( final String dbFileAbsolutePath, final RelationKey relationKey, final String sqlSchemaString, final boolean replaceExisting, final boolean swipeData) throws IOException, SQLiteException { SQLiteConnection sqliteConnection = null; SQLiteStatement statement = null; try { final File f = new File(dbFileAbsolutePath); if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } /* Connect to the database */ sqliteConnection = new SQLiteConnection(f); sqliteConnection.open(true); statement = sqliteConnection.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?"); statement.bind(1, relationKey.toString()); if (statement.step()) { // existing statement.dispose(); if (replaceExisting) { statement = sqliteConnection.prepare( "drop table " + relationKey.toString(MyriaConstants.STORAGE_SYSTEM_SQLITE)); statement.step(); statement.dispose(); } else if (swipeData) { /* Clear table data in case it already exists */ statement = sqliteConnection.prepare( "delete from " + relationKey.toString(MyriaConstants.STORAGE_SYSTEM_SQLITE)); statement.step(); statement.reset(); return; } else { return; } } statement.dispose(); /* Create the table if not exist */ statement = sqliteConnection.prepare( "create table " + relationKey.toString(MyriaConstants.STORAGE_SYSTEM_SQLITE) + " (" + sqlSchemaString + ");"); statement.step(); statement.reset(); } finally { if (statement != null) { statement.dispose(); } if (sqliteConnection != null) { sqliteConnection.dispose(); } } } /** * Deletes a relation in SQLite. * * @throws SQLiteException if SQLite error occur * @param dbFileAbsolutePath the SQLite file absolute path * @param relationKey the relation key to delete * */ public static void deleteTable(final String dbFileAbsolutePath, final RelationKey relationKey) throws IOException, SQLiteException { SQLiteConnection sqliteConnection = null; SQLiteStatement statement = null; try { final File f = new File(dbFileAbsolutePath); if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } /* Connect to the database */ sqliteConnection = new SQLiteConnection(f); sqliteConnection.open(true); statement = sqliteConnection.prepare( "drop table if exists " + relationKey.toString(MyriaConstants.STORAGE_SYSTEM_SQLITE)); statement.step(); } finally { if (statement != null) { statement.dispose(); } if (sqliteConnection != null) { sqliteConnection.dispose(); } } } /** * Checks if a relation exists in the SQLite database * * @throws SQLiteException if SQLite error occur * @param dbFileAbsolutePath the SQLite file absolute path * @param relationKey the relation key to check * */ public static boolean existsTable(final String dbFileAbsolutePath, final RelationKey relationKey) throws IOException, SQLiteException { boolean exists = false; SQLiteConnection sqliteConnection = null; SQLiteStatement statement = null; try { final File f = new File(dbFileAbsolutePath); if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } /* Connect to the database */ sqliteConnection = new SQLiteConnection(f); sqliteConnection.open(true); statement = sqliteConnection.prepare("SELECT * FROM sqlite_master WHERE type='table' AND name=?"); statement.bind(1, relationKey.toString()); if (statement.step()) { return true; } } finally { if (statement != null) { statement.dispose(); } if (sqliteConnection != null) { sqliteConnection.dispose(); } } return exists; } }