001package io.ebeaninternal.dbmigration.ddlgeneration.platform;
002
003import io.ebean.config.DatabaseConfig;
004import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
005import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
006import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
007import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
008import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
009import io.ebeaninternal.dbmigration.model.MTable;
010
011/**
012 * DB2 History support.
013 * 
014 * @author Roland Praml, FOCONIS AG
015 */
016public class Db2HistoryDdl extends DbTableBasedHistoryDdl implements PlatformHistoryDdl {
017
018  private String systemPeriodStart;
019  private String systemPeriodEnd;
020  private String transactionId;
021
022  @Override
023  public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
024    super.configure(config, platformDdl);
025    this.systemPeriodStart = config.getAsOfSysPeriod() + "_start";
026    this.systemPeriodEnd = config.getAsOfSysPeriod() + "_end";
027    this.transactionId = config.getAsOfSysPeriod() + "_txn"; // required for DB2
028  }
029
030  @Override
031  public void createWithHistory(DdlWrite writer, MTable table) {
032    String tableName = table.getName();
033    String historyTableName = historyTableName(tableName);
034
035    // DB2 requires an EXACT copy (same column types with null/non-null, same order)
036    addSysPeriodColumns(writer, tableName);
037    DdlBuffer tableBuf = writer.applyPostAlter();
038    tableBuf.append("create table ").append(historyTableName)
039      .append(" as (select * from ").append(tableName).append(") with no data");
040
041    if (table.getTablespaceMeta() != null) {
042      String tableSpace = platformDdl.extract(table.getTablespaceMeta().getTablespaceName());
043      if (tableSpace != null && !tableSpace.isEmpty()) {
044        platformDdl.addTablespace(tableBuf,
045          tableSpace,
046          platformDdl.extract(table.getTablespaceMeta().getIndexTablespace()),
047          platformDdl.extract(table.getTablespaceMeta().getLobTablespace()));
048      }
049    }
050    tableBuf.endOfStatement();
051    enableSystemVersioning(writer.applyPostAlter(), tableName);
052    platformDdl.alterTable(writer, tableName).setHistoryHandled();
053
054    // drop all: We do not drop columns here, as the whole table will be dropped
055    disableSystemVersioning(writer.dropAll(), tableName);
056    writer.dropAll().append("drop table ").append(historyTableName).endOfStatement();
057  }
058
059  void addSysPeriodColumns(DdlWrite writer, String baseTable) {
060    platformDdl.alterTableAddColumn(writer, baseTable, systemPeriodStart, "timestamp(12) not null generated always as row begin", null);
061    platformDdl.alterTableAddColumn(writer, baseTable, systemPeriodEnd, "timestamp(12) not null generated always as row end", null);
062    platformDdl.alterTableAddColumn(writer, baseTable, transactionId, "timestamp(12) generated always as transaction start id", null);
063    platformDdl.alterTable(writer, baseTable).append("add period system_time", null)
064      .append("(").append(systemPeriodStart).append(",").append(systemPeriodEnd).append(")");
065  }
066
067  @Override
068  public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
069    dropHistoryTable(writer, dropHistoryTable.getBaseTable());
070  }
071
072  protected void dropHistoryTable(DdlWrite writer, String baseTable) {
073    disableSystemVersioning(writer.apply(), baseTable);
074    writer.apply().append("alter table ").append(baseTable).append(" drop period system_time").endOfStatement();
075
076    // drop the period & period columns
077    platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodStart);
078    platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodEnd);
079    platformDdl.alterTableDropColumn(writer, baseTable, transactionId);
080
081    // drop the history table
082    writer.applyPostAlter().append("drop table ").append(historyTableName(baseTable)).endOfStatement();
083  }
084
085  @Override
086  public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
087    MTable table = writer.getTable(addHistoryTable.getBaseTable());
088    if (table == null) {
089      throw new IllegalStateException("MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)");
090    }
091    createWithHistory(writer, table);
092  }
093
094
095  @Override
096  public void updateTriggers(DdlWrite writer, String tableName) {
097    DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
098    MTable table = writer.getTable(tableName);
099    if (table.isWithHistory() && !alter.isHistoryHandled()) {
100      disableSystemVersioning(writer.apply(), tableName);
101      enableSystemVersioning(writer.applyPostAlter(), tableName);
102      alter.setHistoryHandled();
103    }
104  }
105
106  public void disableSystemVersioning(DdlBuffer apply, String tableName) {
107    apply.append("alter table ").append(tableName).append(" drop versioning").endOfStatement();
108  }
109
110  public void enableSystemVersioning(DdlBuffer apply, String tableName) {
111    apply.append("alter table ").append(tableName).append(" add versioning use history table ").append(historyTableName(tableName)).endOfStatement();
112  }
113
114}