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.i18n.Msg; 023import ca.uhn.fhir.jpa.migrate.JdbcUtils; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027import java.sql.SQLException; 028import java.util.Set; 029 030public class AddColumnTask extends BaseTableColumnTypeTask { 031 032 private static final Logger ourLog = LoggerFactory.getLogger(AddColumnTask.class); 033 034 public static AddColumnTask lowerCase(Set<ColumnDriverMappingOverride> theColumnDriverMappingOverrides) { 035 return new AddColumnTask(null, null, ColumnNameCase.ALL_LOWER, theColumnDriverMappingOverrides); 036 } 037 038 public AddColumnTask() { 039 this(null, null); 040 setDryRun(true); 041 myCheckForExistingTables = false; 042 } 043 044 public AddColumnTask(String theProductVersion, String theSchemaVersion) { 045 super(theProductVersion, theSchemaVersion); 046 } 047 048 private AddColumnTask( 049 String theProductVersion, 050 String theSchemaVersion, 051 ColumnNameCase theColumnNameCase, 052 Set<ColumnDriverMappingOverride> theColumnDriverMappingOverrides) { 053 super(theProductVersion, theSchemaVersion, theColumnNameCase, theColumnDriverMappingOverrides); 054 } 055 056 @Override 057 public void validate() { 058 super.validate(); 059 setDescription("Add column " + getColumnName() + " on table " + getTableName()); 060 } 061 062 @Override 063 public void doExecute() throws SQLException { 064 if (myCheckForExistingTables) { 065 Set<String> columnNames = JdbcUtils.getColumnNames(getConnectionProperties(), getTableName()); 066 if (columnNames.contains(getColumnName())) { 067 logInfo( 068 ourLog, 069 "Column {} already exists on table {} - No action performed", 070 getColumnName(), 071 getTableName()); 072 return; 073 } 074 } 075 076 String typeStatement = getTypeStatement(); 077 078 String sql; 079 switch (getDriverType()) { 080 case MYSQL_5_7: 081 case MARIADB_10_1: 082 // Quote the column name as "SYSTEM" is a reserved word in MySQL 083 sql = "alter table " + getTableName() + " add column `" + getColumnName() + "` " + typeStatement; 084 break; 085 case DERBY_EMBEDDED: 086 case POSTGRES_9_4: 087 sql = "alter table " + getTableName() + " add column " + getColumnName() + " " + typeStatement; 088 break; 089 case MSSQL_2012: 090 case ORACLE_12C: 091 case H2_EMBEDDED: 092 sql = "alter table " + getTableName() + " add " + getColumnName() + " " + typeStatement; 093 break; 094 default: 095 throw new IllegalStateException(Msg.code(60)); 096 } 097 098 logInfo(ourLog, "Adding column {} of type {} to table {}", getColumnName(), getSqlType(), getTableName()); 099 executeSql(getTableName(), sql); 100 } 101 102 public String getTypeStatement() { 103 String type = getSqlType(); 104 String nullable = getSqlNotNull(); 105 if (isNullable()) { 106 nullable = ""; 107 } 108 if (myPrettyPrint) { 109 nullable = nullable.trim(); 110 } 111 String space = isNullable() ? "" : " "; 112 return type + space + nullable; 113 } 114}