View Javadoc

1   // Copyright 2011 Leo Przybylski. All rights reserved.
2   //
3   // Redistribution and use in source and binary forms, with or without modification, are
4   // permitted provided that the following conditions are met:
5   //
6   //    1. Redistributions of source code must retain the above copyright notice, this list of
7   //       conditions and the following disclaimer.
8   //
9   //    2. Redistributions in binary form must reproduce the above copyright notice, this list
10  //       of conditions and the following disclaimer in the documentation and/or other materials
11  //       provided with the distribution.
12  //
13  // THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED
14  // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
15  // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
16  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19  // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
21  // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  //
23  // The views and conclusions contained in the software and documentation are those of the
24  // authors and should not be interpreted as representing official policies, either expressed
25  // or implied, of Leo Przybylski.
26  package liquibase.database.typeconversion.ext;
27  
28  import liquibase.database.structure.Column;
29  import liquibase.database.structure.type.BlobType;
30  import liquibase.database.structure.type.BooleanType;
31  import liquibase.database.structure.type.ClobType;
32  import liquibase.database.structure.type.CustomType;
33  import liquibase.database.structure.type.NumberType;
34  import liquibase.database.Database;
35  import liquibase.database.core.MySQLDatabase;
36  import liquibase.database.structure.type.DataType;
37  import liquibase.database.structure.type.DateTimeType;
38  import liquibase.exception.UnexpectedLiquibaseException;
39  
40  import java.lang.reflect.Field;
41  import java.sql.Types;
42  import java.util.Arrays;
43  import java.util.List;
44  
45  import static liquibase.ext.Constants.EXTENSION_PRIORITY;
46  
47  /**
48   *
49   * @author Leo Przybylski
50   */
51  public class MySQLTypeConverter extends liquibase.database.typeconversion.core.MySQLTypeConverter {
52  
53      public int getPriority() {
54          return EXTENSION_PRIORITY;
55      }
56  
57  
58      protected static final List<Integer> oneParam = Arrays.asList(
59          Types.CHAR,
60          -15, // Types.NCHAR in java 1.6,
61          Types.VARCHAR,
62          -9, //Types.NVARCHAR in java 1.6,
63          Types.VARBINARY,
64          Types.DOUBLE,
65          Types.FLOAT
66          );
67          
68      protected static final List<Integer> twoParams = Arrays.asList(
69          Types.DECIMAL,
70          Types.NUMERIC,
71          Types.REAL
72          );
73      
74      
75      @Override
76      public NumberType getNumberType() {
77          return new NumberType("NUMERIC");
78      }
79  
80      @Override
81      public String convertToDatabaseTypeString(Column referenceColumn, Database database) {        
82          final StringBuilder retval = new StringBuilder();
83          try {
84              retval.append(getSqlTypeName(referenceColumn.getDataType()));
85          }
86          catch (Exception e) {
87              retval.append(referenceColumn.getTypeName());
88          }
89  
90          
91          final boolean hasOneParam  = oneParam.contains(referenceColumn.getDataType());
92          final boolean hasTwoParams = twoParams.contains(referenceColumn.getDataType());
93          
94  
95          if (hasOneParam || hasTwoParams) {
96              retval.append("(").append(referenceColumn.getColumnSize());
97              if (hasTwoParams) {
98                  retval.append(",").append(referenceColumn.getDecimalDigits());
99              }
100             retval.append(")");
101         }
102 
103         
104         return retval.toString();
105     }
106 
107     /**
108      * Convert the type value gotten from the metadata which is a value from {@link Types} to a {@link String} value
109      * that can be used in an SQL statement. Example output:
110      * <ul>
111      *   <li>java.sql.Types.DECIMAL(25,0)</li>
112      *   <li>java.sql.Types.BIGINT</li>
113      *   <li>java.sql.Types.VARCHAR(255)</li>
114      * </ul>
115      *
116      * @param type int value found in {@linK Types}
117      * @return String value including package of the type name.
118      */
119     protected String getSqlTypeName(final int type) throws Exception {
120         for (final Field field : Types.class.getFields()) {
121             final int sql_type = field.getInt(null);
122             if (type == sql_type) {
123                 return "java.sql.Types." + field.getName();
124             }
125         }
126         return null;
127     }
128 
129     @Override
130     protected DataType getDataType(String columnTypeString, Boolean autoIncrement, String dataTypeName, String precision, String additionalInformation) {
131         // Translate type to database-specific type, if possible
132         DataType returnTypeName = null;
133         if (dataTypeName.equalsIgnoreCase("BIGINT")) {
134             returnTypeName = getBigIntType();
135         } else if (dataTypeName.equalsIgnoreCase("NUMBER") 
136                    || dataTypeName.equalsIgnoreCase("DECIMAL")
137                    || dataTypeName.equalsIgnoreCase("NUMERIC")) {
138             returnTypeName = getNumberType();
139         } else if (dataTypeName.equalsIgnoreCase("BLOB")) {
140             returnTypeName = getBlobType();
141         } else if (dataTypeName.equalsIgnoreCase("BOOLEAN")) {
142             returnTypeName = getBooleanType();
143         } else if (dataTypeName.equalsIgnoreCase("CHAR")) {
144             returnTypeName = getCharType();
145         } else if (dataTypeName.equalsIgnoreCase("CLOB")) {
146             returnTypeName = getClobType();
147         } else if (dataTypeName.equalsIgnoreCase("CURRENCY")) {
148             returnTypeName = getCurrencyType();
149         } else if (dataTypeName.equalsIgnoreCase("DATE") || dataTypeName.equalsIgnoreCase(getDateType().getDataTypeName())) {
150             returnTypeName = getDateType();
151         } else if (dataTypeName.equalsIgnoreCase("DATETIME") || dataTypeName.equalsIgnoreCase(getDateTimeType().getDataTypeName())) {
152             returnTypeName = getDateTimeType();
153         } else if (dataTypeName.equalsIgnoreCase("DOUBLE")) {
154             returnTypeName = getDoubleType();
155         } else if (dataTypeName.equalsIgnoreCase("FLOAT")) {
156             returnTypeName = getFloatType();
157         } else if (dataTypeName.equalsIgnoreCase("INT")) {
158             returnTypeName = getIntType();
159         } else if (dataTypeName.equalsIgnoreCase("INTEGER")) {
160             returnTypeName = getIntType();
161         } else if (dataTypeName.equalsIgnoreCase("LONGBLOB")) {
162             returnTypeName = getLongBlobType();
163         } else if (dataTypeName.equalsIgnoreCase("LONGVARBINARY")) {
164             returnTypeName = getBlobType();
165         } else if (dataTypeName.equalsIgnoreCase("LONGVARCHAR")) {
166             returnTypeName = getClobType();
167         } else if (dataTypeName.equalsIgnoreCase("SMALLINT")) {
168             returnTypeName = getSmallIntType();
169         } else if (dataTypeName.equalsIgnoreCase("TEXT")) {
170             returnTypeName = getClobType();
171         } else if (dataTypeName.equalsIgnoreCase("TIME") || dataTypeName.equalsIgnoreCase(getTimeType().getDataTypeName())) {
172             returnTypeName = getTimeType();
173         } else if (dataTypeName.toUpperCase().contains("TIMESTAMP")) {
174             returnTypeName = getDateTimeType();
175         } else if (dataTypeName.equalsIgnoreCase("TINYINT")) {
176             returnTypeName = getTinyIntType();
177         } else if (dataTypeName.equalsIgnoreCase("UUID")) {
178             returnTypeName = getUUIDType();
179         } else if (dataTypeName.equalsIgnoreCase("VARCHAR")) {
180             returnTypeName = getVarcharType();
181         } else if (dataTypeName.equalsIgnoreCase("NVARCHAR")) {
182             returnTypeName = getNVarcharType();
183         } else {
184             return new CustomType(columnTypeString,0,2);
185         }
186 
187         if (returnTypeName == null) {
188             throw new UnexpectedLiquibaseException("Could not determine " + dataTypeName + " for " + this.getClass().getName());
189         }
190         addPrecisionToType(precision, returnTypeName);
191         returnTypeName.setAdditionalInformation(additionalInformation);
192 
193          return returnTypeName;
194     }
195 
196 }