001package io.ebeaninternal.dbmigration.ddlgeneration.platform;
002
003import io.ebean.config.dbplatform.DatabasePlatform;
004import io.ebean.util.StringHelper;
005import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
006import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
007import io.ebeaninternal.dbmigration.migration.AlterColumn;
008import io.ebeaninternal.dbmigration.migration.Column;
009
010/**
011 * MySql specific DDL.
012 */
013public class MySqlDdl extends PlatformDdl {
014
015  // check constraint support is disabled by default. See https://groups.google.com/forum/#!topic/ebean/luFN-2xBkUw
016  // this flag is for compatibility. Use it with care.
017  private static final boolean USE_CHECK_CONSTRAINT = Boolean.getBoolean("ebean.mysql.useCheckConstraint");
018
019  private final boolean useMigrationStoredProcedures;
020
021  public MySqlDdl(DatabasePlatform platform) {
022    super(platform);
023    this.alterColumn = "alter";
024    this.dropUniqueConstraint = "drop index";
025    this.historyDdl = new MySqlHistoryDdl();
026    this.inlineComments = true;
027    this.useMigrationStoredProcedures = platform.isUseMigrationStoredProcedures();
028  }
029
030  /**
031   * Return the drop index statement.
032   */
033  @Override
034  public String dropIndex(String indexName, String tableName, boolean concurrent) {
035    return "drop index " + maxConstraintName(indexName) + " on " + quote(tableName);
036  }
037
038  @Override
039  public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
040    if (this.useMigrationStoredProcedures) {
041      alterTable(writer, tableName).raw("CALL usp_ebean_drop_column('").append(naming.normaliseTable(tableName))
042        .append("', '").append(naming.normaliseColumn(columnName)).append("')");
043    } else {
044      super.alterTableDropColumn(writer, tableName, columnName);
045    }
046  }
047
048  /**
049   * Return the drop foreign key clause.
050   */
051  @Override
052  public String alterTableDropForeignKey(String tableName, String fkName) {
053    return "alter table " + quote(tableName) + " drop foreign key " + maxConstraintName(fkName);
054  }
055
056  @Override
057  public String createCheckConstraint(String ckName, String checkConstraint) {
058    if (USE_CHECK_CONSTRAINT) {
059      return super.createCheckConstraint(ckName, checkConstraint);
060    } else {
061      return null;
062    }
063  }
064
065  @Override
066  public String alterTableAddCheckConstraint(String tableName, String checkConstraintName, String checkConstraint) {
067    if (USE_CHECK_CONSTRAINT) {
068      return super.alterTableAddCheckConstraint(tableName, checkConstraintName, checkConstraint);
069    } else {
070      return null;
071    }
072  }
073
074  @Override
075  public String alterTableDropConstraint(String tableName, String constraintName) {
076    // drop constraint not supported in MySQL 5.7 and 8.0 but starting with MariaDB
077    // 10.2.1 CHECK is evaluated
078    if (USE_CHECK_CONSTRAINT) {
079      StringBuilder sb = new StringBuilder();
080      // statement for MySQL >= 8.0.16
081      sb.append("/*!80016 alter table ").append(tableName);
082      sb.append(" drop check ").append(constraintName).append(" */;\n");
083      // statement for MariaDB >= 10.2.1
084      sb.append("/*M!100201 ");
085      sb.append(super.alterTableDropConstraint(tableName, constraintName));
086      sb.append(" */");
087      return sb.toString();
088    } else {
089      return null;
090    }
091  }
092
093  @Override
094  public void alterColumn(DdlWrite writer, AlterColumn alter) {
095    String tableName = alter.getTableName();
096    String columnName = alter.getColumnName();
097
098    if (alter.getType() == null && alter.isNotnull() == null) {
099      // No type change or notNull change -> handle default value change
100      if (hasValue(alter.getDefaultValue())) {
101        alterColumnDefault(writer, alter);
102      }
103    } else {
104      // we must regenerate whole statement -> read altered and current value
105      String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
106      type = convert(type);
107      boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
108      String defaultValue = alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue();
109
110      DdlBuffer buffer = alterTable(writer, tableName).append("modify", columnName);
111      buffer.append(type);
112      if (notnull) {
113        buffer.append(" not null");
114      }
115      if (hasValue(defaultValue) && !DdlHelp.isDropDefault(defaultValue)) {
116        buffer.append(" default ").append(convertDefaultValue(defaultValue));
117      }
118    }
119  }
120
121  @Override
122  protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) {
123    super.writeColumnDefinition(buffer, column, identity);
124    String comment = column.getComment();
125    if (!StringHelper.isNull(comment)) {
126      // in mysql 5.5 column comment save in information_schema.COLUMNS.COLUMN_COMMENT(VARCHAR 1024)
127      if (comment.length() > 500) {
128        comment = comment.substring(0, 500);
129      }
130      buffer.append(String.format(" comment '%s'", comment));
131    }
132  }
133
134  @Override
135  public void inlineTableComment(DdlBuffer apply, String tableComment) {
136    if (tableComment.length() > 1000) {
137      tableComment = tableComment.substring(0, 1000);
138    }
139    apply.append(" comment='").append(tableComment).append("'");
140  }
141
142  /**
143   * Add table comment as a separate statement (from the create table statement).
144   */
145  @Override
146  public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
147    if (DdlHelp.isDropComment(tableComment)) {
148      tableComment = "";
149    }
150    apply.append(String.format("alter table %s comment = '%s'", quote(tableName), tableComment)).endOfStatement();
151  }
152
153  @Override
154  public void addColumnComment(DdlBuffer apply, String table, String column, String comment) {
155    // alter comment currently not supported as it requires to repeat whole column definition
156  }
157
158}