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}