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}