001package ca.uhn.fhir.jpa.migrate.taskdef;
002
003/*-
004 * #%L
005 * HAPI FHIR Server - SQL Migration
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.jpa.migrate.JdbcUtils;
024import org.apache.commons.lang3.Validate;
025import org.apache.commons.lang3.builder.EqualsBuilder;
026import org.apache.commons.lang3.builder.HashCodeBuilder;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030import java.sql.SQLException;
031import java.util.Set;
032
033import static org.apache.commons.lang3.StringUtils.isNotBlank;
034
035public class AddForeignKeyTask extends BaseTableColumnTask {
036
037        private static final Logger ourLog = LoggerFactory.getLogger(AddForeignKeyTask.class);
038        private String myConstraintName;
039        private String myForeignTableName;
040        private String myForeignColumnName;
041
042        public AddForeignKeyTask(String theProductVersion, String theSchemaVersion) {
043                super(theProductVersion, theSchemaVersion);
044        }
045
046        public void setConstraintName(String theConstraintName) {
047                myConstraintName = theConstraintName;
048        }
049
050        public void setForeignTableName(String theForeignTableName) {
051                myForeignTableName = theForeignTableName;
052        }
053
054        public void setForeignColumnName(String theForeignColumnName) {
055                myForeignColumnName = theForeignColumnName;
056        }
057
058        @Override
059        public void validate() {
060                super.validate();
061
062                Validate.isTrue(isNotBlank(myConstraintName));
063                Validate.isTrue(isNotBlank(myForeignTableName));
064                Validate.isTrue(isNotBlank(myForeignColumnName));
065                setDescription("Add foreign key " + myConstraintName + " from column " + getColumnName() + " of table " + getTableName() + " to column " + myForeignColumnName + " of table " + myForeignTableName);
066        }
067
068        @Override
069        public void doExecute() throws SQLException {
070
071                Set<String> existing = JdbcUtils.getForeignKeys(getConnectionProperties(), myForeignTableName, getTableName());
072                if (existing.contains(myConstraintName)) {
073                        logInfo(ourLog, "Already have constraint named {} - No action performed", myConstraintName);
074                        return;
075                }
076
077                String sql;
078                switch (getDriverType()) {
079                        case MARIADB_10_1:
080                        case MYSQL_5_7:
081                                // Quote the column names as "SYSTEM" is a reserved word in MySQL
082                                sql = "alter table " + getTableName() + " add constraint " + myConstraintName + " foreign key (`" + getColumnName() + "`) references " + myForeignTableName + " (`" + myForeignColumnName + "`)";
083                                break;
084                        case POSTGRES_9_4:
085                        case DERBY_EMBEDDED:
086                        case H2_EMBEDDED:
087                        case ORACLE_12C:
088                        case MSSQL_2012:
089                                sql = "alter table " + getTableName() + " add constraint " + myConstraintName + " foreign key (" + getColumnName() + ") references " + myForeignTableName;
090                                break;
091                        default:
092                                throw new IllegalStateException();
093                }
094
095
096                try {
097                        executeSql(getTableName(), sql);
098                } catch (Exception e) {
099                        if (e.toString().contains("already exists")) {
100                                ourLog.warn("Index {} already exists", myConstraintName);
101                        } else {
102                                throw e;
103                        }
104                }
105        }
106
107        @Override
108        protected void generateHashCode(HashCodeBuilder theBuilder) {
109                super.generateHashCode(theBuilder);
110                theBuilder.append(myConstraintName);
111                theBuilder.append(myForeignTableName);
112                theBuilder.append(myForeignColumnName);
113        }
114
115        @Override
116        protected void generateEquals(EqualsBuilder theBuilder, BaseTask theOtherObject) {
117                AddForeignKeyTask otherObject = (AddForeignKeyTask) theOtherObject;
118                super.generateEquals(theBuilder, otherObject);
119                theBuilder.append(myConstraintName, otherObject.myConstraintName);
120                theBuilder.append(myForeignTableName, otherObject.myForeignTableName);
121                theBuilder.append(myForeignColumnName, otherObject.myForeignColumnName);
122        }
123
124}