001: package liquibase.database;
002:
003: import liquibase.database.sql.RawSqlStatement;
004: import liquibase.database.sql.SqlStatement;
005: import liquibase.exception.DateParseException;
006: import liquibase.exception.JDBCException;
007:
008: import java.sql.*;
009: import java.text.ParseException;
010: import java.text.SimpleDateFormat;
011:
012: public class DB2Database extends AbstractDatabase {
013: public boolean isCorrectDatabaseImplementation(Connection conn)
014: throws JDBCException {
015: return getDatabaseProductName(conn).startsWith("DB2");
016: }
017:
018: public String getDefaultDriver(String url) {
019: if (url.startsWith("jdbc:db2")) {
020: return "com.ibm.db2.jcc.DB2Driver";
021: }
022: return null;
023: }
024:
025: public String getProductName() {
026: return "DB2";
027: }
028:
029: public String getTypeName() {
030: return "db2";
031: }
032:
033: protected String getDefaultDatabaseSchemaName()
034: throws JDBCException {//NOPMD
035: return super .getDefaultDatabaseSchemaName().toUpperCase();
036: }
037:
038: public boolean supportsInitiallyDeferrableColumns() {
039: return false;
040: }
041:
042: public String getAutoIncrementClause() {
043: return "GENERATED BY DEFAULT AS IDENTITY";
044: }
045:
046: public String getCurrentDateTimeFunction() {
047: return "CURRENT TIMESTAMP";
048: }
049:
050: public String getBooleanType() {
051: return "SMALLINT";
052: }
053:
054: public String getTrueBooleanValue() {
055: return "1";
056: }
057:
058: public String getFalseBooleanValue() {
059: return "0";
060: }
061:
062: /**
063: * Return an DB2 date literal with the same value as a string formatted using ISO 8601.
064: * <p/>
065: * Convert an ISO8601 date string to one of the following results:
066: * to_date('1995-05-23', 'YYYY-MM-DD')
067: * to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')
068: * <p/>
069: * Implementation restriction:
070: * Currently, only the following subsets of ISO8601 are supported:
071: * YYYY-MM-DD
072: * hh:mm:ss
073: * YYYY-MM-DDThh:mm:ss
074: */
075: public String getDateLiteral(String isoDate) {
076: String normalLiteral = super .getDateLiteral(isoDate);
077:
078: if (isDateOnly(isoDate)) {
079: StringBuffer val = new StringBuffer();
080: val.append("DATE(");
081: val.append(normalLiteral);
082: val.append(')');
083: return val.toString();
084: } else if (isTimeOnly(isoDate)) {
085: StringBuffer val = new StringBuffer();
086: val.append("TIME(");
087: val.append(normalLiteral);
088: val.append(')');
089: return val.toString();
090: } else if (isDateTime(isoDate)) {
091: StringBuffer val = new StringBuffer();
092: val.append("TIMESTAMP(");
093: val.append(normalLiteral);
094: val.append(')');
095: return val.toString();
096: } else {
097: return "UNSUPPORTED:" + isoDate;
098: }
099: }
100:
101: public String getCurrencyType() {
102: return "DECIMAL(19,4)";
103: }
104:
105: public String getUUIDType() {
106: return "VARCHAR(36)";
107: }
108:
109: public String getClobType() {
110: return "CLOB";
111: }
112:
113: public String getBlobType() {
114: return "BLOB";
115: }
116:
117: public String getDateTimeType() {
118: return "TIMESTAMP";
119: }
120:
121: public SqlStatement createFindSequencesSQL(String schema)
122: throws JDBCException {
123: return new RawSqlStatement(
124: "SELECT SEQNAME AS SEQUENCE_NAME FROM SYSCAT.SEQUENCES WHERE SEQTYPE='S' AND SEQSCHEMA = '"
125: + convertRequestedSchemaToSchema(schema) + "'");
126: }
127:
128: public boolean shouldQuoteValue(String value) {
129: return super .shouldQuoteValue(value)
130: && !value.startsWith("\"SYSIBM\"");
131: }
132:
133: public boolean supportsTablespaces() {
134: return true;
135: }
136:
137: public SqlStatement getViewDefinitionSql(String schemaName,
138: String name) throws JDBCException {
139: return new RawSqlStatement(
140: "select view_definition from SYSIBM.VIEWS where TABLE_NAME='"
141: + name + "' and TABLE_SCHEMA='"
142: + convertRequestedSchemaToSchema(schemaName)
143: + "'");
144: }
145:
146: public String getViewDefinition(String schemaName, String name)
147: throws JDBCException {
148: return super .getViewDefinition(schemaName, name).replaceFirst(
149: "CREATE VIEW \\w+ AS ", ""); //db2 returns "create view....as select
150: }
151:
152: public Object convertDatabaseValueToJavaObject(Object defaultValue,
153: int dataType, int columnSize, int decimalDigits)
154: throws ParseException {
155: if (defaultValue != null && defaultValue instanceof String) {
156: if (dataType == Types.TIMESTAMP) {
157: defaultValue = ((String) defaultValue).replaceFirst(
158: "^\"SYSIBM\".\"TIMESTAMP\"\\('", "")
159: .replaceFirst("'\\)", "");
160: } else if (dataType == Types.TIME) {
161: defaultValue = ((String) defaultValue).replaceFirst(
162: "^\"SYSIBM\".\"TIME\"\\('", "").replaceFirst(
163: "'\\)", "");
164: } else if (dataType == Types.DATE) {
165: defaultValue = ((String) defaultValue).replaceFirst(
166: "^\"SYSIBM\".\"DATE\"\\('", "").replaceFirst(
167: "'\\)", "");
168: }
169: }
170: return super .convertDatabaseValueToJavaObject(defaultValue,
171: dataType, columnSize, decimalDigits);
172: }
173:
174: protected java.util.Date parseDate(String dateAsString)
175: throws DateParseException {
176: try {
177: if (dateAsString.indexOf(' ') > 0) {
178: return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
179: .parse(dateAsString);
180: } else if (dateAsString.indexOf('.') > 0
181: && dateAsString.indexOf('-') > 0) {
182: return new SimpleDateFormat(
183: "yyyy-MM-dd-HH.mm.ss.SSSSSS")
184: .parse(dateAsString);
185:
186: } else {
187: if (dateAsString.indexOf(':') > 0) {
188: return new SimpleDateFormat("HH:mm:ss")
189: .parse(dateAsString);
190: } else if (dateAsString.indexOf('.') > 0) {
191: return new SimpleDateFormat("HH.mm.ss")
192: .parse(dateAsString);
193: } else {
194: return new SimpleDateFormat("yyyy-MM-dd")
195: .parse(dateAsString);
196: }
197: }
198: } catch (ParseException e) {
199: throw new DateParseException(dateAsString);
200: }
201: }
202:
203: public String convertRequestedSchemaToSchema(String requestedSchema)
204: throws JDBCException {
205: if (requestedSchema == null) {
206: return getDefaultDatabaseSchemaName();
207: } else {
208: return requestedSchema.toUpperCase();
209: }
210: }
211:
212: public String convertRequestedSchemaToCatalog(String requestedSchema)
213: throws JDBCException {
214: return null;
215: }
216:
217: public String generatePrimaryKeyName(String tableName) {
218: String pkName = super .generatePrimaryKeyName(tableName);
219: if (pkName.length() > 18) {
220: pkName = pkName.substring(0, 17);
221: }
222: return pkName;
223: }
224:
225: public boolean isColumnAutoIncrement(String schemaName,
226: String tableName, String columnName) throws SQLException,
227: JDBCException {
228: boolean autoIncrement = false;
229:
230: PreparedStatement stmt = null;
231: try {
232: stmt = getConnection()
233: .prepareStatement(
234: "SELECT IDENTITY FROM SYSCAT.COLUMNS WHERE TABSCHEMA = ? AND TABNAME = ? AND COLNAME = ? AND HIDDEN != 'S'");
235: stmt.setString(1,
236: convertRequestedSchemaToSchema(schemaName));
237: stmt.setString(2, tableName);
238: stmt.setString(3, columnName);
239:
240: ResultSet rs = stmt.executeQuery();
241:
242: while (rs.next()) {
243: String identity = rs.getString("IDENTITY");
244: if (identity.equalsIgnoreCase("Y")) {
245: autoIncrement = true;
246: }
247: }
248: rs.close();
249: } finally {
250: if (stmt != null) {
251: stmt.close();
252: }
253: }
254:
255: return autoIncrement;
256: }
257: }
|