001/*- 002 * #%L 003 * HAPI FHIR Server - SQL Migration 004 * %% 005 * Copyright (C) 2014 - 2024 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.jpa.migrate.DriverTypeEnum; 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.ArrayList; 032import java.util.List; 033 034public class AddTableByColumnTask extends BaseTableTask { 035 036 private static final Logger ourLog = LoggerFactory.getLogger(AddTableByColumnTask.class); 037 038 private final List<AddColumnTask> myAddColumnTasks = new ArrayList<>(); 039 private List<String> myPkColumns; 040 private final List<ForeignKeyContainer> myFKColumns = new ArrayList<>(); 041 042 public AddTableByColumnTask() { 043 this(null, null); 044 setDryRun(true); 045 myCheckForExistingTables = false; 046 } 047 048 public AddTableByColumnTask(String theProductVersion, String theSchemaVersion) { 049 super(theProductVersion, theSchemaVersion); 050 } 051 052 @Override 053 public void validate() { 054 super.validate(); 055 setDescription("Add table " + getTableName()); 056 } 057 058 public void addAddColumnTask(AddColumnTask theTask) { 059 Validate.notNull(theTask); 060 myAddColumnTasks.add(theTask); 061 } 062 063 public void setPkColumns(List<String> thePkColumns) { 064 myPkColumns = thePkColumns; 065 } 066 067 public void addForeignKey(ForeignKeyContainer theForeignKeyContainer) { 068 myFKColumns.add(theForeignKeyContainer); 069 } 070 071 public List<String> getPkColumns() { 072 return myPkColumns; 073 } 074 075 public String generateSQLCreateScript() { 076 StringBuilder sb = new StringBuilder(); 077 sb.append("CREATE TABLE "); 078 sb.append(getTableName()); 079 sb.append(" ("); 080 if (myPrettyPrint) { 081 sb.append("\n"); 082 } else { 083 sb.append(" "); 084 } 085 086 for (AddColumnTask next : myAddColumnTasks) { 087 next.setDriverType(getDriverType()); 088 next.setTableName(getTableName()); 089 next.validate(); 090 091 if (myPrettyPrint) { 092 sb.append("\t"); 093 } 094 095 sb.append(next.getColumnName()); 096 sb.append(" "); 097 sb.append(next.getTypeStatement()); 098 sb.append(","); 099 if (myPrettyPrint) { 100 sb.append("\n"); 101 } else { 102 sb.append(" "); 103 } 104 } 105 106 // primary keys 107 if (myPrettyPrint) { 108 sb.append("\t"); 109 } else { 110 sb.append(" "); 111 } 112 sb.append("PRIMARY KEY ("); 113 for (int i = 0; i < myPkColumns.size(); i++) { 114 if (i > 0) { 115 sb.append(", "); 116 } 117 sb.append(myPkColumns.get(i)); 118 } 119 120 boolean hasForeignKeys = !myFKColumns.isEmpty(); 121 122 sb.append(")"); 123 if (hasForeignKeys) { 124 sb.append(","); 125 } 126 if (myPrettyPrint) { 127 sb.append("\n"); 128 } else { 129 sb.append(" "); 130 } 131 132 DriverTypeEnum sqlEngine = getDriverType(); 133 134 // foreign keys 135 if (!myFKColumns.isEmpty()) { 136 for (int i = 0; i < myFKColumns.size(); i++) { 137 if (i > 0) { 138 sb.append(", "); 139 } 140 ForeignKeyContainer fk = myFKColumns.get(i); 141 if (myPrettyPrint) { 142 sb.append("\t"); 143 } 144 sb.append(fk.generateSQL(sqlEngine, myPrettyPrint)); 145 if (myPrettyPrint) { 146 sb.append("\n"); 147 } else { 148 sb.append(" "); 149 } 150 } 151 } 152 153 sb.append(")"); 154 155 switch (sqlEngine) { 156 case MARIADB_10_1: 157 case MYSQL_5_7: 158 sb.append(" engine=InnoDB"); 159 break; 160 case DERBY_EMBEDDED: 161 case POSTGRES_9_4: 162 case ORACLE_12C: 163 case MSSQL_2012: 164 case H2_EMBEDDED: 165 case COCKROACHDB_21_1: 166 break; 167 } 168 169 return sb.toString(); 170 } 171 172 @Override 173 public void doExecute() throws SQLException { 174 if (myCheckForExistingTables 175 && JdbcUtils.getTableNames(getConnectionProperties()).contains(getTableName())) { 176 logInfo(ourLog, "Already have table named {} - No action performed", getTableName()); 177 return; 178 } 179 180 executeSql(getTableName(), generateSQLCreateScript()); 181 } 182 183 @Override 184 protected void generateEquals(EqualsBuilder theBuilder, BaseTask theOtherObject) { 185 super.generateEquals(theBuilder, theOtherObject); 186 AddTableByColumnTask otherObject = (AddTableByColumnTask) theOtherObject; 187 theBuilder.append(myAddColumnTasks, otherObject.myAddColumnTasks); 188 theBuilder.append(myPkColumns, otherObject.myPkColumns); 189 } 190 191 @Override 192 protected void generateHashCode(HashCodeBuilder theBuilder) { 193 super.generateHashCode(theBuilder); 194 theBuilder.append(myAddColumnTasks); 195 theBuilder.append(myPkColumns); 196 } 197}