public void register(Class<? extends LiquibaseDataType> dataTypeClass) { try { LiquibaseDataType example = dataTypeClass.newInstance(); List<String> names = new ArrayList<String>(); names.add(example.getName()); names.addAll(Arrays.asList(example.getAliases())); Comparator<Class<? extends LiquibaseDataType>> comparator = new Comparator<Class<? extends LiquibaseDataType>>() { @Override public int compare( Class<? extends LiquibaseDataType> o1, Class<? extends LiquibaseDataType> o2) { try { return -1 * new Integer(o1.newInstance().getPriority()) .compareTo(o2.newInstance().getPriority()); } catch (Exception e) { throw new UnexpectedLiquibaseException(e); } } }; for (String name : names) { name = name.toLowerCase(); if (registry.get(name) == null) { registry.put(name, new ArrayList<Class<? extends LiquibaseDataType>>()); } List<Class<? extends LiquibaseDataType>> classes = registry.get(name); classes.add(dataTypeClass); Collections.sort(classes, comparator); } } catch (Exception e) { throw new UnexpectedLiquibaseException(e); } }
public LiquibaseDataType fromDescription(String dataTypeDefinition, Database database) { String dataTypeName = dataTypeDefinition; if (dataTypeName.matches(".+\\(.*\\).*")) { dataTypeName = dataTypeName.replaceFirst("\\s*\\(.*\\)", ""); } if (dataTypeName.matches(".+\\{.*")) { dataTypeName = dataTypeName.replaceFirst("\\s*\\{.*", ""); } boolean autoIncrement = false; if (dataTypeName.endsWith(" identity")) { dataTypeName = dataTypeName.replaceFirst(" identity$", ""); autoIncrement = true; } // unquote delimited identifiers final String[][] quotePairs = new String[][] { {"\"", "\""}, // double quotes {"[", "]"}, // square brackets (a la mssql) {"`", "`"}, // backticks (a la mysql) {"'", "'"} // single quotes }; for (String[] quotePair : quotePairs) { String openQuote = quotePair[0]; String closeQuote = quotePair[1]; if (dataTypeName.startsWith(openQuote)) { int indexOfCloseQuote = dataTypeName.indexOf(closeQuote, openQuote.length()); if (indexOfCloseQuote != -1 && dataTypeName.indexOf(closeQuote, indexOfCloseQuote + closeQuote.length()) == -1) { dataTypeName = dataTypeName.substring(openQuote.length(), indexOfCloseQuote) + dataTypeName.substring( indexOfCloseQuote + closeQuote.length(), dataTypeName.length()); break; } } } String additionalInfo = null; if (dataTypeName.toLowerCase().startsWith("bit varying") || dataTypeName.toLowerCase().startsWith("character varying")) { // not going to do anything. Special case for postgres in our tests, need to better support // handling these types of differences } else { String[] splitTypeName = dataTypeName.split("\\s+", 2); dataTypeName = splitTypeName[0]; if (splitTypeName.length > 1) { additionalInfo = splitTypeName[1]; } } Collection<Class<? extends LiquibaseDataType>> classes = registry.get(dataTypeName.toLowerCase()); LiquibaseDataType liquibaseDataType = null; if (classes == null) { if (dataTypeName.toUpperCase().startsWith("INTERVAL")) { liquibaseDataType = new UnknownType(dataTypeDefinition); } else { liquibaseDataType = new UnknownType(dataTypeName); } } else { Iterator<Class<? extends LiquibaseDataType>> iterator = classes.iterator(); do { try { liquibaseDataType = iterator.next().newInstance(); } catch (Exception e) { throw new UnexpectedLiquibaseException(e); } } while ((database != null) && !liquibaseDataType.supports(database) && iterator.hasNext()); } if ((database != null) && !liquibaseDataType.supports(database)) { throw new UnexpectedLiquibaseException( "Could not find type for " + liquibaseDataType.toString() + " for databaes " + database.getShortName()); } if (liquibaseDataType == null) { liquibaseDataType = new UnknownType(dataTypeName); } liquibaseDataType.setAdditionalInformation(additionalInfo); if (dataTypeDefinition.matches(".+\\s*\\(.*")) { String paramStrings = dataTypeDefinition.replaceFirst(".*?\\(", "").replaceFirst("\\).*", ""); String[] params = paramStrings.split(","); for (String param : params) { param = StringUtils.trimToNull(param); if (param != null) { liquibaseDataType.addParameter(param); } } } /* The block below seems logically incomplete. It will always end up putting the second word after the entire type name e.g. character varying will become CHARACTER VARYING varying //try to something like "int(11) unsigned" or int unsigned but not "varchar(11 bytes)" String lookingForAdditionalInfo = dataTypeDefinition; lookingForAdditionalInfo = lookingForAdditionalInfo.replaceFirst("\\(.*\\)", ""); if (lookingForAdditionalInfo.contains(" ")) { liquibaseDataType.setAdditionalInformation(lookingForAdditionalInfo.split(" ", 2)[1]); }*/ if (dataTypeDefinition.matches(".*\\{.*")) { String paramStrings = dataTypeDefinition.replaceFirst(".*?\\{", "").replaceFirst("\\}.*", ""); String[] params = paramStrings.split(","); for (String param : params) { param = StringUtils.trimToNull(param); if (param != null) { String[] paramAndValue = param.split(":", 2); try { ObjectUtil.setProperty(liquibaseDataType, paramAndValue[0], paramAndValue[1]); } catch (Exception e) { throw new RuntimeException( "Unknown property " + paramAndValue[0] + " for " + liquibaseDataType.getClass().getName() + " " + liquibaseDataType.toString()); } } } } if (autoIncrement && liquibaseDataType instanceof IntType) { ((IntType) liquibaseDataType).setAutoIncrement(true); } if (autoIncrement && liquibaseDataType instanceof BigIntType) { ((BigIntType) liquibaseDataType).setAutoIncrement(true); } liquibaseDataType.finishInitialization(dataTypeDefinition); return liquibaseDataType; }