1 | |
package liquibase.database; |
2 | |
|
3 | |
import java.io.IOException; |
4 | |
import java.io.Writer; |
5 | |
import java.text.ParseException; |
6 | |
import java.text.SimpleDateFormat; |
7 | |
import java.util.ArrayList; |
8 | |
import java.util.Date; |
9 | |
import java.util.HashSet; |
10 | |
import java.util.List; |
11 | |
import java.util.Map; |
12 | |
import java.util.Set; |
13 | |
import java.util.regex.Pattern; |
14 | |
|
15 | |
import liquibase.change.Change; |
16 | |
import liquibase.change.CheckSum; |
17 | |
import liquibase.change.core.AnonymousChange; |
18 | |
import liquibase.change.core.DropForeignKeyConstraintChange; |
19 | |
import liquibase.change.core.DropSequenceChange; |
20 | |
import liquibase.change.core.DropTableChange; |
21 | |
import liquibase.change.core.DropViewChange; |
22 | |
import liquibase.changelog.ChangeSet; |
23 | |
import liquibase.changelog.DatabaseChangeLog; |
24 | |
import liquibase.changelog.RanChangeSet; |
25 | |
import liquibase.changelog.filter.ContextChangeSetFilter; |
26 | |
import liquibase.changelog.filter.DbmsChangeSetFilter; |
27 | |
import liquibase.database.core.DB2Database; |
28 | |
import liquibase.database.core.DerbyDatabase; |
29 | |
import liquibase.database.core.FirebirdDatabase; |
30 | |
import liquibase.database.core.MSSQLDatabase; |
31 | |
import liquibase.database.core.SQLiteDatabase; |
32 | |
import liquibase.database.core.SybaseASADatabase; |
33 | |
import liquibase.database.core.SybaseDatabase; |
34 | |
import liquibase.database.structure.DatabaseObject; |
35 | |
import liquibase.database.structure.ForeignKey; |
36 | |
import liquibase.database.structure.Sequence; |
37 | |
import liquibase.database.structure.Table; |
38 | |
import liquibase.database.structure.View; |
39 | |
import liquibase.diff.DiffStatusListener; |
40 | |
import liquibase.exception.DatabaseException; |
41 | |
import liquibase.exception.DatabaseHistoryException; |
42 | |
import liquibase.exception.DateParseException; |
43 | |
import liquibase.exception.LiquibaseException; |
44 | |
import liquibase.exception.RollbackImpossibleException; |
45 | |
import liquibase.exception.StatementNotSupportedOnDatabaseException; |
46 | |
import liquibase.exception.UnsupportedChangeException; |
47 | |
import liquibase.executor.Executor; |
48 | |
import liquibase.executor.ExecutorService; |
49 | |
import liquibase.logging.LogFactory; |
50 | |
import liquibase.snapshot.DatabaseSnapshot; |
51 | |
import liquibase.snapshot.DatabaseSnapshotGeneratorFactory; |
52 | |
import liquibase.sql.Sql; |
53 | |
import liquibase.sql.visitor.SqlVisitor; |
54 | |
import liquibase.sqlgenerator.SqlGeneratorFactory; |
55 | |
import liquibase.statement.DatabaseFunction; |
56 | |
import liquibase.statement.SqlStatement; |
57 | |
import liquibase.statement.core.AddColumnStatement; |
58 | |
import liquibase.statement.core.ClearDatabaseChangeLogTableStatement; |
59 | |
import liquibase.statement.core.CreateDatabaseChangeLogLockTableStatement; |
60 | |
import liquibase.statement.core.CreateDatabaseChangeLogTableStatement; |
61 | |
import liquibase.statement.core.GetNextChangeSetSequenceValueStatement; |
62 | |
import liquibase.statement.core.GetViewDefinitionStatement; |
63 | |
import liquibase.statement.core.MarkChangeSetRanStatement; |
64 | |
import liquibase.statement.core.ModifyDataTypeStatement; |
65 | |
import liquibase.statement.core.RawSqlStatement; |
66 | |
import liquibase.statement.core.RemoveChangeSetRanStatusStatement; |
67 | |
import liquibase.statement.core.SelectFromDatabaseChangeLogStatement; |
68 | |
import liquibase.statement.core.SetNullableStatement; |
69 | |
import liquibase.statement.core.TagDatabaseStatement; |
70 | |
import liquibase.statement.core.UpdateChangeSetChecksumStatement; |
71 | |
import liquibase.statement.core.UpdateStatement; |
72 | |
import liquibase.util.ISODateFormat; |
73 | |
import liquibase.util.StreamUtil; |
74 | |
import liquibase.util.StringUtils; |
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
public abstract class AbstractDatabase implements Database { |
82 | |
|
83 | |
private DatabaseConnection connection; |
84 | |
private String defaultSchemaName; |
85 | |
|
86 | |
protected String currentDateTimeFunction; |
87 | |
|
88 | |
|
89 | 124 | protected List<DatabaseFunction> databaseFunctions = new ArrayList<DatabaseFunction>(); |
90 | |
|
91 | |
private List<RanChangeSet> ranChangeSetList; |
92 | |
|
93 | 1 | private static Pattern CREATE_VIEW_AS_PATTERN = Pattern.compile("^CREATE\\s+.*?VIEW\\s+.*?AS\\s+", |
94 | |
Pattern.CASE_INSENSITIVE | Pattern.DOTALL); |
95 | |
|
96 | 124 | private String databaseChangeLogTableName = System.getProperty("liquibase.databaseChangeLogTableName") == null ? "DatabaseChangeLog" |
97 | |
.toUpperCase() : System.getProperty("liquibase.databaseChangeLogTableName"); |
98 | 124 | private String databaseChangeLogLockTableName = System.getProperty("liquibase.databaseChangeLogLockTableName") == null ? "DatabaseChangeLogLock" |
99 | |
.toUpperCase() : System.getProperty("liquibase.databaseChangeLogLockTableName"); |
100 | 124 | private String liquibaseSchemaName = System.getProperty("liquibase.schemaName") == null ? null : System |
101 | |
.getProperty("liquibase.schemaName"); |
102 | |
|
103 | |
private Integer lastChangeSetSequenceValue; |
104 | |
|
105 | 124 | private boolean canCacheLiquibaseTableInfo = false; |
106 | 124 | private boolean hasDatabaseChangeLogTable = false; |
107 | 124 | private boolean hasDatabaseChangeLogLockTable = false; |
108 | |
|
109 | 124 | protected AbstractDatabase() { |
110 | 124 | } |
111 | |
|
112 | |
@Override |
113 | |
public boolean requiresPassword() { |
114 | 0 | return true; |
115 | |
} |
116 | |
|
117 | |
@Override |
118 | |
public boolean requiresUsername() { |
119 | 0 | return true; |
120 | |
} |
121 | |
|
122 | |
@Override |
123 | |
public DatabaseObject[] getContainingObjects() { |
124 | 0 | return null; |
125 | |
} |
126 | |
|
127 | |
|
128 | |
|
129 | |
@Override |
130 | |
public DatabaseConnection getConnection() { |
131 | 176 | return connection; |
132 | |
} |
133 | |
|
134 | |
@Override |
135 | |
public void setConnection(DatabaseConnection conn) { |
136 | 4 | LogFactory.getLogger().debug("Connected to " + conn.getConnectionUserName() + "@" + conn.getURL()); |
137 | 4 | this.connection = conn; |
138 | |
try { |
139 | 4 | connection.setAutoCommit(getAutoCommitMode()); |
140 | 0 | } catch (DatabaseException sqle) { |
141 | 0 | LogFactory.getLogger().warning("Can not set auto commit to " + getAutoCommitMode() + " on connection"); |
142 | 4 | } |
143 | 4 | } |
144 | |
|
145 | |
|
146 | |
|
147 | |
|
148 | |
@Override |
149 | |
public boolean getAutoCommitMode() { |
150 | 4 | return !supportsDDLInTransaction(); |
151 | |
} |
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
@Override |
157 | |
public boolean supportsDDLInTransaction() { |
158 | 0 | return true; |
159 | |
} |
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
@Override |
165 | |
public String getDatabaseProductName() { |
166 | 0 | if (connection == null) { |
167 | 0 | return null; |
168 | |
} |
169 | |
|
170 | |
try { |
171 | 0 | return connection.getDatabaseProductName(); |
172 | 0 | } catch (DatabaseException e) { |
173 | 0 | throw new RuntimeException("Cannot get database name"); |
174 | |
} |
175 | |
} |
176 | |
|
177 | |
@Override |
178 | |
public String getDatabaseProductVersion() throws DatabaseException { |
179 | 0 | if (connection == null) { |
180 | 0 | return null; |
181 | |
} |
182 | |
|
183 | |
try { |
184 | 0 | return connection.getDatabaseProductVersion(); |
185 | 0 | } catch (DatabaseException e) { |
186 | 0 | throw new DatabaseException(e); |
187 | |
} |
188 | |
} |
189 | |
|
190 | |
@Override |
191 | |
public int getDatabaseMajorVersion() throws DatabaseException { |
192 | 3 | if (connection == null) { |
193 | 3 | return -1; |
194 | |
} |
195 | |
try { |
196 | 0 | return connection.getDatabaseMajorVersion(); |
197 | 0 | } catch (DatabaseException e) { |
198 | 0 | throw new DatabaseException(e); |
199 | |
} |
200 | |
} |
201 | |
|
202 | |
@Override |
203 | |
public int getDatabaseMinorVersion() throws DatabaseException { |
204 | 0 | if (connection == null) { |
205 | 0 | return -1; |
206 | |
} |
207 | |
try { |
208 | 0 | return connection.getDatabaseMinorVersion(); |
209 | 0 | } catch (DatabaseException e) { |
210 | 0 | throw new DatabaseException(e); |
211 | |
} |
212 | |
} |
213 | |
|
214 | |
@Override |
215 | |
public String getDefaultCatalogName() throws DatabaseException { |
216 | 0 | return null; |
217 | |
} |
218 | |
|
219 | |
protected String getDefaultDatabaseSchemaName() throws DatabaseException { |
220 | 0 | return getConnection().getConnectionUserName(); |
221 | |
} |
222 | |
|
223 | |
@Override |
224 | |
public String getDefaultSchemaName() { |
225 | 1419 | return defaultSchemaName; |
226 | |
} |
227 | |
|
228 | |
@Override |
229 | |
public void setDefaultSchemaName(String schemaName) throws DatabaseException { |
230 | 1 | this.defaultSchemaName = schemaName; |
231 | 1 | } |
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
protected Set<String> getSystemTablesAndViews() { |
237 | 0 | return new HashSet<String>(); |
238 | |
} |
239 | |
|
240 | |
|
241 | |
|
242 | |
|
243 | |
|
244 | |
|
245 | |
@Override |
246 | |
public boolean supportsSequences() { |
247 | 45 | return true; |
248 | |
} |
249 | |
|
250 | |
@Override |
251 | |
public boolean supportsAutoIncrement() { |
252 | 82 | return true; |
253 | |
} |
254 | |
|
255 | |
|
256 | |
|
257 | |
@Override |
258 | |
public void setCurrentDateTimeFunction(String function) { |
259 | 0 | if (function != null) { |
260 | 0 | this.currentDateTimeFunction = function; |
261 | |
} |
262 | 0 | } |
263 | |
|
264 | |
|
265 | |
|
266 | |
|
267 | |
|
268 | |
|
269 | |
|
270 | |
|
271 | |
|
272 | |
|
273 | |
@Override |
274 | |
public String getDateLiteral(String isoDate) { |
275 | 7 | if (isDateOnly(isoDate) || isTimeOnly(isoDate)) { |
276 | 2 | return "'" + isoDate + "'"; |
277 | 5 | } else if (isDateTime(isoDate)) { |
278 | |
|
279 | |
|
280 | |
|
281 | |
|
282 | |
|
283 | |
|
284 | |
|
285 | |
|
286 | 5 | return "'" + isoDate.replace('T', ' ') + "'"; |
287 | |
} else { |
288 | 0 | return "BAD_DATE_FORMAT:" + isoDate; |
289 | |
} |
290 | |
} |
291 | |
|
292 | |
@Override |
293 | |
public String getDateTimeLiteral(java.sql.Timestamp date) { |
294 | 0 | return getDateLiteral(new ISODateFormat().format(date).replaceFirst("^'", "").replaceFirst("'$", "")); |
295 | |
} |
296 | |
|
297 | |
@Override |
298 | |
public String getDateLiteral(java.sql.Date date) { |
299 | 0 | return getDateLiteral(new ISODateFormat().format(date).replaceFirst("^'", "").replaceFirst("'$", "")); |
300 | |
} |
301 | |
|
302 | |
@Override |
303 | |
public String getTimeLiteral(java.sql.Time date) { |
304 | 0 | return getDateLiteral(new ISODateFormat().format(date).replaceFirst("^'", "").replaceFirst("'$", "")); |
305 | |
} |
306 | |
|
307 | |
@Override |
308 | |
public String getDateLiteral(Date date) { |
309 | 0 | if (date instanceof java.sql.Date) { |
310 | 0 | return getDateLiteral(((java.sql.Date) date)); |
311 | 0 | } else if (date instanceof java.sql.Time) { |
312 | 0 | return getTimeLiteral(((java.sql.Time) date)); |
313 | 0 | } else if (date instanceof java.sql.Timestamp) { |
314 | 0 | return getDateTimeLiteral(((java.sql.Timestamp) date)); |
315 | |
} else { |
316 | 0 | throw new RuntimeException("Unexpected type: " + date.getClass().getName()); |
317 | |
} |
318 | |
} |
319 | |
|
320 | |
@Override |
321 | |
public Date parseDate(String dateAsString) throws DateParseException { |
322 | |
try { |
323 | 0 | if (dateAsString.indexOf(" ") > 0) { |
324 | 0 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAsString); |
325 | 0 | } else if (dateAsString.indexOf("T") > 0) { |
326 | 0 | return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(dateAsString); |
327 | |
} else { |
328 | 0 | if (dateAsString.indexOf(":") > 0) { |
329 | 0 | return new SimpleDateFormat("HH:mm:ss").parse(dateAsString); |
330 | |
} else { |
331 | 0 | return new SimpleDateFormat("yyyy-MM-dd").parse(dateAsString); |
332 | |
} |
333 | |
} |
334 | 0 | } catch (ParseException e) { |
335 | 0 | throw new DateParseException(dateAsString); |
336 | |
} |
337 | |
} |
338 | |
|
339 | |
protected boolean isDateOnly(String isoDate) { |
340 | 13 | return isoDate.length() == "yyyy-MM-dd".length(); |
341 | |
} |
342 | |
|
343 | |
protected boolean isDateTime(String isoDate) { |
344 | 5 | return isoDate.length() >= "yyyy-MM-ddThh:mm:ss".length(); |
345 | |
} |
346 | |
|
347 | |
protected boolean isTimeOnly(String isoDate) { |
348 | 13 | return isoDate.length() == "hh:mm:ss".length(); |
349 | |
} |
350 | |
|
351 | |
|
352 | |
|
353 | |
|
354 | |
@Override |
355 | |
public String getLineComment() { |
356 | 0 | return "--"; |
357 | |
} |
358 | |
|
359 | |
|
360 | |
|
361 | |
|
362 | |
@Override |
363 | |
public String getAutoIncrementClause() { |
364 | 0 | if (!supportsAutoIncrement()) { |
365 | 0 | return ""; |
366 | |
} |
367 | 0 | return "AUTO_INCREMENT"; |
368 | |
} |
369 | |
|
370 | |
@Override |
371 | |
public String getConcatSql(String... values) { |
372 | 0 | StringBuffer returnString = new StringBuffer(); |
373 | 0 | for (String value : values) { |
374 | 0 | returnString.append(value).append(" || "); |
375 | |
} |
376 | |
|
377 | 0 | return returnString.toString().replaceFirst(" \\|\\| $", ""); |
378 | |
} |
379 | |
|
380 | |
|
381 | |
|
382 | |
|
383 | |
|
384 | |
|
385 | |
@Override |
386 | |
public String getDatabaseChangeLogTableName() { |
387 | 0 | return databaseChangeLogTableName; |
388 | |
} |
389 | |
|
390 | |
|
391 | |
|
392 | |
|
393 | |
@Override |
394 | |
public String getDatabaseChangeLogLockTableName() { |
395 | 0 | return databaseChangeLogLockTableName; |
396 | |
} |
397 | |
|
398 | |
|
399 | |
|
400 | |
|
401 | |
@Override |
402 | |
public void setDatabaseChangeLogTableName(String tableName) { |
403 | 0 | this.databaseChangeLogTableName = tableName; |
404 | 0 | } |
405 | |
|
406 | |
|
407 | |
|
408 | |
|
409 | |
@Override |
410 | |
public void setDatabaseChangeLogLockTableName(String tableName) { |
411 | 0 | this.databaseChangeLogLockTableName = tableName; |
412 | 0 | } |
413 | |
|
414 | |
|
415 | |
|
416 | |
|
417 | |
|
418 | |
|
419 | |
|
420 | |
|
421 | |
@Override |
422 | |
public void checkDatabaseChangeLogTable(boolean updateExistingNullChecksums, DatabaseChangeLog databaseChangeLog, |
423 | |
String... contexts) throws DatabaseException { |
424 | 0 | Executor executor = ExecutorService.getInstance().getExecutor(this); |
425 | |
|
426 | 0 | Table changeLogTable = DatabaseSnapshotGeneratorFactory.getInstance().getGenerator(this) |
427 | |
.getDatabaseChangeLogTable(this); |
428 | |
|
429 | 0 | List<SqlStatement> statementsToExecute = new ArrayList<SqlStatement>(); |
430 | |
|
431 | 0 | boolean changeLogCreateAttempted = false; |
432 | 0 | if (changeLogTable != null) { |
433 | 0 | boolean hasDescription = changeLogTable.getColumn("DESCRIPTION") != null; |
434 | 0 | boolean hasComments = changeLogTable.getColumn("COMMENTS") != null; |
435 | 0 | boolean hasTag = changeLogTable.getColumn("TAG") != null; |
436 | 0 | boolean hasLiquibase = changeLogTable.getColumn("LIQUIBASE") != null; |
437 | 0 | boolean liquibaseColumnNotRightSize = changeLogTable.getColumn("LIQUIBASE").getColumnSize() != 20; |
438 | 0 | boolean hasOrderExecuted = changeLogTable.getColumn("ORDEREXECUTED") != null; |
439 | 0 | boolean checksumNotRightSize = changeLogTable.getColumn("MD5SUM").getColumnSize() != 35; |
440 | 0 | boolean hasExecTypeColumn = changeLogTable.getColumn("EXECTYPE") != null; |
441 | |
|
442 | 0 | if (!hasDescription) { |
443 | 0 | executor.comment("Adding missing databasechangelog.description column"); |
444 | 0 | statementsToExecute.add(new AddColumnStatement(getLiquibaseSchemaName(), |
445 | |
getDatabaseChangeLogTableName(), "DESCRIPTION", "VARCHAR(255)", null)); |
446 | |
} |
447 | 0 | if (!hasTag) { |
448 | 0 | executor.comment("Adding missing databasechangelog.tag column"); |
449 | 0 | statementsToExecute.add(new AddColumnStatement(getLiquibaseSchemaName(), |
450 | |
getDatabaseChangeLogTableName(), "TAG", "VARCHAR(255)", null)); |
451 | |
} |
452 | 0 | if (!hasComments) { |
453 | 0 | executor.comment("Adding missing databasechangelog.comments column"); |
454 | 0 | statementsToExecute.add(new AddColumnStatement(getLiquibaseSchemaName(), |
455 | |
getDatabaseChangeLogTableName(), "COMMENTS", "VARCHAR(255)", null)); |
456 | |
} |
457 | 0 | if (!hasLiquibase) { |
458 | 0 | executor.comment("Adding missing databasechangelog.liquibase column"); |
459 | 0 | statementsToExecute.add(new AddColumnStatement(getLiquibaseSchemaName(), |
460 | |
getDatabaseChangeLogTableName(), "LIQUIBASE", "VARCHAR(255)", null)); |
461 | |
} |
462 | 0 | if (!hasOrderExecuted) { |
463 | 0 | executor.comment("Adding missing databasechangelog.orderexecuted column"); |
464 | 0 | statementsToExecute.add(new AddColumnStatement(getLiquibaseSchemaName(), |
465 | |
getDatabaseChangeLogTableName(), "ORDEREXECUTED", "INT", null)); |
466 | 0 | statementsToExecute.add(new UpdateStatement(getLiquibaseSchemaName(), getDatabaseChangeLogTableName()) |
467 | |
.addNewColumnValue("ORDEREXECUTED", -1)); |
468 | 0 | statementsToExecute.add(new SetNullableStatement(getLiquibaseSchemaName(), |
469 | |
getDatabaseChangeLogTableName(), "ORDEREXECUTED", "INT", false)); |
470 | |
} |
471 | 0 | if (checksumNotRightSize) { |
472 | 0 | executor.comment("Modifying size of databasechangelog.md5sum column"); |
473 | |
|
474 | 0 | statementsToExecute.add(new ModifyDataTypeStatement(getLiquibaseSchemaName(), |
475 | |
getDatabaseChangeLogTableName(), "MD5SUM", "VARCHAR(35)")); |
476 | |
} |
477 | 0 | if (liquibaseColumnNotRightSize) { |
478 | 0 | executor.comment("Modifying size of databasechangelog.liquibase column"); |
479 | |
|
480 | 0 | statementsToExecute.add(new ModifyDataTypeStatement(getLiquibaseSchemaName(), |
481 | |
getDatabaseChangeLogTableName(), "LIQUIBASE", "VARCHAR(20)")); |
482 | |
} |
483 | 0 | if (!hasExecTypeColumn) { |
484 | 0 | executor.comment("Adding missing databasechangelog.exectype column"); |
485 | 0 | statementsToExecute.add(new AddColumnStatement(getLiquibaseSchemaName(), |
486 | |
getDatabaseChangeLogTableName(), "EXECTYPE", "VARCHAR(10)", null)); |
487 | 0 | statementsToExecute.add(new UpdateStatement(getLiquibaseSchemaName(), getDatabaseChangeLogTableName()) |
488 | |
.addNewColumnValue("EXECTYPE", "EXECUTED")); |
489 | 0 | statementsToExecute.add(new SetNullableStatement(getLiquibaseSchemaName(), |
490 | |
getDatabaseChangeLogTableName(), "EXECTYPE", "VARCHAR(10)", false)); |
491 | |
} |
492 | |
|
493 | 0 | List<Map> md5sumRS = ExecutorService |
494 | |
.getInstance() |
495 | |
.getExecutor(this) |
496 | |
.queryForList( |
497 | |
new SelectFromDatabaseChangeLogStatement( |
498 | |
new SelectFromDatabaseChangeLogStatement.ByNotNullCheckSum(), "MD5SUM")); |
499 | 0 | if (md5sumRS.size() > 0) { |
500 | 0 | String md5sum = md5sumRS.get(0).get("MD5SUM").toString(); |
501 | 0 | if (!md5sum.startsWith(CheckSum.getCurrentVersion() + ":")) { |
502 | 0 | executor.comment("DatabaseChangeLog checksums are an incompatible version. Setting them to null so they will be updated on next database update"); |
503 | 0 | statementsToExecute.add(new RawSqlStatement("UPDATE " |
504 | |
+ escapeTableName(getLiquibaseSchemaName(), getDatabaseChangeLogTableName()) |
505 | |
+ " SET MD5SUM=null")); |
506 | |
} |
507 | |
} |
508 | |
|
509 | 0 | } else if (!changeLogCreateAttempted) { |
510 | 0 | executor.comment("Create Database Change Log Table"); |
511 | 0 | SqlStatement createTableStatement = new CreateDatabaseChangeLogTableStatement(); |
512 | 0 | if (!canCreateChangeLogTable()) { |
513 | 0 | throw new DatabaseException("Cannot create " |
514 | |
+ escapeTableName(getDefaultSchemaName(), getDatabaseChangeLogTableName()) |
515 | |
+ " table for your database.\n\n" |
516 | |
+ "Please construct it manually using the following SQL as a base and re-run Liquibase:\n\n" |
517 | |
+ createTableStatement); |
518 | |
} |
519 | |
|
520 | 0 | statementsToExecute.add(createTableStatement); |
521 | 0 | LogFactory.getLogger().info( |
522 | |
"Creating database history table with name: " |
523 | |
+ escapeTableName(getDefaultSchemaName(), getDatabaseChangeLogTableName())); |
524 | |
|
525 | |
} |
526 | |
|
527 | 0 | for (SqlStatement sql : statementsToExecute) { |
528 | 0 | executor.execute(sql); |
529 | 0 | this.commit(); |
530 | |
} |
531 | |
|
532 | 0 | if (updateExistingNullChecksums) { |
533 | 0 | for (RanChangeSet ranChangeSet : this.getRanChangeSetList()) { |
534 | 0 | if (ranChangeSet.getLastCheckSum() == null) { |
535 | 0 | ChangeSet changeSet = databaseChangeLog.getChangeSet(ranChangeSet); |
536 | 0 | if (changeSet != null && new ContextChangeSetFilter(contexts).accepts(changeSet) |
537 | |
&& new DbmsChangeSetFilter(this).accepts(changeSet)) { |
538 | 0 | LogFactory.getLogger() |
539 | |
.info("Updating null or out of date checksum on changeSet " + changeSet |
540 | |
+ " to correct value"); |
541 | 0 | executor.execute(new UpdateChangeSetChecksumStatement(changeSet)); |
542 | |
} |
543 | 0 | } |
544 | |
} |
545 | 0 | commit(); |
546 | 0 | this.ranChangeSetList = null; |
547 | |
} |
548 | 0 | } |
549 | |
|
550 | |
protected boolean canCreateChangeLogTable() throws DatabaseException { |
551 | 0 | return true; |
552 | |
} |
553 | |
|
554 | |
@Override |
555 | |
public void setCanCacheLiquibaseTableInfo(boolean canCacheLiquibaseTableInfo) { |
556 | 16 | this.canCacheLiquibaseTableInfo = canCacheLiquibaseTableInfo; |
557 | 16 | hasDatabaseChangeLogTable = false; |
558 | 16 | hasDatabaseChangeLogLockTable = false; |
559 | 16 | } |
560 | |
|
561 | |
@Override |
562 | |
public boolean hasDatabaseChangeLogTable() throws DatabaseException { |
563 | 0 | if (hasDatabaseChangeLogTable) { |
564 | 0 | return true; |
565 | |
} |
566 | 0 | boolean hasTable = DatabaseSnapshotGeneratorFactory.getInstance().getGenerator(this) |
567 | |
.hasDatabaseChangeLogTable(this); |
568 | 0 | if (canCacheLiquibaseTableInfo) { |
569 | 0 | hasDatabaseChangeLogTable = hasTable; |
570 | |
} |
571 | 0 | return hasTable; |
572 | |
} |
573 | |
|
574 | |
@Override |
575 | |
public boolean hasDatabaseChangeLogLockTable() throws DatabaseException { |
576 | 0 | if (canCacheLiquibaseTableInfo && hasDatabaseChangeLogLockTable) { |
577 | 0 | return true; |
578 | |
} |
579 | 0 | boolean hasTable = DatabaseSnapshotGeneratorFactory.getInstance().getGenerator(this) |
580 | |
.hasDatabaseChangeLogLockTable(this); |
581 | 0 | if (canCacheLiquibaseTableInfo) { |
582 | 0 | hasDatabaseChangeLogLockTable = hasTable; |
583 | |
} |
584 | 0 | return hasTable; |
585 | |
} |
586 | |
|
587 | |
@Override |
588 | |
public String getLiquibaseSchemaName() { |
589 | 0 | return liquibaseSchemaName == null ? getDefaultSchemaName() : liquibaseSchemaName; |
590 | |
} |
591 | |
|
592 | |
|
593 | |
|
594 | |
|
595 | |
|
596 | |
|
597 | |
@Override |
598 | |
public void checkDatabaseChangeLogLockTable() throws DatabaseException { |
599 | |
|
600 | 0 | Executor executor = ExecutorService.getInstance().getExecutor(this); |
601 | 0 | if (!hasDatabaseChangeLogLockTable()) { |
602 | |
|
603 | 0 | executor.comment("Create Database Lock Table"); |
604 | 0 | executor.execute(new CreateDatabaseChangeLogLockTableStatement()); |
605 | 0 | this.commit(); |
606 | 0 | LogFactory.getLogger().debug( |
607 | |
"Created database lock table with name: " |
608 | |
+ escapeTableName(getLiquibaseSchemaName(), getDatabaseChangeLogLockTableName())); |
609 | 0 | this.hasDatabaseChangeLogLockTable = true; |
610 | |
} |
611 | 0 | } |
612 | |
|
613 | |
@Override |
614 | |
public boolean isReservedWord(String string) { |
615 | 0 | return false; |
616 | |
} |
617 | |
|
618 | |
|
619 | |
|
620 | |
|
621 | |
|
622 | |
|
623 | |
|
624 | |
|
625 | |
@Override |
626 | |
public void dropDatabaseObjects(String schema) throws DatabaseException { |
627 | |
try { |
628 | 0 | DatabaseSnapshot snapshot = DatabaseSnapshotGeneratorFactory.getInstance().createSnapshot(this, schema, |
629 | |
new HashSet<DiffStatusListener>()); |
630 | |
|
631 | 0 | List<Change> dropChanges = new ArrayList<Change>(); |
632 | |
|
633 | 0 | for (View view : snapshot.getViews()) { |
634 | 0 | DropViewChange dropChange = new DropViewChange(); |
635 | 0 | dropChange.setViewName(view.getName()); |
636 | 0 | dropChange.setSchemaName(schema); |
637 | |
|
638 | 0 | dropChanges.add(dropChange); |
639 | 0 | } |
640 | |
|
641 | 0 | if (!supportsForeignKeyDisable()) { |
642 | 0 | for (ForeignKey fk : snapshot.getForeignKeys()) { |
643 | 0 | DropForeignKeyConstraintChange dropFK = new DropForeignKeyConstraintChange(); |
644 | 0 | dropFK.setBaseTableSchemaName(schema); |
645 | 0 | dropFK.setBaseTableName(fk.getForeignKeyTable().getName()); |
646 | 0 | dropFK.setConstraintName(fk.getName()); |
647 | |
|
648 | 0 | dropChanges.add(dropFK); |
649 | 0 | } |
650 | |
} |
651 | |
|
652 | |
|
653 | |
|
654 | |
|
655 | |
|
656 | |
|
657 | |
|
658 | |
|
659 | |
|
660 | |
|
661 | 0 | for (Table table : snapshot.getTables()) { |
662 | 0 | DropTableChange dropChange = new DropTableChange(); |
663 | 0 | dropChange.setSchemaName(schema); |
664 | 0 | dropChange.setTableName(table.getName()); |
665 | 0 | if (supportsDropTableCascadeConstraints()) { |
666 | 0 | dropChange.setCascadeConstraints(true); |
667 | |
} |
668 | |
|
669 | 0 | dropChanges.add(dropChange); |
670 | 0 | } |
671 | |
|
672 | 0 | if (this.supportsSequences()) { |
673 | 0 | for (Sequence seq : snapshot.getSequences()) { |
674 | 0 | DropSequenceChange dropChange = new DropSequenceChange(); |
675 | 0 | dropChange.setSequenceName(seq.getName()); |
676 | 0 | dropChange.setSchemaName(schema); |
677 | |
|
678 | 0 | dropChanges.add(dropChange); |
679 | 0 | } |
680 | |
} |
681 | |
|
682 | 0 | if (snapshot.hasDatabaseChangeLogTable()) { |
683 | 0 | dropChanges.add(new AnonymousChange(new ClearDatabaseChangeLogTableStatement(schema))); |
684 | |
} |
685 | |
|
686 | 0 | final boolean reEnableFK = supportsForeignKeyDisable() && disableForeignKeyChecks(); |
687 | |
try { |
688 | 0 | for (Change change : dropChanges) { |
689 | 0 | for (SqlStatement statement : change.generateStatements(this)) { |
690 | 0 | ExecutorService.getInstance().getExecutor(this).execute(statement); |
691 | |
} |
692 | |
} |
693 | |
} finally { |
694 | 0 | if (reEnableFK) { |
695 | 0 | enableForeignKeyChecks(); |
696 | |
} |
697 | |
} |
698 | |
|
699 | |
} finally { |
700 | 0 | this.commit(); |
701 | 0 | } |
702 | 0 | } |
703 | |
|
704 | |
@Override |
705 | |
public boolean supportsDropTableCascadeConstraints() { |
706 | 0 | return (this instanceof DerbyDatabase || this instanceof DB2Database || this instanceof MSSQLDatabase |
707 | |
|| this instanceof FirebirdDatabase || this instanceof SQLiteDatabase || this instanceof SybaseDatabase || this instanceof SybaseASADatabase); |
708 | |
} |
709 | |
|
710 | |
@Override |
711 | |
public boolean isSystemTable(String catalogName, String schemaName, String tableName) { |
712 | 0 | if ("information_schema".equalsIgnoreCase(schemaName)) { |
713 | 0 | return true; |
714 | 0 | } else if (tableName.equalsIgnoreCase(getDatabaseChangeLogLockTableName())) { |
715 | 0 | return true; |
716 | 0 | } else if (getSystemTablesAndViews().contains(tableName)) { |
717 | 0 | return true; |
718 | |
} |
719 | 0 | return false; |
720 | |
} |
721 | |
|
722 | |
@Override |
723 | |
public boolean isSystemView(String catalogName, String schemaName, String viewName) { |
724 | 0 | if ("information_schema".equalsIgnoreCase(schemaName)) { |
725 | 0 | return true; |
726 | 0 | } else if (getSystemTablesAndViews().contains(viewName)) { |
727 | 0 | return true; |
728 | |
} |
729 | 0 | return false; |
730 | |
} |
731 | |
|
732 | |
@Override |
733 | |
public boolean isLiquibaseTable(String tableName) { |
734 | 0 | return tableName.equalsIgnoreCase(this.getDatabaseChangeLogTableName()) |
735 | |
|| tableName.equalsIgnoreCase(this.getDatabaseChangeLogLockTableName()); |
736 | |
} |
737 | |
|
738 | |
|
739 | |
|
740 | |
|
741 | |
|
742 | |
|
743 | |
@Override |
744 | |
public void tag(String tagString) throws DatabaseException { |
745 | 0 | Executor executor = ExecutorService.getInstance().getExecutor(this); |
746 | |
try { |
747 | 0 | int totalRows = ExecutorService.getInstance().getExecutor(this) |
748 | |
.queryForInt(new SelectFromDatabaseChangeLogStatement("COUNT(*)")); |
749 | 0 | if (totalRows == 0) { |
750 | 0 | ChangeSet emptyChangeSet = new ChangeSet(String.valueOf(new Date().getTime()), "liquibase", false, |
751 | |
false, "liquibase-internal", null, null); |
752 | 0 | this.markChangeSetExecStatus(emptyChangeSet, ChangeSet.ExecType.EXECUTED); |
753 | |
} |
754 | |
|
755 | |
|
756 | |
|
757 | 0 | executor.execute(new TagDatabaseStatement(tagString)); |
758 | 0 | this.commit(); |
759 | |
|
760 | 0 | getRanChangeSetList().get(getRanChangeSetList().size() - 1).setTag(tagString); |
761 | 0 | } catch (Exception e) { |
762 | 0 | throw new DatabaseException(e); |
763 | 0 | } |
764 | 0 | } |
765 | |
|
766 | |
@Override |
767 | |
public boolean doesTagExist(String tag) throws DatabaseException { |
768 | 0 | int count = ExecutorService |
769 | |
.getInstance() |
770 | |
.getExecutor(this) |
771 | |
.queryForInt( |
772 | |
new SelectFromDatabaseChangeLogStatement(new SelectFromDatabaseChangeLogStatement.ByTag("tag"), |
773 | |
"COUNT(*)")); |
774 | 0 | return count > 0; |
775 | |
} |
776 | |
|
777 | |
@Override |
778 | |
public String toString() { |
779 | 154 | if (getConnection() == null) { |
780 | 154 | return getTypeName() + " Database"; |
781 | |
} |
782 | |
|
783 | 0 | return getConnection().getConnectionUserName() + " @ " + getConnection().getURL() |
784 | |
+ (getDefaultSchemaName() == null ? "" : " (Default Schema: " + getDefaultSchemaName() + ")"); |
785 | |
} |
786 | |
|
787 | |
@Override |
788 | |
public boolean shouldQuoteValue(String value) { |
789 | 7 | return true; |
790 | |
} |
791 | |
|
792 | |
@Override |
793 | |
public String getViewDefinition(String schemaName, String viewName) throws DatabaseException { |
794 | 0 | if (schemaName == null) { |
795 | 0 | schemaName = convertRequestedSchemaToSchema(null); |
796 | |
} |
797 | 0 | String definition = (String) ExecutorService.getInstance().getExecutor(this) |
798 | |
.queryForObject(new GetViewDefinitionStatement(schemaName, viewName), String.class); |
799 | 0 | if (definition == null) { |
800 | 0 | return null; |
801 | |
} |
802 | 0 | return CREATE_VIEW_AS_PATTERN.matcher(definition).replaceFirst(""); |
803 | |
} |
804 | |
|
805 | |
@Override |
806 | |
public String escapeTableName(String schemaName, String tableName) { |
807 | 183 | if (schemaName == null) { |
808 | 116 | schemaName = getDefaultSchemaName(); |
809 | |
} |
810 | |
|
811 | 183 | if (StringUtils.trimToNull(schemaName) == null || !supportsSchemas()) { |
812 | 122 | return escapeDatabaseObject(tableName); |
813 | |
} else { |
814 | 61 | return escapeDatabaseObject(schemaName) + "." + escapeDatabaseObject(tableName); |
815 | |
} |
816 | |
} |
817 | |
|
818 | |
@Override |
819 | |
public String escapeDatabaseObject(String objectName) { |
820 | 103 | return objectName; |
821 | |
} |
822 | |
|
823 | |
@Override |
824 | |
public String escapeIndexName(String schemaName, String indexName) { |
825 | 0 | if (StringUtils.trimToNull(schemaName) == null || !supportsSchemas()) { |
826 | 0 | return escapeDatabaseObject(indexName); |
827 | |
} else { |
828 | 0 | return escapeDatabaseObject(schemaName) + "." + escapeDatabaseObject(indexName); |
829 | |
} |
830 | |
} |
831 | |
|
832 | |
@Override |
833 | |
public String escapeSequenceName(String schemaName, String sequenceName) { |
834 | 0 | if (schemaName == null) { |
835 | 0 | schemaName = getDefaultSchemaName(); |
836 | |
} |
837 | |
|
838 | 0 | if (StringUtils.trimToNull(schemaName) == null || !supportsSchemas()) { |
839 | 0 | return escapeDatabaseObject(sequenceName); |
840 | |
} else { |
841 | 0 | return escapeDatabaseObject(schemaName) + "." + escapeDatabaseObject(sequenceName); |
842 | |
} |
843 | |
} |
844 | |
|
845 | |
@Override |
846 | |
public String escapeConstraintName(String constraintName) { |
847 | 0 | return escapeDatabaseObject(constraintName); |
848 | |
} |
849 | |
|
850 | |
@Override |
851 | |
public String escapeColumnName(String schemaName, String tableName, String columnName) { |
852 | 9 | if (columnName.contains("(")) { |
853 | 0 | return columnName; |
854 | |
} |
855 | |
|
856 | 9 | if (schemaName == null) { |
857 | 0 | schemaName = getDefaultSchemaName(); |
858 | |
} |
859 | |
|
860 | 9 | return escapeDatabaseObject(columnName); |
861 | |
} |
862 | |
|
863 | |
@Override |
864 | |
public String escapeColumnNameList(String columnNames) { |
865 | 0 | StringBuffer sb = new StringBuffer(); |
866 | 0 | for (String columnName : columnNames.split(",")) { |
867 | 0 | if (sb.length() > 0) { |
868 | 0 | sb.append(", "); |
869 | |
} |
870 | 0 | sb.append(escapeDatabaseObject(columnName.trim())); |
871 | |
} |
872 | 0 | return sb.toString(); |
873 | |
|
874 | |
} |
875 | |
|
876 | |
@Override |
877 | |
public String convertRequestedSchemaToCatalog(String requestedSchema) throws DatabaseException { |
878 | 0 | if (getDefaultCatalogName() == null) { |
879 | 0 | return null; |
880 | |
} else { |
881 | 0 | if (requestedSchema == null) { |
882 | 0 | return getDefaultCatalogName(); |
883 | |
} |
884 | 0 | return StringUtils.trimToNull(requestedSchema); |
885 | |
} |
886 | |
} |
887 | |
|
888 | |
@Override |
889 | |
public String convertRequestedSchemaToSchema(String requestedSchema) throws DatabaseException { |
890 | 0 | String returnSchema = requestedSchema; |
891 | 0 | if (returnSchema == null) { |
892 | 0 | returnSchema = getDefaultDatabaseSchemaName(); |
893 | |
} |
894 | |
|
895 | 0 | if (returnSchema != null) { |
896 | 0 | returnSchema = returnSchema.toUpperCase(); |
897 | |
} |
898 | 0 | return returnSchema; |
899 | |
} |
900 | |
|
901 | |
@Override |
902 | |
public boolean supportsSchemas() { |
903 | 62 | return true; |
904 | |
} |
905 | |
|
906 | |
@Override |
907 | |
public String generatePrimaryKeyName(String tableName) { |
908 | 0 | return "PK_" + tableName.toUpperCase(); |
909 | |
} |
910 | |
|
911 | |
@Override |
912 | |
public String escapeViewName(String schemaName, String viewName) { |
913 | 0 | return escapeTableName(schemaName, viewName); |
914 | |
} |
915 | |
|
916 | |
|
917 | |
|
918 | |
|
919 | |
@Override |
920 | |
public ChangeSet.RunStatus getRunStatus(ChangeSet changeSet) throws DatabaseException, DatabaseHistoryException { |
921 | 0 | if (!hasDatabaseChangeLogTable()) { |
922 | 0 | return ChangeSet.RunStatus.NOT_RAN; |
923 | |
} |
924 | |
|
925 | 0 | RanChangeSet foundRan = getRanChangeSet(changeSet); |
926 | |
|
927 | 0 | if (foundRan == null) { |
928 | 0 | return ChangeSet.RunStatus.NOT_RAN; |
929 | |
} else { |
930 | 0 | if (foundRan.getLastCheckSum() == null) { |
931 | |
try { |
932 | 0 | LogFactory.getLogger().info("Updating NULL md5sum for " + changeSet.toString()); |
933 | 0 | ExecutorService |
934 | |
.getInstance() |
935 | |
.getExecutor(this) |
936 | |
.execute( |
937 | |
new RawSqlStatement( |
938 | |
"UPDATE " |
939 | |
+ escapeTableName(getLiquibaseSchemaName(), |
940 | |
getDatabaseChangeLogTableName()) + " SET MD5SUM='" |
941 | |
+ changeSet.generateCheckSum().toString() + "' WHERE ID='" |
942 | |
+ changeSet.getId() + "' AND AUTHOR='" + changeSet.getAuthor() |
943 | |
+ "' AND FILENAME='" + changeSet.getFilePath() + "'")); |
944 | |
|
945 | 0 | this.commit(); |
946 | 0 | } catch (DatabaseException e) { |
947 | 0 | throw new DatabaseException(e); |
948 | 0 | } |
949 | |
|
950 | 0 | return ChangeSet.RunStatus.ALREADY_RAN; |
951 | |
} else { |
952 | 0 | if (foundRan.getLastCheckSum().equals(changeSet.generateCheckSum())) { |
953 | 0 | return ChangeSet.RunStatus.ALREADY_RAN; |
954 | |
} else { |
955 | 0 | if (changeSet.shouldRunOnChange()) { |
956 | 0 | return ChangeSet.RunStatus.RUN_AGAIN; |
957 | |
} else { |
958 | 0 | return ChangeSet.RunStatus.INVALID_MD5SUM; |
959 | |
|
960 | |
} |
961 | |
} |
962 | |
} |
963 | |
} |
964 | |
} |
965 | |
|
966 | |
@Override |
967 | |
public RanChangeSet getRanChangeSet(ChangeSet changeSet) throws DatabaseException, DatabaseHistoryException { |
968 | 0 | if (!hasDatabaseChangeLogTable()) { |
969 | 0 | return null; |
970 | |
} |
971 | |
|
972 | 0 | RanChangeSet foundRan = null; |
973 | 0 | for (RanChangeSet ranChange : getRanChangeSetList()) { |
974 | 0 | if (ranChange.isSameAs(changeSet)) { |
975 | 0 | foundRan = ranChange; |
976 | 0 | break; |
977 | |
} |
978 | |
} |
979 | 0 | return foundRan; |
980 | |
} |
981 | |
|
982 | |
|
983 | |
|
984 | |
|
985 | |
@Override |
986 | |
public List<RanChangeSet> getRanChangeSetList() throws DatabaseException { |
987 | 0 | if (this.ranChangeSetList != null) { |
988 | 0 | return this.ranChangeSetList; |
989 | |
} |
990 | |
|
991 | 0 | String databaseChangeLogTableName = escapeTableName(getLiquibaseSchemaName(), getDatabaseChangeLogTableName()); |
992 | 0 | ranChangeSetList = new ArrayList<RanChangeSet>(); |
993 | 0 | if (hasDatabaseChangeLogTable()) { |
994 | 0 | LogFactory.getLogger().info("Reading from " + databaseChangeLogTableName); |
995 | 0 | SqlStatement select = new SelectFromDatabaseChangeLogStatement("FILENAME", "AUTHOR", "ID", "MD5SUM", |
996 | |
"DATEEXECUTED", "ORDEREXECUTED", "TAG", "EXECTYPE").setOrderBy("DATEEXECUTED ASC", |
997 | |
"ORDEREXECUTED ASC"); |
998 | 0 | List<Map> results = ExecutorService.getInstance().getExecutor(this).queryForList(select); |
999 | 0 | for (Map rs : results) { |
1000 | 0 | String fileName = rs.get("FILENAME").toString(); |
1001 | 0 | String author = rs.get("AUTHOR").toString(); |
1002 | 0 | String id = rs.get("ID").toString(); |
1003 | 0 | String md5sum = rs.get("MD5SUM") == null ? null : rs.get("MD5SUM").toString(); |
1004 | 0 | Date dateExecuted = (Date) rs.get("DATEEXECUTED"); |
1005 | 0 | String tag = rs.get("TAG") == null ? null : rs.get("TAG").toString(); |
1006 | 0 | String execType = rs.get("EXECTYPE") == null ? null : rs.get("EXECTYPE").toString(); |
1007 | |
try { |
1008 | 0 | RanChangeSet ranChangeSet = new RanChangeSet(fileName, id, author, CheckSum.parse(md5sum), |
1009 | |
dateExecuted, tag, ChangeSet.ExecType.valueOf(execType)); |
1010 | 0 | ranChangeSetList.add(ranChangeSet); |
1011 | 0 | } catch (IllegalArgumentException e) { |
1012 | 0 | LogFactory.getLogger().severe("Unknown EXECTYPE from database: " + execType); |
1013 | 0 | throw e; |
1014 | 0 | } |
1015 | 0 | } |
1016 | |
} |
1017 | 0 | return ranChangeSetList; |
1018 | |
} |
1019 | |
|
1020 | |
@Override |
1021 | |
public Date getRanDate(ChangeSet changeSet) throws DatabaseException, DatabaseHistoryException { |
1022 | 0 | RanChangeSet ranChange = getRanChangeSet(changeSet); |
1023 | 0 | if (ranChange == null) { |
1024 | 0 | return null; |
1025 | |
} else { |
1026 | 0 | return ranChange.getDateExecuted(); |
1027 | |
} |
1028 | |
} |
1029 | |
|
1030 | |
|
1031 | |
|
1032 | |
|
1033 | |
|
1034 | |
@Override |
1035 | |
public void markChangeSetExecStatus(ChangeSet changeSet, ChangeSet.ExecType execType) throws DatabaseException { |
1036 | |
|
1037 | 0 | ExecutorService.getInstance().getExecutor(this).execute(new MarkChangeSetRanStatement(changeSet, execType)); |
1038 | 0 | commit(); |
1039 | 0 | getRanChangeSetList().add(new RanChangeSet(changeSet, execType)); |
1040 | 0 | } |
1041 | |
|
1042 | |
@Override |
1043 | |
public void removeRanStatus(ChangeSet changeSet) throws DatabaseException { |
1044 | |
|
1045 | 0 | ExecutorService.getInstance().getExecutor(this).execute(new RemoveChangeSetRanStatusStatement(changeSet)); |
1046 | 0 | commit(); |
1047 | |
|
1048 | 0 | getRanChangeSetList().remove(new RanChangeSet(changeSet)); |
1049 | 0 | } |
1050 | |
|
1051 | |
@Override |
1052 | |
public String escapeStringForDatabase(String string) { |
1053 | 7 | if (string == null) { |
1054 | 0 | return null; |
1055 | |
} |
1056 | 7 | return string.replaceAll("'", "''"); |
1057 | |
} |
1058 | |
|
1059 | |
@Override |
1060 | |
public void commit() throws DatabaseException { |
1061 | |
try { |
1062 | 0 | getConnection().commit(); |
1063 | 0 | } catch (DatabaseException e) { |
1064 | 0 | throw new DatabaseException(e); |
1065 | 0 | } |
1066 | 0 | } |
1067 | |
|
1068 | |
@Override |
1069 | |
public void rollback() throws DatabaseException { |
1070 | |
try { |
1071 | 0 | getConnection().rollback(); |
1072 | 0 | } catch (DatabaseException e) { |
1073 | 0 | throw new DatabaseException(e); |
1074 | 0 | } |
1075 | 0 | } |
1076 | |
|
1077 | |
@Override |
1078 | |
public boolean equals(Object o) { |
1079 | 9 | if (this == o) |
1080 | 9 | return true; |
1081 | 0 | if (o == null || getClass() != o.getClass()) |
1082 | 0 | return false; |
1083 | |
|
1084 | 0 | AbstractDatabase that = (AbstractDatabase) o; |
1085 | |
|
1086 | 0 | if (connection == null) { |
1087 | 0 | if (that.connection == null) { |
1088 | 0 | return this == that; |
1089 | |
} else { |
1090 | 0 | return false; |
1091 | |
} |
1092 | |
} else { |
1093 | 0 | return connection.equals(that.connection); |
1094 | |
} |
1095 | |
} |
1096 | |
|
1097 | |
@Override |
1098 | |
public int hashCode() { |
1099 | 93 | return (connection != null ? connection.hashCode() : super.hashCode()); |
1100 | |
} |
1101 | |
|
1102 | |
@Override |
1103 | |
public void close() throws DatabaseException { |
1104 | |
try { |
1105 | 0 | DatabaseConnection connection = getConnection(); |
1106 | 0 | if (connection != null) { |
1107 | 0 | connection.close(); |
1108 | |
} |
1109 | 0 | } catch (DatabaseException e) { |
1110 | 0 | throw new DatabaseException(e); |
1111 | 0 | } |
1112 | 0 | } |
1113 | |
|
1114 | |
@Override |
1115 | |
public boolean supportsRestrictForeignKeys() { |
1116 | 0 | return true; |
1117 | |
} |
1118 | |
|
1119 | |
@Override |
1120 | |
public boolean isAutoCommit() throws DatabaseException { |
1121 | |
try { |
1122 | 0 | return getConnection().getAutoCommit(); |
1123 | 0 | } catch (DatabaseException e) { |
1124 | 0 | throw new DatabaseException(e); |
1125 | |
} |
1126 | |
} |
1127 | |
|
1128 | |
@Override |
1129 | |
public void setAutoCommit(boolean b) throws DatabaseException { |
1130 | |
try { |
1131 | 0 | getConnection().setAutoCommit(b); |
1132 | 0 | } catch (DatabaseException e) { |
1133 | 0 | throw new DatabaseException(e); |
1134 | 0 | } |
1135 | 0 | } |
1136 | |
|
1137 | |
|
1138 | |
|
1139 | |
|
1140 | |
|
1141 | |
|
1142 | |
|
1143 | |
@Override |
1144 | |
public boolean isLocalDatabase() throws DatabaseException { |
1145 | 0 | DatabaseConnection connection = getConnection(); |
1146 | 0 | if (connection == null) { |
1147 | 0 | return true; |
1148 | |
} |
1149 | 0 | String url = connection.getURL(); |
1150 | 0 | return (url.contains("localhost")) || (url.contains("127.0.0.1")); |
1151 | |
} |
1152 | |
|
1153 | |
@Override |
1154 | |
public void executeStatements(Change change, DatabaseChangeLog changeLog, List<SqlVisitor> sqlVisitors) |
1155 | |
throws LiquibaseException, UnsupportedChangeException { |
1156 | 0 | SqlStatement[] statements = change.generateStatements(this); |
1157 | |
|
1158 | 0 | execute(statements, sqlVisitors); |
1159 | 0 | } |
1160 | |
|
1161 | |
|
1162 | |
|
1163 | |
|
1164 | |
|
1165 | |
|
1166 | |
|
1167 | |
|
1168 | |
|
1169 | |
|
1170 | |
@Override |
1171 | |
public void execute(SqlStatement[] statements, List<SqlVisitor> sqlVisitors) throws LiquibaseException { |
1172 | 0 | for (SqlStatement statement : statements) { |
1173 | 0 | if (statement.skipOnUnsupported() && !SqlGeneratorFactory.getInstance().supports(statement, this)) { |
1174 | 0 | continue; |
1175 | |
} |
1176 | 0 | LogFactory.getLogger().debug("Executing Statement: " + statement); |
1177 | 0 | ExecutorService.getInstance().getExecutor(this).execute(statement, sqlVisitors); |
1178 | |
} |
1179 | 0 | } |
1180 | |
|
1181 | |
@Override |
1182 | |
public void saveStatements(Change change, List<SqlVisitor> sqlVisitors, Writer writer) throws IOException, |
1183 | |
UnsupportedChangeException, StatementNotSupportedOnDatabaseException, LiquibaseException { |
1184 | 0 | SqlStatement[] statements = change.generateStatements(this); |
1185 | 0 | for (SqlStatement statement : statements) { |
1186 | 0 | for (Sql sql : SqlGeneratorFactory.getInstance().generateSql(statement, this)) { |
1187 | 0 | writer.append(sql.toSql()).append(sql.getEndDelimiter()).append(StreamUtil.getLineSeparator()) |
1188 | |
.append(StreamUtil.getLineSeparator()); |
1189 | |
} |
1190 | |
} |
1191 | 0 | } |
1192 | |
|
1193 | |
@Override |
1194 | |
public void executeRollbackStatements(Change change, List<SqlVisitor> sqlVisitors) throws LiquibaseException, |
1195 | |
UnsupportedChangeException, RollbackImpossibleException { |
1196 | 0 | SqlStatement[] statements = change.generateRollbackStatements(this); |
1197 | 0 | List<SqlVisitor> rollbackVisitors = new ArrayList<SqlVisitor>(); |
1198 | 0 | if (sqlVisitors != null) { |
1199 | 0 | for (SqlVisitor visitor : sqlVisitors) { |
1200 | 0 | if (visitor.isApplyToRollback()) { |
1201 | 0 | rollbackVisitors.add(visitor); |
1202 | |
} |
1203 | |
} |
1204 | |
} |
1205 | 0 | execute(statements, rollbackVisitors); |
1206 | 0 | } |
1207 | |
|
1208 | |
@Override |
1209 | |
public void saveRollbackStatement(Change change, List<SqlVisitor> sqlVisitors, Writer writer) throws IOException, |
1210 | |
UnsupportedChangeException, RollbackImpossibleException, StatementNotSupportedOnDatabaseException, |
1211 | |
LiquibaseException { |
1212 | 0 | SqlStatement[] statements = change.generateRollbackStatements(this); |
1213 | 0 | for (SqlStatement statement : statements) { |
1214 | 0 | for (Sql sql : SqlGeneratorFactory.getInstance().generateSql(statement, this)) { |
1215 | 0 | writer.append(sql.toSql()).append(sql.getEndDelimiter()).append("\n\n"); |
1216 | |
} |
1217 | |
} |
1218 | 0 | } |
1219 | |
|
1220 | |
@Override |
1221 | |
public int getNextChangeSetSequenceValue() throws LiquibaseException { |
1222 | 0 | if (lastChangeSetSequenceValue == null) { |
1223 | 0 | if (getConnection() == null) { |
1224 | 0 | lastChangeSetSequenceValue = 0; |
1225 | |
} else { |
1226 | 0 | lastChangeSetSequenceValue = ExecutorService.getInstance().getExecutor(this) |
1227 | |
.queryForInt(new GetNextChangeSetSequenceValueStatement()); |
1228 | |
} |
1229 | |
} |
1230 | |
|
1231 | 0 | return ++lastChangeSetSequenceValue; |
1232 | |
} |
1233 | |
|
1234 | |
public Table getTable(String schemaName, String tableName) throws DatabaseException { |
1235 | 0 | return DatabaseSnapshotGeneratorFactory.getInstance().getGenerator(this).getTable(schemaName, tableName, this); |
1236 | |
} |
1237 | |
|
1238 | |
@Override |
1239 | |
public List<DatabaseFunction> getDatabaseFunctions() { |
1240 | 0 | return databaseFunctions; |
1241 | |
} |
1242 | |
|
1243 | |
@Override |
1244 | |
public void reset() { |
1245 | 0 | this.ranChangeSetList = null; |
1246 | 0 | this.hasDatabaseChangeLogLockTable = false; |
1247 | 0 | } |
1248 | |
|
1249 | |
@Override |
1250 | |
public boolean supportsForeignKeyDisable() { |
1251 | 0 | return false; |
1252 | |
} |
1253 | |
|
1254 | |
@Override |
1255 | |
public boolean disableForeignKeyChecks() throws DatabaseException { |
1256 | 0 | throw new DatabaseException("ForeignKeyChecks Management not supported"); |
1257 | |
} |
1258 | |
|
1259 | |
@Override |
1260 | |
public void enableForeignKeyChecks() throws DatabaseException { |
1261 | 0 | throw new DatabaseException("ForeignKeyChecks Management not supported"); |
1262 | |
} |
1263 | |
} |