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