import java.sql.ResultSet; | import java.sql.ResultSet; | ||||
import java.sql.SQLException; | import java.sql.SQLException; | ||||
import java.util.Locale; | import java.util.Locale; | ||||
import java.util.Optional; | |||||
import java.util.function.Supplier; | |||||
import org.sonar.db.Database; | import org.sonar.db.Database; | ||||
import org.sonar.db.dialect.Dialect; | import org.sonar.db.dialect.Dialect; | ||||
import org.sonar.db.dialect.H2; | import org.sonar.db.dialect.H2; | ||||
public String findConstraintName(String tableName) throws SQLException { | public String findConstraintName(String tableName) throws SQLException { | ||||
String constraintQuery = getDbVendorSpecificQuery(tableName); | String constraintQuery = getDbVendorSpecificQuery(tableName); | ||||
return executeQuery(constraintQuery) | |||||
.orElseThrow(() -> constraintNotFoundException(tableName)); | |||||
return executeQuery(constraintQuery, () -> constraintNotFoundException(tableName)); | |||||
} | } | ||||
String getDbVendorSpecificQuery(String tableName) { | String getDbVendorSpecificQuery(String tableName) { | ||||
return constraintQuery; | return constraintQuery; | ||||
} | } | ||||
private Optional<String> executeQuery(String query) throws SQLException { | |||||
private String executeQuery(String query, Supplier<? extends RuntimeException> exceptionSupplier) throws SQLException { | |||||
try (Connection connection = db.getDataSource().getConnection(); | try (Connection connection = db.getDataSource().getConnection(); | ||||
PreparedStatement pstmt = connection | PreparedStatement pstmt = connection | ||||
.prepareStatement(query); | .prepareStatement(query); | ||||
ResultSet rs = pstmt.executeQuery()) { | ResultSet rs = pstmt.executeQuery()) { | ||||
if (rs.next()) { | if (rs.next()) { | ||||
return Optional.ofNullable(rs.getString(1)); | |||||
return rs.getString(1); | |||||
} | } | ||||
return Optional.empty(); | |||||
throw exceptionSupplier.get(); | |||||
} | } | ||||
} | } | ||||
// FIXME:: this method should be moved somewhere else | // FIXME:: this method should be moved somewhere else | ||||
String getPostgresSqlSequence(String tableName, String columnName) throws SQLException { | String getPostgresSqlSequence(String tableName, String columnName) throws SQLException { | ||||
try (Connection connection = db.getDataSource().getConnection(); | |||||
PreparedStatement pstmt = connection.prepareStatement(format("SELECT pg_get_serial_sequence('%s', '%s')", tableName, columnName)); | |||||
ResultSet rs = pstmt.executeQuery()) { | |||||
if (rs.next()) { | |||||
return rs.getString(1); | |||||
} | |||||
throw new IllegalStateException(format("Cannot find sequence for table '%s' on column '%s'", tableName, columnName)); | |||||
} | |||||
return executeQuery(format("SELECT pg_get_serial_sequence('%s', '%s')", tableName, columnName), | |||||
() -> new IllegalStateException(format("Cannot find sequence for table '%s' on column '%s'", tableName, columnName))); | |||||
} | } | ||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2020 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.version.v84.util; | |||||
import java.sql.Connection; | |||||
import java.sql.PreparedStatement; | |||||
import java.sql.ResultSet; | |||||
import java.sql.SQLException; | |||||
import java.util.Locale; | |||||
import org.sonar.db.Database; | |||||
import static java.lang.String.format; | |||||
public class SqlHelper { | |||||
private final Database db; | |||||
public SqlHelper(Database db) { | |||||
this.db = db; | |||||
} | |||||
String getH2Constraint(String tableName) throws SQLException { | |||||
try (Connection connection = db.getDataSource().getConnection(); | |||||
PreparedStatement pstmt = connection | |||||
.prepareStatement(format("SELECT constraint_name " | |||||
+ "FROM information_schema.constraints " | |||||
+ "WHERE table_name = '%s' and constraint_type = 'PRIMARY KEY'", tableName.toUpperCase(Locale.ENGLISH))); | |||||
ResultSet rs = pstmt.executeQuery()) { | |||||
if (rs.next()) { | |||||
return rs.getString(1); | |||||
} | |||||
throw contraintNotFoundException(tableName); | |||||
} | |||||
} | |||||
String getPostgresSqlConstraint(String tableName) throws SQLException { | |||||
try (Connection connection = db.getDataSource().getConnection(); | |||||
PreparedStatement pstmt = connection | |||||
.prepareStatement(format("SELECT conname " + | |||||
"FROM pg_constraint " + | |||||
"WHERE conrelid = " + | |||||
" (SELECT oid " + | |||||
" FROM pg_class " + | |||||
" WHERE relname LIKE '%s')", tableName)); | |||||
ResultSet rs = pstmt.executeQuery()) { | |||||
if (rs.next()) { | |||||
return rs.getString(1); | |||||
} | |||||
throw contraintNotFoundException(tableName); | |||||
} | |||||
} | |||||
String getPostgresSqlSequence(String tableName, String columnName) throws SQLException { | |||||
try (Connection connection = db.getDataSource().getConnection(); | |||||
PreparedStatement pstmt = connection | |||||
.prepareStatement(format("SELECT pg_get_serial_sequence('%s', '%s')", tableName, columnName)); | |||||
ResultSet rs = pstmt.executeQuery()) { | |||||
if (rs.next()) { | |||||
return rs.getString(1); | |||||
} | |||||
throw new IllegalStateException(format("Cannot find sequence for table '%s' on column '%s'", tableName, columnName)); | |||||
} | |||||
} | |||||
String getOracleConstraint(String tableName) throws SQLException { | |||||
try (Connection connection = db.getDataSource().getConnection(); | |||||
PreparedStatement pstmt = connection | |||||
.prepareStatement(format("SELECT constraint_name " + | |||||
"FROM user_constraints " + | |||||
"WHERE table_name = UPPER('%s') " + | |||||
"AND constraint_type='P'", tableName)); | |||||
ResultSet rs = pstmt.executeQuery()) { | |||||
if (rs.next()) { | |||||
return rs.getString(1); | |||||
} | |||||
throw contraintNotFoundException(tableName); | |||||
} | |||||
} | |||||
String getMssqlConstraint(String tableName) throws SQLException { | |||||
try (Connection connection = db.getDataSource().getConnection(); | |||||
PreparedStatement pstmt = connection | |||||
.prepareStatement(format("SELECT name " + | |||||
"FROM sys.key_constraints " + | |||||
"WHERE type = 'PK' " + | |||||
"AND OBJECT_NAME(parent_object_id) = '%s'", tableName)); | |||||
ResultSet rs = pstmt.executeQuery()) { | |||||
if (rs.next()) { | |||||
return rs.getString(1); | |||||
} | |||||
throw contraintNotFoundException(tableName); | |||||
} | |||||
} | |||||
private static IllegalStateException contraintNotFoundException(String tableName) { | |||||
return new IllegalStateException(format("Cannot find constraint for table '%s'", tableName)); | |||||
} | |||||
} |
import org.junit.Test; | import org.junit.Test; | ||||
import org.sonar.db.CoreDbTester; | import org.sonar.db.CoreDbTester; | ||||
import org.sonar.db.Database; | import org.sonar.db.Database; | ||||
import org.sonar.db.dialect.Dialect; | |||||
import org.sonar.db.dialect.H2; | import org.sonar.db.dialect.H2; | ||||
import org.sonar.db.dialect.MsSql; | import org.sonar.db.dialect.MsSql; | ||||
import org.sonar.db.dialect.Oracle; | import org.sonar.db.dialect.Oracle; | ||||
assertThat(underTest.getDbVendorSpecificQuery("my_table")) | assertThat(underTest.getDbVendorSpecificQuery("my_table")) | ||||
.isEqualTo("SELECT constraint_name FROM information_schema.constraints WHERE table_name = 'MY_TABLE' and constraint_type = 'PRIMARY KEY'"); | .isEqualTo("SELECT constraint_name FROM information_schema.constraints WHERE table_name = 'MY_TABLE' and constraint_type = 'PRIMARY KEY'"); | ||||
} | } | ||||
@Test | |||||
public void getDbVendorSpecificQuery_unknown() { | |||||
Dialect mockDialect = mock(Dialect.class); | |||||
when(mockDialect.getId()).thenReturn("unknown"); | |||||
when(dbMock.getDialect()).thenReturn(mockDialect); | |||||
assertThatThrownBy(() -> underTest.getDbVendorSpecificQuery("my_table")) | |||||
.isInstanceOf(IllegalStateException.class) | |||||
.hasMessage("Unsupported database 'unknown'"); | |||||
} | |||||
} | } |