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}