001package com.avaje.ebean.config.dbplatform; 002 003import com.avaje.ebean.config.ServerConfig; 004 005import java.sql.Types; 006import java.util.HashMap; 007import java.util.Map; 008 009/** 010 * Used to map bean property types to DB specific types for DDL generation. 011 */ 012public class DbTypeMap { 013 014 private static final DbType UUID_NATIVE = new DbType("uuid", false); 015 private static final DbType UUID_PLACEHOLDER = new DbType("uuidPlaceholder"); 016 private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder"); 017 private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder"); 018 private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder"); 019 020 /** 021 * A map to reverse lookup the type by name. 022 * <p> 023 * Used when converting from logical types to platform types which we 024 * want to do with 2 phase DDL generation. 025 */ 026 static Map<String, Integer> lookup = new HashMap<String, Integer>(); 027 028 static { 029 lookup.put("BOOLEAN", Types.BOOLEAN); 030 lookup.put("BIT", Types.BIT); 031 lookup.put("INTEGER", Types.INTEGER); 032 lookup.put("BIGINT", Types.BIGINT); 033 lookup.put("REAL", Types.REAL); 034 // Float is most common REAL mapping to have that as well 035 lookup.put("FLOAT", Types.REAL); 036 037 lookup.put("DOUBLE", Types.DOUBLE); 038 lookup.put("SMALLINT", Types.SMALLINT); 039 lookup.put("TINYINT", Types.TINYINT); 040 lookup.put("DECIMAL", Types.DECIMAL); 041 lookup.put("VARCHAR", Types.VARCHAR); 042 // VARCHAR2 - extra for Oracle specific column definition 043 lookup.put("VARCHAR2", Types.VARCHAR); 044 lookup.put("CHAR", Types.CHAR); 045 lookup.put("BLOB", Types.BLOB); 046 lookup.put("CLOB", Types.CLOB); 047 048 lookup.put("LONGVARBINARY", Types.LONGVARBINARY); 049 lookup.put("LONGVARCHAR", Types.LONGVARCHAR); 050 lookup.put("VARBINARY", Types.VARBINARY); 051 lookup.put("BINARY", Types.BINARY); 052 lookup.put("DATE", Types.DATE); 053 lookup.put("TIME", Types.TIME); 054 lookup.put("TIMESTAMP", Types.TIMESTAMP); 055 056 lookup.put("ARRAY", Types.ARRAY); 057 lookup.put("UUID", DbType.UUID); 058 059 // Not standard java.sql.Types 060 // logical JSON storage types 061 lookup.put("JSON", DbType.JSON); 062 lookup.put("JSONB", DbType.JSONB); 063 lookup.put("JSONCLOB", DbType.JSONClob); 064 lookup.put("JSONBLOB", DbType.JSONBlob); 065 lookup.put("JSONVARCHAR", DbType.JSONVarchar); 066 } 067 068 069 private final Map<Integer, DbType> typeMap = new HashMap<Integer, DbType>(); 070 071 /** 072 * Return the DbTypeMap with standard (not platform specific) types. 073 * <p> 074 * This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob). 075 * These types get translated to specific database platform types during DDL generation. 076 */ 077 public static DbTypeMap logicalTypes() { 078 return new DbTypeMap(true); 079 } 080 081 public DbTypeMap() { 082 loadDefaults(false); 083 } 084 085 private DbTypeMap(boolean logicalTypes) { 086 loadDefaults(logicalTypes); 087 } 088 089 /** 090 * Load the standard types. These can be overridden by DB specific platform. 091 */ 092 private void loadDefaults(boolean logicalTypes) { 093 094 put(Types.BOOLEAN, new DbType("boolean")); 095 put(Types.BIT, new DbType("bit")); 096 097 put(Types.INTEGER, new DbType("integer")); 098 put(Types.BIGINT, new DbType("bigint")); 099 put(Types.REAL, new DbType("float")); 100 put(Types.DOUBLE, new DbType("double")); 101 put(Types.SMALLINT, new DbType("smallint")); 102 put(Types.TINYINT, new DbType("tinyint")); 103 put(Types.DECIMAL, new DbType("decimal", 38)); 104 105 put(Types.VARCHAR, new DbType("varchar", 255)); 106 put(Types.CHAR, new DbType("char", 1)); 107 108 put(Types.BLOB, new DbType("blob")); 109 put(Types.CLOB, new DbType("clob")); 110 111 put(Types.ARRAY, new DbType("array")); 112 113 if (logicalTypes) { 114 // keep it logical for 2 layer DDL generation 115 put(DbType.HSTORE, new DbType("hstore", false)); 116 put(DbType.JSON, new DbType("json", false)); 117 put(DbType.JSONB, new DbType("jsonb", false)); 118 put(DbType.JSONClob, new DbType("jsonclob")); 119 put(DbType.JSONBlob, new DbType("jsonblob")); 120 put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000)); 121 put(DbType.UUID, UUID_NATIVE); 122 123 } else { 124 put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON 125 put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB 126 put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER); 127 put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER); 128 put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER); 129 put(DbType.UUID, UUID_PLACEHOLDER); 130 } 131 132 put(Types.LONGVARBINARY, new DbType("longvarbinary")); 133 put(Types.LONGVARCHAR, new DbType("lonvarchar")); 134 put(Types.VARBINARY, new DbType("varbinary", 255)); 135 put(Types.BINARY, new DbType("binary", 255)); 136 137 put(Types.DATE, new DbType("date")); 138 put(Types.TIME, new DbType("time")); 139 put(Types.TIMESTAMP, new DbType("timestamp")); 140 } 141 142 /** 143 * Lookup the platform specific DbType given the standard sql type name. 144 */ 145 public DbType lookup(String name, boolean withScale) { 146 name = name.trim().toUpperCase(); 147 Integer typeKey = lookup.get(name); 148 if (typeKey == null) { 149 throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type"); 150 } 151 // handle JSON types mapped to clob, blob and varchar 152 switch (typeKey) { 153 case DbType.JSONBlob: 154 return get(Types.BLOB); 155 case DbType.JSONClob: 156 return get(Types.CLOB); 157 case DbType.JSONVarchar: 158 return get(Types.VARCHAR); 159 case DbType.JSON: 160 return getJsonType(DbType.JSON, withScale); 161 case DbType.JSONB: 162 return getJsonType(DbType.JSONB, withScale); 163 default: 164 return get(typeKey); 165 } 166 } 167 168 private DbType getJsonType(int type, boolean withScale) { 169 DbType dbType = get(type); 170 if (dbType == JSON_CLOB_PLACEHOLDER) { 171 // if we have scale that implies this maps to varchar 172 return withScale ? get(Types.VARCHAR) : get(Types.CLOB); 173 } 174 if (dbType == JSON_BLOB_PLACEHOLDER) { 175 return get(Types.BLOB); 176 } 177 if (dbType == JSON_VARCHAR_PLACEHOLDER) { 178 return get(Types.VARCHAR); 179 } 180 // Postgres has specific type 181 return get(type); 182 } 183 184 /** 185 * Override the type for a given JDBC type. 186 */ 187 public void put(int jdbcType, DbType dbType) { 188 typeMap.put(jdbcType, dbType); 189 } 190 191 /** 192 * Return the type for a given jdbc type. 193 */ 194 public DbType get(int jdbcType) { 195 return typeMap.get(jdbcType); 196 } 197 198 /** 199 * Map the UUID appropriately based on native DB support and ServerConfig.DbUuid. 200 */ 201 public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) { 202 if (nativeUuidType && dbUuid.useNativeType()) { 203 put(DbType.UUID, UUID_NATIVE); 204 } else if (dbUuid.useBinary()) { 205 put(DbType.UUID, get(Types.BINARY).withLength(16)); 206 } else { 207 put(DbType.UUID, get(Types.VARCHAR).withLength(40)); 208 } 209 } 210}