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.i18n.Msg; 024import ca.uhn.fhir.jpa.migrate.JdbcUtils; 025import org.apache.commons.lang3.Validate; 026import org.apache.commons.lang3.builder.EqualsBuilder; 027import org.apache.commons.lang3.builder.HashCodeBuilder; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031import java.sql.SQLException; 032import java.util.Set; 033 034import static org.apache.commons.lang3.StringUtils.isNotBlank; 035 036public class AddForeignKeyTask extends BaseTableColumnTask { 037 038 private static final Logger ourLog = LoggerFactory.getLogger(AddForeignKeyTask.class); 039 private String myConstraintName; 040 private String myForeignTableName; 041 private String myForeignColumnName; 042 043 public AddForeignKeyTask(String theProductVersion, String theSchemaVersion) { 044 super(theProductVersion, theSchemaVersion); 045 } 046 047 public void setConstraintName(String theConstraintName) { 048 myConstraintName = theConstraintName; 049 } 050 051 public void setForeignTableName(String theForeignTableName) { 052 myForeignTableName = theForeignTableName; 053 } 054 055 public void setForeignColumnName(String theForeignColumnName) { 056 myForeignColumnName = theForeignColumnName; 057 } 058 059 @Override 060 public void validate() { 061 super.validate(); 062 063 Validate.isTrue(isNotBlank(myConstraintName)); 064 Validate.isTrue(isNotBlank(myForeignTableName)); 065 Validate.isTrue(isNotBlank(myForeignColumnName)); 066 setDescription("Add foreign key " + myConstraintName + " from column " + getColumnName() + " of table " + getTableName() + " to column " + myForeignColumnName + " of table " + myForeignTableName); 067 } 068 069 @Override 070 public void doExecute() throws SQLException { 071 072 Set<String> existing = JdbcUtils.getForeignKeys(getConnectionProperties(), myForeignTableName, getTableName()); 073 if (existing.contains(myConstraintName)) { 074 logInfo(ourLog, "Already have constraint named {} - No action performed", myConstraintName); 075 return; 076 } 077 078 String sql; 079 switch (getDriverType()) { 080 case MARIADB_10_1: 081 case MYSQL_5_7: 082 // Quote the column names as "SYSTEM" is a reserved word in MySQL 083 sql = "alter table " + getTableName() + " add constraint " + myConstraintName + " foreign key (`" + getColumnName() + "`) references " + myForeignTableName + " (`" + myForeignColumnName + "`)"; 084 break; 085 case POSTGRES_9_4: 086 case DERBY_EMBEDDED: 087 case H2_EMBEDDED: 088 case ORACLE_12C: 089 case MSSQL_2012: 090 sql = "alter table " + getTableName() + " add constraint " + myConstraintName + " foreign key (" + getColumnName() + ") references " + myForeignTableName; 091 break; 092 default: 093 throw new IllegalStateException(Msg.code(68)); 094 } 095 096 097 try { 098 executeSql(getTableName(), sql); 099 } catch (Exception e) { 100 if (e.toString().contains("already exists")) { 101 ourLog.warn("Index {} already exists", myConstraintName); 102 } else { 103 throw e; 104 } 105 } 106 } 107 108 @Override 109 protected void generateHashCode(HashCodeBuilder theBuilder) { 110 super.generateHashCode(theBuilder); 111 theBuilder.append(myConstraintName); 112 theBuilder.append(myForeignTableName); 113 theBuilder.append(myForeignColumnName); 114 } 115 116 @Override 117 protected void generateEquals(EqualsBuilder theBuilder, BaseTask theOtherObject) { 118 AddForeignKeyTask otherObject = (AddForeignKeyTask) theOtherObject; 119 super.generateEquals(theBuilder, otherObject); 120 theBuilder.append(myConstraintName, otherObject.myConstraintName); 121 theBuilder.append(myForeignTableName, otherObject.myForeignTableName); 122 theBuilder.append(myForeignColumnName, otherObject.myForeignColumnName); 123 } 124 125}