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.MTable;
009
010import java.io.IOException;
011
012/**
013 * @author Vilmos Nagy
014 */
015public class SqlServerHistoryDdl implements PlatformHistoryDdl {
016
017  private String systemPeriodStart;
018  private String systemPeriodEnd;
019  private PlatformDdl platformDdl;
020
021  @Override
022  public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
023    this.systemPeriodStart = config.getAsOfSysPeriod() + "From";
024    this.systemPeriodEnd = config.getAsOfSysPeriod() + "To";
025    this.platformDdl = platformDdl;
026  }
027
028  @Override
029  public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
030    String baseTable = table.getName();
031    enableSystemVersioning(writer, baseTable);
032  }
033
034  String getHistoryTable(String baseTable) {
035    String historyTable = baseTable + "_history";
036    if (baseTable.startsWith("[")) {
037      historyTable = historyTable.replace("]", "") + "]";
038    }
039    if (historyTable.indexOf('.') == -1) {
040      // history must contain schema, add the default schema if none was specified
041      historyTable = "dbo." + historyTable;
042    }
043    return historyTable;
044  }
045
046  private void enableSystemVersioning(DdlWrite writer, String baseTable) throws IOException {
047    DdlBuffer apply = writer.applyHistoryView();
048    apply.append("alter table ").append(baseTable).newLine()
049      .append("    add ").append(systemPeriodStart).append(" datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(),").newLine()
050      .append("        ").append(systemPeriodEnd).append("   datetime2 GENERATED ALWAYS AS ROW END   NOT NULL DEFAULT '9999-12-31T23:59:59.9999999',").newLine()
051      .append("period for system_time (").append(systemPeriodStart).append(", ").append(systemPeriodEnd).append(")").endOfStatement();
052
053    apply.append("alter table ").append(baseTable).append(" set (system_versioning = on (history_table=")
054      .append(getHistoryTable(baseTable)).append("))").endOfStatement();
055
056    DdlBuffer drop = writer.dropAll();
057    drop.append("IF OBJECT_ID('").append(baseTable).append("', 'U') IS NOT NULL alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
058    drop.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
059  }
060
061  @Override
062  public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
063    String baseTable = dropHistoryTable.getBaseTable();
064    DdlBuffer apply = writer.applyHistoryView();
065    apply.append("-- dropping history support for ").append(baseTable).endOfStatement();
066    // drop default constraints
067
068    apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodStart, DdlHelp.DROP_DEFAULT)).endOfStatement();
069    apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodEnd, DdlHelp.DROP_DEFAULT)).endOfStatement();
070    // switch of versioning & period
071    apply.append("alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
072    apply.append("alter table ").append(baseTable).append(" drop period for system_time").endOfStatement();
073    // now drop tables & columns
074    apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodStart).endOfStatement();
075    apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodEnd).endOfStatement();
076    apply.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
077    apply.end();
078  }
079
080  @Override
081  public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
082    String baseTable = addHistoryTable.getBaseTable();
083    enableSystemVersioning(writer, baseTable);
084  }
085
086  @Override
087  public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) throws IOException {
088    // SQL Server 2016 does not need triggers
089    DdlBuffer apply = writer.applyHistoryView();
090    String baseTableName = baseTable.getBaseTable();
091    apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = off (history_table=")
092      .append(getHistoryTable(baseTableName)).append("))").endOfStatement();
093    apply.append("-- history migration goes here").newLine();
094    apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = on (history_table=")
095      .append(getHistoryTable(baseTableName)).append("))").endOfStatement();
096
097  }
098}