001package io.ebean.config.dbplatform;
002
003import io.ebean.config.PlatformConfig;
004
005import java.util.EnumMap;
006import java.util.Map;
007
008/**
009 * Used to map bean property types to DB specific types for DDL generation.
010 */
011public class DbPlatformTypeMapping {
012
013  /**
014   * Boolean type used for logical model.
015   */
016  private static class BooleanLogicalType extends DbPlatformType {
017    BooleanLogicalType() {
018      super("boolean", false);
019    }
020    @Override
021    protected void renderLengthScale(int deployLength, int deployScale, StringBuilder sb) {
022      // do not have length - even if platform boolean type does like integer(1)
023    }
024  }
025
026  private static final DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
027
028  private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
029
030  private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
031  private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
032  private static final DbPlatformType CIDR_NATIVE = new DbPlatformType("cidr", false);
033  private static final DbPlatformType CIDR_VARCHAR = new DbPlatformType("varchar", 50);
034
035  private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
036  @SuppressWarnings("unused")
037  private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
038  private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
039  private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
040  private static final DbPlatformType JSON_VARCHAR_PLACEHOLDER = new DbPlatformType("jsonVarcharPlaceholder");
041
042  private static final DbPlatformType POINT = new DbPlatformType("point");
043  private static final DbPlatformType POLYGON = new DbPlatformType("polygon");
044  private static final DbPlatformType LINESTRING = new DbPlatformType("linestring");
045  private static final DbPlatformType MULTIPOINT = new DbPlatformType("multipoint");
046  private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
047  private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
048
049  private final Map<DbType, DbPlatformType> typeMap = new EnumMap<>(DbType.class);
050
051  /**
052   * Return the DbTypeMap with standard (not platform specific) types.
053   * <p>
054   * This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
055   * These types get translated to specific database platform types during DDL generation.
056   */
057  public static DbPlatformTypeMapping logicalTypes() {
058    return new DbPlatformTypeMapping(true);
059  }
060
061  public DbPlatformTypeMapping() {
062    loadDefaults(false);
063  }
064
065  private DbPlatformTypeMapping(boolean logicalTypes) {
066    loadDefaults(logicalTypes);
067  }
068
069  /**
070   * Load the standard types. These can be overridden by DB specific platform.
071   */
072  private void loadDefaults(boolean logicalTypes) {
073    put(DbType.BOOLEAN, BOOLEAN_LOGICAL);
074    put(DbType.BIT);
075    put(DbType.INTEGER);
076    put(DbType.BIGINT);
077    put(DbType.DOUBLE);
078    put(DbType.SMALLINT);
079    put(DbType.TINYINT);
080    put(DbType.BLOB);
081    put(DbType.CLOB);
082    put(DbType.ARRAY);
083    put(DbType.DATE);
084    put(DbType.TIME);
085    put(DbType.TIMESTAMP);
086    put(DbType.LONGVARBINARY);
087    put(DbType.LONGVARCHAR);
088    // most commonly real maps to db float
089    put(DbType.REAL, new DbPlatformType("float"));
090    put(DbType.POINT, POINT);
091    put(DbType.POLYGON, POLYGON);
092    put(DbType.LINESTRING, LINESTRING);
093    put(DbType.MULTIPOINT, MULTIPOINT);
094    put(DbType.MULTILINESTRING, MULTILINESTRING);
095    put(DbType.MULTIPOLYGON, MULTIPOLYGON);
096
097    if (logicalTypes) {
098      // keep it logical for 2 layer DDL generation
099      put(DbType.VARCHAR, new DbPlatformType("varchar"));
100      put(DbType.DECIMAL, new DbPlatformType("decimal"));
101      put(DbType.VARBINARY, new DbPlatformType("varbinary"));
102      put(DbType.BINARY, new DbPlatformType("binary"));
103      put(DbType.CHAR, new DbPlatformType("char"));
104      put(DbType.LOCALDATETIME, new DbPlatformType("localdatetime", false));
105      put(DbType.HSTORE, new DbPlatformType("hstore", false));
106      put(DbType.JSON, new DbPlatformType("json", false));
107      put(DbType.JSONB, new DbPlatformType("jsonb", false));
108      put(DbType.JSONCLOB, new DbPlatformType("jsonclob"));
109      put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
110      put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
111      put(DbType.UUID, UUID_NATIVE);
112      put(DbType.INET, INET_NATIVE);
113      put(DbType.CIDR, CIDR_NATIVE);
114
115    } else {
116      put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
117      put(DbType.DECIMAL, new DbPlatformType("decimal", 16, 3));
118      put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
119      put(DbType.BINARY, new DbPlatformType("binary", 255));
120      put(DbType.CHAR, new DbPlatformType("char", 1));
121      put(DbType.LOCALDATETIME, DbType.TIMESTAMP.createPlatformType());
122      put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
123      put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
124      put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
125      put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER);
126      put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
127      // default to native UUID and override on platform configure()
128      put(DbType.UUID, UUID_NATIVE);
129      put(DbType.INET, INET_VARCHAR);
130      put(DbType.CIDR, CIDR_VARCHAR);
131    }
132  }
133
134  /**
135   * Lookup the platform specific DbType given the standard sql type name.
136   */
137  public DbPlatformType lookup(String name, boolean withScale) {
138    DbType type = lookup.byName(name);
139    if (type == null) {
140      throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
141    }
142    // handle JSON types mapped to clob, blob and varchar
143    switch (type) {
144      case JSONBLOB:
145        return get(DbType.BLOB);
146      case JSONCLOB:
147        return get(DbType.CLOB);
148      case JSONVARCHAR:
149        return get(DbType.VARCHAR);
150      case JSON:
151        return getJsonType(DbType.JSON, withScale);
152      case JSONB:
153        return getJsonType(DbType.JSONB, withScale);
154      default:
155        return get(type);
156    }
157  }
158
159  private DbPlatformType getJsonType(DbType type, boolean withScale) {
160    DbPlatformType dbType = get(type);
161    if (dbType == JSON_CLOB_PLACEHOLDER) {
162      // if we have scale that implies this maps to varchar
163      return withScale ? get(DbType.VARCHAR) : get(DbType.CLOB);
164    }
165    if (dbType == JSON_BLOB_PLACEHOLDER) {
166      return get(DbType.BLOB);
167    }
168    if (dbType == JSON_VARCHAR_PLACEHOLDER) {
169      return get(DbType.VARCHAR);
170    }
171    // Postgres has specific type
172    return get(type);
173  }
174
175  /**
176   * Override the type for a given JDBC type.
177   */
178  private void put(DbType type) {
179    typeMap.put(type, type.createPlatformType());
180  }
181
182  /**
183   * Override the type for a given JDBC type.
184   */
185  public void put(DbType type, DbPlatformType platformType) {
186    typeMap.put(type, platformType);
187  }
188
189  /**
190   * Return the type for a given jdbc type.
191   */
192  public DbPlatformType get(int jdbcType) {
193    return get(lookup.byId(jdbcType));
194  }
195
196  /**
197   * Return the type for a given jdbc type.
198   */
199  public DbPlatformType get(DbType dbType) {
200    return typeMap.get(dbType);
201  }
202
203  /**
204   * Map the UUID appropriately based on native DB support and DatabaseConfig.DbUuid.
205   */
206  public void config(boolean nativeUuidType, PlatformConfig.DbUuid dbUuid) {
207    if (nativeUuidType && dbUuid.useNativeType()) {
208      // native UUID already set by default
209    } else if (dbUuid.useBinary()) {
210      put(DbType.UUID, get(DbType.BINARY).withLength(16));
211    } else {
212      put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
213    }
214  }
215}