package liquibase.database.core; import liquibase.database.AbstractDatabase; import liquibase.database.DatabaseConnection; import liquibase.exception.DatabaseException; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.executor.ExecutorService; import liquibase.statement.core.GetViewDefinitionStatement; import liquibase.statement.core.RawSqlStatement; import java.math.BigInteger; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; public class InformixDatabase extends AbstractDatabase { private static final String PRODUCT_NAME = "Informix Dynamic Server"; private static final String INTERVAL_FIELD_QUALIFIER = "HOUR TO FRACTION(5)"; private static final String DATETIME_FIELD_QUALIFIER = "YEAR TO FRACTION(5)"; private Set<String> systemTablesAndViews = new HashSet<String>(); private static final Pattern CREATE_VIEW_AS_PATTERN = Pattern.compile("^CREATE\\s+.*?VIEW\\s+.*?AS\\s+", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); public InformixDatabase() { super(); systemTablesAndViews.add("systables"); systemTablesAndViews.add("syscolumns"); systemTablesAndViews.add("sysindices"); systemTablesAndViews.add("systabauth"); systemTablesAndViews.add("syscolauth"); systemTablesAndViews.add("sysviews"); systemTablesAndViews.add("sysusers"); systemTablesAndViews.add("sysdepend"); systemTablesAndViews.add("syssynonyms"); systemTablesAndViews.add("syssyntable"); systemTablesAndViews.add("sysconstraints"); systemTablesAndViews.add("sysreferences"); systemTablesAndViews.add("syschecks"); systemTablesAndViews.add("sysdefaults"); systemTablesAndViews.add("syscoldepend"); systemTablesAndViews.add("sysprocedures"); systemTablesAndViews.add("sysprocbody"); systemTablesAndViews.add("sysprocplan"); systemTablesAndViews.add("sysprocauth"); systemTablesAndViews.add("sysblobs"); systemTablesAndViews.add("sysopclstr"); systemTablesAndViews.add("systriggers"); systemTablesAndViews.add("systrigbody"); systemTablesAndViews.add("sysdistrib"); systemTablesAndViews.add("sysfragments"); systemTablesAndViews.add("sysobjstate"); systemTablesAndViews.add("sysviolations"); systemTablesAndViews.add("sysfragauth"); systemTablesAndViews.add("sysroleauth"); systemTablesAndViews.add("sysxtdtypes"); systemTablesAndViews.add("sysattrtypes"); systemTablesAndViews.add("sysxtddesc"); systemTablesAndViews.add("sysinherits"); systemTablesAndViews.add("syscolattribs"); systemTablesAndViews.add("syslogmap"); systemTablesAndViews.add("syscasts"); systemTablesAndViews.add("sysxtdtypeauth"); systemTablesAndViews.add("sysroutinelangs"); systemTablesAndViews.add("syslangauth"); systemTablesAndViews.add("sysams"); systemTablesAndViews.add("systabamdata"); systemTablesAndViews.add("sysopclasses"); systemTablesAndViews.add("syserrors"); systemTablesAndViews.add("systraceclasses"); systemTablesAndViews.add("systracemsgs"); systemTablesAndViews.add("sysaggregates"); systemTablesAndViews.add("syssequences"); systemTablesAndViews.add("sysdirectives"); systemTablesAndViews.add("sysxasourcetypes"); systemTablesAndViews.add("sysxadatasources"); systemTablesAndViews.add("sysseclabelcomponents"); systemTablesAndViews.add("sysseclabelcomponentelements"); systemTablesAndViews.add("syssecpolicies"); systemTablesAndViews.add("syssecpolicycomponents"); systemTablesAndViews.add("syssecpolicyexemptions"); systemTablesAndViews.add("sysseclabels"); systemTablesAndViews.add("sysseclabelnames"); systemTablesAndViews.add("sysseclabelauth"); systemTablesAndViews.add("syssurrogateauth"); systemTablesAndViews.add("sysproccolumns"); systemTablesAndViews.add("sysdomains"); systemTablesAndViews.add("sysindexes"); } @Override protected Set<String> getSystemTablesAndViews() { return systemTablesAndViews; } public int getPriority() { return PRIORITY_DEFAULT; } @Override public void setConnection(DatabaseConnection connection) { super.setConnection(connection); try { /* * TODO Maybe there is a better place for this. * For each session this statement has to be executed, * to allow newlines in quoted strings */ ExecutorService.getInstance().getExecutor(this).execute(new RawSqlStatement("EXECUTE PROCEDURE IFX_ALLOW_NEWLINE('T');")); } catch (Exception e) { throw new UnexpectedLiquibaseException("Could not allow newline characters in quoted strings with IFX_ALLOW_NEWLINE", e); } } public String getCurrentDateTimeFunction() { if (currentDateTimeFunction != null) { return currentDateTimeFunction; } return "CURRENT " + DATETIME_FIELD_QUALIFIER; } public String getDefaultDriver(String url) { if (url.startsWith("jdbc:informix-sqli")) { return "com.informix.jdbc.IfxDriver"; } return null; } public String getTypeName() { return "informix"; } public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException { return PRODUCT_NAME.equals(conn.getDatabaseProductName()); } public boolean supportsInitiallyDeferrableColumns() { return false; } /* * Informix calls them Dbspaces */ public boolean supportsTablespaces() { return true; } @Override public String getViewDefinition(String schemaName, String viewName) throws DatabaseException { List<Map> retList = ExecutorService.getInstance().getExecutor(this).queryForList(new GetViewDefinitionStatement(schemaName, viewName)); // building the view definition from the multiple rows StringBuilder sb = new StringBuilder(); for (Map rowMap : retList) { String s = (String) rowMap.get("VIEWTEXT"); sb.append(s); } return CREATE_VIEW_AS_PATTERN.matcher(sb.toString()).replaceFirst(""); } @Override public String getAutoIncrementClause(BigInteger startWith, BigInteger incrementBy) { return ""; } @Override public String getDateLiteral(String isoDate) { if (isTimeOnly(isoDate)) { return "INTERVAL (" + super.getDateLiteral(isoDate).replaceAll("'", "") + ") " + INTERVAL_FIELD_QUALIFIER; } else if (isDateOnly(isoDate)){ return super.getDateLiteral(isoDate); } else { return "DATETIME (" + super.getDateLiteral(isoDate).replaceAll("'", "") + ") " + DATETIME_FIELD_QUALIFIER; } } @Override public boolean supportsRestrictForeignKeys() { // TODO dont know if this correct return false; } @Override public boolean supportsSchemas() { return false; } }