001package io.ebeaninternal.dbmigration.ddlgeneration.platform; 002 003import io.ebean.config.DatabaseConfig; 004import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; 005import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; 006import io.ebeaninternal.dbmigration.migration.AddHistoryTable; 007import io.ebeaninternal.dbmigration.migration.DropHistoryTable; 008import io.ebeaninternal.dbmigration.model.MColumn; 009import io.ebeaninternal.dbmigration.model.MTable; 010 011import java.io.IOException; 012import java.util.Collection; 013import java.util.Map; 014import java.util.concurrent.ConcurrentHashMap; 015import java.util.concurrent.atomic.AtomicInteger; 016 017public class HanaHistoryDdl implements PlatformHistoryDdl { 018 019 private String systemPeriodStart; 020 private String systemPeriodEnd; 021 private PlatformDdl platformDdl; 022 private String historySuffix; 023 private final AtomicInteger counter = new AtomicInteger(0); 024 private Map<String, String> createdHistoryTables = new ConcurrentHashMap<>(); 025 026 @Override 027 public void configure(DatabaseConfig config, PlatformDdl platformDdl) { 028 this.systemPeriodStart = config.getAsOfSysPeriod() + "_start"; 029 this.systemPeriodEnd = config.getAsOfSysPeriod() + "_end"; 030 this.platformDdl = platformDdl; 031 this.historySuffix = config.getHistoryTableSuffix(); 032 } 033 034 @Override 035 public void createWithHistory(DdlWrite writer, MTable table) throws IOException { 036 String tableName = table.getName(); 037 String historyTableName = tableName + historySuffix; 038 DdlBuffer apply = writer.applyHistoryView(); 039 if (apply.isEmpty()) { 040 createdHistoryTables.clear(); 041 } 042 043 apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName).append(" (").newLine(); 044 045 // create history table 046 Collection<MColumn> cols = table.allColumns(); 047 for (MColumn column : cols) { 048 if (!column.isDraftOnly()) { 049 writeColumnDefinition(apply, column.getName(), column.getType(), column.getDefaultValue(), column.isNotnull(), 050 column.isIdentity() ? platformDdl.identitySuffix : null); 051 apply.append(",").newLine(); 052 } 053 } 054 writeColumnDefinition(apply, systemPeriodStart, "TIMESTAMP", null, false, null); 055 apply.append(",").newLine(); 056 writeColumnDefinition(apply, systemPeriodEnd, "TIMESTAMP", null, false, null); 057 apply.newLine().append(")").endOfStatement(); 058 059 // enable system versioning 060 apply.append("alter table ").append(tableName).append(" add (").newLine(); 061 apply.append(" ").append(systemPeriodStart).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, ").newLine(); 062 apply.append(" ").append(systemPeriodEnd).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END").newLine(); 063 apply.append(")").endOfStatement(); 064 065 apply.append("alter table ").append(tableName).append(" add period for system_time(").append(systemPeriodStart) 066 .append(",").append(systemPeriodEnd).append(")").endOfStatement(); 067 068 enableSystemVersioning(apply, tableName, historyTableName, true, false); 069 070 createdHistoryTables.put(tableName, historyTableName); 071 072 dropHistoryTable(writer.dropAll(), tableName, historyTableName); 073 } 074 075 @Override 076 public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException { 077 dropHistoryTable(writer.applyDropDependencies(), dropHistoryTable.getBaseTable(), 078 dropHistoryTable.getBaseTable() + historySuffix); 079 } 080 081 protected void dropHistoryTable(DdlBuffer apply, String baseTable, String historyTable) throws IOException { 082 // disable system versioning 083 disableSystemVersioning(apply, baseTable); 084 085 apply.append("alter table ").append(baseTable).append(" drop period for system_time").endOfStatement(); 086 087 // drop the period columns 088 apply.append("alter table ").append(baseTable).append(" drop (").append(systemPeriodStart).append(",") 089 .append(systemPeriodEnd).append(")").endOfStatement(); 090 091 // drop the history table 092 apply.append("drop table ").append(historyTable).append(" cascade").endOfStatement(); 093 } 094 095 @Override 096 public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException { 097 MTable table = writer.getTable(addHistoryTable.getBaseTable()); 098 if (table == null) { 099 throw new IllegalStateException("MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)"); 100 } 101 createWithHistory(writer, table); 102 } 103 104 @Override 105 public void updateTriggers(DdlWrite write, HistoryTableUpdate baseTable) { 106 // nothing to do 107 } 108 109 protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, String defaultValue, 110 boolean isNotNull, String generated) throws IOException { 111 112 String platformType = platformDdl.convert(type); 113 buffer.append(" ").append(platformDdl.lowerColumnName(columnName)); 114 buffer.append(" ").append(platformType); 115 if (defaultValue != null) { 116 buffer.append(" default ").append(defaultValue); 117 } 118 if (isNotNull) { 119 buffer.append(" not null"); 120 } 121 if (generated != null) { 122 buffer.append(" ").append(generated); 123 } 124 } 125 126 public void disableSystemVersioning(DdlBuffer apply, String tableName) throws IOException { 127 disableSystemVersioning(apply, tableName, false); 128 } 129 130 public void disableSystemVersioning(DdlBuffer apply, String tableName, boolean uniqueStatement) throws IOException { 131 apply.append("alter table ").append(tableName).append(" drop system versioning"); 132 if (uniqueStatement) { 133 // needed for the DB migration test to prevent the statement from being filtered 134 // out as a duplicate 135 apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */"); 136 } 137 apply.endOfStatement(); 138 } 139 140 public void enableSystemVersioning(DdlBuffer apply, String tableName, String historyTableName, boolean validated, 141 boolean uniqueStatement) throws IOException { 142 apply.append("alter table ").append(tableName).append(" add system versioning history table ").append(historyTableName); 143 if (!validated) { 144 apply.append(" not validated"); 145 } 146 if (uniqueStatement) { 147 // needed for the DB migration test to prevent the statement from being filtered 148 // out as a duplicate 149 apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */"); 150 } 151 apply.endOfStatement(); 152 } 153 154 public boolean isSystemVersioningEnabled(String tableName) { 155 return !createdHistoryTables.containsKey(tableName); 156 } 157}