001package io.ebeaninternal.dbmigration.ddlgeneration.platform; 002 003import java.io.IOException; 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.List; 007 008import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable; 009import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; 010 011/** 012 * Contains alter statements per table. 013 * 014 * @author Roland Praml, FOCONIS AG 015 */ 016public class BaseAlterTableWrite implements DdlAlterTable { 017 018 protected static final String RAW_OPERATION = "$RAW"; 019 020 protected final PlatformDdl platformDdl; 021 022 public class AlterCmd { 023 // the command (e.g. "alter", "modify" 024 private final String operation; 025 // the affected column (note: each column can only be altered once on MariaDB) 026 private final String column; 027 028 private final DdlBuffer alternationBuffer = new BaseDdlBuffer() { 029 @Override 030 public DdlBuffer endOfStatement() { 031 throw new UnsupportedOperationException(); 032 }; 033 }; 034 035 protected AlterCmd(String operation, String column) { 036 this.operation = operation; 037 this.column = column; 038 } 039 040 public AlterCmd append(String content) { 041 alternationBuffer.append(content); 042 return this; 043 } 044 045 public String getOperation() { 046 return operation; 047 } 048 049 public String getColumn() { 050 return column; 051 } 052 053 public String getAlternation() { 054 return alternationBuffer.getBuffer(); 055 } 056 057 protected void write(Appendable target) throws IOException { 058 if (operation.equals(RAW_OPERATION)) { 059 // this is a raw command. e.g. an USP call. Must be done in the correct order 060 // of all alter commands 061 target.append(getAlternation()); 062 } else { 063 target.append("alter table ").append(platformDdl.quote(tableName)).append(' ').append(operation); 064 if (column != null) { 065 target.append(' ').append(platformDdl.quote(column)); 066 } 067 if (!getAlternation().isEmpty()) { 068 target.append(' ').append(getAlternation()); 069 } 070 } 071 } 072 @Override 073 public String toString() { 074 StringBuilder sb = new StringBuilder(); 075 try { 076 write(sb); 077 } catch (IOException e) { 078 throw new RuntimeException(e); 079 } 080 return sb.toString(); 081 } 082 } 083 084 private final String tableName; 085 086 private List<AlterCmd> cmds = new ArrayList<>(); 087 088 private boolean historyHandled; 089 090 public BaseAlterTableWrite(String tableName, PlatformDdl platformDdl) { 091 this.tableName = tableName; 092 this.platformDdl = platformDdl; 093 } 094 095 public String tableName() { 096 return tableName; 097 } 098 099 protected AlterCmd newRawCommand(String sql) { 100 AlterCmd cmd = new AlterCmd(RAW_OPERATION, null); 101 cmd.alternationBuffer.append(sql); 102 return cmd; 103 } 104 105 public AlterCmd newOperation(String operation, String column) { 106 return new AlterCmd(operation, column); 107 } 108 109 /** 110 * Adds a statement. The statement is prefixed with "alter table TABLENAME" and may be batched, if platform supports this. The 111 * returned StringBuilder can be used, to complete the statement 112 */ 113 @Override 114 public DdlBuffer append(String operation, String column) { 115 AlterCmd cmd = new AlterCmd(operation, column); 116 cmds.add(cmd); 117 return cmd.alternationBuffer; 118 } 119 120 @Override 121 public DdlBuffer raw(String sql) { 122 AlterCmd cmd = newRawCommand(sql); 123 cmds.add(cmd); 124 return cmd.alternationBuffer; 125 } 126 127 /** 128 * Method can be overwritten to return a new list of commands. The given list must not be modified, but a new command list with 129 * modified commands can be returned (e.g. to handle DB2 reorg or special syntax in Hana) 130 */ 131 protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) { 132 return cmds; 133 } 134 135 /** 136 * Writes the DDL to <code>target</code>. 137 */ 138 @Override 139 public void write(Appendable target) throws IOException { 140 for (AlterCmd cmd : postProcessCommands(Collections.unmodifiableList(cmds))) { 141 cmd.write(target); 142 target.append(";\n"); 143 } 144 } 145 146 @Override 147 public boolean isHistoryHandled() { 148 return historyHandled; 149 } 150 151 @Override 152 public void setHistoryHandled() { 153 historyHandled = true; 154 } 155}