/* * Copyright 2007 - 2017 the original author or authors. * * 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 net.sf.jailer.configuration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.sf.jailer.database.DefaultTemporaryTableManager; import net.sf.jailer.database.SQLDialect; import net.sf.jailer.database.SqlScriptBasedStatisticRenovator; /** * Describes a specific DBMS. * * @author Ralf Wisser */ public class DBMS { // predefined DBMSes public static final DBMS ORACLE; public static final DBMS MSSQL; public static final DBMS DB2; public static final DBMS DB2_ZOS; public static final DBMS MySQL; public static final DBMS POSTGRESQL; public static final DBMS SQLITE; public static final DBMS HSQL; public static final DBMS H2; public static final DBMS SYBASE; public static final DBMS INFORMIX; public static final DBMS CLOADSCAPE; public static final DBMS FIREBIRD; public static final DBMS DERBY; /** * Gets all DBMSes. * * @return array of all DBMSes */ public static DBMS[] values() { return Configuration.getInstance().getDBMS().toArray(new DBMS[0]); } /** * Default constructor. */ public DBMS() { } /** * Copy constructor. */ public DBMS(DBMS other) { this.id = other.id; this.displayName = other.displayName; this.urlPattern = other.urlPattern; this.testQuery = other.testQuery; this.statisticRenovator = other.statisticRenovator; this.typeReplacement = other.typeReplacement; this.stringLiteralEscapeSequences = other.stringLiteralEscapeSequences; this.sqlLimitSuffix = other.sqlLimitSuffix; this.varcharLengthLimit = other.varcharLengthLimit; this.tableProperties = other.tableProperties; this.charToEscapeSequence = other.charToEscapeSequence; this.keysOfCharToEscapeSequence = other.keysOfCharToEscapeSequence; this.ncharPrefix = other.ncharPrefix; this.exportBlocks = other.exportBlocks; this.identityInserts = other.identityInserts; this.appendNanosToTimestamp = other.appendNanosToTimestamp; this.appendMillisToTimestamp = other.appendMillisToTimestamp; this.useToTimestampFunction = other.useToTimestampFunction; this.emptyCLOBValue = other.emptyCLOBValue; this.emptyNCLOBValue = other.emptyNCLOBValue; this.emptyBLOBValue = other.emptyBLOBValue; this.toBlob = other.toBlob; this.toClob = other.toClob; this.toNClob = other.toNClob; this.embeddedLobSizeLimit = other.embeddedLobSizeLimit; this.binaryPattern = other.binaryPattern; this.avoidLeftJoin = other.avoidLeftJoin; this.timestampPattern = other.timestampPattern; this.sqlDialect = other.sqlDialect; this.rowidName = other.rowidName; this.supportsSchemasInIndexDefinitions = other.supportsSchemasInIndexDefinitions; this.useInlineViewsInDataBrowser = other.useInlineViewsInDataBrowser; this.virtualColumnsQuery = other.virtualColumnsQuery; this.userDefinedColumnsQuery = other.userDefinedColumnsQuery; this.importedKeysQuery = other.importedKeysQuery; this.primaryKeysQuery = other.primaryKeysQuery; this.indexInfoQuery = other.indexInfoQuery; this.identifierQuoteString = other.identifierQuoteString; this.rowidType = other.rowidType; this.sessionTemporaryTableManager = other.sessionTemporaryTableManager; this.transactionTemporaryTableManager = other.transactionTemporaryTableManager; this.jdbcProperties = other.jdbcProperties; this.nullableContraint = other.nullableContraint; } /** * Gets DBMS specific configuration. * * @param dbmsId the DBMS id * @return the DBMS with given id, or the default DBMS if id is <code>null</code> */ public static synchronized DBMS forDBMS(String dbmsId) { if (dbmsId == null) { return defaultDBMS; } if (perDBMS.containsKey(dbmsId)) { return perDBMS.get(dbmsId); } List<DBMS> cs = Configuration.getInstance().getDBMS(); for (DBMS c: cs) { if (dbmsId.equals(c.getId())) { perDBMS.put(dbmsId, c); return c; } } throw new RuntimeException("Unknown DBMS: \"" + dbmsId + "\""); } /** * Holds configurations. */ private static Map<String, DBMS> perDBMS = new HashMap<String, DBMS>(); /** * Default configuration for unknown DBMS. */ private static final DBMS defaultDBMS = new DBMS(); static { ORACLE = forDBMS("ORACLE"); MSSQL = forDBMS("MSSQL"); DB2 = forDBMS("DB2"); DB2_ZOS = forDBMS("DB2_ZOS"); MySQL = forDBMS("MySQL"); POSTGRESQL = forDBMS("POSTGRESQL"); SQLITE = forDBMS("SQLITE"); HSQL = forDBMS("HSQL"); H2 = forDBMS("H2"); SYBASE = forDBMS("SYBASE"); INFORMIX = forDBMS("INFORMIX"); CLOADSCAPE = forDBMS("CLOADSCAPE"); FIREBIRD = forDBMS("FIREBIRD"); DERBY = forDBMS("DERBY"); } private String id; private String displayName; /** * DB-URL pattern of DBMS for which this holds the configuration. */ private String urlPattern; /** * Test-query for the DBMS for which this holds the configuration. */ private String testQuery; /** * The {@link SqlScriptBasedStatisticRenovator}. */ private SqlScriptBasedStatisticRenovator statisticRenovator; /** * Replacement map for column types used for DDL generation. */ private Map<String, String> typeReplacement; /** * Replacement map for special characters in string literals. */ private Map<String, String> stringLiteralEscapeSequences; /** * Suffix of SQL-Select statement to limit number of rows. */ private String sqlLimitSuffix; private Integer varcharLengthLimit = null; private String tableProperties = ""; /** * Maps characters to escape sequences according to {@link #stringLiteralEscapeSequences}. */ private Map<Character, String> charToEscapeSequence = new HashMap<Character, String>(); { charToEscapeSequence.put('\'', "''"); } private char[] keysOfCharToEscapeSequence = new char[] { '\'' }; private String ncharPrefix = null; /** * Set of type names for which no data must be exported. */ private Set<String> exportBlocks = new HashSet<String>(); /** * <code>true</code> if DBMS supports identity-type (MS-SQL) */ private boolean identityInserts = false; private boolean appendNanosToTimestamp = true; private boolean appendMillisToTimestamp = false; private boolean useToTimestampFunction = false; private String emptyCLOBValue = null; private String emptyNCLOBValue = null; private String emptyBLOBValue = null; private String toBlob; private String toClob; private String toNClob; private int embeddedLobSizeLimit = 3980; private String binaryPattern = "x'%s'"; private boolean avoidLeftJoin = false; private String timestampPattern = null; private SQLDialect sqlDialect = new SQLDialect(); private String rowidName = null; private Boolean supportsSchemasInIndexDefinitions = null; private boolean useInlineViewsInDataBrowser = true; private String virtualColumnsQuery = null; private String userDefinedColumnsQuery = null; private String importedKeysQuery = "SELECT null, PKCU.TABLE_SCHEMA, PKCU.TABLE_NAME, PKCU.COLUMN_NAME," + " null, KCU.TABLE_SCHEMA, KCU.TABLE_NAME, KCU.COLUMN_NAME, KCU.ORDINAL_POSITION," + " null, null, RC.CONSTRAINT_NAME, RC.UNIQUE_CONSTRAINT_NAME, null" + " FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC" + " JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + " ON KCU.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG" + " AND KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA" + " AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME" + " JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE PKCU" + " ON PKCU.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG" + " AND PKCU.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA" + " AND PKCU.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME" + " AND PKCU.ORDINAL_POSITION = KCU.ORDINAL_POSITION" + " WHERE PKCU.TABLE_SCHEMA = '${SCHEMA}'" + " ORDER BY KCU.ORDINAL_POSITION"; private String primaryKeysQuery = "SELECT null, KCU.TABLE_SCHEMA, KCU.TABLE_NAME, KCU.COLUMN_NAME, KCU.ORDINAL_POSITION, C.CONSTRAINT_NAME" + " FROM" + " INFORMATION_SCHEMA.TABLE_CONSTRAINTS C" + " JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + " ON KCU.CONSTRAINT_CATALOG = C.CONSTRAINT_CATALOG" + " AND KCU.CONSTRAINT_SCHEMA = C.CONSTRAINT_SCHEMA" + " AND KCU.CONSTRAINT_NAME = C.CONSTRAINT_NAME" + " WHERE C.CONSTRAINT_TYPE = 'PRIMARY KEY'" + " AND KCU.TABLE_SCHEMA = '${SCHEMA}'" + " ORDER BY KCU.ORDINAL_POSITION"; private String indexInfoQuery = null; private String identifierQuoteString = "\""; /** * @return the virtualColumnsQuery */ public String getVirtualColumnsQuery() { return virtualColumnsQuery; } /** * @param virtualColumnsQuery the virtualColumnsQuery to set */ public void setVirtualColumnsQuery(String virtualColumnsQuery) { this.virtualColumnsQuery = virtualColumnsQuery; } /** * @return the useInlineViewsInDataBrowser */ public boolean isUseInlineViewsInDataBrowser() { return useInlineViewsInDataBrowser; } /** * @param useInlineViewsInDataBrowser the useInlineViewsInDataBrowser to set */ public void setUseInlineViewsInDataBrowser(boolean useInlineViewsInDataBrowser) { this.useInlineViewsInDataBrowser = useInlineViewsInDataBrowser; } /** * @return the embeddedLobSizeLimit */ public int getEmbeddedLobSizeLimit() { return embeddedLobSizeLimit; } /** * @param embeddedLobSizeLimit the embeddedLobSizeLimit to set */ public void setEmbeddedLobSizeLimit(int embeddedLobSizeLimit) { this.embeddedLobSizeLimit = embeddedLobSizeLimit; } /** * @return the supportsSchemasInIndexDefinitions */ public Boolean getSupportsSchemasInIndexDefinitions() { return supportsSchemasInIndexDefinitions; } /** * @param supportsSchemasInIndexDefinitions the supportsSchemasInIndexDefinitions to set */ public void setSupportsSchemasInIndexDefinitions( Boolean supportsSchemasInIndexDefinitions) { this.supportsSchemasInIndexDefinitions = supportsSchemasInIndexDefinitions; } /** * @return the rowidName */ public String getRowidName() { return rowidName; } /** * @param rowidName the rowidName to set */ public void setRowidName(String rowidName) { this.rowidName = rowidName != null && rowidName.trim().length() == 0? null : rowidName; } /** * @return the rowidType */ public String getRowidType() { return rowidType; } /** * @param rowidType the rowidType to set */ public void setRowidType(String rowidType) { this.rowidType = rowidType; } private String rowidType = null; /** * @return the sqlDialect */ public SQLDialect getSqlDialect() { return sqlDialect; } /** * @return the sqlDialect */ public void setSqlDialect(SQLDialect sqlDialect) { this.sqlDialect = sqlDialect; } /** * Manages session local temporary tables. */ private DefaultTemporaryTableManager sessionTemporaryTableManager = null; /** * Manages transaction local temporary tables. */ private DefaultTemporaryTableManager transactionTemporaryTableManager = null; /** * Optional JDBC properties. */ private Map<String, String> jdbcProperties = null; /** * @return the urlPattern */ public String getUrlPattern() { return urlPattern; } /** * Sets DB-URL pattern of DBMS for which this holds the configuration. */ public void setUrlPattern(String urlPattern) { this.urlPattern = urlPattern; } public Set<String> getExportBlocks() { return exportBlocks; } public void setExportBlocks(Set<String> exportBlocks) { this.exportBlocks = exportBlocks; } /** * Gets the {@link SqlScriptBasedStatisticRenovator}. * * @return the {@link SqlScriptBasedStatisticRenovator} */ public SqlScriptBasedStatisticRenovator getStatisticRenovator() { return statisticRenovator; } /** * Sets the {@link SqlScriptBasedStatisticRenovator}. * * @param statisticRenovator the {@link SqlScriptBasedStatisticRenovator} */ public void setStatisticRenovator(SqlScriptBasedStatisticRenovator statisticRenovator) { this.statisticRenovator = statisticRenovator; } public void setAppendNanosToTimestamp(boolean appendNanosToTimestamp) { this.appendNanosToTimestamp = appendNanosToTimestamp; } public void setAppendMillisToTimestamp(boolean appendMillisToTimestamp) { this.appendMillisToTimestamp = appendMillisToTimestamp; } public void setUseToTimestampFunction(boolean useToTimestampFunction) { this.useToTimestampFunction = useToTimestampFunction; } public void setEmptyCLOBValue(String emptyCLOBValue) { this.emptyCLOBValue = emptyCLOBValue; } public void setEmptyBLOBValue(String emptyBLOBValue) { this.emptyBLOBValue = emptyBLOBValue; } public void setBinaryPattern(String binaryPattern) { this.binaryPattern = binaryPattern; } /** * Sets replacement map for column types used for DDL generation. */ public void setTypeReplacement(Map<String, String> tr) { typeReplacement = tr; } /** * @return the toBlob */ public String getToBlob() { return toBlob; } /** * @param toBlob the toBlob to set */ public void setToBlob(String toBlob) { this.toBlob = toBlob; } /** * @return the toClob */ public String getToClob() { return toClob; } /** * @param toClob the toClob to set */ public void setToClob(String toClob) { this.toClob = toClob; } /** * Gets replacement map for column types used for DDL generation. */ public Map<String, String> getTypeReplacement() { return typeReplacement; } /** * Sets manager for session local temporary tables. */ public void setSessionTemporaryTableManager(DefaultTemporaryTableManager tableManager) { sessionTemporaryTableManager = tableManager; } /** * Sets manager for transaction local temporary tables. */ public void setTransactionTemporaryTableManager(DefaultTemporaryTableManager tableManager) { transactionTemporaryTableManager = tableManager; } public boolean isIdentityInserts() { return identityInserts; } public void setIdentityInserts(boolean identityInserts) { this.identityInserts = identityInserts; } /** * Sets replacement map for special characters in string literals. */ public void setStringLiteralEscapeSequences(Map<String, String> stringLiteralEscapeSequences) { this.stringLiteralEscapeSequences = stringLiteralEscapeSequences; try { for (Map.Entry<String, String> e: stringLiteralEscapeSequences.entrySet()) { if (e.getKey().startsWith("\\")) { char c; char c2 = e.getKey().charAt(1); if (Character.isDigit(c2)) { c = (char) Integer.parseInt(e.getKey().substring(1)); } else if (c2 == '\\') { c = '\\'; } else if (c2 == 'b') { c = '\b'; } else if (c2 == 'n') { c = '\n'; } else if (c2 == 't') { c = '\t'; } else if (c2 == 'r') { c = '\r'; } else { throw new RuntimeException("illegal escape sequence: " + e.getKey()); } charToEscapeSequence.put(c, e.getValue()); } else { charToEscapeSequence.put(e.getKey().charAt(0), e.getValue()); } } keysOfCharToEscapeSequence = new char[charToEscapeSequence.keySet().size()]; int i = 0; for (char c: charToEscapeSequence.keySet()) { keysOfCharToEscapeSequence[i++] = c; } } catch (Exception e) { throw new RuntimeException("cannot recognize key of stringLiteralEscapeSequences-entry", e); } } /** * Gets replacement map for special characters in string literals. */ public Map<String, String> getStringLiteralEscapeSequences() { return stringLiteralEscapeSequences; } /** * Converts a string to a string literal according to the {@link #getStringLiteralEscapeSequences()}. * * @param string the string to convert * @return the string literal */ public String convertToStringLiteral(String string) { boolean esc = false; for (char c: keysOfCharToEscapeSequence) { if (string.indexOf(c) >= 0) { esc = true; break; } } if (!esc) { return string; } StringBuilder qvalue = new StringBuilder(); int l = string.length(); for (int i = 0; i < l; ++i) { char c = string.charAt(i); String es = charToEscapeSequence.get(c); if (es != null) { qvalue.append(es); } else { qvalue.append(c); } } return qvalue.toString(); } public boolean isAvoidLeftJoin() { return avoidLeftJoin; } public void setAvoidLeftJoin(boolean avoidLeftJoin) { this.avoidLeftJoin = avoidLeftJoin; } /** * @param sqlLimitSuffix the sqlLimitSuffix to set */ public void setSqlLimitSuffix(String sqlLimitSuffix) { this.sqlLimitSuffix = sqlLimitSuffix; } /** * @return the sqlLimitSuffix */ public String getSqlLimitSuffix() { return sqlLimitSuffix; } public Integer getVarcharLengthLimit() { return varcharLengthLimit; } public void setVarcharLengthLimit(Integer varcharLengthLimit) { this.varcharLengthLimit = varcharLengthLimit; } /** * @return the timestampPattern */ public String getTimestampPattern() { return timestampPattern; } /** * @param timestampPattern the timestampPattern to set */ public void setTimestampPattern(String timestampPattern) { this.timestampPattern = timestampPattern; } /** * @return the ncharPrefix */ public String getNcharPrefix() { return ncharPrefix; } /** * @param ncharPrefix the ncharPrefix to set */ public void setNcharPrefix(String ncharPrefix) { this.ncharPrefix = ncharPrefix; } /** * @return the tableProperties */ public String getTableProperties() { return tableProperties; } /** * @param tableProperties the tableProperties to set */ public void setTableProperties(String tableProperties) { this.tableProperties = tableProperties; } /** * Gets the JDBC properties. * * @return the jdbcProperties */ public Map<String, String> getJdbcProperties() { return jdbcProperties; } /** * Sets the JDBC properties. * * @param jdbcProperties the jdbcProperties to set */ public void setJdbcProperties(Map<String, String> jdbcProperties) { this.jdbcProperties = jdbcProperties; } /** * @return the identifierQuoteString */ public String getIdentifierQuoteString() { return identifierQuoteString; } /** * @param identifierQuoteString the identifierQuoteString to set */ public void setIdentifierQuoteString(String identifierQuoteString) { this.identifierQuoteString = identifierQuoteString; } public String getTestQuery() { return testQuery; } public void setTestQuery(String testQuery) { this.testQuery = testQuery; } public String getUserDefinedColumnsQuery() { return userDefinedColumnsQuery; } public void setUserDefinedColumnsQuery(String userDefinedColumnsQuery) { this.userDefinedColumnsQuery = userDefinedColumnsQuery; } private String nullableContraint = null; /** * @return the nullableContraint */ public String getNullableContraint() { return nullableContraint; } /** * @param nullableContraint the nullableContraint to set */ public void setNullableContraint(String nullableContraint) { this.nullableContraint = nullableContraint; } /** * @return the emptyNCLOBValue */ public String getEmptyNCLOBValue() { return emptyNCLOBValue; } /** * @param emptyNCLOBValue the emptyNCLOBValue to set */ public void setEmptyNCLOBValue(String emptyNCLOBValue) { this.emptyNCLOBValue = emptyNCLOBValue; } /** * @return the importedKeysQuery */ public String getImportedKeysQuery() { return importedKeysQuery; } /** * @param importedKeysQuery the importedKeysQuery to set */ public void setImportedKeysQuery(String importedKeysQuery) { this.importedKeysQuery = importedKeysQuery; } /** * @return the primaryKeysQuery */ public String getPrimaryKeysQuery() { return primaryKeysQuery; } /** * @param primaryKeysQuery the primaryKeysQuery to set */ public void setPrimaryKeysQuery(String primaryKeysQuery) { this.primaryKeysQuery = primaryKeysQuery; } /** * @return the indexInfoQuery */ public String getIndexInfoQuery() { return indexInfoQuery; } /** * @param indexInfoQuery the indexInfoQuery to set */ public void setIndexInfoQuery(String indexInfoQuery) { this.indexInfoQuery = indexInfoQuery; } /** * @return the toNClob */ public String getToNClob() { return toNClob; } /** * @param toNClob the toNClob to set */ public void setToNClob(String toNClob) { this.toNClob = toNClob; } /** * @return the appendNanosToTimestamp */ public boolean isAppendNanosToTimestamp() { return appendNanosToTimestamp; } /** * @return the appendMillisToTimestamp */ public boolean isAppendMillisToTimestamp() { return appendMillisToTimestamp; } /** * @return the useToTimestampFunction */ public boolean isUseToTimestampFunction() { return useToTimestampFunction; } /** * @return the emptyCLOBValue */ public String getEmptyCLOBValue() { return emptyCLOBValue; } /** * @return the emptyBLOBValue */ public String getEmptyBLOBValue() { return emptyBLOBValue; } /** * @return the binaryPattern */ public String getBinaryPattern() { return binaryPattern; } /** * @return the sessionTemporaryTableManager */ public DefaultTemporaryTableManager getSessionTemporaryTableManager() { return sessionTemporaryTableManager; } /** * @return the transactionTemporaryTableManager */ public DefaultTemporaryTableManager getTransactionTemporaryTableManager() { return transactionTemporaryTableManager; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return id == null ? 0 : id.hashCode(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } DBMS other = (DBMS) obj; if (id == null) { if (other.id != null) { return false; } } else if (!id.equals(other.id)) { return false; } return true; } }