/* * ==================================================================== * Copyright (c) 2004-2010 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.wc17.db.statement; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.sqljet.core.table.ISqlJetTransaction; import org.tmatesoft.sqljet.core.table.SqlJetDb; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.db.SVNSqlJetDb; import org.tmatesoft.svn.core.internal.db.SVNSqlJetStatement; /** * @version 1.4 * @author TMate Software Ltd. */ public class SVNWCDbCreateSchema extends SVNSqlJetStatement { public static final Statement[] MAIN_DB_STATEMENTS = new Statement[] { new Statement(Type.TABLE, "REPOSITORY", "CREATE TABLE REPOSITORY ( id INTEGER PRIMARY KEY AUTOINCREMENT, root TEXT UNIQUE NOT NULL, uuid TEXT NOT NULL ); "), new Statement(Type.INDEX, "I_UUID", "CREATE INDEX I_UUID ON REPOSITORY (uuid); "), new Statement(Type.INDEX, "I_ROOT", "CREATE INDEX I_ROOT ON REPOSITORY (root); "), new Statement(Type.TABLE, "WCROOT", "CREATE TABLE WCROOT ( id INTEGER PRIMARY KEY AUTOINCREMENT, local_abspath TEXT UNIQUE ); "), new Statement(Type.INDEX, "I_LOCAL_ABSPATH", "CREATE UNIQUE INDEX I_LOCAL_ABSPATH ON WCROOT (local_abspath); "), new Statement(Type.TABLE, "PRISTINE", "CREATE TABLE PRISTINE ( checksum TEXT NOT NULL PRIMARY KEY, compression INTEGER, size INTEGER NOT NULL, " + " refcount INTEGER NOT NULL, md5_checksum TEXT NOT NULL ); "), new Statement(Type.TABLE, "ACTUAL_NODE", "CREATE TABLE ACTUAL_NODE ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_relpath TEXT NOT NULL, parent_relpath TEXT, " + " properties BLOB, conflict_old TEXT, conflict_new TEXT, conflict_working TEXT, prop_reject TEXT, changelist TEXT, " + " text_mod TEXT, tree_conflict_data TEXT, conflict_data BLOB, older_checksum TEXT, left_checksum TEXT, right_checksum TEXT, PRIMARY KEY (wc_id, local_relpath) ); "), new Statement(Type.INDEX, "I_ACTUAL_PARENT", "CREATE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath); "), new Statement(Type.TABLE, "LOCK", "CREATE TABLE LOCK ( repos_id INTEGER NOT NULL REFERENCES REPOSITORY (id), repos_relpath TEXT NOT NULL, lock_token TEXT NOT NULL, " + " lock_owner TEXT, lock_comment TEXT, lock_date INTEGER, PRIMARY KEY (repos_id, repos_relpath) ); "), new Statement(Type.TABLE, "WORK_QUEUE", "CREATE TABLE WORK_QUEUE ( id INTEGER PRIMARY KEY AUTOINCREMENT, work BLOB NOT NULL ); "), new Statement(Type.TABLE, "WC_LOCK", "CREATE TABLE WC_LOCK ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_dir_relpath TEXT NOT NULL, " + " locked_levels INTEGER NOT NULL DEFAULT -1, PRIMARY KEY (wc_id, local_dir_relpath) ); "), new Statement(Type.TABLE, "NODES", "CREATE TABLE NODES ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_relpath TEXT NOT NULL, op_depth INTEGER NOT NULL, " + " parent_relpath TEXT, repos_id INTEGER REFERENCES REPOSITORY (id), repos_path TEXT, revision INTEGER, presence TEXT NOT NULL, " + " moved_here INTEGER, moved_to TEXT, kind TEXT NOT NULL, properties BLOB, depth TEXT, checksum TEXT, symlink_target TEXT, " + " changed_revision INTEGER, changed_date INTEGER, changed_author TEXT, translated_size INTEGER, last_mod_time INTEGER, " + " dav_cache BLOB, file_external INTEGER, inherited_props BLOB, PRIMARY KEY (wc_id, local_relpath, op_depth) ); "), // this index is now created after update operation for performance reasons. new Statement(Type.INDEX, "I_NODES_MOVED", "CREATE UNIQUE INDEX I_NODES_MOVED ON NODES (wc_id, moved_to, op_depth);", false, false, true), new Statement(Type.INDEX, "I_NODES_PARENT", "CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, local_relpath, op_depth); "), new Statement(Type.INDEX, "I_PRISTINE_MD5", "CREATE INDEX IF NOT EXISTS I_PRISTINE_MD5 ON PRISTINE (md5_checksum);"), new Statement(Type.TABLE, "EXTERNALS", "CREATE TABLE EXTERNALS ( " + " wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " + " local_relpath TEXT NOT NULL, " + " parent_relpath TEXT NOT NULL, " + " repos_id INTEGER NOT NULL REFERENCES REPOSITORY (id), " + " presence TEXT NOT NULL, " + " kind TEXT NOT NULL, " + " def_local_relpath TEXT NOT NULL, " + " def_repos_relpath TEXT NOT NULL, " + " def_operational_revision TEXT, " + " def_revision TEXT, " + " PRIMARY KEY (wc_id, local_relpath) " + "); "), new Statement(Type.INDEX, "I_EXTERNALS_DEFINED", "CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS " + " (wc_id, def_local_relpath, local_relpath); " ), new Statement(Type.VIEW, "NODES_BASE", "CREATE VIEW NODES_BASE AS SELECT * FROM nodes WHERE op_depth = 0;"), new Statement(Type.VIEW, "NODES_CURRENT", "CREATE VIEW NODES_CURRENT AS SELECT * FROM nodes AS n WHERE op_depth = (SELECT MAX(op_depth) FROM nodes AS n2 WHERE n2.wc_id = n.wc_id AND n2.local_relpath = n.local_relpath);"), new Statement(Type.TRIGGER, "nodes_insert_trigger", "CREATE TRIGGER nodes_insert_trigger AFTER INSERT ON nodes WHEN NEW.checksum IS NOT NULL BEGIN UPDATE pristine SET refcount = refcount + 1 WHERE checksum = NEW.checksum; END;"), new Statement(Type.TRIGGER, "nodes_delete_trigger", "CREATE TRIGGER nodes_delete_trigger AFTER DELETE ON nodes WHEN OLD.checksum IS NOT NULL BEGIN UPDATE pristine SET refcount = refcount - 1 WHERE checksum = OLD.checksum; END;"), new Statement(Type.TRIGGER, "nodes_update_checksum_trigger", "CREATE TRIGGER nodes_update_checksum_trigger AFTER UPDATE OF checksum ON nodes WHEN NEW.checksum IS NOT OLD.checksum BEGIN UPDATE pristine SET refcount = refcount + 1 WHERE checksum = NEW.checksum; UPDATE pristine SET refcount = refcount - 1 WHERE checksum = OLD.checksum; END;"), }; public static final Statement[] TARGETS_LIST = new Statement[] { new Statement(Type.TABLE, "TARGETS_LIST", "CREATE TABLE TARGETS_LIST (wc_id INTEGER NOT NULL, local_relpath TEXT NOT NULL, parent_relpath TEXT, kind TEXT NOT NULL, PRIMARY KEY (wc_id, local_relpath) );", true), new Statement(Type.INDEX, "targets_list_kind", "CREATE INDEX targets_list_kind ON TARGETS_LIST (kind);", true), }; public static final Statement[] DROP_TARGETS_LIST = new Statement[] { new Statement(Type.INDEX, "targets_list_kind", "targets_list_kind", true, true, false), new Statement(Type.TABLE, "TARGETS_LIST", "TARGETS_LIST", true, true, false), }; public static final Statement[] NODE_PROPS_CACHE = new Statement[] { new Statement(Type.TABLE, "NODE_PROPS_CACHE", "CREATE TABLE NODE_PROPS_CACHE (local_Relpath TEXT NOT NULL, kind TEXT NOT NULL, properties BLOB, PRIMARY KEY (local_Relpath) );", true), }; public static final Statement[] DROP_NODE_PROPS_CACHE = new Statement[] { new Statement(Type.TABLE, "NODE_PROPS_CACHE", "NODE_PROPS_CACHE", true, true, false), }; public static final Statement[] DELETE_LIST = new Statement[] { new Statement(Type.TABLE, "DELETE_LIST", "CREATE TABLE DELETE_LIST (local_relpath TEXT PRIMARY KEY NOT NULL);", true), }; public static final Statement[] DROP_DELETE_LIST = new Statement[] { new Statement(Type.TABLE, "DELETE_LIST", "DELETE_LIST", true, true, false), }; public static final Statement[] REVERT_LIST = new Statement[] { new Statement(Type.TABLE, "REVERT_LIST", "CREATE TABLE REVERT_LIST (" + " local_relpath TEXT NOT NULL, " + " actual INTEGER NOT NULL, " + " conflict_data BLOB, " + " notify INTEGER, " + " op_depth INTEGER, " + " repos_id INTEGER, " + " kind TEXT, " + " PRIMARY KEY (local_relpath, actual) );", true) }; public static final Statement[] DROP_REVERT_LIST = new Statement[] { new Statement(Type.TABLE, "REVERT_LIST", "REVERT_LIST", true, true, false), }; public static final Statement[] CHANGELIST_LIST = new Statement[] { new Statement(Type.TABLE, "CHANGELIST_LIST", "CREATE TABLE CHANGELIST_LIST (" + " wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " + " local_relpath TEXT NOT NULL, " + " notify INTEGER, " + " changelist TEXT NOT NULL, PRIMARY KEY (wc_id, local_relpath) );" , true) //, //new Statement(Type.INDEX, "changelist_list_index", "CREATE INDEX changelist_list_index ON changelist_list (wc_id, local_relpath);", true) }; public static final Statement[] DROP_CHANGELIST_LIST = new Statement[] { new Statement(Type.TABLE, "CHANGELIST_LIST", "CHANGELIST_LIST", true, true, false), //new Statement(Type.INDEX, "changelist_list_index", "changelist_list_index", true, true), new Statement(Type.TABLE, "TARGETS_LIST", "TARGETS_LIST", true, true, false), new Statement(Type.INDEX, "targets_list_kind", "targets_list_kind", true, true, false) }; public static final Statement[] CREATE_UPDATE_MOVE_LIST = new Statement[] { new Statement(Type.TABLE, "UPDATE_MOVE_LIST", "CREATE TABLE UPDATE_MOVE_LIST (\n" + " local_relpath TEXT PRIMARY KEY NOT NULL UNIQUE,\n" + " action INTEGER NOT NULL,\n" + " kind INTEGER NOT NULL,\n" + " content_state INTEGER NOT NULL,\n" + " prop_state INTEGER NOT NULL\n" + " )", true) }; public static final Statement[] FINALIZE_UPDATE_MOVE = new Statement[] { new Statement(Type.TABLE, "UPDATE_MOVE_LIST", "UPDATE_MOVE_LIST", true, true, false) }; private enum Type { TABLE, INDEX, VIEW, TRIGGER; } public static class Statement { private Type type; private String sql; private boolean isDrop; private String name; private boolean isDropBeforeCreate; private boolean isRunOnUpgrade; public Statement(Type type, String name, String sql) { this(type, name, sql, false, false, false); } public Statement(Type type, String name, String sql, boolean dropBeforeCreate) { this(type, name, sql, dropBeforeCreate, false, false); } public Statement(Type type, String name, String sql, boolean dropBeforeCreate, boolean isDrop, boolean upgradeOnly) { this.type = type; this.sql = sql; this.name = name; this.isDrop = isDrop; this.isDropBeforeCreate = dropBeforeCreate; this.isRunOnUpgrade = upgradeOnly; } public boolean isDrop() { return isDrop; } public Type getType() { return type; } public String getSql() { return sql; } public String getName() { return name; } public boolean isDropBeforeCreate() { return isDropBeforeCreate; } private boolean isRunOnUpgradeOnly() { return isRunOnUpgrade; } } private Statement[] statements; private int userVersion; private boolean isUpgrade; public SVNWCDbCreateSchema(SVNSqlJetDb sDb, Statement[] statements, int userVersion, boolean isUpgrade) { super(sDb); this.statements = statements; this.userVersion = userVersion; this.isUpgrade = isUpgrade; } public long exec() throws SVNException { try { sDb.getDb().runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { for (Statement stmt : statements) { switch (stmt.getType()) { case TABLE: if (stmt.isDrop()) { if (db.getSchema().getTableNames().contains(stmt.getName())) { db.dropTable(stmt.getSql()); } } else { if (stmt.isDropBeforeCreate()) { if (db.getSchema().getTableNames().contains(stmt.getName())) { db.dropTable(stmt.getName()); } } db.createTable(stmt.getSql()); } break; case INDEX: if (stmt.isDrop()) { if (db.getSchema().getIndexNames().contains(stmt.getName())) { db.dropIndex(stmt.getSql()); } } else { if (stmt.isDropBeforeCreate()) { if (db.getSchema().getIndexNames().contains(stmt.getName())) { db.dropIndex(stmt.getName()); } } if (stmt.isRunOnUpgradeOnly()) { if (isUpgrade) { db.createIndex(stmt.getSql()); } } else { db.createIndex(stmt.getSql()); } } break; case VIEW: if (stmt.isDrop()) { if (db.getSchema().getViewNames().contains(stmt.getName())) { db.dropView(stmt.getSql()); } } else { if (stmt.isDropBeforeCreate()) { if (db.getSchema().getViewNames().contains(stmt.getName())) { db.dropView(stmt.getName()); } } db.createView(stmt.getSql()); } break; case TRIGGER: if (stmt.isDrop()) { if (db.getSchema().getTriggerNames().contains(stmt.getName())) { db.dropTrigger(stmt.getSql()); } } else { if (stmt.isDropBeforeCreate()) { if (db.getSchema().getTriggerNames().contains(stmt.getName())) { db.dropTrigger(stmt.getName()); } } db.createTrigger(stmt.getSql()); } break; default: break; } } if (userVersion >= 0) { db.getOptions().setUserVersion(userVersion); } return null; } }); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); } return 0; } }