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.Database;
29  import liquibase.database.core.OracleDatabase;
30  import liquibase.database.structure.Column;
31  import liquibase.database.structure.type.*;
32  import liquibase.exception.UnexpectedLiquibaseException;
33  import liquibase.util.StringUtils;
34  
35  
36  import java.lang.reflect.Field;
37  import java.sql.Types;
38  import java.text.ParseException;
39  import java.util.Arrays;
40  import java.util.List;
41  
42  import static liquibase.ext.Constants.EXTENSION_PRIORITY;
43  
44  /**
45   *
46   * @author Leo Przybylski
47   */
48  public class OracleTypeConverter extends liquibase.database.typeconversion.core.OracleTypeConverter {
49      protected static final List<Integer> oneParam = Arrays.asList(
50          Types.CHAR,
51          -15, // Types.NCHAR in java 1.6,
52          Types.VARCHAR,
53          -9, //Types.NVARCHAR in java 1.6,
54          Types.VARBINARY,
55          Types.DOUBLE,
56          Types.FLOAT
57          );
58          
59      protected static final List<Integer> twoParams = Arrays.asList(
60          Types.DECIMAL,
61          Types.NUMERIC,
62          Types.REAL
63          );
64      public int getPriority() {
65          return EXTENSION_PRIORITY;
66      }
67  
68      @Override
69      public Object convertDatabaseValueToObject(Object value, int databaseDataType, int firstParameter, int secondParameter, Database database) throws ParseException {
70          if (value == null) {
71              return null;
72          } else if (value instanceof String) {
73              return convertToCorrectObjectType(((String) value).trim().replaceFirst("^'", "").replaceFirst("'$", ""), databaseDataType, firstParameter, secondParameter, database);
74          } else {
75              return value;
76          }
77      }
78  
79      @Override
80      public String convertToDatabaseTypeString(Column referenceColumn, Database database) {        
81          final StringBuilder retval = new StringBuilder();
82          try {
83              retval.append(getSqlTypeName(referenceColumn.getDataType()));
84          }
85          catch (Exception e) {
86              retval.append(referenceColumn.getTypeName());
87          }
88  
89          
90          final boolean hasOneParam  = oneParam.contains(referenceColumn.getDataType());
91          final boolean hasTwoParams = twoParams.contains(referenceColumn.getDataType());
92          
93  
94          if (hasOneParam || hasTwoParams) {
95              retval.append("(").append(referenceColumn.getColumnSize());
96              if (hasTwoParams) {
97                  retval.append(",").append(referenceColumn.getDecimalDigits());
98              }
99              retval.append(")");
100         }
101 
102         
103         return retval.toString();
104     }
105 
106     /**
107      * Convert the type value gotten from the metadata which is a value from {@link Types} to a {@link String} value
108      * that can be used in an SQL statement. Example output:
109      * <ul>
110      *   <li>java.sql.Types.DECIMAL(25,0)</li>
111      *   <li>java.sql.Types.BIGINT</li>
112      *   <li>java.sql.Types.VARCHAR(255)</li>
113      * </ul>
114      *
115      * @param type int value found in {@linK Types}
116      * @return String value including package of the type name.
117      */
118     protected String getSqlTypeName(final int type) throws Exception {
119         for (final Field field : Types.class.getFields()) {
120             final int sql_type = field.getInt(null);
121             if (type == sql_type) {
122                 return "java.sql.Types." + field.getName();
123             }
124         }
125         return null;
126     }
127 
128     @Override
129     protected DataType getDataType(String columnTypeString, Boolean autoIncrement, String dataTypeName, String precision, String additionalInformation) {
130         // Translate type to database-specific type, if possible
131         DataType returnTypeName = null;
132         if (dataTypeName.equalsIgnoreCase("BIGINT")) {
133             returnTypeName = getBigIntType();
134         } else if (dataTypeName.equalsIgnoreCase("NUMBER") 
135                    || dataTypeName.equalsIgnoreCase("DECIMAL")
136                    || dataTypeName.equalsIgnoreCase("NUMERIC")) {
137             returnTypeName = getNumberType();
138         } else if (dataTypeName.equalsIgnoreCase("BLOB")) {
139             returnTypeName = getBlobType();
140         } else if (dataTypeName.equalsIgnoreCase("BOOLEAN")) {
141             returnTypeName = getBooleanType();
142         } else if (dataTypeName.equalsIgnoreCase("CHAR")) {
143             returnTypeName = getCharType();
144         } else if (dataTypeName.equalsIgnoreCase("CLOB")) {
145             returnTypeName = getClobType();
146         } else if (dataTypeName.equalsIgnoreCase("CURRENCY")) {
147             returnTypeName = getCurrencyType();
148         } else if (dataTypeName.equalsIgnoreCase("DATE") || dataTypeName.equalsIgnoreCase(getDateType().getDataTypeName())) {
149             returnTypeName = getDateType();
150         } else if (dataTypeName.equalsIgnoreCase("DATETIME") || dataTypeName.equalsIgnoreCase(getDateTimeType().getDataTypeName())) {
151             returnTypeName = getDateTimeType();
152         } else if (dataTypeName.equalsIgnoreCase("DOUBLE")) {
153             returnTypeName = getDoubleType();
154         } else if (dataTypeName.equalsIgnoreCase("FLOAT")) {
155             returnTypeName = getFloatType();
156         } else if (dataTypeName.equalsIgnoreCase("INT")) {
157             returnTypeName = getIntType();
158         } else if (dataTypeName.equalsIgnoreCase("INTEGER")) {
159             returnTypeName = getIntType();
160         } else if (dataTypeName.equalsIgnoreCase("LONGBLOB")) {
161             returnTypeName = getLongBlobType();
162         } else if (dataTypeName.equalsIgnoreCase("LONGVARBINARY")) {
163             returnTypeName = getBlobType();
164         } else if (dataTypeName.equalsIgnoreCase("LONGVARCHAR")) {
165             returnTypeName = getClobType();
166         } else if (dataTypeName.equalsIgnoreCase("SMALLINT")) {
167             returnTypeName = getSmallIntType();
168         } else if (dataTypeName.equalsIgnoreCase("TEXT")) {
169             returnTypeName = getClobType();
170         } else if (dataTypeName.equalsIgnoreCase("TIME") || dataTypeName.equalsIgnoreCase(getTimeType().getDataTypeName())) {
171             returnTypeName = getTimeType();
172         } else if (dataTypeName.toUpperCase().contains("TIMESTAMP")) {
173             returnTypeName = getDateTimeType();
174         } else if (dataTypeName.equalsIgnoreCase("TINYINT")) {
175             returnTypeName = getTinyIntType();
176         } else if (dataTypeName.equalsIgnoreCase("UUID")) {
177             returnTypeName = getUUIDType();
178         } else if (dataTypeName.equalsIgnoreCase("VARCHAR")) {
179             returnTypeName = getVarcharType();
180         } else if (dataTypeName.equalsIgnoreCase("NVARCHAR")) {
181             returnTypeName = getNVarcharType();
182         } else {
183             return new CustomType(columnTypeString,0,2);
184         }
185 
186         if (returnTypeName == null) {
187             throw new UnexpectedLiquibaseException("Could not determine " + dataTypeName + " for " + this.getClass().getName());
188         }
189         addPrecisionToType(precision, returnTypeName);
190         returnTypeName.setAdditionalInformation(additionalInformation);
191 
192          return returnTypeName;
193     }
194 }