2
* HA-JDBC: High-Availability JDBC
3
* Copyright (c) 2004-2007 Paul Ferraro
5
* This library is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU Lesser General Public License as published by the
7
* Free Software Foundation; either version 2.1 of the License, or (at your
8
* option) any later version.
10
* This library is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15
* You should have received a copy of the GNU Lesser General Public License
16
* along with this library; if not, write to the Free Software Foundation,
17
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* Contact: ferraro@users.sourceforge.net
21
package net.sf.hajdbc.dialect;
23
import java.sql.DatabaseMetaData;
24
import java.sql.ResultSet;
25
import java.sql.SQLException;
26
import java.sql.Types;
27
import java.util.Collection;
28
import java.util.Iterator;
29
import java.util.List;
30
import java.util.regex.Pattern;
32
import net.sf.hajdbc.ColumnProperties;
33
import net.sf.hajdbc.Dialect;
34
import net.sf.hajdbc.ForeignKeyConstraint;
35
import net.sf.hajdbc.QualifiedName;
36
import net.sf.hajdbc.SequenceProperties;
37
import net.sf.hajdbc.TableProperties;
38
import net.sf.hajdbc.UniqueConstraint;
39
import net.sf.hajdbc.cache.ForeignKeyConstraintImpl;
40
import net.sf.hajdbc.cache.UniqueConstraintImpl;
42
import org.easymock.EasyMock;
43
import org.testng.annotations.DataProvider;
44
import org.testng.annotations.Test;
47
* @author Paul Ferraro
50
@SuppressWarnings("nls")
52
public class TestStandardDialect implements Dialect
54
private Dialect dialect;
56
public TestStandardDialect()
58
this(new StandardDialect());
61
protected TestStandardDialect(Dialect dialect)
63
this.dialect = dialect;
66
public void testGetAlterSequenceSQL() throws SQLException
68
SequenceProperties sequence = EasyMock.createStrictMock(SequenceProperties.class);
70
EasyMock.expect(sequence.getName()).andReturn("sequence");
72
EasyMock.replay(sequence);
74
String result = this.getAlterSequenceSQL(sequence, 1000L);
76
EasyMock.verify(sequence);
78
assert result.equals("ALTER SEQUENCE sequence RESTART WITH 1000") : result;
82
public String getAlterSequenceSQL(SequenceProperties sequence, long value) throws SQLException
84
return this.dialect.getAlterSequenceSQL(sequence, value);
87
public void testGetColumnType() throws SQLException
89
ColumnProperties column = EasyMock.createStrictMock(ColumnProperties.class);
91
EasyMock.expect(column.getType()).andReturn(Types.INTEGER);
93
EasyMock.replay(column);
95
int result = this.getColumnType(column);
97
EasyMock.verify(column);
99
assert result == Types.INTEGER : result;
103
public int getColumnType(ColumnProperties column) throws SQLException
105
return this.dialect.getColumnType(column);
108
public void testGetCreateForeignKeyConstraintSQL() throws SQLException
110
ForeignKeyConstraint key = new ForeignKeyConstraintImpl("name", "table");
111
key.getColumnList().add("column1");
112
key.getColumnList().add("column2");
113
key.setForeignTable("foreign_table");
114
key.getForeignColumnList().add("foreign_column1");
115
key.getForeignColumnList().add("foreign_column2");
116
key.setDeferrability(DatabaseMetaData.importedKeyInitiallyDeferred);
117
key.setDeleteRule(DatabaseMetaData.importedKeyCascade);
118
key.setUpdateRule(DatabaseMetaData.importedKeyRestrict);
120
String result = this.getCreateForeignKeyConstraintSQL(key);
122
assert result.equals("ALTER TABLE table ADD CONSTRAINT name FOREIGN KEY (column1, column2) REFERENCES foreign_table (foreign_column1, foreign_column2) ON DELETE CASCADE ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED") : result;
126
public String getCreateForeignKeyConstraintSQL(ForeignKeyConstraint constraint) throws SQLException
128
return this.dialect.getCreateForeignKeyConstraintSQL(constraint);
131
public void testGetCreateUniqueConstraintSQL() throws SQLException
133
UniqueConstraint key = new UniqueConstraintImpl("name", "table");
134
key.getColumnList().add("column1");
135
key.getColumnList().add("column2");
137
String result = this.getCreateUniqueConstraintSQL(key);
139
assert result.equals("ALTER TABLE table ADD CONSTRAINT name UNIQUE (column1, column2)") : result;
143
public String getCreateUniqueConstraintSQL(UniqueConstraint constraint) throws SQLException
145
return this.dialect.getCreateUniqueConstraintSQL(constraint);
148
public void testGetDropForeignKeyConstraintSQL() throws SQLException
150
ForeignKeyConstraint key = new ForeignKeyConstraintImpl("name", "table");
151
key.getColumnList().add("column1");
152
key.getColumnList().add("column2");
153
key.setForeignTable("foreign_table");
154
key.getForeignColumnList().add("foreign_column1");
155
key.getForeignColumnList().add("foreign_column2");
156
key.setDeferrability(DatabaseMetaData.importedKeyInitiallyDeferred);
157
key.setDeleteRule(DatabaseMetaData.importedKeyCascade);
158
key.setUpdateRule(DatabaseMetaData.importedKeyRestrict);
160
String result = this.getDropForeignKeyConstraintSQL(key);
162
assert result.equals("ALTER TABLE table DROP CONSTRAINT name") : result;
166
public String getDropForeignKeyConstraintSQL(ForeignKeyConstraint constraint) throws SQLException
168
return this.dialect.getDropForeignKeyConstraintSQL(constraint);
171
public void testGetDropUniqueConstraintSQL() throws SQLException
173
UniqueConstraint key = new UniqueConstraintImpl("name", "table");
174
key.getColumnList().add("column1");
175
key.getColumnList().add("column2");
177
String result = this.getDropUniqueConstraintSQL(key);
179
assert result.equals("ALTER TABLE table DROP CONSTRAINT name") : result;
183
public String getDropUniqueConstraintSQL(UniqueConstraint constraint) throws SQLException
185
return this.dialect.getDropUniqueConstraintSQL(constraint);
188
public void testGetNextSequenceValueSQL() throws SQLException
190
SequenceProperties sequence = EasyMock.createStrictMock(SequenceProperties.class);
192
EasyMock.expect(sequence.getName()).andReturn("sequence");
194
EasyMock.replay(sequence);
196
String result = this.getNextSequenceValueSQL(sequence);
198
EasyMock.verify(sequence);
200
assert result.equals("SELECT NEXT VALUE FOR sequence") : result;
204
public String getNextSequenceValueSQL(SequenceProperties sequence) throws SQLException
206
return this.dialect.getNextSequenceValueSQL(sequence);
209
public void testGetSequences() throws SQLException
211
DatabaseMetaData metaData = EasyMock.createStrictMock(DatabaseMetaData.class);
212
ResultSet resultSet = EasyMock.createStrictMock(ResultSet.class);
214
EasyMock.expect(metaData.getTables(EasyMock.eq(""), EasyMock.eq((String) null), EasyMock.eq("%"), EasyMock.aryEq(new String[] { "SEQUENCE" }))).andReturn(resultSet);
215
EasyMock.expect(resultSet.next()).andReturn(true);
216
EasyMock.expect(resultSet.getString("TABLE_SCHEM")).andReturn("schema1");
217
EasyMock.expect(resultSet.getString("TABLE_NAME")).andReturn("sequence1");
218
EasyMock.expect(resultSet.next()).andReturn(true);
219
EasyMock.expect(resultSet.getString("TABLE_SCHEM")).andReturn("schema2");
220
EasyMock.expect(resultSet.getString("TABLE_NAME")).andReturn("sequence2");
221
EasyMock.expect(resultSet.next()).andReturn(false);
225
EasyMock.replay(metaData, resultSet);
227
Collection<QualifiedName> results = this.getSequences(metaData);
229
EasyMock.verify(metaData, resultSet);
231
assert results.size() == 2 : results;
233
Iterator<QualifiedName> iterator = results.iterator();
234
QualifiedName sequence = iterator.next();
235
String schema = sequence.getSchema();
236
String name = sequence.getName();
238
assert schema.equals("schema1") : schema;
239
assert name.equals("sequence1") : name;
241
sequence = iterator.next();
242
schema = sequence.getSchema();
243
name = sequence.getName();
245
assert schema.equals("schema2") : schema;
246
assert name.equals("sequence2") : name;
250
public Collection<QualifiedName> getSequences(DatabaseMetaData metaData) throws SQLException
252
return this.dialect.getSequences(metaData);
255
public void testGetSimpleSQL() throws SQLException
257
String result = this.getSimpleSQL();
259
assert result.equals("SELECT CURRENT_TIMESTAMP") : result;
263
public String getSimpleSQL() throws SQLException
265
return this.dialect.getSimpleSQL();
268
public void testGetTruncateTableSQL() throws SQLException
270
TableProperties table = EasyMock.createStrictMock(TableProperties.class);
272
EasyMock.expect(table.getName()).andReturn("table");
274
EasyMock.replay(table);
276
String result = this.getTruncateTableSQL(table);
278
EasyMock.verify(table);
280
assert result.equals("DELETE FROM table") : result;
284
public String getTruncateTableSQL(TableProperties properties) throws SQLException
286
return this.dialect.getTruncateTableSQL(properties);
289
@DataProvider(name = "select-for-update-sql")
290
Object[][] selectForUpdateProvider()
292
return new Object[][] {
293
new Object[] { "SELECT * FROM success FOR UPDATE" },
294
new Object[] { "SELECT * FROM failure" },
298
@Test(dataProvider = "select-for-update-sql")
299
public void testIsSelectForUpdate(String sql) throws SQLException
301
boolean result = this.isSelectForUpdate(sql);
303
assert result == sql.contains("success");
307
public boolean isSelectForUpdate(String sql) throws SQLException
309
return this.dialect.isSelectForUpdate(sql);
312
@DataProvider(name = "sequence-sql")
313
Object[][] sequenceSQLProvider()
315
return new Object[][] {
316
new Object[] { "SELECT NEXT VALUE FOR success" },
317
new Object[] { "SELECT NEXT VALUE FOR success, * FROM table" },
318
new Object[] { "INSERT INTO table VALUES (NEXT VALUE FOR success, 0)" },
319
new Object[] { "UPDATE table SET id = NEXT VALUE FOR success" },
320
new Object[] { "SELECT * FROM table" },
324
@Test(dataProvider = "sequence-sql")
325
public void testParseSequence(String sql) throws SQLException
327
String result = this.parseSequence(sql);
329
if (sql.contains("success"))
331
assert (result != null);
332
assert result.equals("success") : result;
336
assert (result == null) : result;
341
public String parseSequence(String sql) throws SQLException
343
return this.dialect.parseSequence(sql);
346
public void testGetDefaultSchemas() throws SQLException
348
DatabaseMetaData metaData = EasyMock.createStrictMock(DatabaseMetaData.class);
350
String user = "user";
352
EasyMock.expect(metaData.getUserName()).andReturn(user);
354
EasyMock.replay(metaData);
356
List<String> result = this.getDefaultSchemas(metaData);
358
EasyMock.verify(metaData);
360
assert result.size() == 1 : result.size();
362
String schema = result.get(0);
364
assert schema.equals(user) : schema;
368
public List<String> getDefaultSchemas(DatabaseMetaData metaData) throws SQLException
370
return this.dialect.getDefaultSchemas(metaData);
373
@DataProvider(name = "insert-table-sql")
374
Object[][] insertTableProvider()
376
return new Object[][] {
377
new Object[] { "INSERT INTO success (column1, column2) VALUES (1, 2)" },
378
new Object[] { "INSERT INTO success VALUES (1, 2)" },
379
new Object[] { "INSERT success (column1, column2) VALUES (1, 2)" },
380
new Object[] { "INSERT success VALUES (1, 2)" },
381
new Object[] { "INSERT INTO success (column1, column2) SELECT column1, column2 FROM dummy" },
382
new Object[] { "INSERT INTO success SELECT column1, column2 FROM dummy" },
383
new Object[] { "INSERT success (column1, column2) SELECT column1, column2 FROM dummy" },
384
new Object[] { "INSERT success SELECT column1, column2 FROM dummy" },
385
new Object[] { "SELECT * FROM failure WHERE 0=1" },
386
new Object[] { "UPDATE failure SET column = 0" },
390
@Test(dataProvider = "insert-table-sql")
391
public void testParseInsertTable(String sql) throws SQLException
393
String result = this.parseInsertTable(sql);
395
if (sql.contains("success"))
397
assert result != null;
398
assert result.equals("success");
402
assert result == null : result;
407
public String parseInsertTable(String sql) throws SQLException
409
return this.dialect.parseInsertTable(sql);
412
public void testGetIdentifierPattern() throws SQLException
414
DatabaseMetaData metaData = EasyMock.createStrictMock(DatabaseMetaData.class);
416
EasyMock.expect(metaData.getExtraNameCharacters()).andReturn("$");
418
EasyMock.replay(metaData);
420
String result = this.getIdentifierPattern(metaData).pattern();
422
EasyMock.verify(metaData);
424
assert result.equals("[a-zA-Z][\\w\\Q$\\E]*") : result;
428
public Pattern getIdentifierPattern(DatabaseMetaData metaData) throws SQLException
430
return this.dialect.getIdentifierPattern(metaData);
433
@DataProvider(name = "current-date")
434
Object[][] currentDateProvider()
436
java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
438
return new Object[][] {
439
new Object[] { "SELECT CURRENT_DATE FROM success", date },
440
new Object[] { "SELECT CCURRENT_DATE FROM failure", date },
441
new Object[] { "SELECT CURRENT_DATES FROM failure", date },
442
new Object[] { "SELECT 1 FROM failure", date },
446
@Test(dataProvider = "current-date")
447
public void testEvaluateCurrentDate(String sql, java.sql.Date date)
449
String expected = sql.contains("success") ? String.format("SELECT DATE '%s' FROM success", date.toString()) : sql;
451
String result = this.evaluateCurrentDate(sql, date);
453
assert result.equals(expected) : result;
457
public String evaluateCurrentDate(String sql, java.sql.Date date)
459
return this.dialect.evaluateCurrentDate(sql, date);
462
@DataProvider(name = "current-time")
463
Object[][] currentTimeProvider()
465
java.sql.Time date = new java.sql.Time(System.currentTimeMillis());
467
return new Object[][] {
468
new Object[] { "SELECT CURRENT_TIME FROM success", date },
469
new Object[] { "SELECT CURRENT_TIME(2) FROM success", date },
470
new Object[] { "SELECT CURRENT_TIME ( 2 ) FROM success", date },
471
new Object[] { "SELECT LOCALTIME FROM success", date },
472
new Object[] { "SELECT LOCALTIME(2) FROM success", date },
473
new Object[] { "SELECT LOCALTIME ( 2 ) FROM success", date },
474
new Object[] { "SELECT CCURRENT_TIME FROM failure", date },
475
new Object[] { "SELECT LLOCALTIME FROM failure", date },
476
new Object[] { "SELECT CURRENT_TIMESTAMP FROM failure", date },
477
new Object[] { "SELECT LOCALTIMESTAMP FROM failure", date },
478
new Object[] { "SELECT 1 FROM failure", date },
482
@Test(dataProvider = "current-time")
483
public void testEvaluateCurrentTime(String sql, java.sql.Time date)
485
String expected = sql.contains("success") ? String.format("SELECT TIME '%s' FROM success", date.toString()) : sql;
487
String result = this.evaluateCurrentTime(sql, date);
489
assert result.equals(expected) : result;
493
public String evaluateCurrentTime(String sql, java.sql.Time date)
495
return this.dialect.evaluateCurrentTime(sql, date);
498
@DataProvider(name = "current-timestamp")
499
Object[][] currentTimestampProvider()
501
java.sql.Timestamp date = new java.sql.Timestamp(System.currentTimeMillis());
503
return new Object[][] {
504
new Object[] { "SELECT CURRENT_TIMESTAMP FROM success", date },
505
new Object[] { "SELECT CURRENT_TIMESTAMP(2) FROM success", date },
506
new Object[] { "SELECT CURRENT_TIMESTAMP ( 2 ) FROM success", date },
507
new Object[] { "SELECT LOCALTIMESTAMP FROM success", date },
508
new Object[] { "SELECT LOCALTIMESTAMP(2) FROM success", date },
509
new Object[] { "SELECT LOCALTIMESTAMP ( 2 ) FROM success", date },
510
new Object[] { "SELECT CURRENT_TIMESTAMPS FROM failure", date },
511
new Object[] { "SELECT CCURRENT_TIMESTAMP FROM failure", date },
512
new Object[] { "SELECT LOCALTIMESTAMPS FROM failure", date },
513
new Object[] { "SELECT LLOCALTIMESTAMP FROM failure", date },
514
new Object[] { "SELECT 1 FROM failure", date },
518
@Test(dataProvider = "current-timestamp")
519
public void testEvaluateCurrentTimestamp(String sql, java.sql.Timestamp date)
521
String expected = sql.contains("success") ? String.format("SELECT TIMESTAMP '%s' FROM success", date.toString()) : sql;
523
String result = this.evaluateCurrentTimestamp(sql, date);
525
assert result.equals(expected) : result;
529
public String evaluateCurrentTimestamp(String sql, java.sql.Timestamp date)
531
return this.dialect.evaluateCurrentTimestamp(sql, date);
534
@DataProvider(name = "random")
535
Object[][] randomProvider()
537
return new Object[][] {
538
new Object[] { "SELECT RAND() FROM success" },
539
new Object[] { "SELECT RAND ( ) FROM success" },
540
new Object[] { "SELECT RAND FROM failure" },
541
new Object[] { "SELECT OPERAND() FROM failure" },
542
new Object[] { "SELECT 1 FROM failure" },
546
@Test(dataProvider = "random")
547
public void testEvaluateRand(String sql)
549
String result = this.evaluateRand(sql);
551
if (sql.contains("success"))
553
assert Pattern.matches("SELECT ((0\\.\\d+)|([1-9]\\.\\d+E\\-\\d+)) FROM success", result) : result;
557
assert result.equals(sql) : result;
562
public String evaluateRand(String sql)
564
return this.dialect.evaluateRand(sql);
567
public void testGetAlterIdentityColumnSQL() throws SQLException
569
TableProperties table = EasyMock.createStrictMock(TableProperties.class);
570
ColumnProperties column = EasyMock.createStrictMock(ColumnProperties.class);
572
EasyMock.expect(table.getName()).andReturn("table");
573
EasyMock.expect(column.getName()).andReturn("column");
575
EasyMock.replay(table, column);
577
String result = this.getAlterIdentityColumnSQL(table, column, 1000L);
579
EasyMock.verify(table, column);
581
assert result.equals("ALTER TABLE table ALTER COLUMN column RESTART WITH 1000") : result;
585
public String getAlterIdentityColumnSQL(TableProperties table, ColumnProperties column, long value) throws SQLException
587
return this.dialect.getAlterIdentityColumnSQL(table, column, value);