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.dbplatform.DatabasePlatform; 007import io.ebean.config.dbplatform.DbDefaultValue; 008import io.ebean.config.dbplatform.DbIdentity; 009import io.ebean.config.dbplatform.IdType; 010import io.ebean.util.StringHelper; 011import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler; 012import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; 013import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; 014import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions; 015import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; 016import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.PlatformTypeConverter; 017import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.VowelRemover; 018import io.ebeaninternal.dbmigration.migration.AddHistoryTable; 019import io.ebeaninternal.dbmigration.migration.AlterColumn; 020import io.ebeaninternal.dbmigration.migration.Column; 021import io.ebeaninternal.dbmigration.migration.DropHistoryTable; 022import io.ebeaninternal.dbmigration.model.MTable; 023 024import java.io.IOException; 025import java.util.Collection; 026import java.util.List; 027 028/** 029 * Controls the DDL generation for a specific database platform. 030 */ 031public class PlatformDdl { 032 033 protected final DatabasePlatform platform; 034 035 protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl(); 036 037 /** 038 * Converter for logical/standard types to platform specific types. (eg. clob -> text) 039 */ 040 private final PlatformTypeConverter typeConverter; 041 042 /** 043 * For handling support of sequences and autoincrement. 044 */ 045 private final DbIdentity dbIdentity; 046 047 /** 048 * Set to true if table and column comments are included inline with the create statements. 049 */ 050 protected boolean inlineComments; 051 052 /** 053 * Default assumes if exists is supported. 054 */ 055 protected String dropTableIfExists = "drop table if exists "; 056 057 protected String dropTableCascade = ""; 058 059 /** 060 * Default assumes if exists is supported. 061 */ 062 protected String dropSequenceIfExists = "drop sequence if exists "; 063 064 protected String foreignKeyOnDelete = "on delete"; 065 protected String foreignKeyOnUpdate = "on update"; 066 067 protected String identitySuffix = " auto_increment"; 068 protected String identityStartWith = "start with"; 069 protected String identityIncrementBy = "increment by"; 070 protected String identityCache = "cache"; 071 protected String sequenceStartWith = "start with"; 072 protected String sequenceIncrementBy = "increment by"; 073 protected String sequenceCache = "cache"; 074 075 protected String alterTableIfExists = ""; 076 077 protected String dropConstraintIfExists = "drop constraint if exists"; 078 079 protected String dropIndexIfExists = "drop index if exists "; 080 081 protected String alterColumn = "alter column"; 082 083 protected String alterColumnSuffix = ""; 084 085 protected String dropUniqueConstraint = "drop constraint"; 086 087 protected String addConstraint = "add constraint"; 088 089 protected String addColumn = "add column"; 090 091 protected String addColumnSuffix = ""; 092 093 protected String columnSetType = ""; 094 095 protected String columnSetDefault = "set default"; 096 097 protected String columnDropDefault = "drop default"; 098 099 protected String columnSetNotnull = "set not null"; 100 101 protected String columnSetNull = "set null"; 102 103 protected String updateNullWithDefault = "update ${table} set ${column} = ${default} where ${column} is null"; 104 105 protected String createTable = "create table"; 106 107 protected String dropColumn = "drop column"; 108 109 protected String dropColumnSuffix = ""; 110 111 protected String addForeignKeySkipCheck = ""; 112 113 protected String uniqueIndex = "unique"; 114 protected String indexConcurrent = ""; 115 protected String createIndexIfNotExists = ""; 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 if (create.isNotExistsCheck()) { 418 buffer.append(createIndexIfNotExists); 419 } 420 buffer.append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName()); 421 appendColumns(create.getColumns(), buffer); 422 return buffer.toString(); 423 } 424 425 /** 426 * Return the foreign key constraint when used inline with create table. 427 */ 428 public String tableInlineForeignKey(WriteForeignKey request) { 429 430 StringBuilder buffer = new StringBuilder(90); 431 buffer.append("foreign key"); 432 appendColumns(request.cols(), buffer); 433 buffer.append(" references ").append(lowerTableName(request.refTable())); 434 appendColumns(request.refCols(), buffer); 435 appendForeignKeySuffix(request, buffer); 436 return buffer.toString(); 437 } 438 439 /** 440 * Add foreign key. 441 */ 442 public String alterTableAddForeignKey(DdlOptions options, WriteForeignKey request) { 443 444 StringBuilder buffer = new StringBuilder(90); 445 buffer 446 .append("alter table ").append(lowerTableName(request.table())) 447 .append(" add constraint ").append(maxConstraintName(request.fkName())) 448 .append(" foreign key"); 449 appendColumns(request.cols(), buffer); 450 buffer 451 .append(" references ") 452 .append(lowerTableName(request.refTable())); 453 appendColumns(request.refCols(), buffer); 454 appendForeignKeySuffix(request, buffer); 455 if (options.isForeignKeySkipCheck()) { 456 buffer.append(addForeignKeySkipCheck); 457 } 458 return buffer.toString(); 459 } 460 461 protected void appendForeignKeySuffix(WriteForeignKey request, StringBuilder buffer) { 462 appendForeignKeyOnDelete(buffer, withDefault(request.onDelete())); 463 appendForeignKeyOnUpdate(buffer, withDefault(request.onUpdate())); 464 } 465 466 protected ConstraintMode withDefault(ConstraintMode mode) { 467 return (mode == null) ? ConstraintMode.RESTRICT : mode; 468 } 469 470 protected void appendForeignKeyOnDelete(StringBuilder buffer, ConstraintMode mode) { 471 appendForeignKeyMode(buffer, foreignKeyOnDelete, mode); 472 } 473 474 protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) { 475 appendForeignKeyMode(buffer, foreignKeyOnUpdate, mode); 476 } 477 478 protected void appendForeignKeyMode(StringBuilder buffer, String onMode, ConstraintMode mode) { 479 buffer.append(" ").append(onMode).append(" ").append(translate(mode)); 480 } 481 482 protected String translate(ConstraintMode mode) { 483 switch (mode) { 484 case SET_NULL: 485 return "set null"; 486 case SET_DEFAULT: 487 return "set default"; 488 case RESTRICT: 489 return "restrict"; 490 case CASCADE: 491 return "cascade"; 492 default: 493 throw new IllegalStateException("Unknown mode " + mode); 494 } 495 } 496 497 /** 498 * Drop a unique constraint from the table (Sometimes this is an index). 499 */ 500 public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) { 501 return "alter table " + tableName + " " + dropUniqueConstraint + " " + maxConstraintName(uniqueConstraintName); 502 } 503 504 /** 505 * Drop a unique constraint from the table. 506 */ 507 public String alterTableDropConstraint(String tableName, String constraintName) { 508 return "alter table " + tableName + " " + dropConstraintIfExists + " " + maxConstraintName(constraintName); 509 } 510 511 /** 512 * Add a unique constraint to the table. 513 * <p> 514 * Overridden by MsSqlServer for specific null handling on unique constraints. 515 */ 516 public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, String[] nullableColumns) { 517 518 StringBuilder buffer = new StringBuilder(90); 519 buffer.append("alter table ").append(tableName).append(" add constraint ").append(maxConstraintName(uqName)).append(" unique "); 520 appendColumns(columns, buffer); 521 return buffer.toString(); 522 } 523 524 public void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, String defaultValue) throws IOException { 525 526 String convertedType = convert(column.getType()); 527 528 buffer.append("alter table ").append(tableName) 529 .append(" ").append(addColumn).append(" ").append(column.getName()) 530 .append(" ").append(convertedType); 531 532 // Add default value also to history table if it is not excluded 533 if (defaultValue != null) { 534 if (!onHistoryTable || !isTrue(column.isHistoryExclude())) { 535 buffer.append(" default "); 536 buffer.append(defaultValue); 537 } 538 } 539 540 if (!onHistoryTable) { 541 if (isTrue(column.isNotnull())) { 542 writeColumnNotNull(buffer); 543 } 544 buffer.append(addColumnSuffix); 545 buffer.endOfStatement(); 546 547 // check constraints cannot be added in one statement for h2 548 if (!StringHelper.isNull(column.getCheckConstraint())) { 549 String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint()); 550 if (hasValue(ddl)) { 551 buffer.append(ddl).endOfStatement(); 552 } 553 } 554 } else { 555 buffer.append(addColumnSuffix); 556 buffer.endOfStatement(); 557 } 558 559 } 560 561 public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException { 562 buffer.append("alter table ").append(tableName).append(" ").append(dropColumn).append(" ").append(columnName) 563 .append(dropColumnSuffix).endOfStatement(); 564 } 565 566 /** 567 * Return true if unique constraints for nullable columns can be inlined as normal. 568 * Returns false for MsSqlServer and DB2 due to it's not possible to to put a constraint 569 * on a nullable column 570 */ 571 public boolean isInlineUniqueWhenNullable() { 572 return inlineUniqueWhenNullable; 573 } 574 575 /** 576 * Alter a column type. 577 * <p> 578 * Note that that MySql and SQL Server instead use alterColumnBaseAttributes() 579 * </p> 580 */ 581 public String alterColumnType(String tableName, String columnName, String type) { 582 return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type) + alterColumnSuffix; 583 } 584 585 /** 586 * Alter a column adding or removing the not null constraint. 587 * <p> 588 * Note that that MySql, SQL Server, and HANA instead use alterColumnBaseAttributes() 589 * </p> 590 */ 591 public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { 592 String suffix = notnull ? columnSetNotnull : columnSetNull; 593 return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix; 594 } 595 596 /** 597 * Alter table adding the check constraint. 598 */ 599 public String alterTableAddCheckConstraint(String tableName, String checkConstraintName, String checkConstraint) { 600 return "alter table " + tableName + " " + addConstraint + " " + maxConstraintName(checkConstraintName) + " " + checkConstraint; 601 } 602 603 /** 604 * Alter column setting the default value. 605 */ 606 public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) { 607 String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue); 608 return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix; 609 } 610 611 /** 612 * Alter column setting both the type and not null constraint. 613 * <p> 614 * Used by MySql, SQL Server, and HANA as these require both column attributes to be set together. 615 * </p> 616 */ 617 public String alterColumnBaseAttributes(AlterColumn alter) { 618 // by default do nothing, only used by mysql, sql server, and HANA as they can only 619 // modify the column with the full column definition 620 return null; 621 } 622 623 protected void appendColumns(String[] columns, StringBuilder buffer) { 624 buffer.append(" ("); 625 for (int i = 0; i < columns.length; i++) { 626 if (i > 0) { 627 buffer.append(","); 628 } 629 buffer.append(lowerColumnName(columns[i].trim())); 630 } 631 buffer.append(")"); 632 } 633 634 /** 635 * Convert the table to lower case. 636 * <p> 637 * Override as desired. Generally lower case with underscore is a good cross database 638 * choice for column/table names. 639 */ 640 protected String lowerTableName(String name) { 641 return naming.lowerTableName(name); 642 } 643 644 /** 645 * Convert the column name to lower case. 646 * <p> 647 * Override as desired. Generally lower case with underscore is a good cross database 648 * choice for column/table names. 649 */ 650 protected String lowerColumnName(String name) { 651 return naming.lowerColumnName(name); 652 } 653 654 public DatabasePlatform getPlatform() { 655 return platform; 656 } 657 658 public String getUpdateNullWithDefault() { 659 return updateNullWithDefault; 660 } 661 662 /** 663 * Return true if null or trimmed string is empty. 664 */ 665 protected boolean hasValue(String value) { 666 return value != null && !value.trim().isEmpty(); 667 } 668 669 /** 670 * Null safe Boolean true test. 671 */ 672 protected boolean isTrue(Boolean value) { 673 return Boolean.TRUE.equals(value); 674 } 675 676 /** 677 * Add an inline table comment to the create table statement. 678 */ 679 public void inlineTableComment(DdlBuffer apply, String tableComment) throws IOException { 680 // do nothing by default (MySql only) 681 } 682 683 /** 684 * Add an table storage engine to the create table statement. 685 */ 686 public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException { 687 // do nothing by default 688 } 689 690 /** 691 * Add table comment as a separate statement (from the create table statement). 692 */ 693 public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException { 694 if (DdlHelp.isDropComment(tableComment)) { 695 tableComment = ""; 696 } 697 apply.append(String.format("comment on table %s is '%s'", tableName, tableComment)).endOfStatement(); 698 } 699 700 /** 701 * Add column comment as a separate statement. 702 */ 703 public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException { 704 if (DdlHelp.isDropComment(comment)) { 705 comment = ""; 706 } 707 apply.append(String.format("comment on column %s.%s is '%s'", table, column, comment)).endOfStatement(); 708 } 709 710 /** 711 * Use this to generate a prolog for each script (stored procedures) 712 */ 713 public void generateProlog(DdlWrite write) throws IOException { 714 715 } 716 717 /** 718 * Use this to generate an epilog. Will be added at the end of script 719 */ 720 public void generateEpilog(DdlWrite write) throws IOException { 721 722 } 723 724 /** 725 * Shortens the given name to the maximum constraint name length of the platform in a deterministic way. 726 * <p> 727 * First, all vowels are removed, If the string is still to long, 31 bits are taken from the hash code 728 * of the string and base36 encoded (10 digits and 26 chars) string. 729 * <p> 730 * As 36^6 > 31^2, the resulting string is never longer as 6 chars. 731 */ 732 protected String maxConstraintName(String name) { 733 if (name.length() > platform.getMaxConstraintNameLength()) { 734 int hash = name.hashCode() & 0x7FFFFFFF; 735 name = VowelRemover.trim(name, 4); 736 if (name.length() > platform.getMaxConstraintNameLength()) { 737 return name.substring(0, platform.getMaxConstraintNameLength() - 7) + "_" + Integer.toString(hash, 36); 738 } 739 } 740 return name; 741 } 742 743 /** 744 * Mysql-specific: Locks all tables for triggers that have to be updated. 745 */ 746 public void lockTables(DdlBuffer buffer, Collection<String> tables) throws IOException { 747 748 } 749 750 /** 751 * Mysql-specific: Unlocks all tables for triggers that have to be updated. 752 */ 753 public void unlockTables(DdlBuffer buffer, Collection<String> tables) throws IOException { 754 755 } 756 757 /** 758 * Returns the database-specific "create table" command prefix. For HANA this is 759 * either "create column table" or "create row table", for all other databases 760 * it is "create table". 761 * 762 * @return The "create table" command prefix 763 */ 764 public String getCreateTableCommandPrefix() { 765 return createTable; 766 } 767 768 public boolean suppressPrimaryKeyOnPartition() { 769 return false; 770 } 771 772 public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException { 773 // only supported by postgres initially 774 } 775}