|
|
@@ -19,13 +19,19 @@ |
|
|
|
*/ |
|
|
|
package org.sonar.db; |
|
|
|
|
|
|
|
import java.io.PrintWriter; |
|
|
|
import java.sql.Connection; |
|
|
|
import java.sql.SQLException; |
|
|
|
import java.util.List; |
|
|
|
import javax.sql.DataSource; |
|
|
|
import org.apache.commons.dbutils.DbUtils; |
|
|
|
import org.apache.commons.io.output.NullWriter; |
|
|
|
import org.apache.ibatis.io.Resources; |
|
|
|
import org.apache.ibatis.jdbc.ScriptRunner; |
|
|
|
import org.sonar.api.SonarEdition; |
|
|
|
import org.sonar.api.SonarQubeSide; |
|
|
|
import org.sonar.api.config.Settings; |
|
|
|
import org.sonar.api.config.internal.MapSettings; |
|
|
|
import org.sonar.api.internal.SonarRuntimeImpl; |
|
|
|
import org.sonar.api.utils.System2; |
|
|
|
import org.sonar.api.utils.Version; |
|
|
@@ -34,7 +40,7 @@ import org.sonar.core.platform.ComponentContainer; |
|
|
|
import org.sonar.core.util.UuidFactoryFast; |
|
|
|
import org.sonar.core.util.logs.Profiler; |
|
|
|
import org.sonar.db.dialect.Dialect; |
|
|
|
import org.sonar.db.dialect.H2; |
|
|
|
import org.sonar.process.logging.LogbackHelper; |
|
|
|
import org.sonar.server.platform.db.migration.MigrationConfigurationModule; |
|
|
|
import org.sonar.server.platform.db.migration.engine.MigrationContainer; |
|
|
|
import org.sonar.server.platform.db.migration.engine.MigrationContainerImpl; |
|
|
@@ -50,20 +56,28 @@ import org.sonar.server.platform.db.migration.version.DbVersion; |
|
|
|
|
|
|
|
import static com.google.common.base.Preconditions.checkState; |
|
|
|
|
|
|
|
/** |
|
|
|
* H2 in-memory database, used for unit tests against an empty DB, a specific script or against SQ schema. |
|
|
|
*/ |
|
|
|
public class H2Database extends CoreH2Database { |
|
|
|
public class SQDatabase extends DefaultDatabase { |
|
|
|
private final boolean createSchema; |
|
|
|
|
|
|
|
/** |
|
|
|
* IMPORTANT: change DB name in order to not conflict with {@link DefaultDatabaseTest} |
|
|
|
*/ |
|
|
|
public H2Database(String name, boolean createSchema) { |
|
|
|
super(name); |
|
|
|
private SQDatabase(Settings settings, boolean createSchema) { |
|
|
|
super(new LogbackHelper(), settings); |
|
|
|
this.createSchema = createSchema; |
|
|
|
} |
|
|
|
|
|
|
|
public static SQDatabase newDatabase(Settings settings, boolean createSchema) { |
|
|
|
return new SQDatabase(settings, createSchema); |
|
|
|
} |
|
|
|
|
|
|
|
public static SQDatabase newH2Database(String name, boolean createSchema) { |
|
|
|
MapSettings settings = new MapSettings() |
|
|
|
.setProperty("sonar.jdbc.dialect", "h2") |
|
|
|
.setProperty("sonar.jdbc.driverClassName", "org.h2.Driver") |
|
|
|
.setProperty("sonar.jdbc.url", "jdbc:h2:mem:" + name) |
|
|
|
.setProperty("sonar.jdbc.username", "sonar") |
|
|
|
.setProperty("sonar.jdbc.password", "sonar"); |
|
|
|
return new SQDatabase(settings, createSchema); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void start() { |
|
|
|
super.start(); |
|
|
@@ -76,10 +90,10 @@ public class H2Database extends CoreH2Database { |
|
|
|
Connection connection = null; |
|
|
|
try { |
|
|
|
connection = getDataSource().getConnection(); |
|
|
|
NoopH2Database noopH2Database = new NoopH2Database(); |
|
|
|
NoopDatabase noopDatabase = new NoopDatabase(getDialect(), getDataSource()); |
|
|
|
// create and populate schema |
|
|
|
createMigrationHistoryTable(noopH2Database); |
|
|
|
executeDbMigrations(noopH2Database); |
|
|
|
createMigrationHistoryTable(noopDatabase); |
|
|
|
executeDbMigrations(noopDatabase); |
|
|
|
} catch (SQLException e) { |
|
|
|
throw new IllegalStateException("Fail to create schema", e); |
|
|
|
} finally { |
|
|
@@ -116,7 +130,7 @@ public class H2Database extends CoreH2Database { |
|
|
|
} |
|
|
|
|
|
|
|
private void execute(RegisteredMigrationStep step, MigrationStep migrationStep) { |
|
|
|
Profiler stepProfiler = Profiler.create(Loggers.get(H2Database.class)); |
|
|
|
Profiler stepProfiler = Profiler.create(Loggers.get(SQDatabase.class)); |
|
|
|
stepProfiler.startInfo(STEP_START_PATTERN, step); |
|
|
|
boolean done = false; |
|
|
|
try { |
|
|
@@ -134,9 +148,9 @@ public class H2Database extends CoreH2Database { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void executeDbMigrations(NoopH2Database noopH2Database) { |
|
|
|
private void executeDbMigrations(NoopDatabase noopDatabase) { |
|
|
|
ComponentContainer parentContainer = new ComponentContainer(); |
|
|
|
parentContainer.add(noopH2Database); |
|
|
|
parentContainer.add(noopDatabase); |
|
|
|
parentContainer.add(H2MigrationContainerPopulator.class); |
|
|
|
MigrationConfigurationModule migrationConfigurationModule = new MigrationConfigurationModule(); |
|
|
|
migrationConfigurationModule.configure(parentContainer); |
|
|
@@ -154,19 +168,27 @@ public class H2Database extends CoreH2Database { |
|
|
|
.execute(migrationSteps.readAll()); |
|
|
|
} |
|
|
|
|
|
|
|
private void createMigrationHistoryTable(NoopH2Database noopH2Database) { |
|
|
|
new MigrationHistoryTableImpl(noopH2Database).start(); |
|
|
|
private void createMigrationHistoryTable(NoopDatabase noopDatabase) { |
|
|
|
new MigrationHistoryTableImpl(noopDatabase).start(); |
|
|
|
} |
|
|
|
|
|
|
|
private class NoopH2Database implements Database { |
|
|
|
private class NoopDatabase implements Database { |
|
|
|
private final Dialect dialect; |
|
|
|
private final DataSource dataSource; |
|
|
|
|
|
|
|
private NoopDatabase(Dialect dialect, DataSource dataSource) { |
|
|
|
this.dialect = dialect; |
|
|
|
this.dataSource = dataSource; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public DataSource getDataSource() { |
|
|
|
return H2Database.this.getDataSource(); |
|
|
|
return dataSource; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public Dialect getDialect() { |
|
|
|
return new H2(); |
|
|
|
return dialect; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
@@ -184,4 +206,31 @@ public class H2Database extends CoreH2Database { |
|
|
|
// do nothing |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void executeScript(String classloaderPath) { |
|
|
|
try (Connection connection = getDataSource().getConnection()) { |
|
|
|
executeScript(connection, classloaderPath); |
|
|
|
} catch (SQLException e) { |
|
|
|
throw new IllegalStateException("Fail to execute script: " + classloaderPath, e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void executeScript(Connection connection, String path) { |
|
|
|
ScriptRunner scriptRunner = newScriptRunner(connection); |
|
|
|
try { |
|
|
|
scriptRunner.runScript(Resources.getResourceAsReader(path)); |
|
|
|
connection.commit(); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
throw new IllegalStateException("Fail to restore: " + path, e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static ScriptRunner newScriptRunner(Connection connection) { |
|
|
|
ScriptRunner scriptRunner = new ScriptRunner(connection); |
|
|
|
scriptRunner.setDelimiter(";"); |
|
|
|
scriptRunner.setStopOnError(true); |
|
|
|
scriptRunner.setLogWriter(new PrintWriter(new NullWriter())); |
|
|
|
return scriptRunner; |
|
|
|
} |
|
|
|
} |