1 package liquibase;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.PrintStream;
6 import java.io.Writer;
7 import java.text.DateFormat;
8 import java.util.Date;
9 import java.util.List;
10
11 import liquibase.changelog.ChangeLogIterator;
12 import liquibase.changelog.ChangeLogParameters;
13 import liquibase.changelog.ChangeSet;
14 import liquibase.changelog.DatabaseChangeLog;
15 import liquibase.changelog.RanChangeSet;
16 import liquibase.changelog.filter.AfterTagChangeSetFilter;
17 import liquibase.changelog.filter.AlreadyRanChangeSetFilter;
18 import liquibase.changelog.filter.ContextChangeSetFilter;
19 import liquibase.changelog.filter.CountChangeSetFilter;
20 import liquibase.changelog.filter.DbmsChangeSetFilter;
21 import liquibase.changelog.filter.ExecutedAfterChangeSetFilter;
22 import liquibase.changelog.filter.NotRanChangeSetFilter;
23 import liquibase.changelog.filter.ShouldRunChangeSetFilter;
24 import liquibase.changelog.visitor.ChangeLogSyncVisitor;
25 import liquibase.changelog.visitor.DBDocVisitor;
26 import liquibase.changelog.visitor.ListVisitor;
27 import liquibase.changelog.visitor.RollbackVisitor;
28 import liquibase.changelog.visitor.UpdateVisitor;
29 import liquibase.database.Database;
30 import liquibase.database.DatabaseConnection;
31 import liquibase.database.DatabaseFactory;
32 import liquibase.diff.Diff;
33 import liquibase.exception.DatabaseException;
34 import liquibase.exception.LiquibaseException;
35 import liquibase.exception.LockException;
36 import liquibase.executor.Executor;
37 import liquibase.executor.ExecutorService;
38 import liquibase.executor.LoggingExecutor;
39 import liquibase.lockservice.DatabaseChangeLogLock;
40 import liquibase.lockservice.LockService;
41 import liquibase.logging.LogFactory;
42 import liquibase.logging.Logger;
43 import liquibase.parser.ChangeLogParserFactory;
44 import liquibase.resource.ResourceAccessor;
45 import liquibase.statement.core.UpdateStatement;
46 import liquibase.util.LiquibaseUtil;
47 import liquibase.util.StreamUtil;
48 import liquibase.util.StringUtils;
49
50
51
52
53
54 public class Liquibase {
55
56 public static final String SHOULD_RUN_SYSTEM_PROPERTY = "liquibase.should.run";
57
58 private String changeLogFile;
59 private ResourceAccessor resourceAccessor;
60
61 protected Database database;
62 private Logger log;
63
64 private ChangeLogParameters changeLogParameters;
65
66 public Liquibase(String changeLogFile, ResourceAccessor resourceAccessor, DatabaseConnection conn)
67 throws LiquibaseException {
68 this(changeLogFile, resourceAccessor, DatabaseFactory.getInstance().findCorrectDatabaseImplementation(conn));
69 }
70
71 public Liquibase(String changeLogFile, ResourceAccessor resourceAccessor, Database database)
72 throws LiquibaseException {
73 log = LogFactory.getLogger();
74
75 if (changeLogFile != null) {
76 this.changeLogFile = changeLogFile.replace('\\', '/');
77
78 }
79 this.resourceAccessor = resourceAccessor;
80
81 changeLogParameters = new ChangeLogParameters(database);
82 setDatabase(database);
83
84 }
85
86 public ChangeLogParameters getChangeLogParameters() {
87 return changeLogParameters;
88 }
89
90 public Database getDatabase() {
91 return database;
92 }
93
94 private void setDatabase(Database database) throws DatabaseException {
95 this.database = database;
96 if (database != null)
97 setDatabasePropertiesAsChangelogParameters(database);
98 }
99
100
101
102
103 public ResourceAccessor getFileOpener() {
104 return resourceAccessor;
105 }
106
107
108
109
110
111 public void setCurrentDateTimeFunction(String currentDateTimeFunction) {
112 if (currentDateTimeFunction != null) {
113 this.database.setCurrentDateTimeFunction(currentDateTimeFunction);
114 }
115 }
116
117 public void update(String contexts) throws LiquibaseException {
118
119 LockService lockService = LockService.getInstance(database);
120 lockService.waitForLock();
121
122 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
123
124 try {
125 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
126 .getParser(changeLogFile, resourceAccessor)
127 .parse(changeLogFile, changeLogParameters, resourceAccessor);
128
129 checkDatabaseChangeLogTable(true, changeLog, contexts);
130
131 changeLog.validate(database, contexts);
132 ChangeLogIterator changeLogIterator = getStandardChangelogIterator(contexts, changeLog);
133
134 changeLogIterator.run(new UpdateVisitor(database), database);
135 } finally {
136 try {
137 lockService.releaseLock();
138 } catch (LockException e) {
139 log.severe("Could not release lock", e);
140 }
141 }
142 }
143
144 private ChangeLogIterator getStandardChangelogIterator(String contexts, DatabaseChangeLog changeLog)
145 throws DatabaseException {
146 return new ChangeLogIterator(changeLog, new ShouldRunChangeSetFilter(database), new ContextChangeSetFilter(
147 contexts), new DbmsChangeSetFilter(database));
148 }
149
150 public void update(String contexts, Writer output) throws LiquibaseException {
151 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
152
153 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
154 LoggingExecutor loggingExecutor = new LoggingExecutor(ExecutorService.getInstance().getExecutor(database),
155 output, database);
156 ExecutorService.getInstance().setExecutor(database, loggingExecutor);
157
158 outputHeader("Update Database Script");
159
160 LockService lockService = LockService.getInstance(database);
161 lockService.waitForLock();
162
163 try {
164
165 update(contexts);
166
167 output.flush();
168 } catch (IOException e) {
169 throw new LiquibaseException(e);
170 } finally {
171 lockService.releaseLock();
172 }
173
174 ExecutorService.getInstance().setExecutor(database, oldTemplate);
175 }
176
177 public void update(int changesToApply, String contexts) throws LiquibaseException {
178
179 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
180
181 LockService lockService = LockService.getInstance(database);
182 lockService.waitForLock();
183
184 try {
185
186 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
187 .getParser(changeLogFile, resourceAccessor)
188 .parse(changeLogFile, changeLogParameters, resourceAccessor);
189
190 checkDatabaseChangeLogTable(true, changeLog, contexts);
191 changeLog.validate(database, contexts);
192
193 ChangeLogIterator logIterator = new ChangeLogIterator(changeLog, new ShouldRunChangeSetFilter(database),
194 new ContextChangeSetFilter(contexts), new DbmsChangeSetFilter(database), new CountChangeSetFilter(
195 changesToApply));
196
197 logIterator.run(new UpdateVisitor(database), database);
198 } finally {
199 lockService.releaseLock();
200 }
201 }
202
203 public void update(int changesToApply, String contexts, Writer output) throws LiquibaseException {
204 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
205
206 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
207 LoggingExecutor loggingExecutor = new LoggingExecutor(ExecutorService.getInstance().getExecutor(database),
208 output, database);
209 ExecutorService.getInstance().setExecutor(database, loggingExecutor);
210
211 outputHeader("Update " + changesToApply + " Change Sets Database Script");
212
213 update(changesToApply, contexts);
214
215 try {
216 output.flush();
217 } catch (IOException e) {
218 throw new LiquibaseException(e);
219 }
220
221 ExecutorService.getInstance().setExecutor(database, oldTemplate);
222 }
223
224 private void outputHeader(String message) throws DatabaseException {
225 Executor executor = ExecutorService.getInstance().getExecutor(database);
226 executor.comment("*********************************************************************");
227 executor.comment(message);
228 executor.comment("*********************************************************************");
229 executor.comment("Change Log: " + changeLogFile);
230 executor.comment("Ran at: "
231 + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date()));
232 executor.comment("Against: " + getDatabase().getConnection().getConnectionUserName() + "@"
233 + getDatabase().getConnection().getURL());
234 executor.comment("Liquibase version: " + LiquibaseUtil.getBuildVersion());
235 executor.comment("*********************************************************************"
236 + StreamUtil.getLineSeparator());
237 }
238
239 public void rollback(int changesToRollback, String contexts, Writer output) throws LiquibaseException {
240 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
241
242 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
243 ExecutorService.getInstance().setExecutor(database,
244 new LoggingExecutor(ExecutorService.getInstance().getExecutor(database), output, database));
245
246 outputHeader("Rollback " + changesToRollback + " Change(s) Script");
247
248 rollback(changesToRollback, contexts);
249
250 try {
251 output.flush();
252 } catch (IOException e) {
253 throw new LiquibaseException(e);
254 }
255 ExecutorService.getInstance().setExecutor(database, oldTemplate);
256 }
257
258 public void rollback(int changesToRollback, String contexts) throws LiquibaseException {
259 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
260
261 LockService lockService = LockService.getInstance(database);
262 lockService.waitForLock();
263
264 try {
265 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
266 .getParser(changeLogFile, resourceAccessor)
267 .parse(changeLogFile, changeLogParameters, resourceAccessor);
268 checkDatabaseChangeLogTable(false, changeLog, contexts);
269
270 changeLog.validate(database, contexts);
271
272 ChangeLogIterator logIterator = new ChangeLogIterator(database.getRanChangeSetList(), changeLog,
273 new AlreadyRanChangeSetFilter(database.getRanChangeSetList()),
274 new ContextChangeSetFilter(contexts), new DbmsChangeSetFilter(database), new CountChangeSetFilter(
275 changesToRollback));
276
277 logIterator.run(new RollbackVisitor(database), database);
278 } finally {
279 try {
280 lockService.releaseLock();
281 } catch (LockException e) {
282 log.severe("Error releasing lock", e);
283 }
284 }
285 }
286
287 public void rollback(String tagToRollBackTo, String contexts, Writer output) throws LiquibaseException {
288 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
289
290 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
291 ExecutorService.getInstance().setExecutor(database,
292 new LoggingExecutor(ExecutorService.getInstance().getExecutor(database), output, database));
293
294 outputHeader("Rollback to '" + tagToRollBackTo + "' Script");
295
296 rollback(tagToRollBackTo, contexts);
297
298 try {
299 output.flush();
300 } catch (IOException e) {
301 throw new LiquibaseException(e);
302 }
303 ExecutorService.getInstance().setExecutor(database, oldTemplate);
304 }
305
306 public void rollback(String tagToRollBackTo, String contexts) throws LiquibaseException {
307 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
308
309 LockService lockService = LockService.getInstance(database);
310 lockService.waitForLock();
311
312 try {
313
314 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
315 .getParser(changeLogFile, resourceAccessor)
316 .parse(changeLogFile, changeLogParameters, resourceAccessor);
317 checkDatabaseChangeLogTable(false, changeLog, contexts);
318
319 changeLog.validate(database, contexts);
320
321 List<RanChangeSet> ranChangeSetList = database.getRanChangeSetList();
322 ChangeLogIterator logIterator = new ChangeLogIterator(ranChangeSetList, changeLog,
323 new AfterTagChangeSetFilter(tagToRollBackTo, ranChangeSetList), new AlreadyRanChangeSetFilter(
324 ranChangeSetList), new ContextChangeSetFilter(contexts), new DbmsChangeSetFilter(database));
325
326 logIterator.run(new RollbackVisitor(database), database);
327 } finally {
328 lockService.releaseLock();
329 }
330 }
331
332 public void rollback(Date dateToRollBackTo, String contexts, Writer output) throws LiquibaseException {
333 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
334
335 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
336 ExecutorService.getInstance().setExecutor(database,
337 new LoggingExecutor(ExecutorService.getInstance().getExecutor(database), output, database));
338
339 outputHeader("Rollback to " + dateToRollBackTo + " Script");
340
341 rollback(dateToRollBackTo, contexts);
342
343 try {
344 output.flush();
345 } catch (IOException e) {
346 throw new LiquibaseException(e);
347 }
348 ExecutorService.getInstance().setExecutor(database, oldTemplate);
349 }
350
351 public void rollback(Date dateToRollBackTo, String contexts) throws LiquibaseException {
352 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
353
354 LockService lockService = LockService.getInstance(database);
355 lockService.waitForLock();
356
357 try {
358 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
359 .getParser(changeLogFile, resourceAccessor)
360 .parse(changeLogFile, changeLogParameters, resourceAccessor);
361 checkDatabaseChangeLogTable(false, changeLog, contexts);
362 changeLog.validate(database, contexts);
363
364 List<RanChangeSet> ranChangeSetList = database.getRanChangeSetList();
365 ChangeLogIterator logIterator = new ChangeLogIterator(ranChangeSetList, changeLog,
366 new ExecutedAfterChangeSetFilter(dateToRollBackTo, ranChangeSetList),
367 new AlreadyRanChangeSetFilter(ranChangeSetList), new ContextChangeSetFilter(contexts),
368 new DbmsChangeSetFilter(database));
369
370 logIterator.run(new RollbackVisitor(database), database);
371 } finally {
372 lockService.releaseLock();
373 }
374 }
375
376 public void changeLogSync(String contexts, Writer output) throws LiquibaseException {
377 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
378
379 LoggingExecutor outputTemplate = new LoggingExecutor(ExecutorService.getInstance().getExecutor(database),
380 output, database);
381 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
382 ExecutorService.getInstance().setExecutor(database, outputTemplate);
383
384 outputHeader("SQL to add all changesets to database history table");
385
386 changeLogSync(contexts);
387
388 try {
389 output.flush();
390 } catch (IOException e) {
391 throw new LiquibaseException(e);
392 }
393
394 ExecutorService.getInstance().setExecutor(database, oldTemplate);
395 }
396
397 public void changeLogSync(String contexts) throws LiquibaseException {
398 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
399
400 LockService lockService = LockService.getInstance(database);
401 lockService.waitForLock();
402
403 try {
404 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
405 .getParser(changeLogFile, resourceAccessor)
406 .parse(changeLogFile, changeLogParameters, resourceAccessor);
407 checkDatabaseChangeLogTable(true, changeLog, contexts);
408 changeLog.validate(database, contexts);
409
410 ChangeLogIterator logIterator = new ChangeLogIterator(changeLog, new NotRanChangeSetFilter(
411 database.getRanChangeSetList()), new ContextChangeSetFilter(contexts), new DbmsChangeSetFilter(
412 database));
413
414 logIterator.run(new ChangeLogSyncVisitor(database), database);
415 } finally {
416 lockService.releaseLock();
417 }
418 }
419
420 public void markNextChangeSetRan(String contexts, Writer output) throws LiquibaseException {
421 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
422
423 LoggingExecutor outputTemplate = new LoggingExecutor(ExecutorService.getInstance().getExecutor(database),
424 output, database);
425 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
426 ExecutorService.getInstance().setExecutor(database, outputTemplate);
427
428 outputHeader("SQL to add all changesets to database history table");
429
430 markNextChangeSetRan(contexts);
431
432 try {
433 output.flush();
434 } catch (IOException e) {
435 throw new LiquibaseException(e);
436 }
437
438 ExecutorService.getInstance().setExecutor(database, oldTemplate);
439 }
440
441 public void markNextChangeSetRan(String contexts) throws LiquibaseException {
442 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
443
444 LockService lockService = LockService.getInstance(database);
445 lockService.waitForLock();
446
447 try {
448 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
449 .getParser(changeLogFile, resourceAccessor)
450 .parse(changeLogFile, changeLogParameters, resourceAccessor);
451 checkDatabaseChangeLogTable(false, changeLog, contexts);
452 changeLog.validate(database, contexts);
453
454 ChangeLogIterator logIterator = new ChangeLogIterator(changeLog, new NotRanChangeSetFilter(
455 database.getRanChangeSetList()), new ContextChangeSetFilter(contexts), new DbmsChangeSetFilter(
456 database), new CountChangeSetFilter(1));
457
458 logIterator.run(new ChangeLogSyncVisitor(database), database);
459 } finally {
460 lockService.releaseLock();
461 }
462 }
463
464 public void futureRollbackSQL(String contexts, Writer output) throws LiquibaseException {
465 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
466
467 LoggingExecutor outputTemplate = new LoggingExecutor(ExecutorService.getInstance().getExecutor(database),
468 output, database);
469 Executor oldTemplate = ExecutorService.getInstance().getExecutor(database);
470 ExecutorService.getInstance().setExecutor(database, outputTemplate);
471
472 outputHeader("SQL to roll back currently unexecuted changes");
473
474 LockService lockService = LockService.getInstance(database);
475 lockService.waitForLock();
476
477 try {
478 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
479 .getParser(changeLogFile, resourceAccessor)
480 .parse(changeLogFile, changeLogParameters, resourceAccessor);
481 checkDatabaseChangeLogTable(false, changeLog, contexts);
482 changeLog.validate(database, contexts);
483
484 ChangeLogIterator logIterator = new ChangeLogIterator(changeLog, new NotRanChangeSetFilter(
485 database.getRanChangeSetList()), new ContextChangeSetFilter(contexts), new DbmsChangeSetFilter(
486 database));
487
488 logIterator.run(new RollbackVisitor(database), database);
489 } finally {
490 ExecutorService.getInstance().setExecutor(database, oldTemplate);
491 lockService.releaseLock();
492 }
493
494 try {
495 output.flush();
496 } catch (IOException e) {
497 throw new LiquibaseException(e);
498 }
499
500 }
501
502
503
504
505 public final void dropAll() throws DatabaseException, LockException {
506 dropAll(getDatabase().getDefaultSchemaName());
507 }
508
509
510
511
512 public final void dropAll(String... schemas) throws DatabaseException {
513 try {
514 LockService.getInstance(database).waitForLock();
515
516 for (String schema : schemas) {
517 log.info("Dropping Database Objects in schema: " + database.convertRequestedSchemaToSchema(schema));
518 checkDatabaseChangeLogTable(false, null, null);
519 getDatabase().dropDatabaseObjects(schema);
520 checkDatabaseChangeLogTable(false, null, null);
521 log.debug("Objects dropped successfully");
522 }
523 } catch (DatabaseException e) {
524 throw e;
525 } catch (Exception e) {
526 throw new DatabaseException(e);
527 } finally {
528 try {
529 LockService.getInstance(database).releaseLock();
530 } catch (LockException e) {
531 log.severe("Unable to release lock: " + e.getMessage());
532 }
533 }
534 }
535
536
537
538
539 public void tag(String tagString) throws LiquibaseException {
540 LockService lockService = LockService.getInstance(database);
541 lockService.waitForLock();
542
543 try {
544 checkDatabaseChangeLogTable(false, null, null);
545 getDatabase().tag(tagString);
546 } finally {
547 lockService.releaseLock();
548 }
549 }
550
551 public void updateTestingRollback(String contexts) throws LiquibaseException {
552 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
553
554 Date baseDate = new Date();
555 update(contexts);
556 rollback(baseDate, contexts);
557 update(contexts);
558 }
559
560 public void checkDatabaseChangeLogTable(boolean updateExistingNullChecksums, DatabaseChangeLog databaseChangeLog,
561 String contexts) throws LiquibaseException {
562 if (updateExistingNullChecksums && databaseChangeLog == null) {
563 throw new LiquibaseException("changeLog parameter is required if updating existing checksums");
564 }
565 String[] splitContexts = null;
566 if (StringUtils.trimToNull(contexts) != null) {
567 splitContexts = contexts.split(",");
568 }
569 getDatabase().checkDatabaseChangeLogTable(updateExistingNullChecksums, databaseChangeLog, splitContexts);
570 if (!LockService.getInstance(database).hasChangeLogLock()) {
571 getDatabase().checkDatabaseChangeLogLockTable();
572 }
573 }
574
575
576
577
578
579
580 public boolean isSafeToRunMigration() throws DatabaseException {
581 return getDatabase().isLocalDatabase();
582 }
583
584
585
586
587 public DatabaseChangeLogLock[] listLocks() throws LiquibaseException {
588 checkDatabaseChangeLogTable(false, null, null);
589
590 return LockService.getInstance(getDatabase()).listLocks();
591 }
592
593 public void reportLocks(PrintStream out) throws LiquibaseException {
594 DatabaseChangeLogLock[] locks = listLocks();
595 out.println("Database change log locks for " + getDatabase().getConnection().getConnectionUserName() + "@"
596 + getDatabase().getConnection().getURL());
597 if (locks.length == 0) {
598 out.println(" - No locks");
599 }
600 for (DatabaseChangeLogLock lock : locks) {
601 out.println(" - " + lock.getLockedBy() + " at "
602 + DateFormat.getDateTimeInstance().format(lock.getLockGranted()));
603 }
604
605 }
606
607 public void forceReleaseLocks() throws LiquibaseException {
608 checkDatabaseChangeLogTable(false, null, null);
609
610 LockService.getInstance(getDatabase()).forceReleaseLock();
611 }
612
613 public List<ChangeSet> listUnrunChangeSets(String contexts) throws LiquibaseException {
614 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
615
616 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance().getParser(changeLogFile, resourceAccessor)
617 .parse(changeLogFile, changeLogParameters, resourceAccessor);
618
619 changeLog.validate(database, contexts);
620
621 ChangeLogIterator logIterator = getStandardChangelogIterator(contexts, changeLog);
622
623 ListVisitor visitor = new ListVisitor();
624 logIterator.run(visitor, database);
625 return visitor.getSeenChangeSets();
626 }
627
628 public void reportStatus(boolean verbose, String contexts, Writer out) throws LiquibaseException {
629 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
630
631 try {
632 List<ChangeSet> unrunChangeSets = listUnrunChangeSets(contexts);
633 if (unrunChangeSets.size() == 0) {
634 out.append(getDatabase().getConnection().getConnectionUserName());
635 out.append("@");
636 out.append(getDatabase().getConnection().getURL());
637 out.append(" is up to date");
638 out.append(StreamUtil.getLineSeparator());
639 } else {
640 out.append(String.valueOf(unrunChangeSets.size()));
641 out.append(" change sets have not been applied to ");
642 out.append(getDatabase().getConnection().getConnectionUserName());
643 out.append("@");
644 out.append(getDatabase().getConnection().getURL());
645 out.append(StreamUtil.getLineSeparator());
646 if (verbose) {
647 for (ChangeSet changeSet : unrunChangeSets) {
648 out.append(" ").append(changeSet.toString(false)).append(StreamUtil.getLineSeparator());
649 }
650 }
651 }
652
653 out.flush();
654 } catch (IOException e) {
655 throw new LiquibaseException(e);
656 }
657
658 }
659
660
661
662
663 public void clearCheckSums() throws LiquibaseException {
664 log.info("Clearing database change log checksums");
665 LockService lockService = LockService.getInstance(database);
666 lockService.waitForLock();
667
668 try {
669 checkDatabaseChangeLogTable(false, null, null);
670
671 UpdateStatement updateStatement = new UpdateStatement(getDatabase().getLiquibaseSchemaName(), getDatabase()
672 .getDatabaseChangeLogTableName());
673 updateStatement.addNewColumnValue("MD5SUM", null);
674 ExecutorService.getInstance().getExecutor(database).execute(updateStatement);
675 getDatabase().commit();
676 } finally {
677 lockService.releaseLock();
678 }
679 }
680
681 public void generateDocumentation(String outputDirectory) throws LiquibaseException {
682
683 generateDocumentation(outputDirectory, null);
684 }
685
686 public void generateDocumentation(String outputDirectory, String contexts) throws LiquibaseException {
687 log.info("Generating Database Documentation");
688 changeLogParameters.setContexts(StringUtils.splitAndTrim(contexts, ","));
689 LockService lockService = LockService.getInstance(database);
690 lockService.waitForLock();
691
692 try {
693 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance()
694 .getParser(changeLogFile, resourceAccessor)
695 .parse(changeLogFile, changeLogParameters, resourceAccessor);
696 checkDatabaseChangeLogTable(false, changeLog, null);
697
698 String[] splitContexts = null;
699 if (StringUtils.trimToNull(contexts) != null) {
700 splitContexts = contexts.split(",");
701 }
702 changeLog.validate(database, splitContexts);
703
704 ChangeLogIterator logIterator = new ChangeLogIterator(changeLog, new DbmsChangeSetFilter(database));
705
706 DBDocVisitor visitor = new DBDocVisitor(database);
707 logIterator.run(visitor, database);
708
709 visitor.writeHTML(new File(outputDirectory), resourceAccessor);
710 } catch (IOException e) {
711 throw new LiquibaseException(e);
712 } finally {
713 lockService.releaseLock();
714 }
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729 }
730
731 public Diff diff(Database referenceDatabase, Database targetDatabase) {
732 return new Diff(referenceDatabase, targetDatabase);
733 }
734
735
736
737
738 public void validate() throws LiquibaseException {
739
740 DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance().getParser(changeLogFile, resourceAccessor)
741 .parse(changeLogFile, changeLogParameters, resourceAccessor);
742 changeLog.validate(database);
743 }
744
745 public void setChangeLogParameter(String key, Object value) {
746 this.changeLogParameters.set(key, value);
747 }
748
749
750
751
752
753
754
755
756
757
758 private void setDatabasePropertiesAsChangelogParameters(Database database) throws DatabaseException {
759 setChangeLogParameter("database.autoIncrementClause", database.getAutoIncrementClause());
760 setChangeLogParameter("database.currentDateTimeFunction", database.getCurrentDateTimeFunction());
761 setChangeLogParameter("database.databaseChangeLogLockTableName", database.getDatabaseChangeLogLockTableName());
762 setChangeLogParameter("database.databaseChangeLogTableName", database.getDatabaseChangeLogTableName());
763 setChangeLogParameter("database.databaseMajorVersion", database.getDatabaseMajorVersion());
764 setChangeLogParameter("database.databaseMinorVersion", database.getDatabaseMinorVersion());
765 setChangeLogParameter("database.databaseProductName", database.getDatabaseProductName());
766 setChangeLogParameter("database.databaseProductVersion", database.getDatabaseProductVersion());
767 setChangeLogParameter("database.defaultCatalogName", database.getDefaultCatalogName());
768 setChangeLogParameter("database.defaultSchemaName", database.getDefaultSchemaName());
769 setChangeLogParameter("database.lineComment", database.getLineComment());
770 setChangeLogParameter("database.liquibaseSchemaName", database.getLiquibaseSchemaName());
771 setChangeLogParameter("database.typeName", database.getTypeName());
772 setChangeLogParameter("database.isLocalDatabase", database.isLocalDatabase());
773 setChangeLogParameter("database.requiresPassword", database.requiresPassword());
774 setChangeLogParameter("database.requiresUsername", database.requiresUsername());
775 setChangeLogParameter("database.supportsForeignKeyDisable", database.supportsForeignKeyDisable());
776 setChangeLogParameter("database.supportsInitiallyDeferrableColumns",
777 database.supportsInitiallyDeferrableColumns());
778 setChangeLogParameter("database.supportsRestrictForeignKeys", database.supportsRestrictForeignKeys());
779 setChangeLogParameter("database.supportsSchemas", database.supportsSchemas());
780 setChangeLogParameter("database.supportsSequences", database.supportsSequences());
781 setChangeLogParameter("database.supportsTablespaces", database.supportsTablespaces());
782 }
783 }