001package io.ebean.config; 002 003import io.ebean.annotation.Platform; 004import io.ebean.config.dbplatform.DbType; 005import io.ebean.config.dbplatform.IdType; 006import io.ebean.util.StringHelper; 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.Map; 011import java.util.Map.Entry; 012 013/** 014 * Configuration for DB types such as UUID, Geometry etc. 015 */ 016public class PlatformConfig { 017 018 private boolean allQuotedIdentifiers; 019 020 /** 021 * Set this to true for Postgres FOR UPDATE to use NO KEY option. 022 */ 023 private boolean forUpdateNoKey; 024 025 private DbConstraintNaming constraintNaming; 026 027 /** 028 * Flag set when a supplied constraintNaming is used. 029 */ 030 private boolean customConstraintNaming; 031 032 /** 033 * The database boolean true value (typically either 1, T, or Y). 034 */ 035 private String databaseBooleanTrue; 036 037 /** 038 * The database boolean false value (typically either 0, F or N). 039 */ 040 private String databaseBooleanFalse; 041 042 /** 043 * For DB's using sequences this is the number of sequence values prefetched. 044 */ 045 private int databaseSequenceBatchSize = 20; 046 047 /** 048 * Set for DB's that support both Sequence and Identity (and the default choice is not desired). 049 */ 050 private IdType idType; 051 052 /** 053 * The Geometry SRID value (default 4326). 054 */ 055 private int geometrySRID = 4326; 056 057 /** 058 * Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres). 059 */ 060 private DbUuid dbUuid = DbUuid.AUTO_VARCHAR; 061 062 /** 063 * Set to true to force InetAddress to map to Varchar (for Postgres rather than INET) 064 */ 065 private boolean databaseInetAddressVarchar; 066 067 private boolean caseSensitiveCollation = true; 068 069 private boolean useMigrationStoredProcedures = false; 070 071 /** 072 * Modify the default mapping of standard types such as default precision for DECIMAL etc. 073 */ 074 private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<>(); 075 076 /** 077 * Construct with defaults. 078 */ 079 public PlatformConfig() { 080 this.constraintNaming = new DbConstraintNaming(); 081 } 082 083 /** 084 * Construct based on given config - typically for DbMigration generation with many platforms. 085 */ 086 public PlatformConfig(PlatformConfig platformConfig) { 087 this.forUpdateNoKey = platformConfig.forUpdateNoKey; 088 this.databaseBooleanFalse = platformConfig.databaseBooleanFalse; 089 this.databaseBooleanTrue = platformConfig.databaseBooleanTrue; 090 this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize; 091 this.idType = platformConfig.idType; 092 this.geometrySRID = platformConfig.geometrySRID; 093 this.dbUuid = platformConfig.dbUuid; 094 this.caseSensitiveCollation = platformConfig.caseSensitiveCollation; 095 this.useMigrationStoredProcedures = platformConfig.useMigrationStoredProcedures; 096 this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers; 097 this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar; 098 this.customDbTypeMappings = platformConfig.customDbTypeMappings; 099 this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers); 100 } 101 102 public DbConstraintNaming getConstraintNaming() { 103 return constraintNaming; 104 } 105 106 /** 107 * Set a custom database constraint naming convention. 108 */ 109 public void setConstraintNaming(DbConstraintNaming constraintNaming) { 110 this.customConstraintNaming = true; 111 this.constraintNaming = constraintNaming; 112 } 113 114 /** 115 * Return true if all DB column and table names should use quoted identifiers. 116 */ 117 public boolean isAllQuotedIdentifiers() { 118 return allQuotedIdentifiers; 119 } 120 121 /** 122 * Set to true if all DB column and table names should use quoted identifiers. 123 * <p> 124 * For Postgres pgjdbc version 42.3.0 should be used with datasource property 125 * <em>quoteReturningIdentifiers</em> set to <em>false</em> (refer #2303). 126 */ 127 public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) { 128 this.allQuotedIdentifiers = allQuotedIdentifiers; 129 if (!customConstraintNaming) { 130 this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers); 131 } 132 } 133 134 /** 135 * Return true if the collation is case sensitive. 136 */ 137 public boolean isCaseSensitiveCollation() { 138 return caseSensitiveCollation; 139 } 140 141 /** 142 * Set to false to indicate that the collation is case insensitive. 143 */ 144 public void setCaseSensitiveCollation(boolean caseSensitiveCollation) { 145 this.caseSensitiveCollation = caseSensitiveCollation; 146 } 147 148 /** 149 * Return true if force use of helper stored procedures for migrations. 150 */ 151 public boolean isUseMigrationStoredProcedures() { 152 return useMigrationStoredProcedures; 153 } 154 155 /** 156 * Set true to force use of helper stored procedures for migrations. 157 */ 158 public void setUseMigrationStoredProcedures(boolean useMigrationStoredProcedures) { 159 this.useMigrationStoredProcedures = useMigrationStoredProcedures; 160 } 161 162 /** 163 * Return true if Postgres FOR UPDATE should use the NO KEY option. 164 */ 165 public boolean isForUpdateNoKey() { 166 return forUpdateNoKey; 167 } 168 169 /** 170 * Set to true such that Postgres FOR UPDATE should use the NO KEY option. 171 */ 172 public void setForUpdateNoKey(boolean forUpdateNoKey) { 173 this.forUpdateNoKey = forUpdateNoKey; 174 } 175 176 /** 177 * Return a value used to represent TRUE in the database. 178 * <p> 179 * This is used for databases that do not support boolean natively. 180 * <p> 181 * The value returned is either a Integer or a String (e.g. "1", or "T"). 182 */ 183 public String getDatabaseBooleanTrue() { 184 return databaseBooleanTrue; 185 } 186 187 /** 188 * Set the value to represent TRUE in the database. 189 * <p> 190 * This is used for databases that do not support boolean natively. 191 * <p> 192 * The value set is either a Integer or a String (e.g. "1", or "T"). 193 */ 194 public void setDatabaseBooleanTrue(String databaseBooleanTrue) { 195 this.databaseBooleanTrue = databaseBooleanTrue; 196 } 197 198 /** 199 * Return a value used to represent FALSE in the database. 200 */ 201 public String getDatabaseBooleanFalse() { 202 return databaseBooleanFalse; 203 } 204 205 /** 206 * Set the value used to represent FALSE in the database. 207 */ 208 public void setDatabaseBooleanFalse(String databaseBooleanFalse) { 209 this.databaseBooleanFalse = databaseBooleanFalse; 210 } 211 212 /** 213 * Return the number of DB sequence values that should be preallocated. 214 */ 215 public int getDatabaseSequenceBatchSize() { 216 return databaseSequenceBatchSize; 217 } 218 219 /** 220 * Set the number of DB sequence values that should be preallocated. 221 */ 222 public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) { 223 this.databaseSequenceBatchSize = databaseSequenceBatchSize; 224 } 225 226 /** 227 * Return the Geometry SRID. 228 */ 229 public int getGeometrySRID() { 230 return geometrySRID; 231 } 232 233 /** 234 * Set the Geometry SRID. 235 */ 236 public void setGeometrySRID(int geometrySRID) { 237 this.geometrySRID = geometrySRID; 238 } 239 240 /** 241 * Return the DB type used to store UUID. 242 */ 243 public DbUuid getDbUuid() { 244 return dbUuid; 245 } 246 247 /** 248 * Set the DB type used to store UUID. 249 */ 250 public void setDbUuid(DbUuid dbUuid) { 251 this.dbUuid = dbUuid; 252 } 253 254 /** 255 * Return the IdType to use (or null for the default choice). 256 */ 257 public IdType getIdType() { 258 return idType; 259 } 260 261 /** 262 * Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired). 263 */ 264 public void setIdType(IdType idType) { 265 this.idType = idType; 266 } 267 268 /** 269 * Return true if InetAddress should map to varchar column (rather than Postgres INET). 270 */ 271 public boolean isDatabaseInetAddressVarchar() { 272 return databaseInetAddressVarchar; 273 } 274 275 /** 276 * Set to true to force InetAddress to map to varchar column. 277 */ 278 public void setDatabaseInetAddressVarchar(boolean databaseInetAddressVarchar) { 279 this.databaseInetAddressVarchar = databaseInetAddressVarchar; 280 } 281 282 /** 283 * Add a custom type mapping. 284 * <pre>{@code 285 * 286 * // set the default mapping for BigDecimal.class/decimal 287 * config.addCustomMapping(DbType.DECIMAL, "decimal(18,6)"); 288 * 289 * // set the default mapping for String.class/varchar but only for Postgres 290 * config.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES); 291 * 292 * }</pre> 293 * 294 * @param type The DB type this mapping should apply to 295 * @param columnDefinition The column definition that should be used 296 * @param platform Optionally specify the platform this mapping should apply to. 297 */ 298 public void addCustomMapping(DbType type, String columnDefinition, Platform platform) { 299 customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform)); 300 } 301 302 /** 303 * Add a custom type mapping that applies to all platforms. 304 * <pre>{@code 305 * 306 * // set the default mapping for BigDecimal/decimal 307 * config.addCustomMapping(DbType.DECIMAL, "decimal(18,6)"); 308 * 309 * // set the default mapping for String/varchar 310 * config.addCustomMapping(DbType.VARCHAR, "text"); 311 * 312 * }</pre> 313 * 314 * @param type The DB type this mapping should apply to 315 * @param columnDefinition The column definition that should be used 316 */ 317 public void addCustomMapping(DbType type, String columnDefinition) { 318 customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition)); 319 } 320 321 /** 322 * Return the list of custom type mappings. 323 */ 324 public List<CustomDbTypeMapping> getCustomTypeMappings() { 325 return customDbTypeMappings; 326 } 327 328 public void loadSettings(PropertiesWrapper p) { 329 330 idType = p.getEnum(IdType.class, "idType", idType); 331 forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey); 332 databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize); 333 databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue); 334 databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse); 335 databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar); 336 caseSensitiveCollation = p.getBoolean("caseSensitiveCollation", caseSensitiveCollation); 337 useMigrationStoredProcedures = p.getBoolean("useMigrationStoredProcedures", useMigrationStoredProcedures); 338 339 DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null); 340 if (dbUuid != null) { 341 setDbUuid(dbUuid); 342 } 343 if (p.getBoolean("uuidStoreAsBinary", false)) { 344 setDbUuid(DbUuid.BINARY); 345 } 346 347 int srid = p.getInt("geometrySRID", 0); 348 if (srid > 0) { 349 setGeometrySRID(srid); 350 } 351 352 // Mapping is specified in the form: BOOLEAN=int(1);BIT=int(1); 353 String mapping = p.get("mapping"); 354 if (mapping != null && !mapping.isEmpty()) { 355 Map<String, String> map = StringHelper.delimitedToMap(mapping, ";", "="); 356 for (Entry<String, String> entry : map.entrySet()) { 357 addCustomMapping(DbType.valueOf(entry.getKey()), entry.getValue()); 358 } 359 } 360 361 boolean quotedIdentifiers = p.getBoolean("allQuotedIdentifiers", allQuotedIdentifiers); 362 if (quotedIdentifiers != allQuotedIdentifiers) { 363 // potentially also set to use matching naming convention 364 setAllQuotedIdentifiers(quotedIdentifiers); 365 } 366 } 367 368 /** 369 * Specify how UUID is stored. 370 */ 371 public enum DbUuid { 372 373 /** 374 * Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40). 375 */ 376 AUTO_VARCHAR(true, false, false), 377 378 /** 379 * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16). 380 */ 381 AUTO_BINARY(true, true, false), 382 383 /** 384 * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16) with optimized packing. 385 */ 386 AUTO_BINARY_OPTIMIZED(true, true, true), 387 388 /** 389 * Store using DB VARCHAR(40). 390 */ 391 VARCHAR(false, false, false), 392 393 /** 394 * Store using DB BINARY(16). 395 */ 396 BINARY(false, true, false), 397 398 /** 399 * Store using DB BINARY(16) with optimized packing. 400 */ 401 BINARY_OPTIMIZED(false, true, true); 402 403 boolean nativeType; 404 boolean binary; 405 boolean binaryOptimized; 406 407 DbUuid(boolean nativeType, boolean binary, boolean binaryOptimized) { 408 this.nativeType = nativeType; 409 this.binary = binary; 410 this.binaryOptimized = binaryOptimized; 411 } 412 413 /** 414 * Return true if native UUID type is preferred. 415 */ 416 public boolean useNativeType() { 417 return nativeType; 418 } 419 420 /** 421 * Return true if BINARY(16) storage is preferred over VARCHAR(40). 422 */ 423 public boolean useBinary() { 424 return binary; 425 } 426 427 /** 428 * Return true, if optimized packing should be used. 429 */ 430 public boolean useBinaryOptimized() { 431 return binaryOptimized; 432 } 433 } 434}