/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.database.dialect; import java.io.File; import java.math.BigDecimal; import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.GenerationType; import javax.persistence.SequenceGenerator; import javax.persistence.TableGenerator; import jef.database.ORMConfig; import jef.database.annotation.DateGenerateType; import jef.database.annotation.HiloGeneration; import jef.database.dialect.type.AutoGuidMapping; import jef.database.dialect.type.AutoIntMapping; import jef.database.dialect.type.AutoLongMapping; import jef.database.dialect.type.AutoStringMapping; import jef.database.dialect.type.BlobByteArrayMapping; import jef.database.dialect.type.BlobFileMapping; import jef.database.dialect.type.BlobObjectMapping; import jef.database.dialect.type.BlobStringMapping; import jef.database.dialect.type.CharBooleanMapping; import jef.database.dialect.type.CharCharMapping; import jef.database.dialect.type.CharDateMapping; import jef.database.dialect.type.CharEnumMapping; import jef.database.dialect.type.CharIntMapping; import jef.database.dialect.type.CharLongMapping; import jef.database.dialect.type.CharStringMapping; import jef.database.dialect.type.CharTimestampMapping; import jef.database.dialect.type.ClobCharArrayMapping; import jef.database.dialect.type.ClobFileMapping; import jef.database.dialect.type.ClobStringMapping; import jef.database.dialect.type.ColumnMapping; import jef.database.dialect.type.DateDateMapping; import jef.database.dialect.type.DateSDateMapping; import jef.database.dialect.type.DateStringMapping; import jef.database.dialect.type.DelegatorBoolean; import jef.database.dialect.type.NumBigDateMapping; import jef.database.dialect.type.NumBigDecimalMapping; import jef.database.dialect.type.NumBigIntMapping; import jef.database.dialect.type.NumBigLongMapping; import jef.database.dialect.type.NumBigStringMapping; import jef.database.dialect.type.NumDoubleDoubleMapping; import jef.database.dialect.type.NumDoubleFloatMapping; import jef.database.dialect.type.NumDoubleStringMapping; import jef.database.dialect.type.NumFloatDoubleMapping; import jef.database.dialect.type.NumFloatMapping; import jef.database.dialect.type.NumIntBooleanMapping; import jef.database.dialect.type.NumIntEnumMapping; import jef.database.dialect.type.NumIntIntMapping; import jef.database.dialect.type.NumIntLongMapping; import jef.database.dialect.type.NumIntStringMapping; import jef.database.dialect.type.TimestampDateMapping; import jef.database.dialect.type.TimestampLongMapping; import jef.database.dialect.type.TimestampTsMapping; import jef.database.dialect.type.VarcharDateMapping; import jef.database.dialect.type.VarcharDoubleMapping; import jef.database.dialect.type.VarcharEnumMapping; import jef.database.dialect.type.VarcharFloatMapping; import jef.database.dialect.type.VarcharIntMapping; import jef.database.dialect.type.VarcharLongMapping; import jef.database.dialect.type.VarcharStringMapping; import jef.database.dialect.type.VarcharTimestampMapping; import jef.database.dialect.type.XmlStringMapping; import jef.database.meta.AnnotationProvider.FieldAnnotationProvider; import jef.database.meta.Column; import jef.database.meta.ColumnChange; import jef.database.meta.ColumnChange.Change; import jef.database.meta.Feature; import jef.database.support.RDBMS; import jef.tools.StringUtils; /** * 描述一个数据库列的类型 * * @author Administrator * */ public abstract class ColumnType { protected boolean nullable = true; protected boolean unique = false; public Object defaultValue; public String toString() { Map<String, Object> map = toJpaAnnonation(); return String.valueOf(map.get("columnDefinition")); } public boolean isUnique() { return unique; } public void setUnique(boolean unique) { this.unique = unique; } /** * 返回字段是否可为空 * * @return */ public boolean isNullable() { return nullable; } /** * 指定字段为空或者可空 * * @param nullAble * @return */ public ColumnType setNullable(boolean nullAble) { this.nullable = nullAble; return this; } /** * 指定某个数据库字段为非空 * * @return */ public ColumnType notNull() { this.nullable = false; return this; } /** * 为某个数据库字段指定缺省值 * * @param obj * @return */ public ColumnType defaultIs(Object obj) { this.defaultValue = obj; return this; } /** * 当代码生成时,转换为需要加注在属性上的Annotation * * @return */ public Map<String, Object> toJpaAnnonation() { Map<String, Object> map = new HashMap<String, Object>(); putAnnonation(map); return map; } /** * 设置列的缺省值 * * @param obj */ public void setDefault(Object obj) { this.defaultValue = obj; } /** * 比较列定义, 一样就返回true * * @param c * @param profile * @return */ public List<ColumnChange> isEqualTo(Column c, DatabaseDialect profile) { ColumnType oldType = c.toColumnType(profile); ColumnType newType = this; List<ColumnChange> result = new ArrayList<ColumnChange>(); // 对自增类型的数据不检查缺省值(兼容PG) if (!(this instanceof AutoIncrement)) { // 检查缺省值 String a1 = profile.toDefaultString(oldType.defaultValue, oldType.getSqlType(), oldType.getSqlType()); String a2 = profile.toDefaultString(newType.defaultValue, newType.getSqlType(), newType.getSqlType()); // 非字符串比较情况下全部按小写处理 if (a1 != null && !a1.startsWith("'")) { a1 = StringUtils.lowerCase(a1); } if (a2 != null && !a2.startsWith("'")) { a2 = StringUtils.lowerCase(a2); } if (!StringUtils.equals(a1, a2)) { ColumnChange chg; if (StringUtils.isEmpty(a2)) { chg = new ColumnChange(Change.CHG_DROP_DEFAULT); } else { chg = new ColumnChange(Change.CHG_DEFAULT); } chg.setFrom(a1); chg.setTo(a2); result.add(chg); } } // 针对NUll特性检查 if (oldType.nullable != this.nullable) { if (this.nullable) { result.add(new ColumnChange(Change.CHG_TO_NULL)); } else { result.add(new ColumnChange(Change.CHG_TO_NOT_NULL)); } } // 再检查数据类型 if (this.getClass() == Boolean.class) {// 长度为1的字符或数字都算匹配.目前对boolean的处理较为含糊 if (c.getColumnSize() == 1) { return result;// 不用再比了。 } } if (profile.getName() == RDBMS.oracle) {// 很特殊的情况,Oracle下不映射其Timestamp类型,因此Oracle的Date和TimeStamp即被认为是等效的 if (oldType.getClass() == Date.class || oldType.getClass() == TimeStamp.class) { if (newType.getClass() == Date.class || newType.getClass() == TimeStamp.class) { return result;// 不用再比了,认为数据类型一样 } } } if (c.getDataTypeCode() == newType.getSqlType()) { if (!newType.compare(oldType, profile)) { ColumnChange cg = createChange(oldType, c.getDataType(), newType, profile); if (cg != null) result.add(cg); } } else { ColumnChange cg = createChange(oldType, c.getDataType(), newType, profile); if (cg != null) result.add(cg); } return result; } /** * 针对几个非常规类型才进行的比较,目的是比较其长度等定义,最终返回变化 * * @param type * @param profile * @return */ protected abstract boolean compare(ColumnType type, DatabaseDialect profile); /** * 生成Annotation * * @param map */ protected abstract void putAnnonation(Map<String, Object> map); /** * 返回缺省的Java数据类型 * * @return */ public abstract Class<?> getDefaultJavaType(); /** * 返回对应于java.sql.Types的类型 * * @return */ public abstract int getSqlType(); /** * 生成到特定字段类型的映射对象 * * @param fieldType * @return */ public abstract ColumnMapping getMappingType(Class<?> fieldType); public final static class Char extends ColumnType implements SqlTypeSized { protected int length; public Char(int length) { this.length = length; } public int getLength() { return length; } public Class<?> getDefaultJavaType() { return java.lang.String.class; } @Override protected void putAnnonation(Map<String, Object> map) { String def = "char(" + length + ")"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); map.put("length", length); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { Char rhs = (Char) type; return rhs.length == this.length; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == String.class || fieldType == Object.class) { return new CharStringMapping(); } else if (fieldType == Character.class || fieldType == Character.TYPE) { return new CharCharMapping(); } else if (fieldType.isEnum()) { return new CharEnumMapping(); } else if (fieldType == java.util.Date.class) { return new CharDateMapping(); } else if (fieldType == java.sql.Timestamp.class) { return new CharTimestampMapping(); } else if (fieldType == Integer.class || fieldType == Integer.TYPE) { return new CharIntMapping(); } else if (fieldType == Long.class || fieldType == Long.TYPE) { return new CharLongMapping(); } else if (length == 1 && (fieldType == java.lang.Boolean.class || fieldType == java.lang.Boolean.TYPE)) { return new CharBooleanMapping(); } throw new IllegalArgumentException("Char can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { return Types.CHAR; } @Override public int getPrecision() { return 0; } @Override public int getScale() { return 0; } } public static class Varchar extends ColumnType implements SqlTypeSized { protected int length; public Varchar(int length) { this.length = length; } public int getLength() { return length; } @Override public Class<?> getDefaultJavaType() { return java.lang.String.class; } @Override protected void putAnnonation(Map<String, Object> map) { String def = "varchar(" + length + ")"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); map.put("length", length); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { if (!(type instanceof Varchar)) { return false; } Varchar rhs = (Varchar) type; return rhs.length == this.length; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == String.class || fieldType == Object.class) { return new VarcharStringMapping(); } else if (fieldType.isEnum()) { return new VarcharEnumMapping(); } else if (fieldType == Integer.class || fieldType == Integer.TYPE) { return new VarcharIntMapping(); } else if (fieldType == Float.class || fieldType == Float.TYPE) { return new VarcharFloatMapping(); } else if (fieldType == java.lang.Double.class || fieldType == java.lang.Double.TYPE) { return new VarcharDoubleMapping(); } else if (fieldType == java.lang.Long.class || fieldType == java.lang.Long.TYPE) { return new VarcharLongMapping(); } else if (fieldType == java.util.Date.class) { return new VarcharDateMapping(); } else if (fieldType == java.sql.Timestamp.class) { return new VarcharTimestampMapping(); } throw new IllegalArgumentException("Varchar can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { return Types.VARCHAR; } @Override public int getPrecision() { return 0; } @Override public int getScale() { return 0; } } /** * 对应Java类型: Boolean/boolean 对应数据库类型: Oracle: number(1) mySql: text Derby: * varchar2 sql server:不支持 其他:不支持 */ public static final class Boolean extends ColumnType { @Override public Class<?> getDefaultJavaType() { return java.lang.Boolean.class; } @Override protected void putAnnonation(Map<String, Object> map) { String def = "boolean"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { return true; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == java.lang.Boolean.class || fieldType == java.lang.Boolean.TYPE || fieldType == Object.class) { return new DelegatorBoolean(); } else { throw new UnsupportedOperationException("can not support mapping from [" + fieldType.getName() + " -> boolean]"); } } @Override public int getSqlType() { return Types.BOOLEAN; } } public static final class Double extends ColumnType implements SqlTypeSized { int precision = 16; int scale = 6; public Double(int precision, int scale) { if (precision > 0) this.precision = precision; if (scale > 0) this.scale = scale; } public Class<?> getDefaultJavaType() { if (precision >= 12 || precision + scale >= 16) { return java.lang.Double.class; } else { return java.lang.Float.class; } } @Override protected void putAnnonation(Map<String, Object> map) { String def = "number(" + precision + "," + scale + ")"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); map.put("precision", precision); map.put("scale", scale); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { Double rhs = (Double) type; if (profile.getName() == RDBMS.oracle) { return rhs.precision == this.precision && rhs.scale == this.scale; } else { int p1 = Math.abs(rhs.precision - this.precision); int p2 = Math.abs(rhs.scale - this.scale); return p1 < 3 && p2 < 3; } } @Override public ColumnMapping getMappingType(Class<?> fieldType) { boolean isBig = (precision >= 18); if (fieldType == BigDecimal.class) { return new NumBigDecimalMapping(); } if (isBig) { if (fieldType == java.lang.Double.class || fieldType == java.lang.Double.TYPE || fieldType == Object.class) { return new NumDoubleDoubleMapping(); } else if (fieldType == Float.class || fieldType == Float.TYPE) { return new NumDoubleFloatMapping(); } else if (fieldType == String.class) { return new NumDoubleStringMapping(); } } else { if (fieldType == java.lang.Double.class || fieldType == java.lang.Double.TYPE) { return new NumFloatDoubleMapping(); } else if (fieldType == Float.class || fieldType == Float.TYPE || fieldType == Object.class) { return new NumFloatMapping(); } } throw new IllegalArgumentException("Double can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { if (precision >= 12 || precision + scale >= 16) { return Types.DOUBLE; } else { return Types.FLOAT; } } @Override public int getLength() { return precision; } @Override public int getPrecision() { return precision; } @Override public int getScale() { return scale; } } // Int 和BigInt,BigInt对应Long,默认10 public static class Int extends ColumnType implements SqlTypeSized, SqlTypeVersioned, SqlTypeDateTimeGenerated { int precision = 8; boolean isVersion; private DateGenerateType generateType; public Int(int precision) { if (precision > 0) { this.precision = precision; } if (precision > 100) { throw new IllegalArgumentException("A type of number(" + precision + ") is too big for database."); } } public Class<?> getDefaultJavaType() { if (precision > 10) { return nullable ? java.lang.Long.class : java.lang.Long.TYPE; } else { return nullable ? java.lang.Integer.class : java.lang.Integer.TYPE; } } @Override protected void putAnnonation(Map<String, Object> map) { if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); String def = "number(" + precision + ")"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); map.put("precision", precision); } public int getPrecision() { return precision; } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { Int rhs = (Int) type; if (profile.getName() == RDBMS.oracle) { return rhs.precision == this.precision; } else { return Math.abs(rhs.precision - this.precision) < 3;// 轻微长度误差不管 } } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == java.lang.Boolean.class || fieldType == java.lang.Boolean.TYPE) { return new NumIntBooleanMapping(); } boolean isBig = precision > 10; if (isBig) { if (fieldType == Long.class || fieldType == Long.TYPE || fieldType == Object.class) { return new NumBigLongMapping(); } else if (fieldType == Integer.class || fieldType == Integer.TYPE) { return new NumBigIntMapping(); } else if (fieldType == java.util.Date.class) { return new NumBigDateMapping(); } else if (fieldType == String.class) { return new NumBigStringMapping(); } else if (fieldType.isEnum()) { return new NumIntEnumMapping(); } } else { if (fieldType == Long.class || fieldType == Long.TYPE) { return new NumIntLongMapping(); } else if (fieldType == Integer.class || fieldType == Integer.TYPE || fieldType == Object.class) { return new NumIntIntMapping(); } else if (fieldType == String.class) { return new NumIntStringMapping(); } else if (fieldType == java.util.Date.class) { return new NumBigDateMapping(); } else if (fieldType == java.lang.Boolean.class || fieldType == java.lang.Boolean.TYPE) { return new NumIntBooleanMapping(); } else if (fieldType.isEnum()) { return new NumIntEnumMapping(); } } throw new IllegalArgumentException("Int can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { if (precision < 3) { return Types.TINYINT; } else if (precision < 5) { return Types.SMALLINT; } else if (precision < 13) { return Types.INTEGER; } else { return Types.BIGINT; } } @Override public int getLength() { return precision; } @Override public int getScale() { return 0; } @Override public boolean isVersion() { return isVersion; } @Override public ColumnType setVersion(boolean flag) { this.isVersion = flag; return this; } @Override public DateGenerateType getGenerateType() { return generateType; } @Override public ColumnType setGenerateType(DateGenerateType dateGenerateType) { this.generateType = dateGenerateType; return this; } } public static final class Date extends ColumnType implements SqlTypeDateTimeGenerated { private DateGenerateType generateType; public DateGenerateType getGenerateType() { return generateType; } public ColumnType setGenerateType(DateGenerateType generateType) { this.generateType = generateType; return this; } public Class<?> getDefaultJavaType() { return java.util.Date.class; } @Override protected void putAnnonation(Map<String, Object> map) { if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); String def = "date"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { return true; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == java.sql.Date.class) { return new DateSDateMapping(); } else if (fieldType == java.util.Date.class || fieldType == Object.class) { return new DateDateMapping(); } else if (fieldType == String.class) { return new DateStringMapping(); } throw new IllegalArgumentException("Date can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { return Types.DATE; } } public static final class TimeStamp extends ColumnType implements SqlTypeDateTimeGenerated, SqlTypeVersioned { private DateGenerateType generateType; private boolean isVersion; public DateGenerateType getGenerateType() { return generateType; } public ColumnType setGenerateType(DateGenerateType generated) { this.generateType = generated; return this; } public Class<?> getDefaultJavaType() { return java.util.Date.class; } @Override protected void putAnnonation(Map<String, Object> map) { if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); String def = "timestamp"; if (defaultValue != null) { def = def + " default " + String.valueOf(defaultValue); } map.put("columnDefinition", def); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { return true; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == java.sql.Timestamp.class) { return new TimestampTsMapping(); } else if (fieldType == java.util.Date.class || fieldType == Object.class) { return new TimestampDateMapping(); } else if (fieldType == java.lang.Long.class || fieldType == java.lang.Long.TYPE) { return new TimestampLongMapping(); } throw new IllegalArgumentException("TimeStamp can not mapping to class " + fieldType.getName()); } public int getSqlType() { return Types.TIMESTAMP; } @Override public boolean isVersion() { return isVersion; } @Override public ColumnType setVersion(boolean flag) { this.isVersion = flag; return this; } } /** * 对应Java数据类型:int/Integer 对应数据库类型:oracle:Clob mySql: text Derby: varchar2 * sql server:不支持 其他:不支持 其他:自增 * * @author Administrator */ public static final class AutoIncrement extends Int { private GenerationType type; private TableGenerator tableGenerator; private SequenceGenerator seqGenerator; private HiloGeneration hilo; public TableGenerator getTableGenerator() { return tableGenerator; } public SequenceGenerator getSeqGenerator() { return seqGenerator; } public GenerationType getType() { return type; } public HiloGeneration getHiloConfig() { return hilo; } public AutoIncrement(int i) { super(i); init(GenerationType.AUTO, null, null, null); } public AutoIncrement(int i, GenerationType type, FieldAnnotationProvider fieldProvider) { super(i); TableGenerator tg = fieldProvider.getAnnotation(TableGenerator.class); SequenceGenerator sg = fieldProvider.getAnnotation(SequenceGenerator.class); HiloGeneration hilo = fieldProvider.getAnnotation(HiloGeneration.class); init(type, tg, sg, hilo); } private void init(GenerationType type, TableGenerator tg, SequenceGenerator sg, HiloGeneration hilo) { this.nullable = false; if (ORMConfig.getInstance().isGenerateBySequenceAndIdentityToAUTO()) { if (type == GenerationType.IDENTITY || type == GenerationType.SEQUENCE) { type = GenerationType.AUTO; } } this.type = type; this.tableGenerator = tg; this.seqGenerator = sg; } @Override protected void putAnnonation(Map<String, Object> map) { super.putAnnonation(map); map.put("@Id", null); map.put("@GeneratedValue", "strategy=GenerationType.SEQUENCE"); } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == Integer.class || fieldType == Integer.TYPE) { return new AutoIntMapping(); } else if (fieldType == Long.class || fieldType == Long.TYPE) { return new AutoLongMapping(); } else if (fieldType == String.class) { return new AutoStringMapping(); } else if (fieldType == Object.class) { return this.precision > 10 ? new AutoLongMapping() : new AutoIntMapping(); } throw new IllegalArgumentException("AutoIncrement can not mapping to class " + fieldType.getName()); } /** * 返回自增实现方式 * * @param profile * @param allowIdentity * @return 以下三种之一 * <ol> * <li>GenerationType.IDENTITY</li> * <li>GenerationType.SEQUENCE</li> * <li>GenerationType.TABLE</li> * </ol> */ public GenerationType getGenerationType(DatabaseDialect profile, boolean allowIdentity) { boolean supportSequence = profile.has(Feature.SUPPORT_SEQUENCE); // 如果配置为自动的 if (type == GenerationType.AUTO) { if (allowIdentity) { if (profile.notHas(Feature.AUTOINCREMENT_NEED_SEQUENCE)) return GenerationType.IDENTITY; } if (supportSequence) return GenerationType.SEQUENCE; return GenerationType.TABLE; } // 配置为自增,但不允许自增的情况 if (type == GenerationType.IDENTITY && !allowIdentity) { return supportSequence ? GenerationType.SEQUENCE : GenerationType.TABLE; } // 配置为序列,但不支持序列时 if (type == GenerationType.SEQUENCE && !supportSequence) { return allowIdentity ? GenerationType.IDENTITY : GenerationType.TABLE; } return type; } public Int toNormalType() { Int i = new ColumnType.Int(precision); i.nullable = false; return i; } } /** * 对应Java数据类型:String 对应数据库类型:oracle:Clob mySql: text Derby: varchar2 sql * server:不支持 其他:不支持 其他:第一次插入时自动生成 */ public static final class GUID extends Varchar { private boolean removeDash; public GUID() { super(36); } public boolean isRemoveDash() { return removeDash; } public void setRemoveDash(boolean removeDash) { this.removeDash = removeDash; } @Override protected void putAnnonation(Map<String, Object> map) { super.putAnnonation(map); map.put("@Id", null); map.put("@GeneratedValue", "strategy=GenerationType.IDENTITY"); } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (!CharSequence.class.isAssignableFrom(fieldType)) { throw new IllegalArgumentException(); } return new AutoGuidMapping(); } public ColumnType toNormalType() { return new ColumnType.Varchar(36).setNullable(false); } } /** * 对应Java数据类型:String/char[]/File/CharBuffer/BigDataBuffer * 对应数据库类型:oracle:Clob mySql: text Derby: varchar2 sql server:不支持 其他:不支持 * * @author Administrator * */ public static class Clob extends ColumnType implements SqlTypeSized { private int length; public Class<?> getDefaultJavaType() { return java.lang.String.class; } @Override protected void putAnnonation(Map<String, Object> map) { if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); map.put("columnDefinition", "clob"); map.put("@Lob", null); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { return type instanceof Clob; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == char[].class) { return new ClobCharArrayMapping(); } else if (fieldType == File.class) { return new ClobFileMapping(); } else if (fieldType == String.class) { return new ClobStringMapping(); } else if (fieldType == Object.class) { return new ClobStringMapping(); } throw new IllegalArgumentException("Clob can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { return Types.CLOB; } @Override public int getLength() { return length; } @Override public int getPrecision() { return 0; } @Override public int getScale() { return 0; } } /** * 对应Java数据类型:String/char[]/byte[]/File/Image/BigDataBuffer * 对应数据库类型:oracle:Clob mySql: text Derby: varchar2 sql server:不支持 其他:不支持 * * @author Administrator */ public static class Blob extends ColumnType implements SqlTypeSized { private int length; public Class<?> getDefaultJavaType() { return byte[].class; } @Override protected void putAnnonation(Map<String, Object> map) { if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); map.put("columnDefinition", "blob"); map.put("@Lob", null); } @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { return type instanceof Blob; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { if (fieldType == byte[].class) { return new BlobByteArrayMapping(); } else if (fieldType == File.class) { return new BlobFileMapping(); } else if (fieldType == String.class) { return new BlobStringMapping(); } else if (fieldType == Object.class) { return new BlobObjectMapping(); } throw new IllegalArgumentException("Blob can not mapping to class " + fieldType.getName()); } @Override public int getSqlType() { return Types.BLOB; } @Override public int getLength() { return length; } @Override public int getPrecision() { return 0; } @Override public int getScale() { return 0; } } public static class XML extends ColumnType { @Override protected boolean compare(ColumnType type, DatabaseDialect profile) { return true; } @Override protected void putAnnonation(Map<String, Object> map) { if (!nullable) map.put("nullable", java.lang.Boolean.FALSE); map.put("columnDefinition", "xml"); } @Override public Class<?> getDefaultJavaType() { return String.class; } @Override public ColumnMapping getMappingType(Class<?> fieldType) { return new XmlStringMapping(); } @Override public int getSqlType() { return Types.SQLXML; } } static ColumnChange createChange(ColumnType oldType, String rawType, ColumnType newType, DatabaseDialect profile) { ColumnChange change = new ColumnChange(Change.CHG_DATATYPE); change.setFrom(rawType);// 这里要注意不要生成带有null // 值的文字,即只单纯的类型 change.setTo(profile.getCreationComment(newType, false)); if (change.getFrom().equalsIgnoreCase(change.getTo())) return null; String oldValue = profile.getCreationComment(oldType, false); if (oldValue.equals(change.getTo())) { return null; } return change; } }