Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
H2Database |
|
| 2.3;2.3 |
1 | package liquibase.database.core; | |
2 | ||
3 | import liquibase.database.DatabaseConnection; | |
4 | import liquibase.database.AbstractDatabase; | |
5 | import liquibase.exception.DatabaseException; | |
6 | import liquibase.exception.DateParseException; | |
7 | import liquibase.statement.DatabaseFunction; | |
8 | import liquibase.util.ISODateFormat; | |
9 | ||
10 | import java.text.ParseException; | |
11 | import java.text.SimpleDateFormat; | |
12 | import java.text.DateFormat; | |
13 | import java.util.Date; | |
14 | import java.util.Arrays; | |
15 | import java.util.List; | |
16 | ||
17 | public class H2Database extends AbstractDatabase { | |
18 | ||
19 | 1 | private static String START_CONCAT = "CONCAT("; |
20 | 1 | private static String END_CONCAT = ")"; |
21 | 1 | private static String SEP_CONCAT = ", "; |
22 | ||
23 | 15 | public H2Database() { |
24 | 15 | this.databaseFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP()")); |
25 | 15 | } |
26 | ||
27 | public String getTypeName() { | |
28 | 59 | return "h2"; |
29 | } | |
30 | ||
31 | public String getDefaultDriver(String url) { | |
32 | 2 | if (url.startsWith("jdbc:h2")) { |
33 | 1 | return "org.h2.Driver"; |
34 | } | |
35 | 1 | return null; |
36 | } | |
37 | ||
38 | public int getPriority() { | |
39 | 0 | return PRIORITY_DATABASE; |
40 | } | |
41 | ||
42 | public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException { | |
43 | 1 | return "H2".equals(conn.getDatabaseProductName()); |
44 | } | |
45 | ||
46 | // public void dropDatabaseObjects(String schema) throws DatabaseException { | |
47 | // DatabaseConnection conn = getConnection(); | |
48 | // Statement dropStatement = null; | |
49 | // try { | |
50 | // dropStatement = conn.createStatement(); | |
51 | // dropStatement.executeUpdate("DROP ALL OBJECTS"); | |
52 | // changeLogTableExists = false; | |
53 | // changeLogLockTableExists = false; | |
54 | // changeLogCreateAttempted = false; | |
55 | // changeLogLockCreateAttempted = false; | |
56 | // } catch (SQLException e) { | |
57 | // throw new DatabaseException(e); | |
58 | // } finally { | |
59 | // try { | |
60 | // if (dropStatement != null) { | |
61 | // dropStatement.close(); | |
62 | // } | |
63 | // conn.commit(); | |
64 | // } catch (SQLException e) { | |
65 | // ; | |
66 | // } | |
67 | // } | |
68 | // | |
69 | // } | |
70 | ||
71 | public boolean supportsTablespaces() { | |
72 | 0 | return false; |
73 | } | |
74 | ||
75 | @Override | |
76 | public String getViewDefinition(String schemaName, String name) throws DatabaseException { | |
77 | 0 | String definition = super.getViewDefinition(schemaName, name); |
78 | 0 | if (!definition.startsWith("SELECT")) { |
79 | 0 | definition = definition.replaceFirst(".*?\n", ""); // some h2 versions return "create view....as\nselect |
80 | } | |
81 | ||
82 | 0 | definition = definition.replaceFirst("/\\*.*", ""); // sometimes includes comments at the end |
83 | 0 | return definition; |
84 | } | |
85 | ||
86 | @Override | |
87 | public Date parseDate(String dateAsString) throws DateParseException { | |
88 | try { | |
89 | 0 | if (dateAsString.indexOf(' ') > 0) { |
90 | 0 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSSSS").parse(dateAsString); |
91 | } else { | |
92 | 0 | if (dateAsString.indexOf(':') > 0) { |
93 | 0 | return new SimpleDateFormat("HH:mm:ss").parse(dateAsString); |
94 | } else { | |
95 | 0 | return new SimpleDateFormat("yyyy-MM-dd").parse(dateAsString); |
96 | } | |
97 | } | |
98 | 0 | } catch (ParseException e) { |
99 | 0 | throw new DateParseException(dateAsString); |
100 | } | |
101 | } | |
102 | ||
103 | @Override | |
104 | public boolean isLocalDatabase() throws DatabaseException { | |
105 | 0 | String url = getConnection().getURL(); |
106 | 0 | boolean isLocalURL = (super.isLocalDatabase() || url.startsWith("jdbc:h2:file:") |
107 | || url.startsWith("jdbc:h2:mem:") || url.startsWith("jdbc:h2:zip:") || url.startsWith("jdbc:h2:~")); | |
108 | 0 | return isLocalURL; |
109 | } | |
110 | ||
111 | // @Override | |
112 | // public String convertRequestedSchemaToSchema(String requestedSchema) throws DatabaseException { | |
113 | // return super.convertRequestedSchemaToSchema(requestedSchema).toLowerCase(); | |
114 | // } | |
115 | ||
116 | @Override | |
117 | public boolean supportsSequences() { | |
118 | 14 | return true; |
119 | } | |
120 | ||
121 | @Override | |
122 | protected String getDefaultDatabaseSchemaName() throws DatabaseException { | |
123 | 0 | return "PUBLIC"; |
124 | } | |
125 | ||
126 | @Override | |
127 | public String getAutoIncrementClause() { | |
128 | 0 | return "GENERATED BY DEFAULT AS IDENTITY IDENTITY"; |
129 | } | |
130 | ||
131 | @Override | |
132 | public String getConcatSql(String... values) { | |
133 | 0 | if (values == null) { |
134 | 0 | return null; |
135 | } | |
136 | ||
137 | 0 | return getConcatSql(Arrays.asList(values)); |
138 | } | |
139 | ||
140 | /** | |
141 | * Recursive way of building CONCAT instruction | |
142 | * | |
143 | * @param values | |
144 | * a non null List of String | |
145 | * @return a String containing the CONCAT instruction with all elements, or only a value if there is only one | |
146 | * element in the list | |
147 | */ | |
148 | private String getConcatSql(List<String> values) { | |
149 | 0 | if (values.size() == 1) { |
150 | 0 | return values.get(0); |
151 | } else { | |
152 | 0 | return START_CONCAT + values.get(0) + SEP_CONCAT + getConcatSql(values.subList(1, values.size())) |
153 | + END_CONCAT; | |
154 | } | |
155 | } | |
156 | ||
157 | @Override | |
158 | public String getDateLiteral(String isoDate) { | |
159 | 0 | String returnString = isoDate; |
160 | try { | |
161 | 0 | if (isDateTime(isoDate)) { |
162 | 0 | ISODateFormat isoTimestampFormat = new ISODateFormat(); |
163 | 0 | DateFormat dbTimestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); |
164 | 0 | returnString = dbTimestampFormat.format(isoTimestampFormat.parse(isoDate)); |
165 | } | |
166 | 0 | } catch (ParseException e) { |
167 | 0 | throw new RuntimeException("Unexpected date format: " + isoDate, e); |
168 | 0 | } |
169 | 0 | return "'" + returnString + "'"; |
170 | } | |
171 | ||
172 | @Override | |
173 | public String convertRequestedSchemaToSchema(String requestedSchema) throws DatabaseException { | |
174 | 0 | return super.convertRequestedSchemaToSchema(requestedSchema).toUpperCase(); |
175 | } | |
176 | ||
177 | @Override | |
178 | public String escapeDatabaseObject(String objectName) { | |
179 | 13 | if (objectName != null) { |
180 | 7 | if (isReservedWord(objectName)) { |
181 | 0 | return "\"" + objectName + "\""; |
182 | } | |
183 | } | |
184 | 13 | return objectName; |
185 | } | |
186 | ||
187 | @Override | |
188 | public boolean isReservedWord(String objectName) { | |
189 | 7 | return keywords.contains(objectName.toUpperCase()); |
190 | } | |
191 | ||
192 | 1 | private static List keywords = Arrays.asList( |
193 | // "ADD", | |
194 | // "ALL", | |
195 | // "ALLOCATE", | |
196 | // "ALTER", | |
197 | // "AND", | |
198 | // "ANY", | |
199 | // "ARE", | |
200 | // "ARRAY", | |
201 | // "AS", | |
202 | // "ASENSITIVE", | |
203 | // "ASYMMETRIC", | |
204 | // "AT", | |
205 | // "ATOMIC", | |
206 | // "AUTHORIZATION", | |
207 | // "BEGIN", | |
208 | // "BETWEEN", | |
209 | // "BIGINT", | |
210 | // "BINARY", | |
211 | // "BLOB", | |
212 | // "BOOLEAN", | |
213 | // "BOTH", | |
214 | // "BY", | |
215 | // "CALL", | |
216 | // "CALLED", | |
217 | // "CASCADED", | |
218 | // "CASE", | |
219 | // "CAST", | |
220 | // "CHAR", | |
221 | // "CHARACTER", | |
222 | // "CHECK", | |
223 | // "CLOB", | |
224 | // "CLOSE", | |
225 | // "COLLATE", | |
226 | // "COLUMN", | |
227 | // "COMMIT", | |
228 | // "CONDITION", | |
229 | // "CONNECT", | |
230 | // "CONSTRAINT", | |
231 | // "CONTINUE", | |
232 | // "CORRESPONDING", | |
233 | // "CREATE", | |
234 | // "CROSS", | |
235 | // "CUBE", | |
236 | // "CURRENT", | |
237 | // "CURRENT_DATE", | |
238 | // "CURRENT_DEFAULT_TRANSFORM_GRO", | |
239 | // "CURRENT_PATH", | |
240 | // "CURRENT_ROLE", | |
241 | // "CURRENT_TIME", | |
242 | // "CURRENT_TIMESTAMP", | |
243 | // "CURRENT_TRANSFORM_GROUP_FOR_T", | |
244 | // "CURRENT_USER", | |
245 | // "CURSOR", | |
246 | // "CYCLE", | |
247 | // "DATE", | |
248 | // "DAY", | |
249 | // "DEALLOCATE", | |
250 | // "DEC", | |
251 | // "DECIMAL", | |
252 | // "DECLARE", | |
253 | // "DEFAULT", | |
254 | // "DELETE", | |
255 | // "DEREF", | |
256 | // "DESCRIBE", | |
257 | // "DETERMINISTIC", | |
258 | // "DISCONNECT", | |
259 | // "DISTINCT", | |
260 | // "DO", | |
261 | // "DOUBLE", | |
262 | // "DROP", | |
263 | // "DYNAMIC", | |
264 | // "EACH", | |
265 | // "ELEMENT", | |
266 | // "ELSE", | |
267 | // "ELSEIF", | |
268 | // "END", | |
269 | // "ESCAPE", | |
270 | // "EXCEPT", | |
271 | // "EXEC", | |
272 | // "EXECUTE", | |
273 | // "EXISTS", | |
274 | // "EXIT", | |
275 | // "EXTERNAL", | |
276 | // "FALSE", | |
277 | // "FETCH", | |
278 | // "FILTER", | |
279 | // "FLOAT", | |
280 | // "FOR", | |
281 | // "FOREIGN", | |
282 | // "FREE", | |
283 | // "FROM", | |
284 | // "FULL", | |
285 | // "FUNCTION", | |
286 | // "GET", | |
287 | // "GLOBAL", | |
288 | // "GRANT", | |
289 | // "GROUP", | |
290 | // "GROUPING", | |
291 | // "HANDLER", | |
292 | // "HAVING", | |
293 | // "HOLD", | |
294 | // "HOUR", | |
295 | // "IDENTITY", | |
296 | // "IF", | |
297 | // "IMMEDIATE", | |
298 | // "IN", | |
299 | // "INDICATOR", | |
300 | // "INNER", | |
301 | // "INOUT", | |
302 | // "INPUT", | |
303 | // "INSENSITIVE", | |
304 | // "INSERT", | |
305 | // "INT", | |
306 | // "INTEGER", | |
307 | // "INTERSECT", | |
308 | // "INTERVAL", | |
309 | // "INTO", | |
310 | // "IS", | |
311 | // "ITERATE", | |
312 | // "JOIN", | |
313 | // "LANGUAGE", | |
314 | // "LARGE", | |
315 | // "LATERAL", | |
316 | // "LEADING", | |
317 | // "LEAVE", | |
318 | // "LEFT", | |
319 | // "LIKE", | |
320 | // "LOCAL", | |
321 | // "LOCALTIME", | |
322 | // "LOCALTIMESTAMP", | |
323 | // "LOOP", | |
324 | // "MATCH", | |
325 | // "MEMBER", | |
326 | // "MERGE", | |
327 | // "METHOD", | |
328 | // "MINUTE", | |
329 | // "MODIFIES", | |
330 | // "MODULE", | |
331 | // "MONTH", | |
332 | // "MULTISET", | |
333 | // "NATIONAL", | |
334 | // "NATURAL", | |
335 | // "NCHAR", | |
336 | // "NCLOB", | |
337 | // "NEW", | |
338 | // "NO", | |
339 | // "NONE", | |
340 | // "NOT", | |
341 | // "NULL", | |
342 | // "NUMERIC", | |
343 | // "OF", | |
344 | // "OLD", | |
345 | // "ON", | |
346 | // "ONLY", | |
347 | // "OPEN", | |
348 | // "OR", | |
349 | // "ORDER", | |
350 | // "OUT", | |
351 | // "OUTER", | |
352 | // "OUTPUT", | |
353 | // "OVER", | |
354 | // "OVERLAPS", | |
355 | // "PARAMETER", | |
356 | // "PARTITION", | |
357 | // "PRECISION", | |
358 | // "PREPARE", | |
359 | // "PRIMARY", | |
360 | // "PROCEDURE", | |
361 | // "RANGE", | |
362 | // "READS", | |
363 | // "REAL", | |
364 | // "RECURSIVE", | |
365 | // "REF", | |
366 | // "REFERENCES", | |
367 | // "REFERENCING", | |
368 | // "RELEASE", | |
369 | // "REPEAT", | |
370 | // "RESIGNAL", | |
371 | // "RESULT", | |
372 | // "RETURN", | |
373 | // "RETURNS", | |
374 | // "REVOKE", | |
375 | // "RIGHT", | |
376 | // "ROLLBACK", | |
377 | // "ROLLUP", | |
378 | // "ROW", | |
379 | // "ROWS", | |
380 | // "SAVEPOINT", | |
381 | // "SCOPE", | |
382 | // "SCROLL", | |
383 | // "SEARCH", | |
384 | // "SECOND", | |
385 | // "SELECT", | |
386 | // "SENSITIVE", | |
387 | // "SESSION_USER", | |
388 | // "SET", | |
389 | // "SIGNAL", | |
390 | // "SIMILAR", | |
391 | // "SMALLINT", | |
392 | // "SOME", | |
393 | // "SPECIFIC", | |
394 | // "SPECIFICTYPE", | |
395 | // "SQL", | |
396 | // "SQLEXCEPTION", | |
397 | // "SQLSTATE", | |
398 | // "SQLWARNING", | |
399 | // "START", | |
400 | // "STATIC", | |
401 | // "SUBMULTISET", | |
402 | // "SYMMETRIC", | |
403 | // "SYSTEM", | |
404 | // "SYSTEM_USER", | |
405 | // "TABLE", | |
406 | // "TABLESAMPLE", | |
407 | // "THEN", | |
408 | // "TIME", | |
409 | // "TIMESTAMP", | |
410 | // "TIMEZONE_HOUR", | |
411 | // "TIMEZONE_MINUTE", | |
412 | // "TO", | |
413 | // "TRAILING", | |
414 | // "TRANSLATION", | |
415 | // "TREAT", | |
416 | // "TRIGGER", | |
417 | // "TRUE", | |
418 | // "UNDO", | |
419 | // "UNION", | |
420 | // "UNIQUE", | |
421 | // "UNKNOWN", | |
422 | // "UNNEST", | |
423 | // "UNTIL", | |
424 | // "UPDATE", | |
425 | "USER", | |
426 | // "USING", | |
427 | // "VALUE", | |
428 | // "VALUES", | |
429 | // "VARCHAR", | |
430 | // "VARYING", | |
431 | // "WHEN", | |
432 | // "WHENEVER", | |
433 | // "WHERE", | |
434 | // "WHILE", | |
435 | // "WINDOW", | |
436 | // "WITH", | |
437 | // "WITHIN", | |
438 | // "WITHOUT", | |
439 | // "YEAR", | |
440 | // "ALIAS", | |
441 | // "AUTOCOMMIT", | |
442 | // "CACHED", | |
443 | // "CHECKPOINT", | |
444 | // "EXPLAIN", | |
445 | // "IGNORECASE", | |
446 | // "INDEX", | |
447 | // "LOGSIZE", | |
448 | // "MATCHED", | |
449 | // "MAXROWS", | |
450 | // "MEMORY", | |
451 | // "MINUS", | |
452 | // "NEXT", | |
453 | // "OPENBRACKET", | |
454 | "PASSWORD" | |
455 | // "PLAN", | |
456 | // "PROPERTY", | |
457 | // "READONLY", | |
458 | // "REFERENTIAL_INTEGRITY", | |
459 | // "RENAME", | |
460 | // "RESTART", | |
461 | // "SCRIPT", | |
462 | // "SCRIPTFORMAT", | |
463 | // "SEMICOLON", | |
464 | // "SEQUENCE", | |
465 | // "SHUTDOWN", | |
466 | // "SOURCE", | |
467 | // "TEMP", | |
468 | // "TEXT", | |
469 | // "VIEW", | |
470 | // "WRITE_DELAY", | |
471 | // "VAR_POP", | |
472 | // "VAR_SAMP", | |
473 | // "STDDEV_POP", | |
474 | // "STDDEV_SAMP", | |
475 | // "DEFRAG", | |
476 | // "INCREMENT", | |
477 | // "TOCHAR", | |
478 | // "DATABASE", | |
479 | // "SCHEMA", | |
480 | // "ROLE", | |
481 | // "DOW", | |
482 | // "INITIAL" | |
483 | ); | |
484 | ||
485 | public boolean supportsInitiallyDeferrableColumns() { | |
486 | 1 | return false; |
487 | } | |
488 | ||
489 | public String getCurrentDateTimeFunction() { | |
490 | 1 | if (currentDateTimeFunction != null) { |
491 | 0 | return currentDateTimeFunction; |
492 | } | |
493 | ||
494 | 1 | return "NOW()"; |
495 | } | |
496 | ||
497 | } |