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
074    put(DbType.BOOLEAN, BOOLEAN_LOGICAL);
075    put(DbType.BIT);
076    put(DbType.INTEGER);
077    put(DbType.BIGINT);
078    put(DbType.DOUBLE);
079    put(DbType.SMALLINT);
080    put(DbType.TINYINT);
081    put(DbType.BLOB);
082    put(DbType.CLOB);
083    put(DbType.ARRAY);
084    put(DbType.DATE);
085    put(DbType.TIME);
086    put(DbType.TIMESTAMP);
087    put(DbType.LONGVARBINARY);
088    put(DbType.LONGVARCHAR);
089    // most commonly real maps to db float
090    put(DbType.REAL, new DbPlatformType("float"));
091
092    put(DbType.POINT, POINT);
093    put(DbType.POLYGON, POLYGON);
094    put(DbType.LINESTRING, LINESTRING);
095    put(DbType.MULTIPOINT, MULTIPOINT);
096    put(DbType.MULTILINESTRING, MULTILINESTRING);
097    put(DbType.MULTIPOLYGON, MULTIPOLYGON);
098
099    if (logicalTypes) {
100      // keep it logical for 2 layer DDL generation
101      put(DbType.VARCHAR, new DbPlatformType("varchar"));
102      put(DbType.DECIMAL, new DbPlatformType("decimal"));
103      put(DbType.VARBINARY, new DbPlatformType("varbinary"));
104      put(DbType.BINARY, new DbPlatformType("binary"));
105      put(DbType.CHAR, new DbPlatformType("char"));
106
107      put(DbType.HSTORE, new DbPlatformType("hstore", false));
108      put(DbType.JSON, new DbPlatformType("json", false));
109      put(DbType.JSONB, new DbPlatformType("jsonb", false));
110      put(DbType.JSONCLOB, new DbPlatformType("jsonclob"));
111      put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
112      put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
113      put(DbType.UUID, UUID_NATIVE);
114      put(DbType.INET, INET_NATIVE);
115      put(DbType.CIDR, CIDR_NATIVE);
116
117    } else {
118      put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
119      put(DbType.DECIMAL, new DbPlatformType("decimal", 16, 3));
120      put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
121      put(DbType.BINARY, new DbPlatformType("binary", 255));
122      put(DbType.CHAR, new DbPlatformType("char", 1));
123
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      // default to native UUID and override on platform configure()
130      put(DbType.UUID, UUID_NATIVE);
131      put(DbType.INET, INET_VARCHAR);
132      put(DbType.CIDR, CIDR_VARCHAR);
133    }
134  }
135
136  /**
137   * Lookup the platform specific DbType given the standard sql type name.
138   */
139  public DbPlatformType lookup(String name, boolean withScale) {
140
141    DbType type = lookup.byName(name);
142    if (type == null) {
143      throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
144    }
145    // handle JSON types mapped to clob, blob and varchar
146    switch (type) {
147      case JSONBLOB:
148        return get(DbType.BLOB);
149      case JSONCLOB:
150        return get(DbType.CLOB);
151      case JSONVARCHAR:
152        return get(DbType.VARCHAR);
153      case JSON:
154        return getJsonType(DbType.JSON, withScale);
155      case JSONB:
156        return getJsonType(DbType.JSONB, withScale);
157      default:
158        return get(type);
159    }
160  }
161
162  private DbPlatformType getJsonType(DbType type, boolean withScale) {
163
164    DbPlatformType dbType = get(type);
165    if (dbType == JSON_CLOB_PLACEHOLDER) {
166      // if we have scale that implies this maps to varchar
167      return withScale ? get(DbType.VARCHAR) : get(DbType.CLOB);
168    }
169    if (dbType == JSON_BLOB_PLACEHOLDER) {
170      return get(DbType.BLOB);
171    }
172    if (dbType == JSON_VARCHAR_PLACEHOLDER) {
173      return get(DbType.VARCHAR);
174    }
175    // Postgres has specific type
176    return get(type);
177  }
178
179  /**
180   * Override the type for a given JDBC type.
181   */
182  private void put(DbType type) {
183    typeMap.put(type, type.createPlatformType());
184  }
185
186  /**
187   * Override the type for a given JDBC type.
188   */
189  public void put(DbType type, DbPlatformType platformType) {
190    typeMap.put(type, platformType);
191  }
192
193  /**
194   * Return the type for a given jdbc type.
195   */
196  public DbPlatformType get(int jdbcType) {
197    return get(lookup.byId(jdbcType));
198  }
199
200  /**
201   * Return the type for a given jdbc type.
202   */
203  public DbPlatformType get(DbType dbType) {
204    return typeMap.get(dbType);
205  }
206
207  /**
208   * Map the UUID appropriately based on native DB support and DatabaseConfig.DbUuid.
209   */
210  public void config(boolean nativeUuidType, PlatformConfig.DbUuid dbUuid) {
211    if (nativeUuidType && dbUuid.useNativeType()) {
212      // native UUID already set by default
213    } else if (dbUuid.useBinary()) {
214      put(DbType.UUID, get(DbType.BINARY).withLength(16));
215    } else {
216      put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
217    }
218  }
219}