From cc7ed224ffbae0a190e3645dea130132928811e6 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Thu, 6 Feb 2020 16:25:06 -0500 Subject: [PATCH] Interim commit - isolated scheme creation code from DBSettings classes and put them in the new RdmsCentralRepoSchemaFactory. --- .../datamodel/PostgresCentralRepo.java | 9 +- .../PostgresCentralRepoSettings.java | 289 +------- .../datamodel/RdbmsCentralRepo.java | 33 +- .../RdbmsCentralRepoSchemaFactory.java | 696 ++++++++++++++++++ .../datamodel/SqliteCentralRepo.java | 9 +- .../datamodel/SqliteCentralRepoSettings.java | 319 +------- .../optionspanel/EamDbSettingsDialog.form | 4 +- .../optionspanel/EamDbSettingsDialog.java | 23 +- 8 files changed, 757 insertions(+), 625 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoSchemaFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java index 42772a9bd3..93c82c7bdf 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java @@ -131,7 +131,10 @@ final class PostgresCentralRepo extends RdbmsCentralRepo { CentralRepoDbUtil.closeConnection(conn); } - dbSettings.insertDefaultDatabaseContent(); + + //dbSettings.insertDefaultDatabaseContent(); + RdbmsCentralRepoSchemaFactory centralRepoSchemaFactory = new RdbmsCentralRepoSchemaFactory(CentralRepoPlatforms.POSTGRESQL); + centralRepoSchemaFactory.insertDefaultDatabaseContent(); } /** @@ -209,6 +212,10 @@ final class PostgresCentralRepo extends RdbmsCentralRepo { return CONFLICT_CLAUSE; } + @Override + protected Connection getEphemeralConnection() { + return this.dbSettings.getEphemeralConnection(false); + } /** * Gets an exclusive lock (if applicable). Will return the lock if * successful, null if unsuccessful because locking isn't supported, and diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepoSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepoSettings.java index 9b5b013540..10204e0ffe 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepoSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepoSettings.java @@ -162,7 +162,7 @@ public final class PostgresCentralRepoSettings { * * @return Connection or null. */ - private Connection getEphemeralConnection(boolean usePostgresDb) { + Connection getEphemeralConnection(boolean usePostgresDb) { Connection conn; try { String url = getConnectionURL(usePostgresDb); @@ -290,308 +290,25 @@ public final class PostgresCentralRepoSettings { } - /** - * Initialize the database schema. - * - * Requires valid connectionPool. - * - * This method is called from within connect(), so we cannot call connect() - * to get a connection. This method is called after setupConnectionPool(), - * so it is safe to assume that a valid connectionPool exists. The - * implementation of connect() is synchronized, so we can safely use the - * connectionPool object directly. - */ - public boolean initializeDatabaseSchema() { - // The "id" column is an alias for the built-in 64-bit int "rowid" column. - // It is autoincrementing by default and must be of type "integer primary key". - // We've omitted the autoincrement argument because we are not currently - // using the id value to search for specific rows, so we do not care - // if a rowid is re-used after an existing rows was previously deleted. - StringBuilder createOrganizationsTable = new StringBuilder(); - createOrganizationsTable.append("CREATE TABLE IF NOT EXISTS organizations ("); - createOrganizationsTable.append("id SERIAL PRIMARY KEY,"); - createOrganizationsTable.append("org_name text NOT NULL,"); - createOrganizationsTable.append("poc_name text NOT NULL,"); - createOrganizationsTable.append("poc_email text NOT NULL,"); - createOrganizationsTable.append("poc_phone text NOT NULL,"); - createOrganizationsTable.append("CONSTRAINT org_name_unique UNIQUE (org_name)"); - createOrganizationsTable.append(")"); + - // NOTE: The organizations will only have a small number of rows, so - // an index is probably not worthwhile. - StringBuilder createCasesTable = new StringBuilder(); - createCasesTable.append("CREATE TABLE IF NOT EXISTS cases ("); - createCasesTable.append("id SERIAL PRIMARY KEY,"); - createCasesTable.append("case_uid text NOT NULL,"); - createCasesTable.append("org_id integer,"); - createCasesTable.append("case_name text NOT NULL,"); - createCasesTable.append("creation_date text NOT NULL,"); - createCasesTable.append("case_number text,"); - createCasesTable.append("examiner_name text,"); - createCasesTable.append("examiner_email text,"); - createCasesTable.append("examiner_phone text,"); - createCasesTable.append("notes text,"); - createCasesTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); - createCasesTable.append("CONSTRAINT case_uid_unique UNIQUE (case_uid)"); - createCasesTable.append(")"); - // NOTE: when there are few cases in the cases table, these indices may not be worthwhile - String casesIdx1 = "CREATE INDEX IF NOT EXISTS cases_org_id ON cases (org_id)"; - String casesIdx2 = "CREATE INDEX IF NOT EXISTS cases_case_uid ON cases (case_uid)"; - StringBuilder createReferenceSetsTable = new StringBuilder(); - createReferenceSetsTable.append("CREATE TABLE IF NOT EXISTS reference_sets ("); - createReferenceSetsTable.append("id SERIAL PRIMARY KEY,"); - createReferenceSetsTable.append("org_id integer NOT NULL,"); - createReferenceSetsTable.append("set_name text NOT NULL,"); - createReferenceSetsTable.append("version text NOT NULL,"); - createReferenceSetsTable.append("known_status integer NOT NULL,"); - createReferenceSetsTable.append("read_only boolean NOT NULL,"); - createReferenceSetsTable.append("type integer NOT NULL,"); - createReferenceSetsTable.append("import_date text NOT NULL,"); - createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); - createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); - createReferenceSetsTable.append(")"); + - String referenceSetsIdx1 = "CREATE INDEX IF NOT EXISTS reference_sets_org_id ON reference_sets (org_id)"; - // Each "%s" will be replaced with the relevant reference_TYPE table name. - StringBuilder createReferenceTypesTableTemplate = new StringBuilder(); - createReferenceTypesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s ("); - createReferenceTypesTableTemplate.append("id SERIAL PRIMARY KEY,"); - createReferenceTypesTableTemplate.append("reference_set_id integer,"); - createReferenceTypesTableTemplate.append("value text NOT NULL,"); - createReferenceTypesTableTemplate.append("known_status integer NOT NULL,"); - createReferenceTypesTableTemplate.append("comment text,"); - createReferenceTypesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE (reference_set_id, value),"); - createReferenceTypesTableTemplate.append("foreign key (reference_set_id) references reference_sets(id) ON UPDATE SET NULL ON DELETE SET NULL"); - createReferenceTypesTableTemplate.append(")"); - // Each "%s" will be replaced with the relevant reference_TYPE table name. - String referenceTypesIdx1 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; - String referenceTypesIdx2 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; - StringBuilder createCorrelationTypesTable = new StringBuilder(); - createCorrelationTypesTable.append("CREATE TABLE IF NOT EXISTS correlation_types ("); - createCorrelationTypesTable.append("id SERIAL PRIMARY KEY,"); - createCorrelationTypesTable.append("display_name text NOT NULL,"); - createCorrelationTypesTable.append("db_table_name text NOT NULL,"); - createCorrelationTypesTable.append("supported integer NOT NULL,"); - createCorrelationTypesTable.append("enabled integer NOT NULL,"); - createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)"); - createCorrelationTypesTable.append(")"); - String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(); - String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); - String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate(); - String instancesValueIdx = getAddValueIndexTemplate(); - String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate(); - String instancesObjectIdIdx = getAddObjectIdIndexTemplate(); - // NOTE: the db_info table currenly only has 1 row, so having an index - // provides no benefit. - Connection conn = null; - try { - conn = getEphemeralConnection(false); - if (null == conn) { - return false; - } - Statement stmt = conn.createStatement(); - stmt.execute(createOrganizationsTable.toString()); - stmt.execute(createCasesTable.toString()); - stmt.execute(casesIdx1); - stmt.execute(casesIdx2); - stmt.execute(getCreateDataSourcesTableStatement()); - stmt.execute(getAddDataSourcesNameIndexStatement()); - stmt.execute(getAddDataSourcesObjectIdIndexStatement()); - stmt.execute(createReferenceSetsTable.toString()); - stmt.execute(referenceSetsIdx1); - stmt.execute(createCorrelationTypesTable.toString()); - /* - * Note that the essentially useless id column in the following - * table is required for backwards compatibility. Otherwise, the - * name column could be the primary key. - */ - stmt.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - // Create a separate instance and reference table for each correlation type - List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); - - String reference_type_dbname; - String instance_type_dbname; - for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) { - reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); - instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); - - stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); - - // FUTURE: allow more than the FILES type - if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { - stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname)); - } - } - - } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS - return false; - } catch (CentralRepoException ex) { - LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS - return false; - } finally { - CentralRepoDbUtil.closeConnection(conn); - } - return true; - } - - /** - * Get the template String for creating a new _instances table in a Postgres - * central repository. %s will exist in the template where the name of the - * new table will be addedd. - * - * @return a String which is a template for cretating a new _instances table - */ - static String getCreateArtifactInstancesTableTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return ("CREATE TABLE IF NOT EXISTS %s (id SERIAL PRIMARY KEY,case_id integer NOT NULL," - + "data_source_id integer NOT NULL,value text NOT NULL,file_path text NOT NULL," - + "known_status integer NOT NULL,comment text,file_obj_id BIGINT," - + "CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path)," - + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," - + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"); - } - - /** - * Get the statement String for creating a new data_sources table in a - * Postgres central repository. - * - * @return a String which is a statement for cretating a new data_sources - * table - */ - static String getCreateDataSourcesTableStatement() { - return "CREATE TABLE IF NOT EXISTS data_sources " - + "(id SERIAL PRIMARY KEY,case_id integer NOT NULL,device_id text NOT NULL," - + "name text NOT NULL,datasource_obj_id BIGINT,md5 text DEFAULT NULL," - + "sha1 text DEFAULT NULL,sha256 text DEFAULT NULL," - + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," - + "CONSTRAINT datasource_unique UNIQUE (case_id, datasource_obj_id))"; - } - - /** - * Get the statement for creating an index on the name column of the - * data_sources table. - * - * @return a String which is a statement for adding an index on the name - * column of the data_sources table. - */ - static String getAddDataSourcesNameIndexStatement() { - return "CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)"; - } - - /** - * Get the statement for creating an index on the data_sources_object_id - * column of the data_sources table. - * - * @return a String which is a statement for adding an index on the - * data_sources_object_id column of the data_sources table. - */ - static String getAddDataSourcesObjectIdIndexStatement() { - return "CREATE INDEX IF NOT EXISTS data_sources_object_id ON data_sources (datasource_obj_id)"; - } - - /** - * Get the template for creating an index on the case_id column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the case_id - * column of a _instances table - */ - static String getAddCaseIdIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)"; - } - - /** - * Get the template for creating an index on the data_source_id column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the - * data_source_id column of a _instances table - */ - static String getAddDataSourceIdIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)"; - } - - /** - * Get the template for creating an index on the value column of an instance - * table. %s will exist in the template where the name of the new table will - * be addedd. - * - * @return a String which is a template for adding an index to the value - * column of a _instances table - */ - static String getAddValueIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; - } - - /** - * Get the template for creating an index on the known_status column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the - * known_status column of a _instances table - */ - static String getAddKnownStatusIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; - } - - /** - * Get the template for creating an index on the file_obj_id column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the - * file_obj_id column of a _instances table - */ - static String getAddObjectIdIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)"; - } - - public boolean insertDefaultDatabaseContent() { - Connection conn = getEphemeralConnection(false); - if (null == conn) { - return false; - } - - boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) && CentralRepoDbUtil.insertDefaultOrganization(conn); - CentralRepoDbUtil.closeConnection(conn); - - return result; - } boolean isChanged() { String hostString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index 1a641c5a28..38191e572e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -116,6 +116,10 @@ abstract class RdbmsCentralRepo implements CentralRepository { */ protected abstract Connection connect() throws CentralRepoException; + /** + * Get an ephemeral connection. + */ + protected abstract Connection getEphemeralConnection(); /** * Add a new name/value pair in the db_info table. * @@ -3414,22 +3418,23 @@ abstract class RdbmsCentralRepo implements CentralRepository { case POSTGRESQL: addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS - addSsidTableTemplate = PostgresCentralRepoSettings.getCreateArtifactInstancesTableTemplate(); - addCaseIdIndexTemplate = PostgresCentralRepoSettings.getAddCaseIdIndexTemplate(); - addDataSourceIdIndexTemplate = PostgresCentralRepoSettings.getAddDataSourceIdIndexTemplate(); - addValueIndexTemplate = PostgresCentralRepoSettings.getAddValueIndexTemplate(); - addKnownStatusIndexTemplate = PostgresCentralRepoSettings.getAddKnownStatusIndexTemplate(); - addObjectIdIndexTemplate = PostgresCentralRepoSettings.getAddObjectIdIndexTemplate(); + // RAMAN TBD: get these from RdbmsCentralRepoSchemaFactory + addSsidTableTemplate = RdbmsCentralRepoSchemaFactory.PostgresCRSchemaCreator.getCreateArtifactInstancesTableTemplate(); + addCaseIdIndexTemplate = RdbmsCentralRepoSchemaFactory.PostgresCRSchemaCreator.getAddCaseIdIndexTemplate(); + addDataSourceIdIndexTemplate = RdbmsCentralRepoSchemaFactory.PostgresCRSchemaCreator.getAddDataSourceIdIndexTemplate(); + addValueIndexTemplate = RdbmsCentralRepoSchemaFactory.PostgresCRSchemaCreator.getAddValueIndexTemplate(); + addKnownStatusIndexTemplate = RdbmsCentralRepoSchemaFactory.PostgresCRSchemaCreator.getAddKnownStatusIndexTemplate(); + addObjectIdIndexTemplate = RdbmsCentralRepoSchemaFactory.PostgresCRSchemaCreator.getAddObjectIdIndexTemplate(); break; case SQLITE: addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS - addSsidTableTemplate = SqliteCentralRepoSettings.getCreateArtifactInstancesTableTemplate(); - addCaseIdIndexTemplate = SqliteCentralRepoSettings.getAddCaseIdIndexTemplate(); - addDataSourceIdIndexTemplate = SqliteCentralRepoSettings.getAddDataSourceIdIndexTemplate(); - addValueIndexTemplate = SqliteCentralRepoSettings.getAddValueIndexTemplate(); - addKnownStatusIndexTemplate = SqliteCentralRepoSettings.getAddKnownStatusIndexTemplate(); - addObjectIdIndexTemplate = SqliteCentralRepoSettings.getAddObjectIdIndexTemplate(); + addSsidTableTemplate = RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getCreateArtifactInstancesTableTemplate(); + addCaseIdIndexTemplate = RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddCaseIdIndexTemplate(); + addDataSourceIdIndexTemplate = RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddDataSourceIdIndexTemplate(); + addValueIndexTemplate = RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddValueIndexTemplate(); + addKnownStatusIndexTemplate = RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddKnownStatusIndexTemplate(); + addObjectIdIndexTemplate = RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddObjectIdIndexTemplate(); break; default: throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name())); @@ -3586,8 +3591,8 @@ abstract class RdbmsCentralRepo implements CentralRepository { + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL," + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))"); - statement.execute(SqliteCentralRepoSettings.getAddDataSourcesNameIndexStatement()); - statement.execute(SqliteCentralRepoSettings.getAddDataSourcesObjectIdIndexStatement()); + statement.execute(RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddDataSourcesNameIndexStatement()); + statement.execute(RdbmsCentralRepoSchemaFactory.SQLiteCRSchemaCreator.getAddDataSourcesObjectIdIndexStatement()); statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources"); statement.execute("DROP TABLE old_data_sources"); break; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoSchemaFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoSchemaFactory.java new file mode 100644 index 0000000000..1db99ee3b7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoSchemaFactory.java @@ -0,0 +1,696 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.centralrepository.datamodel; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import java.util.logging.Level; +import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo.SOFTWARE_CR_DB_SCHEMA_VERSION; +import org.sleuthkit.autopsy.coreutils.Logger; +//import static org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings.getCreateArtifactInstancesTableTemplate; + +/** + * Creates the CR schema and populates it with initial data. + * + */ +public class RdbmsCentralRepoSchemaFactory { + + private final static Logger LOGGER = Logger.getLogger(RdbmsCentralRepoSchemaFactory.class.getName()); + + private static RdbmsCentralRepoSchemaFactory instance; + private final RdbmsCentralRepo rdbmsCentralRepo; + + private final CentralRepoPlatforms selectedPlatform; + + // SQLite pragmas + private final static String PRAGMA_SYNC_OFF = "PRAGMA synchronous = OFF"; + private final static String PRAGMA_SYNC_NORMAL = "PRAGMA synchronous = NORMAL"; + private final static String PRAGMA_JOURNAL_WAL = "PRAGMA journal_mode = WAL"; + private final static String PRAGMA_READ_UNCOMMITTED_TRUE = "PRAGMA read_uncommitted = True"; + private final static String PRAGMA_ENCODING_UTF8 = "PRAGMA encoding = 'UTF-8'"; + private final static String PRAGMA_PAGE_SIZE_4096 = "PRAGMA page_size = 4096"; + private final static String PRAGMA_FOREIGN_KEYS_ON = "PRAGMA foreign_keys = ON"; + + /** + * Returns instance of singleton. + * + * @throws CentralRepoException + */ +// public static RdbmsCentralRepoSchemaFactory getInstance() throws CentralRepoException { +// +// if (instance == null) { +// instance = new RdbmsCentralRepoSchemaFactory(); +// } +// +// return instance; +// } + public RdbmsCentralRepoSchemaFactory(CentralRepoPlatforms selectedPlatform) throws CentralRepoException { + //CentralRepoPlatforms selectedPlatform = CentralRepoPlatforms.DISABLED; + //if (CentralRepoDbUtil.allowUseOfCentralRepository()) { + // selectedPlatform = CentralRepoPlatforms.getSelectedPlatform(); + //} + + this.selectedPlatform = selectedPlatform; + switch (selectedPlatform) { + case POSTGRESQL: + rdbmsCentralRepo = PostgresCentralRepo.getInstance(); + break; + case SQLITE: + rdbmsCentralRepo = SqliteCentralRepo.getInstance(); + break; + default: + throw new CentralRepoException("Central Repo platform disabled."); + } + } + + public boolean initializeDatabaseSchema() { + switch (selectedPlatform) { + case POSTGRESQL: + // RAMAN TBD + return PostgresCRSchemaCreator.initializeDatabaseSchema(rdbmsCentralRepo); + //break; + case SQLITE: + return SQLiteCRSchemaCreator.initializeDatabaseSchema(rdbmsCentralRepo); + //break; + default: + return false; + } + } + + // TBD RAMAN - temporary container to store all SQLite methods, till we unify... + public static class SQLiteCRSchemaCreator { + + /** + * Initialize the database schema. + * + * Requires valid connectionPool. + * + * This method is called from within connect(), so we cannot call + * connect() to get a connection. This method is called after + * setupConnectionPool(), so it is safe to assume that a valid + * connectionPool exists. The implementation of connect() is + * synchronized, so we can safely use the connectionPool object + * directly. + */ + public static boolean initializeDatabaseSchema(RdbmsCentralRepo rdbmsCentralRepo) { + // The "id" column is an alias for the built-in 64-bit int "rowid" column. + // It is autoincrementing by default and must be of type "integer primary key". + // We've omitted the autoincrement argument because we are not currently + // using the id value to search for specific rows, so we do not care + // if a rowid is re-used after an existing rows was previously deleted. + StringBuilder createOrganizationsTable = new StringBuilder(); + createOrganizationsTable.append("CREATE TABLE IF NOT EXISTS organizations ("); + createOrganizationsTable.append("id integer primary key autoincrement NOT NULL,"); + createOrganizationsTable.append("org_name text NOT NULL,"); + createOrganizationsTable.append("poc_name text NOT NULL,"); + createOrganizationsTable.append("poc_email text NOT NULL,"); + createOrganizationsTable.append("poc_phone text NOT NULL,"); + createOrganizationsTable.append("CONSTRAINT org_name_unique UNIQUE (org_name)"); + createOrganizationsTable.append(")"); + + // NOTE: The organizations will only have a small number of rows, so + // an index is probably not worthwhile. + StringBuilder createCasesTable = new StringBuilder(); + createCasesTable.append("CREATE TABLE IF NOT EXISTS cases ("); + createCasesTable.append("id integer primary key autoincrement NOT NULL,"); + createCasesTable.append("case_uid text NOT NULL,"); + createCasesTable.append("org_id integer,"); + createCasesTable.append("case_name text NOT NULL,"); + createCasesTable.append("creation_date text NOT NULL,"); + createCasesTable.append("case_number text,"); + createCasesTable.append("examiner_name text,"); + createCasesTable.append("examiner_email text,"); + createCasesTable.append("examiner_phone text,"); + createCasesTable.append("notes text,"); + createCasesTable.append("CONSTRAINT case_uid_unique UNIQUE(case_uid) ON CONFLICT IGNORE,"); + createCasesTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL"); + createCasesTable.append(")"); + + // NOTE: when there are few cases in the cases table, these indices may not be worthwhile + String casesIdx1 = "CREATE INDEX IF NOT EXISTS cases_org_id ON cases (org_id)"; + String casesIdx2 = "CREATE INDEX IF NOT EXISTS cases_case_uid ON cases (case_uid)"; + + StringBuilder createReferenceSetsTable = new StringBuilder(); + createReferenceSetsTable.append("CREATE TABLE IF NOT EXISTS reference_sets ("); + createReferenceSetsTable.append("id integer primary key autoincrement NOT NULL,"); + createReferenceSetsTable.append("org_id integer NOT NULL,"); + createReferenceSetsTable.append("set_name text NOT NULL,"); + createReferenceSetsTable.append("version text NOT NULL,"); + createReferenceSetsTable.append("known_status integer NOT NULL,"); + createReferenceSetsTable.append("read_only boolean NOT NULL,"); + createReferenceSetsTable.append("type integer NOT NULL,"); + createReferenceSetsTable.append("import_date text NOT NULL,"); + createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); + createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); + createReferenceSetsTable.append(")"); + + String referenceSetsIdx1 = "CREATE INDEX IF NOT EXISTS reference_sets_org_id ON reference_sets (org_id)"; + + // Each "%s" will be replaced with the relevant reference_TYPE table name. + StringBuilder createReferenceTypesTableTemplate = new StringBuilder(); + createReferenceTypesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s ("); + createReferenceTypesTableTemplate.append("id integer primary key autoincrement NOT NULL,"); + createReferenceTypesTableTemplate.append("reference_set_id integer,"); + createReferenceTypesTableTemplate.append("value text NOT NULL,"); + createReferenceTypesTableTemplate.append("known_status integer NOT NULL,"); + createReferenceTypesTableTemplate.append("comment text,"); + createReferenceTypesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(reference_set_id, value) ON CONFLICT IGNORE,"); + createReferenceTypesTableTemplate.append("foreign key (reference_set_id) references reference_sets(id) ON UPDATE SET NULL ON DELETE SET NULL"); + createReferenceTypesTableTemplate.append(")"); + + // Each "%s" will be replaced with the relevant reference_TYPE table name. + String referenceTypesIdx1 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; + String referenceTypesIdx2 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; + + StringBuilder createCorrelationTypesTable = new StringBuilder(); + createCorrelationTypesTable.append("CREATE TABLE IF NOT EXISTS correlation_types ("); + createCorrelationTypesTable.append("id integer primary key autoincrement NOT NULL,"); + createCorrelationTypesTable.append("display_name text NOT NULL,"); + createCorrelationTypesTable.append("db_table_name text NOT NULL,"); + createCorrelationTypesTable.append("supported integer NOT NULL,"); + createCorrelationTypesTable.append("enabled integer NOT NULL,"); + createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)"); + createCorrelationTypesTable.append(")"); + + String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(); + + String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); + String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate(); + String instancesValueIdx = getAddValueIndexTemplate(); + String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate(); + String instancesObjectIdIdx = getAddObjectIdIndexTemplate(); + + // NOTE: the db_info table currenly only has 1 row, so having an index + // provides no benefit. + Connection conn = null; + try { + conn = rdbmsCentralRepo.getEphemeralConnection(); + if (null == conn) { + return false; + } + Statement stmt = conn.createStatement(); + stmt.execute(PRAGMA_JOURNAL_WAL); + stmt.execute(PRAGMA_SYNC_OFF); + stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE); + stmt.execute(PRAGMA_ENCODING_UTF8); + stmt.execute(PRAGMA_PAGE_SIZE_4096); + stmt.execute(PRAGMA_FOREIGN_KEYS_ON); + + stmt.execute(createOrganizationsTable.toString()); + + stmt.execute(createCasesTable.toString()); + stmt.execute(casesIdx1); + stmt.execute(casesIdx2); + + stmt.execute(getCreateDataSourcesTableStatement()); + stmt.execute(getAddDataSourcesNameIndexStatement()); + stmt.execute(getAddDataSourcesObjectIdIndexStatement()); + + stmt.execute(createReferenceSetsTable.toString()); + stmt.execute(referenceSetsIdx1); + + stmt.execute(createCorrelationTypesTable.toString()); + + /* + * Note that the essentially useless id column in the following + * table is required for backwards compatibility. Otherwise, the + * name column could be the primary key. + */ + stmt.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + + // Create a separate instance and reference table for each artifact type + List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + + String reference_type_dbname; + String instance_type_dbname; + for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) { + reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); + instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); + + stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); + + // FUTURE: allow more than the FILES type + if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { + stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname)); + } + } + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS + return false; + } catch (CentralRepoException ex) { + LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS + return false; + } finally { + CentralRepoDbUtil.closeConnection(conn); + } + return true; + } + + /** + * Get the template String for creating a new _instances table in a + * Sqlite central repository. %s will exist in the template where the + * name of the new table will be addedd. + * + * @return a String which is a template for cretating a new _instances + * table + */ + static String getCreateArtifactInstancesTableTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE TABLE IF NOT EXISTS %s (id integer primary key autoincrement NOT NULL," + + "case_id integer NOT NULL,data_source_id integer NOT NULL,value text NOT NULL," + + "file_path text NOT NULL,known_status integer NOT NULL,comment text,file_obj_id integer," + + "CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE," + + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"; + } + + /** + * Get the template for creating an index on the case_id column of an + * instance table. %s will exist in the template where the name of the + * new table will be addedd. + * + * @return a String which is a template for adding an index to the + * case_id column of a _instances table + */ + static String getAddCaseIdIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)"; + } + + /** + * Get the template for creating an index on the data_source_id column + * of an instance table. %s will exist in the template where the name of + * the new table will be addedd. + * + * @return a String which is a template for adding an index to the + * data_source_id column of a _instances table + */ + static String getAddDataSourceIdIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)"; + } + + /** + * Get the template for creating an index on the value column of an + * instance table. %s will exist in the template where the name of the + * new table will be addedd. + * + * @return a String which is a template for adding an index to the value + * column of a _instances table + */ + static String getAddValueIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; + } + + /** + * Get the template for creating an index on the known_status column of + * an instance table. %s will exist in the template where the name of + * the new table will be addedd. + * + * @return a String which is a template for adding an index to the + * known_status column of a _instances table + */ + static String getAddKnownStatusIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; + } + + /** + * Get the template for creating an index on the file_obj_id column of + * an instance table. %s will exist in the template where the name of + * the new table will be addedd. + * + * @return a String which is a template for adding an index to the + * file_obj_id column of a _instances table + */ + static String getAddObjectIdIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)"; + } + + /** + * Get the statement String for creating a new data_sources table in a + * Sqlite central repository. + * + * @return a String which is a statement for cretating a new + * data_sources table + */ + static String getCreateDataSourcesTableStatement() { + return "CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL," + + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer," + + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL," + + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + + "CONSTRAINT datasource_unique UNIQUE (case_id, datasource_obj_id))"; + } + + /** + * Get the statement for creating an index on the name column of the + * data_sources table. + * + * @return a String which is a statement for adding an index on the name + * column of the data_sources table. + */ + static String getAddDataSourcesNameIndexStatement() { + return "CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)"; + } + + /** + * Get the statement for creating an index on the data_sources_object_id + * column of the data_sources table. + * + * @return a String which is a statement for adding an index on the + * data_sources_object_id column of the data_sources table. + */ + static String getAddDataSourcesObjectIdIndexStatement() { + return "CREATE INDEX IF NOT EXISTS data_sources_object_id ON data_sources (datasource_obj_id)"; + } + + } + + // TBD RAMAN - temporary container to store all Pstgres methods, till we unify... + public static class PostgresCRSchemaCreator { + + /** + * Initialize the database schema. + * + * Requires valid connectionPool. + * + * This method is called from within connect(), so we cannot call + * connect() to get a connection. This method is called after + * setupConnectionPool(), so it is safe to assume that a valid + * connectionPool exists. The implementation of connect() is + * synchronized, so we can safely use the connectionPool object + * directly. + */ + public static boolean initializeDatabaseSchema(RdbmsCentralRepo rdbmsCentralRepo) { + // The "id" column is an alias for the built-in 64-bit int "rowid" column. + // It is autoincrementing by default and must be of type "integer primary key". + // We've omitted the autoincrement argument because we are not currently + // using the id value to search for specific rows, so we do not care + // if a rowid is re-used after an existing rows was previously deleted. + StringBuilder createOrganizationsTable = new StringBuilder(); + createOrganizationsTable.append("CREATE TABLE IF NOT EXISTS organizations ("); + createOrganizationsTable.append("id SERIAL PRIMARY KEY,"); + createOrganizationsTable.append("org_name text NOT NULL,"); + createOrganizationsTable.append("poc_name text NOT NULL,"); + createOrganizationsTable.append("poc_email text NOT NULL,"); + createOrganizationsTable.append("poc_phone text NOT NULL,"); + createOrganizationsTable.append("CONSTRAINT org_name_unique UNIQUE (org_name)"); + createOrganizationsTable.append(")"); + + // NOTE: The organizations will only have a small number of rows, so + // an index is probably not worthwhile. + StringBuilder createCasesTable = new StringBuilder(); + createCasesTable.append("CREATE TABLE IF NOT EXISTS cases ("); + createCasesTable.append("id SERIAL PRIMARY KEY,"); + createCasesTable.append("case_uid text NOT NULL,"); + createCasesTable.append("org_id integer,"); + createCasesTable.append("case_name text NOT NULL,"); + createCasesTable.append("creation_date text NOT NULL,"); + createCasesTable.append("case_number text,"); + createCasesTable.append("examiner_name text,"); + createCasesTable.append("examiner_email text,"); + createCasesTable.append("examiner_phone text,"); + createCasesTable.append("notes text,"); + createCasesTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); + createCasesTable.append("CONSTRAINT case_uid_unique UNIQUE (case_uid)"); + createCasesTable.append(")"); + + // NOTE: when there are few cases in the cases table, these indices may not be worthwhile + String casesIdx1 = "CREATE INDEX IF NOT EXISTS cases_org_id ON cases (org_id)"; + String casesIdx2 = "CREATE INDEX IF NOT EXISTS cases_case_uid ON cases (case_uid)"; + + StringBuilder createReferenceSetsTable = new StringBuilder(); + createReferenceSetsTable.append("CREATE TABLE IF NOT EXISTS reference_sets ("); + createReferenceSetsTable.append("id SERIAL PRIMARY KEY,"); + createReferenceSetsTable.append("org_id integer NOT NULL,"); + createReferenceSetsTable.append("set_name text NOT NULL,"); + createReferenceSetsTable.append("version text NOT NULL,"); + createReferenceSetsTable.append("known_status integer NOT NULL,"); + createReferenceSetsTable.append("read_only boolean NOT NULL,"); + createReferenceSetsTable.append("type integer NOT NULL,"); + createReferenceSetsTable.append("import_date text NOT NULL,"); + createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); + createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); + createReferenceSetsTable.append(")"); + + String referenceSetsIdx1 = "CREATE INDEX IF NOT EXISTS reference_sets_org_id ON reference_sets (org_id)"; + + // Each "%s" will be replaced with the relevant reference_TYPE table name. + StringBuilder createReferenceTypesTableTemplate = new StringBuilder(); + createReferenceTypesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s ("); + createReferenceTypesTableTemplate.append("id SERIAL PRIMARY KEY,"); + createReferenceTypesTableTemplate.append("reference_set_id integer,"); + createReferenceTypesTableTemplate.append("value text NOT NULL,"); + createReferenceTypesTableTemplate.append("known_status integer NOT NULL,"); + createReferenceTypesTableTemplate.append("comment text,"); + createReferenceTypesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE (reference_set_id, value),"); + createReferenceTypesTableTemplate.append("foreign key (reference_set_id) references reference_sets(id) ON UPDATE SET NULL ON DELETE SET NULL"); + createReferenceTypesTableTemplate.append(")"); + + // Each "%s" will be replaced with the relevant reference_TYPE table name. + String referenceTypesIdx1 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; + String referenceTypesIdx2 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; + + StringBuilder createCorrelationTypesTable = new StringBuilder(); + createCorrelationTypesTable.append("CREATE TABLE IF NOT EXISTS correlation_types ("); + createCorrelationTypesTable.append("id SERIAL PRIMARY KEY,"); + createCorrelationTypesTable.append("display_name text NOT NULL,"); + createCorrelationTypesTable.append("db_table_name text NOT NULL,"); + createCorrelationTypesTable.append("supported integer NOT NULL,"); + createCorrelationTypesTable.append("enabled integer NOT NULL,"); + createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)"); + createCorrelationTypesTable.append(")"); + + String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(); + + String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); + String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate(); + String instancesValueIdx = getAddValueIndexTemplate(); + String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate(); + String instancesObjectIdIdx = getAddObjectIdIndexTemplate(); + + // NOTE: the db_info table currenly only has 1 row, so having an index + // provides no benefit. + Connection conn = null; + try { + conn = rdbmsCentralRepo.getEphemeralConnection(); + if (null == conn) { + return false; + } + Statement stmt = conn.createStatement(); + + stmt.execute(createOrganizationsTable.toString()); + + stmt.execute(createCasesTable.toString()); + stmt.execute(casesIdx1); + stmt.execute(casesIdx2); + + stmt.execute(getCreateDataSourcesTableStatement()); + stmt.execute(getAddDataSourcesNameIndexStatement()); + stmt.execute(getAddDataSourcesObjectIdIndexStatement()); + + stmt.execute(createReferenceSetsTable.toString()); + stmt.execute(referenceSetsIdx1); + + stmt.execute(createCorrelationTypesTable.toString()); + + /* + * Note that the essentially useless id column in the following + * table is required for backwards compatibility. Otherwise, the + * name column could be the primary key. + */ + stmt.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + + // Create a separate instance and reference table for each correlation type + List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + + String reference_type_dbname; + String instance_type_dbname; + for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) { + reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); + instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); + + stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); + + // FUTURE: allow more than the FILES type + if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { + stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname)); + } + } + + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS + return false; + } catch (CentralRepoException ex) { + LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS + return false; + } finally { + CentralRepoDbUtil.closeConnection(conn); + } + return true; + } + + /** + * Get the template String for creating a new _instances table in a + * Postgres central repository. %s will exist in the template where the + * name of the new table will be addedd. + * + * @return a String which is a template for cretating a new _instances + * table + */ + static String getCreateArtifactInstancesTableTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return ("CREATE TABLE IF NOT EXISTS %s (id SERIAL PRIMARY KEY,case_id integer NOT NULL," + + "data_source_id integer NOT NULL,value text NOT NULL,file_path text NOT NULL," + + "known_status integer NOT NULL,comment text,file_obj_id BIGINT," + + "CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path)," + + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"); + } + + /** + * Get the template for creating an index on the case_id column of an + * instance table. %s will exist in the template where the name of the + * new table will be addedd. + * + * @return a String which is a template for adding an index to the + * case_id column of a _instances table + */ + static String getAddCaseIdIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)"; + } + + /** + * Get the template for creating an index on the data_source_id column + * of an instance table. %s will exist in the template where the name of + * the new table will be addedd. + * + * @return a String which is a template for adding an index to the + * data_source_id column of a _instances table + */ + static String getAddDataSourceIdIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)"; + } + + /** + * Get the template for creating an index on the value column of an + * instance table. %s will exist in the template where the name of the + * new table will be addedd. + * + * @return a String which is a template for adding an index to the value + * column of a _instances table + */ + static String getAddValueIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; + } + + /** + * Get the template for creating an index on the known_status column of + * an instance table. %s will exist in the template where the name of + * the new table will be addedd. + * + * @return a String which is a template for adding an index to the + * known_status column of a _instances table + */ + static String getAddKnownStatusIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; + } + + /** + * Get the template for creating an index on the file_obj_id column of + * an instance table. %s will exist in the template where the name of + * the new table will be addedd. + * + * @return a String which is a template for adding an index to the + * file_obj_id column of a _instances table + */ + static String getAddObjectIdIndexTemplate() { + // Each "%s" will be replaced with the relevant TYPE_instances table name. + return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)"; + } + + /** + * Get the statement String for creating a new data_sources table in a + * Postgres central repository. + * + * @return a String which is a statement for cretating a new + * data_sources table + */ + static String getCreateDataSourcesTableStatement() { + return "CREATE TABLE IF NOT EXISTS data_sources " + + "(id SERIAL PRIMARY KEY,case_id integer NOT NULL,device_id text NOT NULL," + + "name text NOT NULL,datasource_obj_id BIGINT,md5 text DEFAULT NULL," + + "sha1 text DEFAULT NULL,sha256 text DEFAULT NULL," + + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + + "CONSTRAINT datasource_unique UNIQUE (case_id, datasource_obj_id))"; + } + + /** + * Get the statement for creating an index on the name column of the + * data_sources table. + * + * @return a String which is a statement for adding an index on the name + * column of the data_sources table. + */ + static String getAddDataSourcesNameIndexStatement() { + return "CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)"; + } + + /** + * Get the statement for creating an index on the data_sources_object_id + * column of the data_sources table. + * + * @return a String which is a statement for adding an index on the + * data_sources_object_id column of the data_sources table. + */ + static String getAddDataSourcesObjectIdIndexStatement() { + return "CREATE INDEX IF NOT EXISTS data_sources_object_id ON data_sources (datasource_obj_id)"; + } + + } + + public boolean insertDefaultDatabaseContent() { + Connection conn = rdbmsCentralRepo.getEphemeralConnection(); + if (null == conn) { + return false; + } + + boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) && CentralRepoDbUtil.insertDefaultOrganization(conn); + CentralRepoDbUtil.closeConnection(conn); + return result; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java index 17d1393bbf..2c3bf174b6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java @@ -113,6 +113,7 @@ final class SqliteCentralRepo extends RdbmsCentralRepo { @Override public void reset() throws CentralRepoException { try { + // RAMAN TBD: this should be moved to RdbmsCentralRepoSchemaFactory ?? acquireExclusiveLock(); Connection conn = connect(); @@ -144,7 +145,9 @@ final class SqliteCentralRepo extends RdbmsCentralRepo { CentralRepoDbUtil.closeConnection(conn); } - dbSettings.insertDefaultDatabaseContent(); + //RdbmsCentralRepoSchemaFactory.getInstance().insertDefaultDatabaseContent(); + RdbmsCentralRepoSchemaFactory centralRepoSchemaFactory = new RdbmsCentralRepoSchemaFactory(CentralRepoPlatforms.SQLITE); + centralRepoSchemaFactory.insertDefaultDatabaseContent(); } finally { releaseExclusiveLock(); } @@ -226,6 +229,10 @@ final class SqliteCentralRepo extends RdbmsCentralRepo { return ""; } + @Override + protected Connection getEphemeralConnection() { + return this.dbSettings.getEphemeralConnection(); + } /** * Add a new name/value pair in the db_info table. * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepoSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepoSettings.java index 3b2a424c4a..25b71e1dcc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepoSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepoSettings.java @@ -25,14 +25,11 @@ import java.nio.file.InvalidPathException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; import java.util.logging.Level; import java.util.regex.Pattern; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo.SOFTWARE_CR_DB_SCHEMA_VERSION; /** * Settings for the sqlite implementation of the Central Repository database @@ -48,13 +45,7 @@ public final class SqliteCentralRepoSettings { private final static String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS private final static String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS private final static String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS - private final static String PRAGMA_SYNC_OFF = "PRAGMA synchronous = OFF"; - private final static String PRAGMA_SYNC_NORMAL = "PRAGMA synchronous = NORMAL"; - private final static String PRAGMA_JOURNAL_WAL = "PRAGMA journal_mode = WAL"; - private final static String PRAGMA_READ_UNCOMMITTED_TRUE = "PRAGMA read_uncommitted = True"; - private final static String PRAGMA_ENCODING_UTF8 = "PRAGMA encoding = 'UTF-8'"; - private final static String PRAGMA_PAGE_SIZE_4096 = "PRAGMA page_size = 4096"; - private final static String PRAGMA_FOREIGN_KEYS_ON = "PRAGMA foreign_keys = ON"; + private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*(\\.db)?"; private String dbName; private String dbDirectory; @@ -182,7 +173,7 @@ public final class SqliteCentralRepoSettings { * * @return Connection or null. */ - private Connection getEphemeralConnection() { + Connection getEphemeralConnection() { if (!dbDirectoryExists()) { return null; } @@ -233,312 +224,6 @@ public final class SqliteCentralRepoSettings { return result; } - /** - * Initialize the database schema. - * - * Requires valid connectionPool. - * - * This method is called from within connect(), so we cannot call connect() - * to get a connection. This method is called after setupConnectionPool(), - * so it is safe to assume that a valid connectionPool exists. The - * implementation of connect() is synchronized, so we can safely use the - * connectionPool object directly. - */ - public boolean initializeDatabaseSchema() { - // The "id" column is an alias for the built-in 64-bit int "rowid" column. - // It is autoincrementing by default and must be of type "integer primary key". - // We've omitted the autoincrement argument because we are not currently - // using the id value to search for specific rows, so we do not care - // if a rowid is re-used after an existing rows was previously deleted. - StringBuilder createOrganizationsTable = new StringBuilder(); - createOrganizationsTable.append("CREATE TABLE IF NOT EXISTS organizations ("); - createOrganizationsTable.append("id integer primary key autoincrement NOT NULL,"); - createOrganizationsTable.append("org_name text NOT NULL,"); - createOrganizationsTable.append("poc_name text NOT NULL,"); - createOrganizationsTable.append("poc_email text NOT NULL,"); - createOrganizationsTable.append("poc_phone text NOT NULL,"); - createOrganizationsTable.append("CONSTRAINT org_name_unique UNIQUE (org_name)"); - createOrganizationsTable.append(")"); - - // NOTE: The organizations will only have a small number of rows, so - // an index is probably not worthwhile. - StringBuilder createCasesTable = new StringBuilder(); - createCasesTable.append("CREATE TABLE IF NOT EXISTS cases ("); - createCasesTable.append("id integer primary key autoincrement NOT NULL,"); - createCasesTable.append("case_uid text NOT NULL,"); - createCasesTable.append("org_id integer,"); - createCasesTable.append("case_name text NOT NULL,"); - createCasesTable.append("creation_date text NOT NULL,"); - createCasesTable.append("case_number text,"); - createCasesTable.append("examiner_name text,"); - createCasesTable.append("examiner_email text,"); - createCasesTable.append("examiner_phone text,"); - createCasesTable.append("notes text,"); - createCasesTable.append("CONSTRAINT case_uid_unique UNIQUE(case_uid) ON CONFLICT IGNORE,"); - createCasesTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL"); - createCasesTable.append(")"); - - // NOTE: when there are few cases in the cases table, these indices may not be worthwhile - String casesIdx1 = "CREATE INDEX IF NOT EXISTS cases_org_id ON cases (org_id)"; - String casesIdx2 = "CREATE INDEX IF NOT EXISTS cases_case_uid ON cases (case_uid)"; - - StringBuilder createReferenceSetsTable = new StringBuilder(); - createReferenceSetsTable.append("CREATE TABLE IF NOT EXISTS reference_sets ("); - createReferenceSetsTable.append("id integer primary key autoincrement NOT NULL,"); - createReferenceSetsTable.append("org_id integer NOT NULL,"); - createReferenceSetsTable.append("set_name text NOT NULL,"); - createReferenceSetsTable.append("version text NOT NULL,"); - createReferenceSetsTable.append("known_status integer NOT NULL,"); - createReferenceSetsTable.append("read_only boolean NOT NULL,"); - createReferenceSetsTable.append("type integer NOT NULL,"); - createReferenceSetsTable.append("import_date text NOT NULL,"); - createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); - createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); - createReferenceSetsTable.append(")"); - - String referenceSetsIdx1 = "CREATE INDEX IF NOT EXISTS reference_sets_org_id ON reference_sets (org_id)"; - - // Each "%s" will be replaced with the relevant reference_TYPE table name. - StringBuilder createReferenceTypesTableTemplate = new StringBuilder(); - createReferenceTypesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s ("); - createReferenceTypesTableTemplate.append("id integer primary key autoincrement NOT NULL,"); - createReferenceTypesTableTemplate.append("reference_set_id integer,"); - createReferenceTypesTableTemplate.append("value text NOT NULL,"); - createReferenceTypesTableTemplate.append("known_status integer NOT NULL,"); - createReferenceTypesTableTemplate.append("comment text,"); - createReferenceTypesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(reference_set_id, value) ON CONFLICT IGNORE,"); - createReferenceTypesTableTemplate.append("foreign key (reference_set_id) references reference_sets(id) ON UPDATE SET NULL ON DELETE SET NULL"); - createReferenceTypesTableTemplate.append(")"); - - // Each "%s" will be replaced with the relevant reference_TYPE table name. - String referenceTypesIdx1 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; - String referenceTypesIdx2 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; - - StringBuilder createCorrelationTypesTable = new StringBuilder(); - createCorrelationTypesTable.append("CREATE TABLE IF NOT EXISTS correlation_types ("); - createCorrelationTypesTable.append("id integer primary key autoincrement NOT NULL,"); - createCorrelationTypesTable.append("display_name text NOT NULL,"); - createCorrelationTypesTable.append("db_table_name text NOT NULL,"); - createCorrelationTypesTable.append("supported integer NOT NULL,"); - createCorrelationTypesTable.append("enabled integer NOT NULL,"); - createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)"); - createCorrelationTypesTable.append(")"); - - String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(); - - String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); - String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate(); - String instancesValueIdx = getAddValueIndexTemplate(); - String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate(); - String instancesObjectIdIdx = getAddObjectIdIndexTemplate(); - - // NOTE: the db_info table currenly only has 1 row, so having an index - // provides no benefit. - Connection conn = null; - try { - conn = getEphemeralConnection(); - if (null == conn) { - return false; - } - Statement stmt = conn.createStatement(); - stmt.execute(PRAGMA_JOURNAL_WAL); - stmt.execute(PRAGMA_SYNC_OFF); - stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE); - stmt.execute(PRAGMA_ENCODING_UTF8); - stmt.execute(PRAGMA_PAGE_SIZE_4096); - stmt.execute(PRAGMA_FOREIGN_KEYS_ON); - - stmt.execute(createOrganizationsTable.toString()); - - stmt.execute(createCasesTable.toString()); - stmt.execute(casesIdx1); - stmt.execute(casesIdx2); - - stmt.execute(getCreateDataSourcesTableStatement()); - stmt.execute(getAddDataSourcesNameIndexStatement()); - stmt.execute(getAddDataSourcesObjectIdIndexStatement()); - - stmt.execute(createReferenceSetsTable.toString()); - stmt.execute(referenceSetsIdx1); - - stmt.execute(createCorrelationTypesTable.toString()); - - /* - * Note that the essentially useless id column in the following - * table is required for backwards compatibility. Otherwise, the - * name column could be the primary key. - */ - stmt.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - - // Create a separate instance and reference table for each artifact type - List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); - - String reference_type_dbname; - String instance_type_dbname; - for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) { - reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); - instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); - - stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); - - // FUTURE: allow more than the FILES type - if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { - stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname)); - } - } - } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS - return false; - } catch (CentralRepoException ex) { - LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS - return false; - } finally { - CentralRepoDbUtil.closeConnection(conn); - } - return true; - } - - /** - * Get the template String for creating a new _instances table in a Sqlite - * central repository. %s will exist in the template where the name of the - * new table will be addedd. - * - * @return a String which is a template for cretating a new _instances table - */ - static String getCreateArtifactInstancesTableTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE TABLE IF NOT EXISTS %s (id integer primary key autoincrement NOT NULL," - + "case_id integer NOT NULL,data_source_id integer NOT NULL,value text NOT NULL," - + "file_path text NOT NULL,known_status integer NOT NULL,comment text,file_obj_id integer," - + "CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE," - + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," - + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"; - } - - /** - * Get the statement String for creating a new data_sources table in a - * Sqlite central repository. - * - * @return a String which is a statement for cretating a new data_sources - * table - */ - static String getCreateDataSourcesTableStatement() { - return "CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL," - + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer," - + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL," - + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," - + "CONSTRAINT datasource_unique UNIQUE (case_id, datasource_obj_id))"; - } - - /** - * Get the statement for creating an index on the name column of the - * data_sources table. - * - * @return a String which is a statement for adding an index on the name - * column of the data_sources table. - */ - static String getAddDataSourcesNameIndexStatement() { - return "CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)"; - } - - /** - * Get the statement for creating an index on the data_sources_object_id - * column of the data_sources table. - * - * @return a String which is a statement for adding an index on the - * data_sources_object_id column of the data_sources table. - */ - static String getAddDataSourcesObjectIdIndexStatement() { - return "CREATE INDEX IF NOT EXISTS data_sources_object_id ON data_sources (datasource_obj_id)"; - } - - /** - * Get the template for creating an index on the case_id column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the case_id - * column of a _instances table - */ - static String getAddCaseIdIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)"; - } - - /** - * Get the template for creating an index on the data_source_id column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the - * data_source_id column of a _instances table - */ - static String getAddDataSourceIdIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)"; - } - - /** - * Get the template for creating an index on the value column of an instance - * table. %s will exist in the template where the name of the new table will - * be addedd. - * - * @return a String which is a template for adding an index to the value - * column of a _instances table - */ - static String getAddValueIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)"; - } - - /** - * Get the template for creating an index on the known_status column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the - * known_status column of a _instances table - */ - static String getAddKnownStatusIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)"; - } - - /** - * Get the template for creating an index on the file_obj_id column of an - * instance table. %s will exist in the template where the name of the new - * table will be addedd. - * - * @return a String which is a template for adding an index to the - * file_obj_id column of a _instances table - */ - static String getAddObjectIdIndexTemplate() { - // Each "%s" will be replaced with the relevant TYPE_instances table name. - return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)"; - } - - public boolean insertDefaultDatabaseContent() { - Connection conn = getEphemeralConnection(); - if (null == conn) { - return false; - } - - boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) && CentralRepoDbUtil.insertDefaultOrganization(conn); - CentralRepoDbUtil.closeConnection(conn); - return result; - } - boolean isChanged() { String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form index 0f39326bec..27eae7629c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.form @@ -133,7 +133,7 @@ - + @@ -410,4 +410,4 @@ - \ No newline at end of file + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java index 271a8a4f04..cc25b69141 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java @@ -35,6 +35,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.filechooser.FileFilter; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.corecomponents.TextPrompt; @@ -45,6 +46,7 @@ import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatf import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings; import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoSchemaFactory; /** * Configuration dialog for Central Repository database settings. @@ -447,12 +449,19 @@ public class EamDbSettingsDialog extends JDialog { dbCreated = dbSettingsPostgres.createDatabase(); } if (dbCreated) { - result = dbSettingsPostgres.initializeDatabaseSchema() - && dbSettingsPostgres.insertDefaultDatabaseContent(); + try { + RdbmsCentralRepoSchemaFactory centralRepoSchemaFactory = new RdbmsCentralRepoSchemaFactory(selectedPlatform); + + result = centralRepoSchemaFactory.initializeDatabaseSchema() + && centralRepoSchemaFactory.insertDefaultDatabaseContent(); + } catch (CentralRepoException ex) { + logger.log( Level.SEVERE, "Unable to initialize database schema or insert contents into Postgres central repository.", ex); + } } if (!result) { // Remove the incomplete database if (dbCreated) { + // RAMAN TBD: migrate deleteDatabase() to RdbmsCentralRepoSchemaFactory dbSettingsPostgres.deleteDatabase(); } @@ -469,8 +478,14 @@ public class EamDbSettingsDialog extends JDialog { dbCreated = dbSettingsSqlite.createDbDirectory(); } if (dbCreated) { - result = dbSettingsSqlite.initializeDatabaseSchema() - && dbSettingsSqlite.insertDefaultDatabaseContent(); + try { + RdbmsCentralRepoSchemaFactory centralRepoSchemaFactory = new RdbmsCentralRepoSchemaFactory(selectedPlatform); + result = centralRepoSchemaFactory.initializeDatabaseSchema() + && centralRepoSchemaFactory.insertDefaultDatabaseContent(); + } catch (CentralRepoException ex) { + logger.log( Level.SEVERE, "Unable to initialize database schema or insert contents into SQLite central repository.", ex); + } + } if (!result) { if (dbCreated) {