001package io.ebeaninternal.dbmigration.ddlgeneration.platform; 002 003import io.ebean.annotation.ConstraintMode; 004import io.ebean.config.DatabaseConfig; 005import io.ebean.config.DbConstraintNaming; 006import io.ebean.config.ServerConfig; 007import io.ebean.config.dbplatform.DatabasePlatform; 008import io.ebean.config.dbplatform.DbDefaultValue; 009import io.ebean.config.dbplatform.DbIdentity; 010import io.ebean.config.dbplatform.IdType; 011import io.ebean.util.StringHelper; 012import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler; 013import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; 014import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; 015import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions; 016import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; 017import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.PlatformTypeConverter; 018import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.VowelRemover; 019import io.ebeaninternal.dbmigration.migration.AddHistoryTable; 020import io.ebeaninternal.dbmigration.migration.AlterColumn; 021import io.ebeaninternal.dbmigration.migration.Column; 022import io.ebeaninternal.dbmigration.migration.DropHistoryTable; 023import io.ebeaninternal.dbmigration.model.MTable; 024 025import java.io.IOException; 026import java.util.Collection; 027import java.util.List; 028 029/** 030 * Controls the DDL generation for a specific database platform. 031 */ 032public class PlatformDdl { 033 034 protected final DatabasePlatform platform; 035 036 protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl(); 037 038 /** 039 * Converter for logical/standard types to platform specific types. (eg. clob -> text) 040 */ 041 private final PlatformTypeConverter typeConverter; 042 043 /** 044 * For handling support of sequences and autoincrement. 045 */ 046 private final DbIdentity dbIdentity; 047 048 /** 049 * Set to true if table and column comments are included inline with the create statements. 050 */ 051 protected boolean inlineComments; 052 053 /** 054 * Default assumes if exists is supported. 055 */ 056 protected String dropTableIfExists = "drop table if exists "; 057 058 protected String dropTableCascade = ""; 059 060 /** 061 * Default assumes if exists is supported. 062 */ 063 protected String dropSequenceIfExists = "drop sequence if exists "; 064 065 protected String foreignKeyOnDelete = "on delete"; 066 protected String foreignKeyOnUpdate = "on update"; 067 068 protected String identitySuffix = " auto_increment"; 069 protected String identityStartWith = "start with"; 070 protected String identityIncrementBy = "increment by"; 071 protected String identityCache = "cache"; 072 protected String sequenceStartWith = "start with"; 073 protected String sequenceIncrementBy = "increment by"; 074 protected String sequenceCache = "cache"; 075 076 protected String alterTableIfExists = ""; 077 078 protected String dropConstraintIfExists = "drop constraint if exists"; 079 080 protected String dropIndexIfExists = "drop index if exists "; 081 082 protected String alterColumn = "alter column"; 083 084 protected String alterColumnSuffix = ""; 085 086 protected String dropUniqueConstraint = "drop constraint"; 087 088 protected String addConstraint = "add constraint"; 089 090 protected String addColumn = "add column"; 091 092 protected String addColumnSuffix = ""; 093 094 protected String columnSetType = ""; 095 096 protected String columnSetDefault = "set default"; 097 098 protected String columnDropDefault = "drop default"; 099 100 protected String columnSetNotnull = "set not null"; 101 102 protected String columnSetNull = "set null"; 103 104 protected String updateNullWithDefault = "update ${table} set ${column} = ${default} where ${column} is null"; 105 106 protected String createTable = "create table"; 107 108 protected String dropColumn = "drop column"; 109 110 protected String dropColumnSuffix = ""; 111 112 protected String addForeignKeySkipCheck = ""; 113 114 protected String uniqueIndex = "unique"; 115 protected String indexConcurrent = ""; 116 117 /** 118 * Set false for MsSqlServer to allow multiple nulls for OneToOne mapping. 119 */ 120 protected boolean inlineUniqueWhenNullable = true; 121 122 protected DbConstraintNaming naming; 123 124 /** 125 * Generally not desired as then they are not named (used with SQLite). 126 */ 127 protected boolean inlineForeignKeys; 128 129 protected boolean includeStorageEngine; 130 131 protected final DbDefaultValue dbDefaultValue; 132 133 protected String fallbackArrayType = "varchar(1000)"; 134 135 public PlatformDdl(DatabasePlatform platform) { 136 this.platform = platform; 137 this.dbIdentity = platform.getDbIdentity(); 138 this.dbDefaultValue = platform.getDbDefaultValue(); 139 this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap()); 140 } 141 142 /** 143 * Set configuration options. 144 */ 145 public void configure(DatabaseConfig config) { 146 historyDdl.configure(config, this); 147 naming = config.getConstraintNaming(); 148 } 149 150 /** 151 * Create a DdlHandler for the specific database platform. 152 */ 153 public DdlHandler createDdlHandler(DatabaseConfig config) { 154 return new BaseDdlHandler(config, this); 155 } 156 157 /** 158 * Return the identity type to use given the support in the underlying database 159 * platform for sequences and identity/autoincrement. 160 */ 161 public IdType useIdentityType(IdType modelIdentity) { 162 if (modelIdentity == null) { 163 // use the default 164 return dbIdentity.getIdType(); 165 } 166 return identityType(modelIdentity, dbIdentity.getIdType(), dbIdentity.isSupportsSequence(), dbIdentity.isSupportsIdentity()); 167 } 168 169 /** 170 * Determine the id type to use based on requested identityType and 171 * the support for that in the database platform. 172 */ 173 private IdType identityType(IdType modelIdentity, IdType platformIdType, boolean supportsSequence, boolean supportsIdentity) { 174 switch (modelIdentity) { 175 case GENERATOR: 176 return IdType.GENERATOR; 177 case EXTERNAL: 178 return IdType.EXTERNAL; 179 case SEQUENCE: 180 return supportsSequence ? IdType.SEQUENCE : platformIdType; 181 case IDENTITY: 182 return supportsIdentity ? IdType.IDENTITY : platformIdType; 183 default: 184 return platformIdType; 185 } 186 } 187 188 /** 189 * Modify and return the column definition for autoincrement or identity definition. 190 */ 191 public String asIdentityColumn(String columnDefn, DdlIdentity identity) { 192 return columnDefn + identitySuffix; 193 } 194 195 /** 196 * SQl2003 standard identity definition. 197 */ 198 protected String asIdentityStandardOptions(String columnDefn, DdlIdentity identity) { 199 StringBuilder sb = new StringBuilder(columnDefn.length() + 60); 200 sb.append(columnDefn).append(identity.optionGenerated()); 201 sb.append(identity.identityOptions(identityStartWith, identityIncrementBy, identityCache)); 202 return sb.toString(); 203 } 204 205 /** 206 * Return true if the table and column comments are included inline. 207 */ 208 public boolean isInlineComments() { 209 return inlineComments; 210 } 211 212 /** 213 * Return true if the platform includes storage engine clause. 214 */ 215 public boolean isIncludeStorageEngine() { 216 return includeStorageEngine; 217 } 218 219 /** 220 * Return true if foreign key reference constraints need to inlined with create table. 221 * Ideally we don't do this as then the constraints are not named. Do this for SQLite. 222 */ 223 public boolean isInlineForeignKeys() { 224 return inlineForeignKeys; 225 } 226 227 /** 228 * By default this does nothing returning null / no lock timeout. 229 */ 230 public String setLockTimeout(int lockTimeoutSeconds) { 231 return null; 232 } 233 234 /** 235 * Write all the table columns converting to platform types as necessary. 236 */ 237 public void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) throws IOException { 238 for (int i = 0; i < columns.size(); i++) { 239 if (i > 0) { 240 apply.append(","); 241 } 242 apply.newLine(); 243 writeColumnDefinition(apply, columns.get(i), identity); 244 } 245 246 for (Column column : columns) { 247 String checkConstraint = column.getCheckConstraint(); 248 if (hasValue(checkConstraint)) { 249 checkConstraint = createCheckConstraint(maxConstraintName(column.getCheckConstraintName()), checkConstraint); 250 if (hasValue(checkConstraint)) { 251 apply.append(",").newLine(); 252 apply.append(checkConstraint); 253 } 254 } 255 } 256 } 257 258 /** 259 * Write the column definition to the create table statement. 260 */ 261 protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) throws IOException { 262 263 String columnDefn = convert(column.getType()); 264 if (identity.useIdentity() && isTrue(column.isPrimaryKey())) { 265 columnDefn = asIdentityColumn(columnDefn, identity); 266 } 267 268 buffer.append(" "); 269 buffer.append(lowerColumnName(column.getName()), 29); 270 buffer.append(columnDefn); 271 if (!Boolean.TRUE.equals(column.isPrimaryKey())) { 272 String defaultValue = convertDefaultValue(column.getDefaultValue()); 273 if (defaultValue != null) { 274 buffer.append(" default ").append(defaultValue); 275 } 276 } 277 if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) { 278 writeColumnNotNull(buffer); 279 } 280 281 // add check constraints later as we really want to give them a nice name 282 // so that the database can potentially provide a nice SQL error 283 } 284 285 /** 286 * Allow for platform overriding (e.g. ClickHouse). 287 */ 288 protected void writeColumnNotNull(DdlBuffer buffer) throws IOException { 289 buffer.append(" not null"); 290 } 291 292 /** 293 * Returns the check constraint. 294 */ 295 public String createCheckConstraint(String ckName, String checkConstraint) { 296 return " constraint " + ckName + " " + checkConstraint; 297 } 298 299 /** 300 * Convert the DB column default literal to platform specific. 301 */ 302 public String convertDefaultValue(String dbDefault) { 303 return dbDefaultValue.convert(dbDefault); 304 } 305 306 /** 307 * Return the drop foreign key clause. 308 */ 309 public String alterTableDropForeignKey(String tableName, String fkName) { 310 return "alter table " + alterTableIfExists + tableName + " " + dropConstraintIfExists + " " + maxConstraintName(fkName); 311 } 312 313 /** 314 * Convert the standard type to the platform specific type. 315 */ 316 public String convert(String type) { 317 if (type == null) { 318 return null; 319 } 320 if (type.contains("[]")) { 321 return convertArrayType(type); 322 } 323 return typeConverter.convert(type); 324 } 325 326 /** 327 * Convert the logical array type to a db platform specific type to support the array data. 328 */ 329 protected String convertArrayType(String logicalArrayType) { 330 if (logicalArrayType.endsWith("]")) { 331 return fallbackArrayType; 332 } 333 int colonPos = logicalArrayType.lastIndexOf(']'); 334 return "varchar" + logicalArrayType.substring(colonPos + 1); 335 } 336 337 /** 338 * Add history support to this table using the platform specific mechanism. 339 */ 340 public void createWithHistory(DdlWrite writer, MTable table) throws IOException { 341 historyDdl.createWithHistory(writer, table); 342 } 343 344 /** 345 * Drop history support for a given table. 346 */ 347 public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException { 348 historyDdl.dropHistoryTable(writer, dropHistoryTable); 349 } 350 351 /** 352 * Add history support to an existing table. 353 */ 354 public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException { 355 historyDdl.addHistoryTable(writer, addHistoryTable); 356 } 357 358 /** 359 * Regenerate the history triggers (or function) due to a column being added/dropped/excluded or included. 360 */ 361 public void regenerateHistoryTriggers(DdlWrite write, HistoryTableUpdate update) throws IOException { 362 historyDdl.updateTriggers(write, update); 363 } 364 365 /** 366 * Generate and return the create sequence DDL. 367 */ 368 public String createSequence(String sequenceName, DdlIdentity identity) { 369 StringBuilder sb = new StringBuilder("create sequence "); 370 sb.append(sequenceName); 371 sb.append(identity.sequenceOptions(sequenceStartWith, sequenceIncrementBy, sequenceCache)); 372 sb.append(";"); 373 return sb.toString(); 374 } 375 376 /** 377 * Return the drop sequence statement (potentially with if exists clause). 378 */ 379 public String dropSequence(String sequenceName) { 380 return dropSequenceIfExists + sequenceName; 381 } 382 383 /** 384 * Return the drop table statement (potentially with if exists clause). 385 */ 386 public String dropTable(String tableName) { 387 return dropTableIfExists + tableName + dropTableCascade; 388 } 389 390 /** 391 * Return the drop index statement for known non concurrent index. 392 */ 393 public String dropIndex(String indexName, String tableName) { 394 return dropIndex(indexName, tableName, false); 395 } 396 397 /** 398 * Return the drop index statement. 399 */ 400 public String dropIndex(String indexName, String tableName, boolean concurrent) { 401 return dropIndexIfExists + maxConstraintName(indexName); 402 } 403 404 public String createIndex(WriteCreateIndex create) { 405 if (create.useDefinition()) { 406 return create.getDefinition(); 407 } 408 StringBuilder buffer = new StringBuilder(); 409 buffer.append("create "); 410 if (create.isUnique()) { 411 buffer.append(uniqueIndex).append(" "); 412 } 413 buffer.append("index "); 414 if (create.isConcurrent()) { 415 buffer.append(indexConcurrent); 416 } 417 buffer.append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName()); 418 appendColumns(create.getColumns(), buffer); 419 return buffer.toString(); 420 } 421 422 /** 423 * Return the foreign key constraint when used inline with create table. 424 */ 425 public String tableInlineForeignKey(WriteForeignKey request) { 426 427 StringBuilder buffer = new StringBuilder(90); 428 buffer.append("foreign key"); 429 appendColumns(request.cols(), buffer); 430 buffer.append(" references ").append(lowerTableName(request.refTable())); 431 appendColumns(request.refCols(), buffer); 432 appendForeignKeySuffix(request, buffer); 433 return buffer.toString(); 434 } 435 436 /** 437 * Add foreign key. 438 */ 439 public String alterTableAddForeignKey(DdlOptions options, WriteForeignKey request) { 440 441 StringBuilder buffer = new StringBuilder(90); 442 buffer 443 .append("alter table ").append(lowerTableName(request.table())) 444 .append(" add constraint ").append(maxConstraintName(request.fkName())) 445 .append(" foreign key"); 446 appendColumns(request.cols(), buffer); 447 buffer 448 .append(" references ") 449 .append(lowerTableName(request.refTable())); 450 appendColumns(request.refCols(), buffer); 451 appendForeignKeySuffix(request, buffer); 452 if (options.isForeignKeySkipCheck()) { 453 buffer.append(addForeignKeySkipCheck); 454 } 455 return buffer.toString(); 456 } 457 458 protected void appendForeignKeySuffix(WriteForeignKey request, StringBuilder buffer) { 459 appendForeignKeyOnDelete(buffer, withDefault(request.onDelete())); 460 appendForeignKeyOnUpdate(buffer, withDefault(request.onUpdate())); 461 } 462 463 protected ConstraintMode withDefault(ConstraintMode mode) { 464 return (mode == null) ? ConstraintMode.RESTRICT : mode; 465 } 466 467 protected void appendForeignKeyOnDelete(StringBuilder buffer, ConstraintMode mode) { 468 appendForeignKeyMode(buffer, foreignKeyOnDelete, mode); 469 } 470 471 protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) { 472 appendForeignKeyMode(buffer, foreignKeyOnUpdate, mode); 473 } 474 475 protected void appendForeignKeyMode(StringBuilder buffer, String onMode, ConstraintMode mode) { 476 buffer.append(" ").append(onMode).append(" ").append(translate(mode)); 477 } 478 479 protected String translate(ConstraintMode mode) { 480 switch (mode) { 481 case SET_NULL: 482 return "set null"; 483 case SET_DEFAULT: 484 return "set default"; 485 case RESTRICT: 486 return "restrict"; 487 case CASCADE: 488 return "cascade"; 489 default: 490 throw new IllegalStateException("Unknown mode " + mode); 491 } 492 } 493 494 /** 495 * Drop a unique constraint from the table (Sometimes this is an index). 496 */ 497 public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) { 498 return "alter table " + tableName + " " + dropUniqueConstraint + " " + maxConstraintName(uniqueConstraintName); 499 } 500 501 /** 502 * Drop a unique constraint from the table. 503 */ 504 public String alterTableDropConstraint(String tableName, String constraintName) { 505 return "alter table " + tableName + " " + dropConstraintIfExists + " " + maxConstraintName(constraintName); 506 } 507 508 /** 509 * Add a unique constraint to the table. 510 * <p> 511 * Overridden by MsSqlServer for specific null handling on unique constraints. 512 */ 513 public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, String[] nullableColumns) { 514 515 StringBuilder buffer = new StringBuilder(90); 516 buffer.append("alter table ").append(tableName).append(" add constraint ").append(maxConstraintName(uqName)).append(" unique "); 517 appendColumns(columns, buffer); 518 return buffer.toString(); 519 } 520 521 public void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, String defaultValue) throws IOException { 522 523 String convertedType = convert(column.getType()); 524 525 buffer.append("alter table ").append(tableName) 526 .append(" ").append(addColumn).append(" ").append(column.getName()) 527 .append(" ").append(convertedType); 528 529 // Add default value also to history table if it is not excluded 530 if (defaultValue != null) { 531 if (!onHistoryTable || !isTrue(column.isHistoryExclude())) { 532 buffer.append(" default "); 533 buffer.append(defaultValue); 534 } 535 } 536 537 if (!onHistoryTable) { 538 if (isTrue(column.isNotnull())) { 539 writeColumnNotNull(buffer); 540 } 541 buffer.append(addColumnSuffix); 542 buffer.endOfStatement(); 543 544 // check constraints cannot be added in one statement for h2 545 if (!StringHelper.isNull(column.getCheckConstraint())) { 546 String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint()); 547 if (hasValue(ddl)) { 548 buffer.append(ddl).endOfStatement(); 549 } 550 } 551 } else { 552 buffer.append(addColumnSuffix); 553 buffer.endOfStatement(); 554 } 555 556 } 557 558 public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException { 559 buffer.append("alter table ").append(tableName).append(" ").append(dropColumn).append(" ").append(columnName) 560 .append(dropColumnSuffix).endOfStatement(); 561 } 562 563 /** 564 * Return true if unique constraints for nullable columns can be inlined as normal. 565 * Returns false for MsSqlServer and DB2 due to it's not possible to to put a constraint 566 * on a nullable column 567 */ 568 public boolean isInlineUniqueWhenNullable() { 569 return inlineUniqueWhenNullable; 570 } 571 572 /** 573 * Alter a column type. 574 * <p> 575 * Note that that MySql and SQL Server instead use alterColumnBaseAttributes() 576 * </p> 577 */ 578 public String alterColumnType(String tableName, String columnName, String type) { 579 return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type) + alterColumnSuffix; 580 } 581 582 /** 583 * Alter a column adding or removing the not null constraint. 584 * <p> 585 * Note that that MySql, SQL Server, and HANA instead use alterColumnBaseAttributes() 586 * </p> 587 */ 588 public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { 589 String suffix = notnull ? columnSetNotnull : columnSetNull; 590 return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix; 591 } 592 593 /** 594 * Alter table adding the check constraint. 595 */ 596 public String alterTableAddCheckConstraint(String tableName, String checkConstraintName, String checkConstraint) { 597 return "alter table " + tableName + " " + addConstraint + " " + maxConstraintName(checkConstraintName) + " " + checkConstraint; 598 } 599 600 /** 601 * Alter column setting the default value. 602 */ 603 public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) { 604 String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue); 605 return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix; 606 } 607 608 /** 609 * Alter column setting both the type and not null constraint. 610 * <p> 611 * Used by MySql, SQL Server, and HANA as these require both column attributes to be set together. 612 * </p> 613 */ 614 public String alterColumnBaseAttributes(AlterColumn alter) { 615 // by default do nothing, only used by mysql, sql server, and HANA as they can only 616 // modify the column with the full column definition 617 return null; 618 } 619 620 protected void appendColumns(String[] columns, StringBuilder buffer) { 621 buffer.append(" ("); 622 for (int i = 0; i < columns.length; i++) { 623 if (i > 0) { 624 buffer.append(","); 625 } 626 buffer.append(lowerColumnName(columns[i].trim())); 627 } 628 buffer.append(")"); 629 } 630 631 /** 632 * Convert the table to lower case. 633 * <p> 634 * Override as desired. Generally lower case with underscore is a good cross database 635 * choice for column/table names. 636 */ 637 protected String lowerTableName(String name) { 638 return naming.lowerTableName(name); 639 } 640 641 /** 642 * Convert the column name to lower case. 643 * <p> 644 * Override as desired. Generally lower case with underscore is a good cross database 645 * choice for column/table names. 646 */ 647 protected String lowerColumnName(String name) { 648 return naming.lowerColumnName(name); 649 } 650 651 public DatabasePlatform getPlatform() { 652 return platform; 653 } 654 655 public String getUpdateNullWithDefault() { 656 return updateNullWithDefault; 657 } 658 659 /** 660 * Return true if null or trimmed string is empty. 661 */ 662 protected boolean hasValue(String value) { 663 return value != null && !value.trim().isEmpty(); 664 } 665 666 /** 667 * Null safe Boolean true test. 668 */ 669 protected boolean isTrue(Boolean value) { 670 return Boolean.TRUE.equals(value); 671 } 672 673 /** 674 * Add an inline table comment to the create table statement. 675 */ 676 public void inlineTableComment(DdlBuffer apply, String tableComment) throws IOException { 677 // do nothing by default (MySql only) 678 } 679 680 /** 681 * Add an table storage engine to the create table statement. 682 */ 683 public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException { 684 // do nothing by default 685 } 686 687 /** 688 * Add table comment as a separate statement (from the create table statement). 689 */ 690 public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException { 691 if (DdlHelp.isDropComment(tableComment)) { 692 tableComment = ""; 693 } 694 apply.append(String.format("comment on table %s is '%s'", tableName, tableComment)).endOfStatement(); 695 } 696 697 /** 698 * Add column comment as a separate statement. 699 */ 700 public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException { 701 if (DdlHelp.isDropComment(comment)) { 702 comment = ""; 703 } 704 apply.append(String.format("comment on column %s.%s is '%s'", table, column, comment)).endOfStatement(); 705 } 706 707 /** 708 * Use this to generate a prolog for each script (stored procedures) 709 */ 710 public void generateProlog(DdlWrite write) throws IOException { 711 712 } 713 714 /** 715 * Use this to generate an epilog. Will be added at the end of script 716 */ 717 public void generateEpilog(DdlWrite write) throws IOException { 718 719 } 720 721 /** 722 * Shortens the given name to the maximum constraint name length of the platform in a deterministic way. 723 * <p> 724 * First, all vowels are removed, If the string is still to long, 31 bits are taken from the hash code 725 * of the string and base36 encoded (10 digits and 26 chars) string. 726 * <p> 727 * As 36^6 > 31^2, the resulting string is never longer as 6 chars. 728 */ 729 protected String maxConstraintName(String name) { 730 if (name.length() > platform.getMaxConstraintNameLength()) { 731 int hash = name.hashCode() & 0x7FFFFFFF; 732 name = VowelRemover.trim(name, 4); 733 if (name.length() > platform.getMaxConstraintNameLength()) { 734 return name.substring(0, platform.getMaxConstraintNameLength() - 7) + "_" + Integer.toString(hash, 36); 735 } 736 } 737 return name; 738 } 739 740 /** 741 * Mysql-specific: Locks all tables for triggers that have to be updated. 742 */ 743 public void lockTables(DdlBuffer buffer, Collection<String> tables) throws IOException { 744 745 } 746 747 /** 748 * Mysql-specific: Unlocks all tables for triggers that have to be updated. 749 */ 750 public void unlockTables(DdlBuffer buffer, Collection<String> tables) throws IOException { 751 752 } 753 754 /** 755 * Returns the database-specific "create table" command prefix. For HANA this is 756 * either "create column table" or "create row table", for all other databases 757 * it is "create table". 758 * 759 * @return The "create table" command prefix 760 */ 761 public String getCreateTableCommandPrefix() { 762 return createTable; 763 } 764 765 public boolean suppressPrimaryKeyOnPartition() { 766 return false; 767 } 768 769 public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException { 770 // only supported by postgres initially 771 } 772}