3 * Copyright (C) 2009-2021 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.platform.db.migration.sql;
22 import java.sql.Connection;
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.util.Locale;
27 import java.util.Optional;
28 import org.sonar.db.Database;
29 import org.sonar.db.dialect.Dialect;
30 import org.sonar.db.dialect.H2;
31 import org.sonar.db.dialect.MsSql;
32 import org.sonar.db.dialect.Oracle;
33 import org.sonar.db.dialect.PostgreSql;
35 import static java.lang.String.format;
37 public class DbPrimaryKeyConstraintFinder {
39 private final Database db;
41 public DbPrimaryKeyConstraintFinder(Database db) {
45 public String findConstraintName(String tableName) throws SQLException {
46 String constraintQuery = getDbVendorSpecificQuery(tableName);
47 return executeQuery(constraintQuery)
48 .orElseThrow(() -> constraintNotFoundException(tableName));
51 String getDbVendorSpecificQuery(String tableName) {
52 Dialect dialect = db.getDialect();
53 String constraintQuery;
54 switch (dialect.getId()) {
56 constraintQuery = getPostgresSqlConstraintQuery(tableName);
59 constraintQuery = getMssqlConstraintQuery(tableName);
62 constraintQuery = getOracleConstraintQuery(tableName);
65 constraintQuery = getH2ConstraintQuery(tableName);
68 throw new IllegalStateException(format("Unsupported database '%s'", dialect.getId()));
70 return constraintQuery;
73 private Optional<String> executeQuery(String query) throws SQLException {
74 try (Connection connection = db.getDataSource().getConnection();
75 PreparedStatement pstmt = connection
76 .prepareStatement(query);
77 ResultSet rs = pstmt.executeQuery()) {
79 return Optional.ofNullable(rs.getString(1));
81 return Optional.empty();
85 private String getPostgresSqlConstraintQuery(String tableName) {
86 try (Connection connection = db.getDataSource().getConnection()) {
87 return format("SELECT conname " +
88 "FROM pg_constraint c " +
89 "JOIN pg_namespace n on c.connamespace = n.oid " +
90 "JOIN pg_class cls on c.conrelid = cls.oid " +
91 "WHERE cls.relname = '%s' AND n.nspname = '%s'", tableName, connection.getSchema());
92 } catch (SQLException throwables) {
93 throw new IllegalStateException("Can not get database connection");
97 private static String getMssqlConstraintQuery(String tableName) {
98 return format("SELECT name " +
99 "FROM sys.key_constraints " +
100 "WHERE type = 'PK' " +
101 "AND OBJECT_NAME(parent_object_id) = '%s'", tableName);
104 private static String getOracleConstraintQuery(String tableName) {
105 return format("SELECT constraint_name " +
106 "FROM user_constraints " +
107 "WHERE table_name = UPPER('%s') " +
108 "AND constraint_type='P'", tableName);
111 private static String getH2ConstraintQuery(String tableName) {
112 return format("SELECT constraint_name "
113 + "FROM information_schema.constraints "
114 + "WHERE table_name = '%s' and constraint_type = 'PRIMARY KEY'", tableName.toUpperCase(Locale.ENGLISH));
117 static IllegalStateException constraintNotFoundException(String tableName) {
118 return new IllegalStateException(format("Cannot find constraint for table '%s'", tableName));
121 // FIXME:: this method should be moved somewhere else
122 String getPostgresSqlSequence(String tableName, String columnName) throws SQLException {
123 try (Connection connection = db.getDataSource().getConnection();
124 PreparedStatement pstmt = connection.prepareStatement(format("SELECT pg_get_serial_sequence('%s', '%s')", tableName, columnName));
125 ResultSet rs = pstmt.executeQuery()) {
127 return rs.getString(1);
129 throw new IllegalStateException(format("Cannot find sequence for table '%s' on column '%s'", tableName, columnName));