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 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
033  private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
034  @SuppressWarnings("unused")
035  private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
036  private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
037  private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
038  private static final DbPlatformType JSON_VARCHAR_PLACEHOLDER = new DbPlatformType("jsonVarcharPlaceholder");
039
040  private static final DbPlatformType POINT = new DbPlatformType("point");
041  private static final DbPlatformType POLYGON = new DbPlatformType("polygon");
042  private static final DbPlatformType LINESTRING = new DbPlatformType("linestring");
043  private static final DbPlatformType MULTIPOINT = new DbPlatformType("multipoint");
044  private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
045  private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
046
047  private final Map<DbType, DbPlatformType> typeMap = new EnumMap<>(DbType.class);
048
049  /**
050   * Return the DbTypeMap with standard (not platform specific) types.
051   * <p>
052   * This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
053   * These types get translated to specific database platform types during DDL generation.
054   */
055  public static DbPlatformTypeMapping logicalTypes() {
056    return new DbPlatformTypeMapping(true);
057  }
058
059  public DbPlatformTypeMapping() {
060    loadDefaults(false);
061  }
062
063  private DbPlatformTypeMapping(boolean logicalTypes) {
064    loadDefaults(logicalTypes);
065  }
066
067  /**
068   * Load the standard types. These can be overridden by DB specific platform.
069   */
070  private void loadDefaults(boolean logicalTypes) {
071
072    put(DbType.BOOLEAN, BOOLEAN_LOGICAL);
073    put(DbType.BIT);
074    put(DbType.INTEGER);
075    put(DbType.BIGINT);
076    put(DbType.DOUBLE);
077    put(DbType.SMALLINT);
078    put(DbType.TINYINT);
079    put(DbType.BLOB);
080    put(DbType.CLOB);
081    put(DbType.ARRAY);
082    put(DbType.DATE);
083    put(DbType.TIME);
084    put(DbType.TIMESTAMP);
085    put(DbType.LONGVARBINARY);
086    put(DbType.LONGVARCHAR);
087    // most commonly real maps to db float
088    put(DbType.REAL, new DbPlatformType("float"));
089
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
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
114    } else {
115      put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
116      put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
117      put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
118      put(DbType.BINARY, new DbPlatformType("binary", 255));
119      put(DbType.CHAR, new DbPlatformType("char", 1));
120
121      put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
122      put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
123      put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
124      put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER);
125      put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
126      // default to native UUID and override on platform configure()
127      put(DbType.UUID, UUID_NATIVE);
128      put(DbType.INET, INET_VARCHAR);
129    }
130  }
131
132  /**
133   * Lookup the platform specific DbType given the standard sql type name.
134   */
135  public DbPlatformType lookup(String name, boolean withScale) {
136
137    DbType type = lookup.byName(name);
138    if (type == null) {
139      throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
140    }
141    // handle JSON types mapped to clob, blob and varchar
142    switch (type) {
143      case JSONBLOB:
144        return get(DbType.BLOB);
145      case JSONCLOB:
146        return get(DbType.CLOB);
147      case JSONVARCHAR:
148        return get(DbType.VARCHAR);
149      case JSON:
150        return getJsonType(DbType.JSON, withScale);
151      case JSONB:
152        return getJsonType(DbType.JSONB, withScale);
153      default:
154        return get(type);
155    }
156  }
157
158  private DbPlatformType getJsonType(DbType type, boolean withScale) {
159
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 ServerConfig.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}