001package com.avaje.ebean.config.dbplatform; 002 003import com.avaje.ebean.BackgroundExecutor; 004import com.avaje.ebean.Query; 005import com.avaje.ebean.config.ServerConfig; 006import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler; 007import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl; 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011import javax.sql.DataSource; 012import java.sql.Types; 013 014/** 015 * Database platform specific settings. 016 */ 017public class DatabasePlatform { 018 019 private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class); 020 021 022 /** 023 * Behavior used when ending a query only transaction (at read committed isolation level). 024 */ 025 public enum OnQueryOnly { 026 027 /** 028 * Rollback the transaction. 029 */ 030 ROLLBACK, 031 032 /** 033 * Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases 034 * as a performance optimisation. 035 */ 036 CLOSE, 037 038 /** 039 * Commit the transaction 040 */ 041 COMMIT 042 } 043 044 045 /** 046 * Set to true for MySql, no other jdbc drivers need this workaround. 047 */ 048 protected boolean useExtraTransactionOnIterateSecondaryQueries; 049 050 /** 051 * The behaviour used when ending a read only transaction at read committed isolation level. 052 */ 053 protected OnQueryOnly onQueryOnly = OnQueryOnly.ROLLBACK; 054 055 /** 056 * The open quote used by quoted identifiers. 057 */ 058 protected String openQuote = "\""; 059 060 /** 061 * The close quote used by quoted identifiers. 062 */ 063 protected String closeQuote = "\""; 064 065 /** 066 * For limit/offset, row_number etc limiting of SQL queries. 067 */ 068 protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter(); 069 070 /** 071 * Mapping of JDBC to Database types. 072 */ 073 protected DbTypeMap dbTypeMap = new DbTypeMap(); 074 075 /** 076 * Set to true if the DB has native UUID type support. 077 */ 078 protected boolean nativeUuidType; 079 080 /** 081 * Defines DB identity/sequence features. 082 */ 083 protected DbIdentity dbIdentity = new DbIdentity(); 084 085 /** 086 * The history support for this database platform. 087 */ 088 protected DbHistorySupport historySupport; 089 090 /** 091 * The JDBC type to map booleans to (by default). 092 */ 093 protected int booleanDbType = Types.BOOLEAN; 094 095 /** 096 * The JDBC type to map Blob to. 097 */ 098 protected int blobDbType = Types.BLOB; 099 100 /** 101 * The JDBC type to map Clob to. 102 */ 103 protected int clobDbType = Types.CLOB; 104 105 /** 106 * For Oracle treat empty strings as null. 107 */ 108 protected boolean treatEmptyStringsAsNull; 109 110 /** 111 * The database platform name. 112 */ 113 protected String name = "generic"; 114 115 protected String columnAliasPrefix = "c"; 116 117 protected String tableAliasPlaceHolder = "${ta}"; 118 119 /** 120 * Use a BackTick ` at the beginning and end of table or column names that you 121 * want to use quoted identifiers for. The backticks get converted to the 122 * appropriate characters in convertQuotedIdentifiers 123 */ 124 private static final char BACK_TICK = '`'; 125 126 /** 127 * The like clause. Can be overridden to disable default escape character. 128 */ 129 protected String likeClause = "like ?"; 130 131 protected DbEncrypt dbEncrypt; 132 133 protected boolean idInExpandedForm; 134 135 protected boolean selectCountWithAlias; 136 137 /** 138 * If set then use the FORWARD ONLY hint when creating ResultSets for 139 * findIterate() and findVisit(). 140 */ 141 protected boolean forwardOnlyHintOnFindIterate; 142 143 /** 144 * Flag set for SQL Server due to lack of support of getGeneratedKeys in 145 * batch mode (meaning for batch inserts you should explicitly turn off 146 * getGeneratedKeys - joy). 147 */ 148 protected boolean disallowBatchOnCascade; 149 150 protected PlatformDdl platformDdl; 151 152 /** 153 * The maximum length of table names - used specifically when derived 154 * default table names for intersection tables. 155 */ 156 protected int maxTableNameLength = 60; 157 158 /** 159 * A value of 60 is a reasonable default for all databases except 160 * Oracle (limited to 30) and DB2 (limited to 18). 161 */ 162 protected int maxConstraintNameLength = 60; 163 164 /** 165 * Instantiates a new database platform. 166 */ 167 public DatabasePlatform() { 168 } 169 170 /** 171 * Return the name of the DatabasePlatform. 172 * <p> 173 * "generic" is returned when no specific database platform has been set or 174 * found. 175 * </p> 176 */ 177 public String getName() { 178 return name; 179 } 180 181 /** 182 * Return the maximum table name length. 183 * <p> 184 * This is used when deriving names of intersection tables. 185 * </p> 186 */ 187 public int getMaxTableNameLength() { 188 return maxTableNameLength; 189 } 190 191 /** 192 * Return the maximum constraint name allowed for the platform. 193 */ 194 public int getMaxConstraintNameLength() { 195 return maxConstraintNameLength; 196 } 197 198 /** 199 * Return the platform specific DDL. 200 */ 201 public PlatformDdl getPlatformDdl() { 202 return platformDdl; 203 } 204 205 /** 206 * Create and return a DDL handler for generating DDL scripts. 207 */ 208 public DdlHandler createDdlHandler(ServerConfig serverConfig) { 209 return platformDdl.createDdlHandler(serverConfig); 210 } 211 212 /** 213 * Return true if the JDBC driver does not allow additional queries to execute 214 * when a resultSet is being 'streamed' as is the case with findEach() etc. 215 * <p> 216 * Honestly, this is a workaround for a stupid MySql JDBC driver limitation. 217 * </p> 218 */ 219 public boolean useExtraTransactionOnIterateSecondaryQueries() { 220 return useExtraTransactionOnIterateSecondaryQueries; 221 } 222 223 /** 224 * Return a DB Sequence based IdGenerator. 225 * 226 * @param be the BackgroundExecutor that can be used to load the sequence if 227 * desired 228 * @param ds the DataSource 229 * @param seqName the name of the sequence 230 * @param batchSize the number of sequences that should be loaded 231 */ 232 public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { 233 return null; 234 } 235 236 /** 237 * Return the behaviour to use when ending a read only transaction. 238 */ 239 public OnQueryOnly getOnQueryOnly() { 240 return onQueryOnly; 241 } 242 243 /** 244 * Set the behaviour to use when ending a read only transaction. 245 */ 246 public void setOnQueryOnly(OnQueryOnly onQueryOnly) { 247 this.onQueryOnly = onQueryOnly; 248 } 249 250 /** 251 * Return the DbEncrypt handler for this DB platform. 252 */ 253 public DbEncrypt getDbEncrypt() { 254 return dbEncrypt; 255 } 256 257 /** 258 * Set the DbEncrypt handler for this DB platform. 259 */ 260 public void setDbEncrypt(DbEncrypt dbEncrypt) { 261 this.dbEncrypt = dbEncrypt; 262 } 263 264 /** 265 * Return the history support for this database platform. 266 */ 267 public DbHistorySupport getHistorySupport() { 268 return historySupport; 269 } 270 271 /** 272 * Set the history support for this database platform. 273 */ 274 public void setHistorySupport(DbHistorySupport historySupport) { 275 this.historySupport = historySupport; 276 } 277 278 /** 279 * Return true if the DB supports native UUID. 280 */ 281 public boolean isNativeUuidType() { 282 return nativeUuidType; 283 } 284 285 /** 286 * Return the mapping of JDBC to DB types. 287 * 288 * @return the db type map 289 */ 290 public DbTypeMap getDbTypeMap() { 291 return dbTypeMap; 292 } 293 294 /** 295 * Return the column alias prefix. 296 */ 297 public String getColumnAliasPrefix() { 298 return columnAliasPrefix; 299 } 300 301 /** 302 * Set the column alias prefix. 303 */ 304 public void setColumnAliasPrefix(String columnAliasPrefix) { 305 this.columnAliasPrefix = columnAliasPrefix; 306 } 307 308 /** 309 * Return the table alias placeholder. 310 */ 311 public String getTableAliasPlaceHolder() { 312 return tableAliasPlaceHolder; 313 } 314 315 /** 316 * Set the table alias placeholder. 317 */ 318 public void setTableAliasPlaceHolder(String tableAliasPlaceHolder) { 319 this.tableAliasPlaceHolder = tableAliasPlaceHolder; 320 } 321 322 /** 323 * Return the close quote for quoted identifiers. 324 * 325 * @return the close quote 326 */ 327 public String getCloseQuote() { 328 return closeQuote; 329 } 330 331 /** 332 * Return the open quote for quoted identifiers. 333 * 334 * @return the open quote 335 */ 336 public String getOpenQuote() { 337 return openQuote; 338 } 339 340 /** 341 * Return the JDBC type used to store booleans. 342 * 343 * @return the boolean db type 344 */ 345 public int getBooleanDbType() { 346 return booleanDbType; 347 } 348 349 /** 350 * Return the data type that should be used for Blob. 351 * <p> 352 * This is typically Types.BLOB but for Postgres is Types.LONGVARBINARY for 353 * example. 354 * </p> 355 */ 356 public int getBlobDbType() { 357 return blobDbType; 358 } 359 360 /** 361 * Return the data type that should be used for Clob. 362 * <p> 363 * This is typically Types.CLOB but for Postgres is Types.VARCHAR. 364 * </p> 365 */ 366 public int getClobDbType() { 367 return clobDbType; 368 } 369 370 /** 371 * Return true if empty strings should be treated as null. 372 * 373 * @return true, if checks if is treat empty strings as null 374 */ 375 public boolean isTreatEmptyStringsAsNull() { 376 return treatEmptyStringsAsNull; 377 } 378 379 /** 380 * Return true if a compound ID in (...) type expression needs to be in 381 * expanded form of (a=? and b=?) or (a=? and b=?) or ... rather than (a,b) in 382 * ((?,?),(?,?),...); 383 */ 384 public boolean isIdInExpandedForm() { 385 return idInExpandedForm; 386 } 387 388 /** 389 * Return true if the ResultSet TYPE_FORWARD_ONLY Hint should be used on 390 * findIterate() and findVisit() PreparedStatements. 391 * <p> 392 * This specifically is required for MySql when processing large results. 393 * </p> 394 */ 395 public boolean isForwardOnlyHintOnFindIterate() { 396 return forwardOnlyHintOnFindIterate; 397 } 398 399 /** 400 * Set to true if the ResultSet TYPE_FORWARD_ONLY Hint should be used by default on findIterate PreparedStatements. 401 */ 402 public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) { 403 this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate; 404 } 405 406 /** 407 * Return the DB identity/sequence features for this platform. 408 * 409 * @return the db identity 410 */ 411 public DbIdentity getDbIdentity() { 412 return dbIdentity; 413 } 414 415 /** 416 * Return the SqlLimiter used to apply additional sql around a query to limit 417 * its results. 418 * <p> 419 * Basically add the clauses for limit/offset, rownum, row_number(). 420 * </p> 421 * 422 * @return the sql limiter 423 */ 424 public SqlLimiter getSqlLimiter() { 425 return sqlLimiter; 426 } 427 428 /** 429 * Convert backticks to the platform specific open quote and close quote 430 * <p> 431 * Specific plugins may implement this method to cater for platform specific 432 * naming rules. 433 * </p> 434 * 435 * @param dbName the db name 436 * @return the string 437 */ 438 public String convertQuotedIdentifiers(String dbName) { 439 // Ignore null values e.g. schema name or catalog 440 if (dbName != null && dbName.length() > 0) { 441 if (dbName.charAt(0) == BACK_TICK) { 442 if (dbName.charAt(dbName.length() - 1) == BACK_TICK) { 443 444 String quotedName = getOpenQuote(); 445 quotedName += dbName.substring(1, dbName.length() - 1); 446 quotedName += getCloseQuote(); 447 448 return quotedName; 449 450 } else { 451 logger.error("Missing backquote on [" + dbName + "]"); 452 } 453 } 454 } 455 return dbName; 456 } 457 458 /** 459 * Set to true if select count against anonymous view requires an alias. 460 */ 461 public boolean isSelectCountWithAlias() { 462 return selectCountWithAlias; 463 } 464 465 public String completeSql(String sql, Query<?> query) { 466 if (Boolean.TRUE.equals(query.isForUpdate())) { 467 sql = withForUpdate(sql); 468 } 469 470 return sql; 471 } 472 473 protected String withForUpdate(String sql) { 474 // silently assume the database does not support the "for update" clause. 475 logger.info("it seems your database does not support the 'for update' clause"); 476 477 return sql; 478 } 479 480 /** 481 * Returns the like clause used by this database platform. 482 * <p> 483 * This may include an escape clause to disable a default escape character. 484 */ 485 public String getLikeClause() { 486 return likeClause; 487 } 488 489 /** 490 * Return true if the persistBatchOnCascade setting should be ignored. 491 * <p> 492 * This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode 493 * so can't really be transparently used. 494 * </p> 495 */ 496 public boolean isDisallowBatchOnCascade() { 497 return disallowBatchOnCascade; 498 } 499 500}