001package io.ebeaninternal.dbmigration.ddlgeneration.platform;
002
003import io.ebean.annotation.ConstraintMode;
004import io.ebean.config.dbplatform.DatabasePlatform;
005
006/**
007 * Oracle platform specific DDL.
008 */
009public class OracleDdl extends PlatformDdl {
010
011  public OracleDdl(DatabasePlatform platform) {
012    super(platform);
013    this.dropTableIfExists = "drop table ";
014    this.dropSequenceIfExists = "drop sequence ";
015    this.dropConstraintIfExists = "drop constraint";
016    this.dropIndexIfExists = "drop index ";
017    this.dropTableCascade = " cascade constraints purge";
018    this.addColumn = "add";
019    this.alterColumn = "modify";
020    this.columnSetNotnull = "not null";
021    this.columnSetNull = "null";
022    this.columnSetDefault = "default";
023    this.columnDropDefault = "default null"; // dropping default is not supported. See:
024    // https://stackoverflow.com/questions/8481532/how-do-i-remove-the-default-value-from-a-column-in-oracle
025    this.identitySuffix = " generated by default as identity";
026  }
027
028  @Override
029  public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, String[] nullableColumns) {
030    if (nullableColumns == null || nullableColumns.length == 0) {
031      return super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns);
032    } else {
033      // Hmm: https://stackoverflow.com/questions/11893134/oracle-create-unique-index-but-ignore-nulls
034      return "-- NOT YET IMPLEMENTED: " + super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns);
035    }
036  }
037
038  @Override
039  public String dropSequence(String sequenceName) {
040    return ignoreError(-2289, super.dropSequence(sequenceName));
041  }
042
043  @Override
044  public String alterTableDropConstraint(String tableName, String constraintName) {
045    return ignoreError(-2443, super.alterTableDropConstraint(tableName, constraintName));
046  }
047
048  @Override
049  public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
050    return ignoreError(-2443, super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
051  }
052
053  @Override
054  protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) {
055    // do nothing, no on update clause for oracle
056  }
057
058  @Override
059  protected void appendForeignKeyMode(StringBuilder buffer, String onMode, ConstraintMode mode) {
060    switch (mode) {
061      case SET_NULL:
062      case CASCADE:
063        super.appendForeignKeyMode(buffer, onMode, mode);
064      default:
065        // do nothing, defaults to RESTRICT effectively
066    }
067  }
068
069  /**
070   * Modify and return the column definition for autoincrement or identity definition.
071   */
072  @Override
073  public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
074    return asIdentityStandardOptions(columnDefn, identity);
075  }
076
077  /**
078   * generates anonymous pl/sql block that catches expected error so that we can
079   * effectively do a 'drop if exists'
080   */
081  private String ignoreError(int errorNr, String statement) {
082    StringBuilder sb = new StringBuilder();
083    sb.append("delimiter $$\n")
084        .append("declare\n")
085        .append("  expected_error exception;\n")
086        .append("  pragma exception_init(expected_error, ").append(errorNr).append(");\n")
087        .append("begin\n")
088        .append("  execute immediate '").append(statement).append("';\n")
089        .append("exception\n")
090        .append("  when expected_error then null;\n")
091        .append("end;\n$$");
092    return sb.toString();
093  }
094}