Source Code Cross Referenced for AbstractDatabase.java in  » Database-Client » LiquiBase » liquibase » database » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database Client » LiquiBase » liquibase.database 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package liquibase.database;
0002:
0003:        import liquibase.ChangeSet;
0004:        import liquibase.RanChangeSet;
0005:        import liquibase.change.*;
0006:        import liquibase.database.sql.*;
0007:        import liquibase.database.structure.*;
0008:        import liquibase.database.template.JdbcTemplate;
0009:        import liquibase.diff.DiffStatusListener;
0010:        import liquibase.exception.DatabaseHistoryException;
0011:        import liquibase.exception.DateParseException;
0012:        import liquibase.exception.JDBCException;
0013:        import liquibase.exception.UnsupportedChangeException;
0014:        import liquibase.log.LogFactory;
0015:        import liquibase.util.ISODateFormat;
0016:        import liquibase.util.LiquibaseUtil;
0017:        import liquibase.util.StringUtils;
0018:
0019:        import java.math.BigInteger;
0020:        import java.sql.*;
0021:        import java.text.ParseException;
0022:        import java.text.SimpleDateFormat;
0023:        import java.util.*;
0024:        import java.util.Date;
0025:        import java.util.logging.Logger;
0026:
0027:        /**
0028:         * AbstractDatabase is extended by all supported databases as a facade to the underlying database.
0029:         * The physical connection can be retrieved from the AbstractDatabase implementation, as well as any
0030:         * database-specific characteristics such as the datatype for "boolean" fields.
0031:         */
0032:        public abstract class AbstractDatabase implements  Database {
0033:
0034:            private DatabaseConnection connection;
0035:            private String defaultSchemaName;
0036:
0037:            static final protected Logger log = LogFactory.getLogger();
0038:            protected boolean changeLogTableExists;
0039:            protected boolean changeLogLockTableExists;
0040:            protected boolean changeLogCreateAttempted;
0041:            protected boolean changeLogLockCreateAttempted;
0042:
0043:            protected String currentDateTimeFunction;
0044:
0045:            private JdbcTemplate jdbcTemplate = new JdbcTemplate(this );
0046:
0047:            protected AbstractDatabase() {
0048:            }
0049:
0050:            // ------- DATABASE INFORMATION METHODS ---- //
0051:
0052:            public DatabaseConnection getConnection() {
0053:                return connection;
0054:            }
0055:
0056:            public void setConnection(Connection conn) {
0057:                this .connection = new SQLConnectionDelegate(conn);
0058:                try {
0059:                    connection.setAutoCommit(getAutoCommitMode());
0060:                } catch (SQLException sqle) {
0061:                    log.warning("Can not set auto commit to "
0062:                            + getAutoCommitMode() + " on connection");
0063:                }
0064:            }
0065:
0066:            public void setConnection(DatabaseConnection conn) {
0067:                this .connection = conn;
0068:                try {
0069:                    connection.setAutoCommit(getAutoCommitMode());
0070:                } catch (SQLException sqle) {
0071:                    log.warning("Can not set auto commit to "
0072:                            + getAutoCommitMode() + " on connection");
0073:                }
0074:            }
0075:
0076:            /**
0077:             * Auto-commit mode to run in
0078:             */
0079:            public boolean getAutoCommitMode() {
0080:                return !supportsDDLInTransaction();
0081:            }
0082:
0083:            /**
0084:             * By default databases should support DDL within a transaction.
0085:             */
0086:            public boolean supportsDDLInTransaction() {
0087:                return true;
0088:            }
0089:
0090:            /**
0091:             * Returns the name of the database product according to the underlying database.
0092:             */
0093:            public String getDatabaseProductName() {
0094:                try {
0095:                    return connection.getMetaData().getDatabaseProductName();
0096:                } catch (SQLException e) {
0097:                    throw new RuntimeException("Cannot get database name");
0098:                }
0099:            }
0100:
0101:            public String getDatabaseProductName(Connection conn)
0102:                    throws JDBCException {
0103:                try {
0104:                    return conn.getMetaData().getDatabaseProductName();
0105:                } catch (SQLException e) {
0106:                    throw new JDBCException(e);
0107:                }
0108:            }
0109:
0110:            public String getDatabaseProductVersion() throws JDBCException {
0111:                try {
0112:                    return connection.getMetaData().getDatabaseProductVersion();
0113:                } catch (SQLException e) {
0114:                    throw new JDBCException(e);
0115:                }
0116:            }
0117:
0118:            public String getDriverName() throws JDBCException {
0119:                try {
0120:                    return connection.getMetaData().getDriverName();
0121:                } catch (SQLException e) {
0122:                    throw new JDBCException(e);
0123:                }
0124:            }
0125:
0126:            public String getConnectionURL() throws JDBCException {
0127:                try {
0128:                    return connection.getMetaData().getURL();
0129:                } catch (SQLException e) {
0130:                    throw new JDBCException(e);
0131:                }
0132:            }
0133:
0134:            public String getConnectionUsername() throws JDBCException {
0135:                try {
0136:                    return connection.getMetaData().getUserName();
0137:                } catch (SQLException e) {
0138:                    throw new JDBCException(e);
0139:                }
0140:            }
0141:
0142:            public String getDefaultCatalogName() throws JDBCException {
0143:                return null;
0144:            }
0145:
0146:            protected String getDefaultDatabaseSchemaName()
0147:                    throws JDBCException {
0148:                return getConnectionUsername();
0149:            }
0150:
0151:            public String getDefaultSchemaName() {
0152:                return defaultSchemaName;
0153:            }
0154:
0155:            public void setDefaultSchemaName(String schemaName)
0156:                    throws JDBCException {
0157:                this .defaultSchemaName = schemaName;
0158:            }
0159:
0160:            /**
0161:             * Returns system (undroppable) tables and views.
0162:             */
0163:            protected Set<String> getSystemTablesAndViews() {
0164:                return new HashSet<String>();
0165:            }
0166:
0167:            // ------- DATABASE FEATURE INFORMATION METHODS ---- //
0168:
0169:            /**
0170:             * Does the database type support sequence.
0171:             */
0172:            public boolean supportsSequences() {
0173:                return true;
0174:            }
0175:
0176:            public boolean supportsAutoIncrement() {
0177:                return true;
0178:            }
0179:
0180:            // ------- DATABASE-SPECIFIC SQL METHODS ---- //
0181:
0182:            public void setCurrentDateTimeFunction(String function) {
0183:                if (function != null) {
0184:                    this .currentDateTimeFunction = function;
0185:                }
0186:            }
0187:
0188:            /**
0189:             * Returns the database-specific datatype for the given column configuration.
0190:             * This method will convert some generic column types (e.g. boolean, currency) to the correct type
0191:             * for the current database.
0192:             */
0193:            public String getColumnType(String columnType, Boolean autoIncrement) {
0194:                if (columnType.startsWith("java.sql.Types")) {
0195:                    String dataTypeName = columnType.substring(columnType
0196:                            .lastIndexOf(".") + 1);
0197:                    String precision = null;
0198:                    if (dataTypeName.indexOf("(") >= 0) {
0199:                        precision = dataTypeName.substring(dataTypeName
0200:                                .indexOf("(") + 1, dataTypeName.indexOf(")"));
0201:                        dataTypeName = dataTypeName.substring(0, dataTypeName
0202:                                .indexOf("("));
0203:                    }
0204:
0205:                    ResultSet resultSet = null;
0206:                    try {
0207:                        DatabaseConnection connection = getConnection();
0208:                        if (connection == null) {
0209:                            throw new RuntimeException(
0210:                                    "Cannot evaluate java.sql.Types without a connection");
0211:                        }
0212:                        resultSet = connection.getMetaData().getTypeInfo();
0213:                        while (resultSet.next()) {
0214:                            String typeName = resultSet.getString("TYPE_NAME");
0215:                            int dataType = resultSet.getInt("DATA_TYPE");
0216:                            Integer requestedType = (Integer) Class.forName(
0217:                                    "java.sql.Types").getDeclaredField(
0218:                                    dataTypeName).get(null);
0219:                            if (requestedType == dataType) {
0220:                                if (precision == null) {
0221:                                    return typeName;
0222:                                } else {
0223:                                    return typeName + "(" + precision + ")";
0224:                                }
0225:                            }
0226:                        }
0227:                        //did not find type, fall back on our defaults for ones we can figure out
0228:                        if (dataTypeName.equalsIgnoreCase("BLOB")) {
0229:                            return getBlobType();
0230:                        } else if (dataTypeName.equalsIgnoreCase("CLOB")) {
0231:                            return getClobType();
0232:                        } else if (dataTypeName.equalsIgnoreCase("BOOLEAN")) {
0233:                            return getBooleanType();
0234:                        } else if (dataTypeName.equalsIgnoreCase("DATE")) {
0235:                            return getDateType();
0236:                        } else if (dataTypeName.equalsIgnoreCase("TIME")) {
0237:                            return getTimeType();
0238:                        }
0239:
0240:                        throw new RuntimeException(
0241:                                "Could not find java.sql.Types value for "
0242:                                        + dataTypeName);
0243:                    } catch (Exception e) {
0244:                        throw new RuntimeException(e);
0245:                    } finally {
0246:                        if (resultSet != null) {
0247:                            try {
0248:                                resultSet.close();
0249:                            } catch (SQLException e) {
0250:                                ;
0251:                            }
0252:                        }
0253:                    }
0254:                } else if ("boolean".equalsIgnoreCase(columnType)) {
0255:                    return getBooleanType();
0256:                } else if ("currency".equalsIgnoreCase(columnType)) {
0257:                    return getCurrencyType();
0258:                } else if ("UUID".equalsIgnoreCase(columnType)) {
0259:                    return getUUIDType();
0260:                } else if ("BLOB".equalsIgnoreCase(columnType)
0261:                        || "LONGVARBINARY".equalsIgnoreCase(columnType)) {
0262:                    return getBlobType();
0263:                } else if ("CLOB".equalsIgnoreCase(columnType)
0264:                        || "TEXT".equalsIgnoreCase(columnType)
0265:                        || "LONGVARCHAR".equalsIgnoreCase(columnType)) {
0266:                    return getClobType();
0267:                } else if ("date".equalsIgnoreCase(columnType)) {
0268:                    return getDateType();
0269:                } else if ("time".equalsIgnoreCase(columnType)) {
0270:                    return getTimeType();
0271:                } else if ("dateTime".equalsIgnoreCase(columnType)) {
0272:                    return getDateTimeType();
0273:                } else if (columnType.toUpperCase().startsWith("FLOAT(")) {
0274:                    return "FLOAT";
0275:                } else if (columnType.toUpperCase().startsWith("DOUBLE(")) {
0276:                    return "DOUBLE";
0277:                } else {
0278:                    return columnType;
0279:                }
0280:            }
0281:
0282:            public final String getColumnType(ColumnConfig columnConfig) {
0283:                return getColumnType(columnConfig.getType(), columnConfig
0284:                        .isAutoIncrement());
0285:            }
0286:
0287:            /**
0288:             * The database-specific value to use for "false" "boolean" columns.
0289:             */
0290:            public String getFalseBooleanValue() {
0291:                return "false";
0292:            }
0293:
0294:            /**
0295:             * The database-specific value to use for "true" "boolean" columns.
0296:             */
0297:            public String getTrueBooleanValue() {
0298:                return "true";
0299:            }
0300:
0301:            /**
0302:             * Return a date literal with the same value as a string formatted using ISO 8601.
0303:             * <p/>
0304:             * Note: many databases accept date literals in ISO8601 format with the 'T' replaced with
0305:             * a space. Only databases which do not accept these strings should need to override this
0306:             * method.
0307:             * <p/>
0308:             * Implementation restriction:
0309:             * Currently, only the following subsets of ISO8601 are supported:
0310:             * yyyy-MM-dd
0311:             * hh:mm:ss
0312:             * yyyy-MM-ddThh:mm:ss
0313:             */
0314:            public String getDateLiteral(String isoDate) {
0315:                if (isDateOnly(isoDate) || isTimeOnly(isoDate)) {
0316:                    return "'" + isoDate + "'";
0317:                } else if (isDateTime(isoDate)) {
0318:                    StringBuffer val = new StringBuffer();
0319:                    val.append("'");
0320:                    val.append(isoDate.substring(0, 10));
0321:                    val.append(" ");
0322:                    //noinspection MagicNumber
0323:                    val.append(isoDate.substring(11));
0324:                    val.append("'");
0325:                    return val.toString();
0326:                } else {
0327:                    return "BAD_DATE_FORMAT:" + isoDate;
0328:                }
0329:            }
0330:
0331:            public String getDateLiteral(java.sql.Timestamp date) {
0332:                return getDateLiteral(new ISODateFormat().format(date)
0333:                        .replaceFirst("^'", "").replaceFirst("'$", ""));
0334:            }
0335:
0336:            public String getDateLiteral(java.sql.Date date) {
0337:                return getDateLiteral(new ISODateFormat().format(date)
0338:                        .replaceFirst("^'", "").replaceFirst("'$", ""));
0339:            }
0340:
0341:            public String getDateLiteral(java.sql.Time date) {
0342:                return getDateLiteral(new ISODateFormat().format(date)
0343:                        .replaceFirst("^'", "").replaceFirst("'$", ""));
0344:            }
0345:
0346:            public String getDateLiteral(Date date) {
0347:                if (date instanceof  java.sql.Date) {
0348:                    return getDateLiteral(((java.sql.Date) date));
0349:                } else if (date instanceof  java.sql.Time) {
0350:                    return getDateLiteral(((java.sql.Time) date));
0351:                } else if (date instanceof  Timestamp) {
0352:                    return getDateLiteral(((Timestamp) date));
0353:                } else if (date instanceof  ComputedDateValue) {
0354:                    return date.toString();
0355:                } else {
0356:                    throw new RuntimeException("Unexpected type: "
0357:                            + date.getClass().getName());
0358:                }
0359:            }
0360:
0361:            protected Date parseDate(String dateAsString)
0362:                    throws DateParseException {
0363:                try {
0364:                    if (dateAsString.indexOf(" ") > 0) {
0365:                        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
0366:                                .parse(dateAsString);
0367:                    } else {
0368:                        if (dateAsString.indexOf(":") > 0) {
0369:                            return new SimpleDateFormat("HH:mm:ss")
0370:                                    .parse(dateAsString);
0371:                        } else {
0372:                            return new SimpleDateFormat("yyyy-MM-dd")
0373:                                    .parse(dateAsString);
0374:                        }
0375:                    }
0376:                } catch (ParseException e) {
0377:                    throw new DateParseException(dateAsString);
0378:                }
0379:            }
0380:
0381:            protected boolean isDateOnly(String isoDate) {
0382:                return isoDate.length() == "yyyy-MM-dd".length();
0383:            }
0384:
0385:            protected boolean isDateTime(String isoDate) {
0386:                return isoDate.length() >= "yyyy-MM-ddThh:mm:ss".length();
0387:            }
0388:
0389:            protected boolean isTimeOnly(String isoDate) {
0390:                return isoDate.length() == "hh:mm:ss".length();
0391:            }
0392:
0393:            /**
0394:             * Returns the actual database-specific data type to use a "date" (no time information) column.
0395:             */
0396:            public String getDateType() {
0397:                return "DATE";
0398:            }
0399:
0400:            /**
0401:             * Returns the actual database-specific data type to use a "time" column.
0402:             */
0403:            public String getTimeType() {
0404:                return "TIME";
0405:            }
0406:
0407:            /**
0408:             * Returns database-specific line comment string.
0409:             */
0410:            public String getLineComment() {
0411:                return "--";
0412:            }
0413:
0414:            /**
0415:             * Returns database-specific auto-increment DDL clause.
0416:             */
0417:            public String getAutoIncrementClause() {
0418:                return "AUTO_INCREMENT";
0419:            }
0420:
0421:            public String getConcatSql(String... values) {
0422:                StringBuffer returnString = new StringBuffer();
0423:                for (String value : values) {
0424:                    returnString.append(value).append(" || ");
0425:                }
0426:
0427:                return returnString.toString().replaceFirst(" \\|\\| $", "");
0428:            }
0429:
0430:            // ------- DATABASECHANGELOG / DATABASECHANGELOGLOCK METHODS ---- //
0431:
0432:            public String getDatabaseChangeLogTableName() {
0433:                return "DatabaseChangeLog".toUpperCase();
0434:            }
0435:
0436:            public String getDatabaseChangeLogLockTableName() {
0437:                return "DatabaseChangeLogLock".toUpperCase();
0438:            }
0439:
0440:            private SqlStatement getChangeLogLockInsertSQL() {
0441:                return new InsertStatement(getDefaultSchemaName(),
0442:                        getDatabaseChangeLogLockTableName()).addColumnValue(
0443:                        "ID", 1).addColumnValue("LOCKED", Boolean.FALSE);
0444:            }
0445:
0446:            protected SqlStatement getCreateChangeLogLockSQL() {
0447:                return new CreateTableStatement(getDefaultSchemaName(),
0448:                        getDatabaseChangeLogLockTableName())
0449:                        .addPrimaryKeyColumn("ID", "INT",
0450:                                new NotNullConstraint()).addColumn("LOCKED",
0451:                                getBooleanType(), new NotNullConstraint())
0452:                        .addColumn("LOCKGRANTED", getDateTimeType()).addColumn(
0453:                                "LOCKEDBY", "VARCHAR(255)");
0454:            }
0455:
0456:            protected SqlStatement getCreateChangeLogSQL() {
0457:                return new CreateTableStatement(getDefaultSchemaName(),
0458:                        getDatabaseChangeLogTableName()).addPrimaryKeyColumn(
0459:                        "ID", "VARCHAR(63)", new NotNullConstraint())
0460:                        .addPrimaryKeyColumn("AUTHOR", "VARCHAR(63)",
0461:                                new NotNullConstraint()).addPrimaryKeyColumn(
0462:                                "FILENAME", "VARCHAR(200)",
0463:                                new NotNullConstraint()).addColumn(
0464:                                "DATEEXECUTED", getDateTimeType(),
0465:                                new NotNullConstraint()).addColumn("MD5SUM",
0466:                                "VARCHAR(32)").addColumn("DESCRIPTION",
0467:                                "VARCHAR(255)").addColumn("COMMENTS",
0468:                                "VARCHAR(255)")
0469:                        .addColumn("TAG", "VARCHAR(255)").addColumn(
0470:                                "LIQUIBASE", "VARCHAR(10)");
0471:            }
0472:
0473:            public SqlStatement getSelectChangeLogLockSQL()
0474:                    throws JDBCException {
0475:                return new RawSqlStatement(
0476:                        ("SELECT LOCKED FROM "
0477:                                + escapeTableName(getDefaultSchemaName(),
0478:                                        getDatabaseChangeLogLockTableName()) + " WHERE ID=1"));
0479:            }
0480:
0481:            public boolean doesChangeLogTableExist() {
0482:                return changeLogTableExists;
0483:            }
0484:
0485:            public boolean doesChangeLogLockTableExist() {
0486:                return changeLogLockTableExists;
0487:            }
0488:
0489:            /**
0490:             * This method will check the database ChangeLog table used to keep track of
0491:             * the changes in the file. If the table does not exist it will create one
0492:             * otherwise it will not do anything besides outputting a log message.
0493:             */
0494:            public void checkDatabaseChangeLogTable() throws JDBCException {
0495:                DatabaseConnection connection = getConnection();
0496:                ResultSet checkTableRS = null;
0497:                ResultSet checkColumnsRS = null;
0498:                List<SqlStatement> statementsToExecute = new ArrayList<SqlStatement>();
0499:
0500:                try {
0501:                    checkTableRS = connection
0502:                            .getMetaData()
0503:                            .getTables(
0504:                                    convertRequestedSchemaToCatalog(getDefaultSchemaName()),
0505:                                    convertRequestedSchemaToSchema(getDefaultSchemaName()),
0506:                                    getDatabaseChangeLogTableName(),
0507:                                    new String[] { "TABLE" });
0508:                    if (checkTableRS.next()) {
0509:                        changeLogTableExists = true;
0510:                        checkColumnsRS = connection
0511:                                .getMetaData()
0512:                                .getColumns(
0513:                                        convertRequestedSchemaToCatalog(getDefaultSchemaName()),
0514:                                        convertRequestedSchemaToSchema(getDefaultSchemaName()),
0515:                                        getDatabaseChangeLogTableName(), null);
0516:                        boolean hasDescription = false;
0517:                        boolean hasComments = false;
0518:                        boolean hasTag = false;
0519:                        boolean hasLiquibase = false;
0520:                        while (checkColumnsRS.next()) {
0521:                            String columnName = checkColumnsRS
0522:                                    .getString("COLUMN_NAME");
0523:                            if ("DESCRIPTION".equalsIgnoreCase(columnName)) {
0524:                                hasDescription = true;
0525:                            } else if ("COMMENTS".equalsIgnoreCase(columnName)) {
0526:                                hasComments = true;
0527:                            } else if ("TAG".equalsIgnoreCase(columnName)) {
0528:                                hasTag = true;
0529:                            } else if ("LIQUIBASE".equalsIgnoreCase(columnName)) {
0530:                                hasLiquibase = true;
0531:                            }
0532:                        }
0533:
0534:                        if (!hasDescription) {
0535:                            statementsToExecute.add(new AddColumnStatement(
0536:                                    getDefaultSchemaName(),
0537:                                    getDatabaseChangeLogTableName(),
0538:                                    "DESCRIPTION", "VARCHAR(255)", null));
0539:                        }
0540:                        if (!hasTag) {
0541:                            statementsToExecute.add(new AddColumnStatement(
0542:                                    getDefaultSchemaName(),
0543:                                    getDatabaseChangeLogTableName(), "TAG",
0544:                                    "VARCHAR(255)", null));
0545:                        }
0546:                        if (!hasComments) {
0547:                            statementsToExecute.add(new AddColumnStatement(
0548:                                    getDefaultSchemaName(),
0549:                                    getDatabaseChangeLogTableName(),
0550:                                    "COMMENTS", "VARCHAR(255)", null));
0551:                        }
0552:                        if (!hasLiquibase) {
0553:                            statementsToExecute.add(new AddColumnStatement(
0554:                                    getDefaultSchemaName(),
0555:                                    getDatabaseChangeLogTableName(),
0556:                                    "LIQUIBASE", "VARCHAR(255)", null));
0557:                        }
0558:
0559:                    } else if (!changeLogCreateAttempted) {
0560:                        changeLogCreateAttempted = true;
0561:                        getJdbcTemplate().comment(
0562:                                "Create Database Change Log Table");
0563:                        SqlStatement createTableStatement = getCreateChangeLogSQL();
0564:                        if (!canCreateChangeLogTable()) {
0565:                            throw new JDBCException(
0566:                                    "Cannot create "
0567:                                            + escapeTableName(
0568:                                                    getDefaultSchemaName(),
0569:                                                    getDatabaseChangeLogTableName())
0570:                                            + " table for your database.\n\n"
0571:                                            + "Please construct it manually using the following SQL as a base and re-run LiquiBase:\n\n"
0572:                                            + createTableStatement);
0573:                        }
0574:                        // If there is no table in the database for recording change history create one.
0575:                        statementsToExecute.add(createTableStatement);
0576:                        log.info("Creating database history table with name: "
0577:                                + escapeTableName(getDefaultSchemaName(),
0578:                                        getDatabaseChangeLogTableName()));
0579:                        changeLogTableExists = true;
0580:                        //                }
0581:                    }
0582:
0583:                    for (SqlStatement sql : statementsToExecute) {
0584:                        this .getJdbcTemplate().execute(sql);
0585:                        this .commit();
0586:                    }
0587:                } catch (SQLException e) {
0588:                    throw new JDBCException(e);
0589:                } finally {
0590:                    if (checkTableRS != null) {
0591:                        try {
0592:                            checkTableRS.close();
0593:                        } catch (SQLException e) {
0594:                            //noinspection ThrowFromFinallyBlock
0595:                            throw new JDBCException(e);
0596:                        }
0597:                    }
0598:                    if (checkColumnsRS != null) {
0599:                        try {
0600:                            checkColumnsRS.close();
0601:                        } catch (SQLException e) {
0602:                            //noinspection ThrowFromFinallyBlock
0603:                            throw new JDBCException(e);
0604:                        }
0605:                    }
0606:                }
0607:            }
0608:
0609:            protected boolean canCreateChangeLogTable() throws JDBCException {
0610:                return true;
0611:            }
0612:
0613:            /**
0614:             * This method will check the database ChangeLogLock table used to keep track of
0615:             * if a machine is updating the database. If the table does not exist it will create one
0616:             * otherwise it will not do anything besides outputting a log message.
0617:             */
0618:            public void checkDatabaseChangeLogLockTable() throws JDBCException {
0619:                DatabaseConnection connection = getConnection();
0620:                ResultSet rs = null;
0621:                boolean knowMustInsertIntoLockTable = false;
0622:                try {
0623:                    rs = connection
0624:                            .getMetaData()
0625:                            .getTables(
0626:                                    convertRequestedSchemaToCatalog(getDefaultSchemaName()),
0627:                                    convertRequestedSchemaToSchema(getDefaultSchemaName()),
0628:                                    getDatabaseChangeLogLockTableName(),
0629:                                    new String[] { "TABLE" });
0630:                    if (!rs.next()) {
0631:                        if (!changeLogLockCreateAttempted) {
0632:                            changeLogLockCreateAttempted = true;
0633:                            SqlStatement createTableStatement = getCreateChangeLogLockSQL();
0634:
0635:                            getJdbcTemplate().comment(
0636:                                    "Create Database Lock Table");
0637:                            this .getJdbcTemplate()
0638:                                    .execute(createTableStatement);
0639:                            this .commit();
0640:                            log
0641:                                    .info("Created database lock table with name: "
0642:                                            + escapeTableName(
0643:                                                    getDefaultSchemaName(),
0644:                                                    getDatabaseChangeLogLockTableName()));
0645:                            changeLogLockTableExists = true;
0646:                            knowMustInsertIntoLockTable = true;
0647:                        }
0648:                    } else {
0649:                        changeLogLockTableExists = true;
0650:                    }
0651:                    rs.close();
0652:
0653:                    if (changeLogLockTableExists) {
0654:                        int rows = -1;
0655:                        if (!knowMustInsertIntoLockTable) {
0656:                            RawSqlStatement selectStatement = new RawSqlStatement(
0657:                                    "SELECT COUNT(*) FROM "
0658:                                            + escapeTableName(
0659:                                                    getDefaultSchemaName(),
0660:                                                    getDatabaseChangeLogLockTableName())
0661:                                            + " WHERE ID=1");
0662:                            rows = this .getJdbcTemplate().queryForInt(
0663:                                    selectStatement);
0664:                        }
0665:                        if (knowMustInsertIntoLockTable || rows == 0) {
0666:                            this .getJdbcTemplate().update(
0667:                                    getChangeLogLockInsertSQL());
0668:                            this .commit();
0669:                            log
0670:                                    .info("Inserted lock row into: "
0671:                                            + escapeTableName(
0672:                                                    getDefaultSchemaName(),
0673:                                                    getDatabaseChangeLogLockTableName()));
0674:                            rs.close();
0675:                        }
0676:                    } else {
0677:                        throw new JDBCException(
0678:                                "Change log lock table does not exist");
0679:                    }
0680:
0681:                } catch (SQLException e) {
0682:                    throw new JDBCException(e);
0683:                } finally {
0684:                    if (rs != null) {
0685:                        try {
0686:                            rs.close();
0687:                        } catch (SQLException e) {
0688:                            //noinspection ThrowFromFinallyBlock
0689:                            throw new JDBCException(e);
0690:                        }
0691:                    }
0692:                }
0693:            }
0694:
0695:            // ------- DATABASE OBJECT DROPPING METHODS ---- //
0696:
0697:            /**
0698:             * Drops all objects owned by the connected user.
0699:             *
0700:             * @param schema
0701:             */
0702:            public void dropDatabaseObjects(String schema) throws JDBCException {
0703:                try {
0704:                    DatabaseSnapshot snapshot = new DatabaseSnapshot(this ,
0705:                            new HashSet<DiffStatusListener>(), schema);
0706:
0707:                    List<Change> dropChanges = new ArrayList<Change>();
0708:
0709:                    for (ForeignKey fk : snapshot.getForeignKeys()) {
0710:                        DropForeignKeyConstraintChange dropFK = new DropForeignKeyConstraintChange();
0711:                        dropFK.setBaseTableSchemaName(schema);
0712:                        dropFK.setBaseTableName(fk.getForeignKeyTable()
0713:                                .getName());
0714:                        dropFK.setConstraintName(fk.getName());
0715:
0716:                        dropChanges.add(dropFK);
0717:                    }
0718:
0719:                    for (View view : snapshot.getViews()) {
0720:                        DropViewChange dropChange = new DropViewChange();
0721:                        dropChange.setViewName(view.getName());
0722:                        dropChange.setSchemaName(schema);
0723:
0724:                        dropChanges.add(dropChange);
0725:                    }
0726:
0727:                    //            for (Index index : snapshot.getIndexes()) {
0728:                    //                DropIndexChange dropChange = new DropIndexChange();
0729:                    //                dropChange.setIndexName(index.getName());
0730:                    //                dropChange.setSchemaName(schema);
0731:                    //                dropChange.setTableName(index.getTableName());
0732:                    //
0733:                    //                dropChanges.add(dropChange);
0734:                    //            }
0735:
0736:                    for (Table table : snapshot.getTables()) {
0737:                        DropTableChange dropChange = new DropTableChange();
0738:                        dropChange.setSchemaName(schema);
0739:                        dropChange.setTableName(table.getName());
0740:
0741:                        dropChanges.add(dropChange);
0742:                    }
0743:
0744:                    if (this .supportsSequences()) {
0745:                        for (Sequence seq : snapshot.getSequences()) {
0746:                            DropSequenceChange dropChange = new DropSequenceChange();
0747:                            dropChange.setSequenceName(seq.getName());
0748:                            dropChange.setSchemaName(schema);
0749:
0750:                            dropChanges.add(dropChange);
0751:                        }
0752:                    }
0753:
0754:                    if (this .changeLogTableExists) {
0755:                        RawSQLChange clearChangeLogChange = new RawSQLChange();
0756:                        clearChangeLogChange
0757:                                .setSql("DELETE FROM "
0758:                                        + escapeTableName(
0759:                                                convertRequestedSchemaToSchema(getDefaultSchemaName()),
0760:                                                getDatabaseChangeLogTableName()));
0761:                        dropChanges.add(clearChangeLogChange);
0762:                    }
0763:
0764:                    try {
0765:                        for (Change change : dropChanges) {
0766:                            for (SqlStatement statement : change
0767:                                    .generateStatements(this )) {
0768:                                this .getJdbcTemplate().execute(statement);
0769:                            }
0770:                        }
0771:                    } catch (UnsupportedChangeException e) {
0772:                        throw new JDBCException(e);
0773:                    }
0774:
0775:                } finally {
0776:                    this .commit();
0777:                }
0778:            }
0779:
0780:            public boolean isSystemTable(String catalogName, String schemaName,
0781:                    String tableName) {
0782:                if ("information_schema".equalsIgnoreCase(schemaName)) {
0783:                    return true;
0784:                } else if (tableName
0785:                        .equalsIgnoreCase(getDatabaseChangeLogLockTableName())) {
0786:                    return true;
0787:                } else if (getSystemTablesAndViews().contains(tableName)) {
0788:                    return true;
0789:                }
0790:                return false;
0791:            }
0792:
0793:            public boolean isSystemView(String catalogName, String schemaName,
0794:                    String viewName) {
0795:                if ("information_schema".equalsIgnoreCase(schemaName)) {
0796:                    return true;
0797:                } else if (getSystemTablesAndViews().contains(viewName)) {
0798:                    return true;
0799:                }
0800:                return false;
0801:            }
0802:
0803:            public boolean isLiquibaseTable(String tableName) {
0804:                return tableName.equalsIgnoreCase(this 
0805:                        .getDatabaseChangeLogTableName())
0806:                        || tableName.equalsIgnoreCase(this 
0807:                                .getDatabaseChangeLogLockTableName());
0808:            }
0809:
0810:            // ------- DATABASE TAGGING METHODS ---- //
0811:
0812:            /**
0813:             * Tags the database changelog with the given string.
0814:             */
0815:            public void tag(String tagString) throws JDBCException {
0816:                try {
0817:                    int totalRows = this .getJdbcTemplate().queryForInt(
0818:                            new RawSqlStatement("SELECT COUNT(*) FROM "
0819:                                    + escapeTableName(getDefaultSchemaName(),
0820:                                            getDatabaseChangeLogTableName())));
0821:                    if (totalRows == 0) {
0822:                        throw new JDBCException("Cannot tag an empty database");
0823:                    }
0824:
0825:                    Timestamp lastExecutedDate = (Timestamp) this 
0826:                            .getJdbcTemplate().queryForObject(
0827:                                    createChangeToTagSQL(), Timestamp.class);
0828:                    int rowsUpdated = this .getJdbcTemplate().update(
0829:                            createTagSQL(tagString, lastExecutedDate));
0830:                    if (rowsUpdated == 0) {
0831:                        throw new JDBCException(
0832:                                "Did not tag database change log correctly.  Should have tagged changeset from "
0833:                                        + lastExecutedDate.toString());
0834:                    }
0835:                    this .commit();
0836:                } catch (Exception e) {
0837:                    throw new JDBCException(e);
0838:                }
0839:            }
0840:
0841:            /**
0842:             * Returns SQL to return the date of the most recient changeset execution.
0843:             */
0844:            protected SqlStatement createChangeToTagSQL() {
0845:                return new RawSqlStatement("SELECT MAX(DATEEXECUTED) FROM "
0846:                        + escapeTableName(getDefaultSchemaName(),
0847:                                getDatabaseChangeLogTableName()));
0848:            }
0849:
0850:            /**
0851:             * Returns SQL to tag the database.  SQL Contains two ?:
0852:             * <ol>
0853:             * <li>tag string</li>
0854:             * <li>date executed</li>
0855:             * </ol>
0856:             */
0857:            protected SqlStatement createTagSQL(String tagName,
0858:                    Date dateExecuted) {
0859:                UpdateStatement statement = new UpdateStatement(
0860:                        getDefaultSchemaName(), getDatabaseChangeLogTableName());
0861:                statement.addNewColumnValue("TAG", tagName);
0862:                statement.setWhereClause("DATEEXECUTED = ?");
0863:                statement.addWhereParameter(dateExecuted);
0864:
0865:                return statement;
0866:            }
0867:
0868:            public SqlStatement createFindSequencesSQL(String schema)
0869:                    throws JDBCException {
0870:                return null;
0871:            }
0872:
0873:            public boolean doesTagExist(String tag) throws JDBCException {
0874:                int count = this .getJdbcTemplate().queryForInt(
0875:                        new RawSqlStatement("SELECT COUNT(*) FROM "
0876:                                + escapeTableName(getDefaultSchemaName(),
0877:                                        getDatabaseChangeLogTableName())
0878:                                + " WHERE TAG='" + tag + "'"));
0879:                return count > 0;
0880:            }
0881:
0882:            public DatabaseSnapshot getSnapshot() throws JDBCException {
0883:                return new DatabaseSnapshot(this );
0884:            }
0885:
0886:            public String toString() {
0887:                if (getConnection() == null) {
0888:                    return getProductName() + " Database";
0889:                }
0890:                try {
0891:                    return getConnectionUsername()
0892:                            + " @ "
0893:                            + getConnectionURL()
0894:                            + (getDefaultSchemaName() == null ? ""
0895:                                    : " (Default Schema: "
0896:                                            + getDefaultSchemaName() + ")");
0897:                } catch (JDBCException e) {
0898:                    return super .toString();
0899:                }
0900:            }
0901:
0902:            public boolean shouldQuoteValue(String value) {
0903:                return true;
0904:            }
0905:
0906:            public String getViewDefinition(String schemaName, String viewName)
0907:                    throws JDBCException {
0908:                if (schemaName == null) {
0909:                    schemaName = convertRequestedSchemaToSchema(schemaName);
0910:                }
0911:                String definition = (String) this .getJdbcTemplate()
0912:                        .queryForObject(
0913:                                getViewDefinitionSql(schemaName, viewName),
0914:                                String.class);
0915:                if (definition == null) {
0916:                    return null;
0917:                }
0918:                return definition.replaceFirst("^CREATE VIEW [\\S]+ AS", "");
0919:            }
0920:
0921:            public SqlStatement getViewDefinitionSql(String schemaName,
0922:                    String viewName) throws JDBCException {
0923:                String sql = "select view_definition from information_schema.views where upper(table_name)='"
0924:                        + viewName.toUpperCase() + "'";
0925:                if (convertRequestedSchemaToCatalog(schemaName) != null) {
0926:                    sql += " and table_schema='"
0927:                            + convertRequestedSchemaToSchema(schemaName) + "'";
0928:                } else if (convertRequestedSchemaToCatalog(schemaName) != null) {
0929:                    sql += " and table_catalog='"
0930:                            + convertRequestedSchemaToCatalog(schemaName) + "'";
0931:                }
0932:
0933:                log.info("GetViewDefinitionSQL: " + sql);
0934:                return new RawSqlStatement(sql);
0935:            }
0936:
0937:            public int getDatabaseType(int type) {
0938:                int returnType = type;
0939:                if (returnType == Types.BOOLEAN) {
0940:                    String booleanType = getBooleanType();
0941:                    if (!booleanType.equalsIgnoreCase("boolean")) {
0942:                        returnType = Types.TINYINT;
0943:                    }
0944:                }
0945:
0946:                return returnType;
0947:            }
0948:
0949:            public Object convertDatabaseValueToJavaObject(Object defaultValue,
0950:                    int dataType, int columnSize, int decimalDigits)
0951:                    throws ParseException {
0952:                if (defaultValue == null) {
0953:                    return null;
0954:                } else if (defaultValue instanceof  String) {
0955:                    return convertToCorrectJavaType(((String) defaultValue)
0956:                            .replaceFirst("^'", "").replaceFirst("'$", ""),
0957:                            dataType, columnSize, decimalDigits);
0958:                } else {
0959:                    return defaultValue;
0960:                }
0961:            }
0962:
0963:            protected Object convertToCorrectJavaType(String value,
0964:                    int dataType, int columnSize, int decimalDigits)
0965:                    throws ParseException {
0966:                if (value == null) {
0967:                    return null;
0968:                }
0969:                if (dataType == Types.CLOB || dataType == Types.VARCHAR
0970:                        || dataType == Types.CHAR
0971:                        || dataType == Types.LONGVARCHAR) {
0972:                    if (value.equalsIgnoreCase("NULL")) {
0973:                        return null;
0974:                    } else {
0975:                        return value;
0976:                    }
0977:                }
0978:
0979:                value = StringUtils.trimToNull(value);
0980:                if (value == null) {
0981:                    return null;
0982:                }
0983:
0984:                try {
0985:                    if (dataType == Types.DATE) {
0986:                        return new java.sql.Date(parseDate(value).getTime());
0987:                    } else if (dataType == Types.TIMESTAMP) {
0988:                        return new Timestamp(parseDate(value).getTime());
0989:                    } else if (dataType == Types.TIME) {
0990:                        return new Time(parseDate(value).getTime());
0991:                    } else if (dataType == Types.BIGINT) {
0992:                        return new BigInteger(value);
0993:                    } else if (dataType == Types.BIT) {
0994:                        if (value.equalsIgnoreCase("true")) {
0995:                            return Boolean.TRUE;
0996:                        } else if (value.equalsIgnoreCase("false")) {
0997:                            return Boolean.FALSE;
0998:                        } else if (value.equals("1")) {
0999:                            return Boolean.TRUE;
1000:                        } else if (value.equals("0")) {
1001:                            return Boolean.FALSE;
1002:                        } else if (value.equals("(1)")) {
1003:                            return Boolean.TRUE;
1004:                        } else if (value.equals("(0)")) {
1005:                            return Boolean.FALSE;
1006:                        }
1007:                        throw new ParseException("Unknown bit value: " + value,
1008:                                0);
1009:                    } else if (dataType == Types.BOOLEAN) {
1010:                        return Boolean.valueOf(value);
1011:                    } else if (dataType == Types.DECIMAL) {
1012:                        if (decimalDigits == 0) {
1013:                            return new Integer(value);
1014:                        }
1015:                        return new Double(value);
1016:                    } else if (dataType == Types.DOUBLE
1017:                            || dataType == Types.NUMERIC) {
1018:                        return new Double(value);
1019:                    } else if (dataType == Types.FLOAT) {
1020:                        return new Float(value);
1021:                    } else if (dataType == Types.INTEGER) {
1022:                        return new Integer(value);
1023:                    } else if (dataType == Types.NULL) {
1024:                        return null;
1025:                    } else if (dataType == Types.REAL) {
1026:                        return new Float(value);
1027:                    } else if (dataType == Types.SMALLINT) {
1028:                        return new Integer(value);
1029:                    } else if (dataType == Types.TINYINT) {
1030:                        return new Integer(value);
1031:                    } else {
1032:                        throw new RuntimeException("Cannot convert type: "
1033:                                + dataType);
1034:                    }
1035:                } catch (DateParseException e) {
1036:                    return new ComputedDateValue(value);
1037:                } catch (NumberFormatException e) {
1038:                    return new ComputedNumericValue(value);
1039:                }
1040:            }
1041:
1042:            public String convertJavaObjectToString(Object value) {
1043:                if (value != null) {
1044:                    if (value instanceof  String) {
1045:                        if ("null".equalsIgnoreCase(((String) value))) {
1046:                            return null;
1047:                        }
1048:                        return "'" + ((String) value).replaceAll("'", "''")
1049:                                + "'";
1050:                    } else if (value instanceof  Number) {
1051:                        return value.toString();
1052:                    } else if (value instanceof  Boolean) {
1053:                        String returnValue;
1054:                        if (((Boolean) value)) {
1055:                            returnValue = this .getTrueBooleanValue();
1056:                        } else {
1057:                            returnValue = this .getFalseBooleanValue();
1058:                        }
1059:                        if (returnValue.matches("\\d+")) {
1060:                            return returnValue;
1061:                        } else {
1062:                            return "'" + returnValue + "'";
1063:                        }
1064:                    } else if (value instanceof  java.sql.Date) {
1065:                        return this .getDateLiteral(((java.sql.Date) value));
1066:                    } else if (value instanceof  java.sql.Time) {
1067:                        return this .getDateLiteral(((java.sql.Time) value));
1068:                    } else if (value instanceof  java.sql.Timestamp) {
1069:                        return this 
1070:                                .getDateLiteral(((java.sql.Timestamp) value));
1071:                    } else {
1072:                        throw new RuntimeException(
1073:                                "Unknown default value type: "
1074:                                        + value.getClass().getName());
1075:                    }
1076:                } else {
1077:                    return null;
1078:                }
1079:            }
1080:
1081:            public String escapeTableName(String schemaName, String tableName) {
1082:                if (StringUtils.trimToNull(schemaName) == null
1083:                        || !supportsSchemas()) {
1084:                    return tableName;
1085:                } else {
1086:                    return schemaName + "." + tableName;
1087:                }
1088:            }
1089:
1090:            public String escapeSequenceName(String schemaName,
1091:                    String sequenceName) {
1092:                if (StringUtils.trimToNull(schemaName) == null
1093:                        || !supportsSchemas()) {
1094:                    return sequenceName;
1095:                } else {
1096:                    return schemaName + "." + sequenceName;
1097:                }
1098:            }
1099:
1100:            public String escapeColumnName(String columnName) {
1101:                return columnName;
1102:            }
1103:
1104:            public String escapeColumnNameList(String columnNames) {
1105:                return columnNames;
1106:            }
1107:
1108:            public String convertRequestedSchemaToCatalog(String requestedSchema)
1109:                    throws JDBCException {
1110:                if (getDefaultCatalogName() == null) {
1111:                    return null;
1112:                } else {
1113:                    if (requestedSchema == null) {
1114:                        return getDefaultCatalogName();
1115:                    }
1116:                    return StringUtils.trimToNull(requestedSchema);
1117:                }
1118:            }
1119:
1120:            public String convertRequestedSchemaToSchema(String requestedSchema)
1121:                    throws JDBCException {
1122:                String returnSchema = requestedSchema;
1123:                if (returnSchema == null) {
1124:                    returnSchema = getDefaultDatabaseSchemaName();
1125:                }
1126:
1127:                if (returnSchema != null) {
1128:                    returnSchema = returnSchema.toUpperCase();
1129:                }
1130:                return returnSchema;
1131:            }
1132:
1133:            public boolean supportsSchemas() {
1134:                return true;
1135:            }
1136:
1137:            public String generatePrimaryKeyName(String tableName) {
1138:                return "PK_" + tableName.toUpperCase();
1139:            }
1140:
1141:            public String escapeViewName(String schemaName, String viewName) {
1142:                return escapeTableName(schemaName, viewName);
1143:            }
1144:
1145:            public boolean isColumnAutoIncrement(String schemaName,
1146:                    String tableName, String columnName) throws SQLException,
1147:                    JDBCException {
1148:                if (!supportsAutoIncrement()) {
1149:                    return false;
1150:                }
1151:
1152:                boolean autoIncrement = false;
1153:
1154:                ResultSet selectRS = null;
1155:                try {
1156:                    selectRS = getConnection().createStatement().executeQuery(
1157:                            "SELECT " + escapeColumnName(columnName) + " FROM "
1158:                                    + escapeTableName(schemaName, tableName)
1159:                                    + " WHERE 1 = 0");
1160:                    ResultSetMetaData meta = selectRS.getMetaData();
1161:                    autoIncrement = meta.isAutoIncrement(1);
1162:                } finally {
1163:                    if (selectRS != null) {
1164:                        selectRS.close();
1165:                    }
1166:                }
1167:
1168:                return autoIncrement;
1169:            }
1170:
1171:            /**
1172:             * Returns the run status for the given ChangeSet
1173:             */
1174:            public ChangeSet.RunStatus getRunStatus(ChangeSet changeSet)
1175:                    throws JDBCException, DatabaseHistoryException {
1176:                if (!doesChangeLogTableExist()) {
1177:                    return ChangeSet.RunStatus.NOT_RAN;
1178:                }
1179:
1180:                RanChangeSet foundRan = getRanChangeSet(changeSet);
1181:
1182:                if (foundRan == null) {
1183:                    return ChangeSet.RunStatus.NOT_RAN;
1184:                } else {
1185:                    if (foundRan.getMd5sum() == null) {
1186:                        try {
1187:                            log.info("Updating NULL md5sum for "
1188:                                    + changeSet.toString());
1189:                            DatabaseConnection connection = getConnection();
1190:                            PreparedStatement updatePstmt = connection
1191:                                    .prepareStatement("UPDATE "
1192:                                            + escapeTableName(
1193:                                                    getDefaultSchemaName(),
1194:                                                    getDatabaseChangeLogTableName())
1195:                                            + " SET MD5SUM=? WHERE ID=? AND AUTHOR=? AND FILENAME=?");
1196:                            updatePstmt.setString(1, changeSet.getMd5sum());
1197:                            updatePstmt.setString(2, changeSet.getId());
1198:                            updatePstmt.setString(3, changeSet.getAuthor());
1199:                            updatePstmt.setString(4, changeSet.getFilePath());
1200:
1201:                            updatePstmt.executeUpdate();
1202:                            updatePstmt.close();
1203:                            this .commit();
1204:                        } catch (SQLException e) {
1205:                            throw new JDBCException(e);
1206:                        }
1207:
1208:                        return ChangeSet.RunStatus.ALREADY_RAN;
1209:                    } else {
1210:                        if (foundRan.getMd5sum().equals(changeSet.getMd5sum())) {
1211:                            return ChangeSet.RunStatus.ALREADY_RAN;
1212:                        } else {
1213:                            if (changeSet.shouldRunOnChange()) {
1214:                                return ChangeSet.RunStatus.RUN_AGAIN;
1215:                            } else {
1216:                                return ChangeSet.RunStatus.INVALID_MD5SUM;
1217:                                //                        throw new DatabaseHistoryException("MD5 Check for " + changeSet.toString() + " failed");
1218:                            }
1219:                        }
1220:                    }
1221:                }
1222:            }
1223:
1224:            public RanChangeSet getRanChangeSet(ChangeSet changeSet)
1225:                    throws JDBCException, DatabaseHistoryException {
1226:                if (!doesChangeLogTableExist()) {
1227:                    throw new DatabaseHistoryException(
1228:                            "Database change table does not exist");
1229:                }
1230:
1231:                RanChangeSet foundRan = null;
1232:                for (RanChangeSet ranChange : getRanChangeSetList()) {
1233:                    if (ranChange.isSameAs(changeSet)) {
1234:                        foundRan = ranChange;
1235:                        break;
1236:                    }
1237:                }
1238:                return foundRan;
1239:            }
1240:
1241:            /**
1242:             * Returns the ChangeSets that have been run against the current database.
1243:             */
1244:            public List<RanChangeSet> getRanChangeSetList()
1245:                    throws JDBCException {
1246:                try {
1247:                    String databaseChangeLogTableName = escapeTableName(
1248:                            getDefaultSchemaName(),
1249:                            getDatabaseChangeLogTableName());
1250:                    List<RanChangeSet> ranChangeSetList = new ArrayList<RanChangeSet>();
1251:                    if (doesChangeLogTableExist()) {
1252:                        log.info("Reading from " + databaseChangeLogTableName);
1253:                        String sql = "SELECT * FROM "
1254:                                + databaseChangeLogTableName
1255:                                + " ORDER BY DATEEXECUTED ASC".toUpperCase();
1256:                        Statement statement = getConnection().createStatement();
1257:                        ResultSet rs = statement.executeQuery(sql);
1258:                        while (rs.next()) {
1259:                            String fileName = rs.getString("FILENAME");
1260:                            String author = rs.getString("AUTHOR");
1261:                            String id = rs.getString("ID");
1262:                            String md5sum = rs.getString("MD5SUM");
1263:                            Date dateExecuted = rs.getTimestamp("DATEEXECUTED");
1264:                            String tag = rs.getString("TAG");
1265:                            RanChangeSet ranChangeSet = new RanChangeSet(
1266:                                    fileName, id, author, md5sum, dateExecuted,
1267:                                    tag);
1268:                            ranChangeSetList.add(ranChangeSet);
1269:                        }
1270:                        rs.close();
1271:                        statement.close();
1272:                    }
1273:                    return ranChangeSetList;
1274:                } catch (SQLException e) {
1275:                    if (!getJdbcTemplate().executesStatements()) {
1276:                        //probably not created, no problem
1277:                        return new ArrayList<RanChangeSet>();
1278:                    } else {
1279:                        throw new JDBCException(e);
1280:                    }
1281:                }
1282:            }
1283:
1284:            public Date getRanDate(ChangeSet changeSet) throws JDBCException,
1285:                    DatabaseHistoryException {
1286:                RanChangeSet ranChange = getRanChangeSet(changeSet);
1287:                if (ranChange == null) {
1288:                    return null;
1289:                } else {
1290:                    return ranChange.getDateExecuted();
1291:                }
1292:            }
1293:
1294:            /**
1295:             * After the change set has been ran against the database this method will update the change log table
1296:             * with the information.
1297:             */
1298:            public void markChangeSetAsRan(ChangeSet changeSet)
1299:                    throws JDBCException {
1300:                String dateValue = getCurrentDateTimeFunction();
1301:
1302:                InsertStatement statement = new InsertStatement(
1303:                        getDefaultSchemaName(), getDatabaseChangeLogTableName());
1304:                statement.addColumnValue("ID",
1305:                        escapeStringForDatabase(changeSet.getId()));
1306:                statement.addColumnValue("AUTHOR", changeSet.getAuthor());
1307:                statement.addColumnValue("FILENAME", changeSet.getFilePath());
1308:                statement.addColumnValue("DATEEXECUTED", new ComputedDateValue(
1309:                        dateValue));
1310:                statement.addColumnValue("MD5SUM", changeSet.getMd5sum());
1311:                statement.addColumnValue("DESCRIPTION", limitSize(changeSet
1312:                        .getDescription()));
1313:                statement.addColumnValue("COMMENTS", limitSize(StringUtils
1314:                        .trimToEmpty(changeSet.getComments())));
1315:                statement.addColumnValue("LIQUIBASE", LiquibaseUtil
1316:                        .getBuildVersion());
1317:
1318:                this .getJdbcTemplate().execute(statement);
1319:
1320:                getRanChangeSetList().add(new RanChangeSet(changeSet));
1321:            }
1322:
1323:            public void markChangeSetAsReRan(ChangeSet changeSet)
1324:                    throws JDBCException {
1325:                String dateValue = getCurrentDateTimeFunction();
1326:                String sql = "UPDATE DATABASECHANGELOG SET DATEEXECUTED="
1327:                        + dateValue
1328:                        + ", MD5SUM='?' WHERE ID='?' AND AUTHOR='?' AND FILENAME='?'";
1329:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1330:                        .getMd5sum()));
1331:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1332:                        .getId()));
1333:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1334:                        .getAuthor()));
1335:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1336:                        .getFilePath()));
1337:
1338:                this .getJdbcTemplate().execute(new RawSqlStatement(sql));
1339:                this .commit();
1340:            }
1341:
1342:            public void removeRanStatus(ChangeSet changeSet)
1343:                    throws JDBCException {
1344:                String sql = "DELETE FROM "
1345:                        + escapeTableName(getDefaultSchemaName(),
1346:                                getDatabaseChangeLogTableName())
1347:                        + " WHERE ID='?' AND AUTHOR='?' AND FILENAME='?'";
1348:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1349:                        .getId()));
1350:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1351:                        .getAuthor()));
1352:                sql = sql.replaceFirst("\\?", escapeStringForDatabase(changeSet
1353:                        .getFilePath()));
1354:
1355:                this .getJdbcTemplate().execute(new RawSqlStatement(sql));
1356:                commit();
1357:            }
1358:
1359:            public String escapeStringForDatabase(String string) {
1360:                return string.replaceAll("'", "''");
1361:            }
1362:
1363:            private String limitSize(String string) {
1364:                int maxLength = 255;
1365:                if (string.length() > maxLength) {
1366:                    return string.substring(0, maxLength - 3) + "...";
1367:                }
1368:                return string;
1369:            }
1370:
1371:            public void commit() throws JDBCException {
1372:                try {
1373:                    getConnection().commit();
1374:                } catch (SQLException e) {
1375:                    throw new JDBCException(e);
1376:                }
1377:            }
1378:
1379:            public void rollback() throws JDBCException {
1380:                try {
1381:                    getConnection().rollback();
1382:                } catch (SQLException e) {
1383:                    throw new JDBCException(e);
1384:                }
1385:            }
1386:
1387:            public JdbcTemplate getJdbcTemplate() {
1388:                return jdbcTemplate;
1389:            }
1390:
1391:            public void setJdbcTemplate(JdbcTemplate template) {
1392:                this .jdbcTemplate = template;
1393:            }
1394:
1395:            public boolean equals(Object o) {
1396:                if (this  == o)
1397:                    return true;
1398:                if (o == null || getClass() != o.getClass())
1399:                    return false;
1400:
1401:                AbstractDatabase that = (AbstractDatabase) o;
1402:
1403:                return !(connection != null ? !connection
1404:                        .equals(that.connection) : that.connection != null);
1405:
1406:            }
1407:
1408:            public int hashCode() {
1409:                return (connection != null ? connection.hashCode() : 0);
1410:            }
1411:
1412:            public void close() throws JDBCException {
1413:                try {
1414:                    DatabaseConnection connection = getConnection();
1415:                    if (connection != null) {
1416:                        connection.close();
1417:                    }
1418:                } catch (SQLException e) {
1419:                    throw new JDBCException(e);
1420:                }
1421:            }
1422:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.