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}