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