001/*-
002 * #%L
003 * HAPI FHIR Server - SQL Migration
004 * %%
005 * Copyright (C) 2014 - 2026 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.migrate.taskdef;
021
022import ca.uhn.fhir.i18n.Msg;
023import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
024import ca.uhn.fhir.jpa.migrate.JdbcUtils;
025import jakarta.annotation.Nonnull;
026import org.apache.commons.lang3.Validate;
027import org.apache.commons.lang3.builder.EqualsBuilder;
028import org.apache.commons.lang3.builder.HashCodeBuilder;
029import org.intellij.lang.annotations.Language;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033import java.sql.Connection;
034import java.sql.SQLException;
035import java.util.ArrayList;
036import java.util.List;
037import java.util.Locale;
038import java.util.Set;
039
040import static org.apache.commons.lang3.StringUtils.isNotBlank;
041
042public class DropForeignKeyTask extends BaseTableTask {
043
044        private static final Logger ourLog = LoggerFactory.getLogger(DropForeignKeyTask.class);
045        private String myConstraintName;
046        private String myParentTableName;
047
048        public DropForeignKeyTask(String theProductVersion, String theSchemaVersion) {
049                super(theProductVersion, theSchemaVersion);
050        }
051
052        @Nonnull
053        static List<String> generateSql(String theTableName, String theConstraintName, DriverTypeEnum theDriverType) {
054                List<String> sqls = new ArrayList<>();
055                switch (theDriverType) {
056                        case MYSQL_5_7:
057                        case MARIADB_10_1:
058                                // Lousy MYQL....
059                                sqls.add("alter table " + theTableName + " drop foreign key " + theConstraintName);
060                                break;
061                        case POSTGRES_9_4:
062                        case DERBY_EMBEDDED:
063                        case H2_EMBEDDED:
064                        case ORACLE_12C:
065                        case MSSQL_2012:
066                                sqls.add("alter table " + theTableName + " drop constraint " + theConstraintName);
067                                break;
068                        case COCKROACHDB_21_1:
069                                sqls.add("drop index if exists " + theTableName + "@" + theConstraintName + " cascade");
070                                break;
071                        default:
072                                throw new IllegalStateException(Msg.code(59));
073                }
074                return sqls;
075        }
076
077        public void setConstraintName(String theConstraintName) {
078                myConstraintName = theConstraintName;
079        }
080
081        public void setParentTableName(String theParentTableName) {
082                myParentTableName = theParentTableName;
083        }
084
085        @Override
086        public void validate() {
087                super.validate();
088
089                Validate.isTrue(isNotBlank(myConstraintName));
090                Validate.isTrue(isNotBlank(myParentTableName));
091                setDescription("Drop foreign key " + myConstraintName + " from table " + getTableName());
092        }
093
094        @Override
095        public void doExecute() throws SQLException {
096
097                Set<String> existing = JdbcUtils.getForeignKeys(getConnectionProperties(), myParentTableName, getTableName());
098                if (!existing.contains(myConstraintName.toUpperCase(Locale.US))) {
099                        logInfo(ourLog, "Don't have constraint named {} - No action performed", myConstraintName);
100                        return;
101                }
102
103                List<String> sqlStatements;
104                try (Connection connection = getConnectionProperties().getDataSource().getConnection()) {
105                        String constraintName = JdbcUtils.massageIdentifier(connection.getMetaData(), myConstraintName);
106                        sqlStatements = generateSql(getTableName(), constraintName, getDriverType());
107                }
108
109                for (@Language("SQL") String next : sqlStatements) {
110                        executeSql(getTableName(), next);
111                }
112        }
113
114        @Override
115        protected void generateEquals(EqualsBuilder theBuilder, BaseTask theOtherObject) {
116                DropForeignKeyTask otherObject = (DropForeignKeyTask) theOtherObject;
117                super.generateEquals(theBuilder, otherObject);
118                theBuilder.append(myConstraintName, otherObject.myConstraintName);
119                theBuilder.append(myParentTableName, otherObject.myParentTableName);
120        }
121
122        @Override
123        protected void generateHashCode(HashCodeBuilder theBuilder) {
124                super.generateHashCode(theBuilder);
125                theBuilder.append(myConstraintName);
126                theBuilder.append(myParentTableName);
127        }
128}