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