import org.sonar.server.platform.db.migration.history.MigrationHistoryMeddler;
import org.sonar.server.platform.db.migration.sql.DbPrimaryKeyConstraintFinder;
import org.sonar.server.platform.db.migration.sql.DropPrimaryKeySqlGenerator;
+import org.sonar.server.platform.db.migration.sql.OracleTriggerFinder;
import org.sonar.server.platform.db.migration.step.MigrationStepRegistryImpl;
import org.sonar.server.platform.db.migration.step.MigrationStepsProvider;
import org.sonar.server.platform.db.migration.version.v00.DbVersion00;
MigrationHistoryMeddler.class,
// Utility classes
+ OracleTriggerFinder.class,
DbPrimaryKeyConstraintFinder.class,
DropPrimaryKeySqlGenerator.class,
NetworkInterfaceProvider.class);
*/
package org.sonar.server.platform.db.migration.sql;
+import com.google.common.annotations.VisibleForTesting;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
private final Database db;
private final DbPrimaryKeyConstraintFinder dbConstraintFinder;
+ private final OracleTriggerFinder oracleTriggerFinder;
- public DropPrimaryKeySqlGenerator(Database db, DbPrimaryKeyConstraintFinder dbConstraintFinder) {
+ public DropPrimaryKeySqlGenerator(Database db, DbPrimaryKeyConstraintFinder dbConstraintFinder, OracleTriggerFinder oracleTriggerFinder) {
this.db = db;
this.dbConstraintFinder = dbConstraintFinder;
+ this.oracleTriggerFinder = oracleTriggerFinder;
+ }
+
+ @VisibleForTesting
+ public DropPrimaryKeySqlGenerator(Database db, DbPrimaryKeyConstraintFinder dbConstraintFinder) {
+ this(db, dbConstraintFinder, null);
}
public List<String> generate(String tableName, String columnName, boolean isAutoGenerated) throws SQLException {
return statements;
}
- private static List<String> generateForOracle(String tableName, String constraintName, boolean isAutoGenerated) {
+ private List<String> generateForOracle(String tableName, String constraintName, boolean isAutoGenerated)
+ throws SQLException {
List<String> statements = new ArrayList<>();
if (isAutoGenerated) {
- statements.add(format("DROP TRIGGER %s_IDT", tableName));
+ Optional<String> triggerNameOpt = oracleTriggerFinder.findTriggerName(tableName);
+ triggerNameOpt.ifPresent(s -> statements.add(format("DROP TRIGGER %s", s)));
statements.add(format("DROP SEQUENCE %s_SEQ", tableName));
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.sql;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+import org.sonar.db.Database;
+
+import static java.lang.String.format;
+
+public class OracleTriggerFinder {
+
+ private final Database db;
+
+ public OracleTriggerFinder(Database db) {
+ this.db = db;
+ }
+
+ public Optional<String> findTriggerName(String tableName) throws SQLException {
+ String constraintQuery = getTriggerNameQueryBy(tableName);
+ return executeQuery(constraintQuery);
+ }
+
+ private Optional<String> executeQuery(String query) throws SQLException {
+ try (Connection connection = db.getDataSource().getConnection();
+ PreparedStatement pstmt = connection
+ .prepareStatement(query);
+ ResultSet rs = pstmt.executeQuery()) {
+ if (rs.next()) {
+ return Optional.ofNullable(rs.getString(1));
+ }
+ return Optional.empty();
+ }
+ }
+
+ private static String getTriggerNameQueryBy(String tableName) {
+ return format("SELECT trigger_name FROM user_triggers WHERE upper(table_name) = upper('%s')", tableName);
+ }
+}
private final Database db = mock(Database.class);
private final DbPrimaryKeyConstraintFinder dbConstraintFinder = mock(DbPrimaryKeyConstraintFinder.class);
+ private final OracleTriggerFinder oracleTriggerFinder = mock(OracleTriggerFinder.class);
- private final DropPrimaryKeySqlGenerator underTest = new DropPrimaryKeySqlGenerator(db, dbConstraintFinder);
+ private final DropPrimaryKeySqlGenerator underTest = new DropPrimaryKeySqlGenerator(db, dbConstraintFinder, oracleTriggerFinder);
@Test
public void generate_unknown_dialect() throws SQLException {
@Test
public void generate_for_oracle_autogenerated_true() throws SQLException {
when(dbConstraintFinder.findConstraintName(TABLE_NAME)).thenReturn(Optional.of(CONSTRAINT));
+ when(oracleTriggerFinder.findTriggerName(TABLE_NAME)).thenReturn(Optional.of("a_trigger"));
when(db.getDialect()).thenReturn(ORACLE);
List<String> sqls = underTest.generate(TABLE_NAME, PK_COLUMN, true);
- assertThat(sqls).containsExactly("DROP TRIGGER issues_IDT",
+ assertThat(sqls).containsExactly("DROP TRIGGER a_trigger",
"DROP SEQUENCE issues_SEQ",
"ALTER TABLE issues DROP CONSTRAINT pk_id DROP INDEX");
}
@Test
public void generate_for_oracle_autogenerated_false() throws SQLException {
when(dbConstraintFinder.findConstraintName(TABLE_NAME)).thenReturn(Optional.of(CONSTRAINT));
+ when(oracleTriggerFinder.findTriggerName(TABLE_NAME)).thenReturn(Optional.of("a_trigger"));
when(db.getDialect()).thenReturn(ORACLE);
List<String> sqls = underTest.generate(TABLE_NAME, PK_COLUMN, false);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.sql;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+import javax.sql.DataSource;
+import org.junit.Test;
+import org.sonar.db.Database;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class OracleTriggerFinderTest {
+
+ private final Database mockDb = mock(Database.class);
+ private final OracleTriggerFinder underTest = new OracleTriggerFinder(mockDb);
+
+ @Test
+ public void execute_query_to_get_trigger_name() throws SQLException {
+ DataSource mockDataSource = mock(DataSource.class);
+ when(mockDb.getDataSource()).thenReturn(mockDataSource);
+ Connection mockConnection = mock(Connection.class);
+ when(mockDataSource.getConnection()).thenReturn(mockConnection);
+ PreparedStatement mockPreparedStatement = mock(PreparedStatement.class);
+ when(mockConnection.prepareStatement("SELECT trigger_name FROM user_triggers WHERE upper(table_name) = upper('table_with_trg')")).thenReturn(mockPreparedStatement);
+ ResultSet mockResultSet = mock(ResultSet.class);
+ when(mockResultSet.next()).thenReturn(true);
+ when(mockResultSet.getString(1)).thenReturn("my_trigger");
+ when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet);
+
+ Optional<String> foundTrigger = underTest.findTriggerName("table_with_trg");
+
+ assertThat(foundTrigger).hasValue("my_trigger");
+ }
+
+ @Test
+ public void execute_query_to_get_trigger_name_empty_result() throws SQLException {
+ DataSource mockDataSource = mock(DataSource.class);
+ when(mockDb.getDataSource()).thenReturn(mockDataSource);
+ Connection mockConnection = mock(Connection.class);
+ when(mockDataSource.getConnection()).thenReturn(mockConnection);
+ PreparedStatement mockPreparedStatement = mock(PreparedStatement.class);
+ when(mockConnection.prepareStatement("SELECT trigger_name FROM user_triggers WHERE upper(table_name) = upper('table_with_trg')")).thenReturn(mockPreparedStatement);
+ ResultSet mockResultSet = mock(ResultSet.class);
+ when(mockResultSet.next()).thenReturn(false);
+ when(mockPreparedStatement.executeQuery()).thenReturn(mockResultSet);
+
+ Optional<String> foundTrigger = underTest.findTriggerName("table_with_trg");
+
+ assertThat(foundTrigger).isEmpty();
+ }
+
+}