~brian-thomason/+junk/ha-jdbc

1 by Brian Thomason
Initial import
1
/*
2
 * HA-JDBC: High-Availability JDBC
3
 * Copyright (c) 2004-2007 Paul Ferraro
4
 * 
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.
9
 * 
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 
13
 * for more details.
14
 * 
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
18
 * 
19
 * Contact: ferraro@users.sourceforge.net
20
 */
21
package net.sf.hajdbc.dialect;
22
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;
31
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;
41
42
import org.easymock.EasyMock;
43
import org.testng.annotations.DataProvider;
44
import org.testng.annotations.Test;
45
46
/**
47
 * @author Paul Ferraro
48
 *
49
 */
50
@SuppressWarnings("nls")
51
@Test
52
public class TestStandardDialect implements Dialect
53
{
54
 	private Dialect dialect;
55
 	
56
	public TestStandardDialect()
57
	{
58
		this(new StandardDialect());
59
	}
60
	
61
	protected TestStandardDialect(Dialect dialect)
62
	{
63
		this.dialect = dialect;
64
	}
65
66
	public void testGetAlterSequenceSQL() throws SQLException
67
	{
68
		SequenceProperties sequence = EasyMock.createStrictMock(SequenceProperties.class);
69
		
70
		EasyMock.expect(sequence.getName()).andReturn("sequence");
71
		
72
		EasyMock.replay(sequence);
73
		
74
		String result = this.getAlterSequenceSQL(sequence, 1000L);
75
76
		EasyMock.verify(sequence);
77
		
78
		assert result.equals("ALTER SEQUENCE sequence RESTART WITH 1000") : result;
79
	}
80
	
81
	@Override
82
	public String getAlterSequenceSQL(SequenceProperties sequence, long value) throws SQLException
83
	{
84
		return this.dialect.getAlterSequenceSQL(sequence, value);
85
	}
86
87
	public void testGetColumnType() throws SQLException
88
	{
89
		ColumnProperties column = EasyMock.createStrictMock(ColumnProperties.class);
90
		
91
		EasyMock.expect(column.getType()).andReturn(Types.INTEGER);
92
		
93
		EasyMock.replay(column);
94
		
95
		int result = this.getColumnType(column);
96
		
97
		EasyMock.verify(column);
98
		
99
		assert result == Types.INTEGER : result;
100
	}
101
	
102
	@Override
103
	public int getColumnType(ColumnProperties column) throws SQLException
104
	{
105
		return this.dialect.getColumnType(column);
106
	}
107
108
	public void testGetCreateForeignKeyConstraintSQL() throws SQLException
109
	{
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);
119
		
120
		String result = this.getCreateForeignKeyConstraintSQL(key);
121
		
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;
123
	}
124
	
125
	@Override
126
	public String getCreateForeignKeyConstraintSQL(ForeignKeyConstraint constraint) throws SQLException
127
	{
128
		return this.dialect.getCreateForeignKeyConstraintSQL(constraint);
129
	}
130
131
	public void testGetCreateUniqueConstraintSQL() throws SQLException
132
	{
133
		UniqueConstraint key = new UniqueConstraintImpl("name", "table");
134
		key.getColumnList().add("column1");
135
		key.getColumnList().add("column2");
136
		
137
		String result = this.getCreateUniqueConstraintSQL(key);
138
		
139
		assert result.equals("ALTER TABLE table ADD CONSTRAINT name UNIQUE (column1, column2)") : result;
140
	}
141
	
142
	@Override
143
	public String getCreateUniqueConstraintSQL(UniqueConstraint constraint) throws SQLException
144
	{
145
		return this.dialect.getCreateUniqueConstraintSQL(constraint);
146
	}
147
148
	public void testGetDropForeignKeyConstraintSQL() throws SQLException
149
	{
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);
159
		
160
		String result = this.getDropForeignKeyConstraintSQL(key);
161
		
162
		assert result.equals("ALTER TABLE table DROP CONSTRAINT name") : result;
163
	}
164
	
165
	@Override
166
	public String getDropForeignKeyConstraintSQL(ForeignKeyConstraint constraint) throws SQLException
167
	{
168
		return this.dialect.getDropForeignKeyConstraintSQL(constraint);
169
	}
170
171
	public void testGetDropUniqueConstraintSQL() throws SQLException
172
	{
173
		UniqueConstraint key = new UniqueConstraintImpl("name", "table");
174
		key.getColumnList().add("column1");
175
		key.getColumnList().add("column2");
176
		
177
		String result = this.getDropUniqueConstraintSQL(key);
178
		
179
		assert result.equals("ALTER TABLE table DROP CONSTRAINT name") : result;
180
	}
181
	
182
	@Override
183
	public String getDropUniqueConstraintSQL(UniqueConstraint constraint) throws SQLException
184
	{
185
		return this.dialect.getDropUniqueConstraintSQL(constraint);
186
	}
187
188
	public void testGetNextSequenceValueSQL() throws SQLException
189
	{
190
		SequenceProperties sequence = EasyMock.createStrictMock(SequenceProperties.class);
191
		
192
		EasyMock.expect(sequence.getName()).andReturn("sequence");
193
		
194
		EasyMock.replay(sequence);
195
		
196
		String result = this.getNextSequenceValueSQL(sequence);
197
		
198
		EasyMock.verify(sequence);
199
		
200
		assert result.equals("SELECT NEXT VALUE FOR sequence") : result;
201
	}
202
	
203
	@Override
204
	public String getNextSequenceValueSQL(SequenceProperties sequence) throws SQLException
205
	{
206
		return this.dialect.getNextSequenceValueSQL(sequence);
207
	}
208
	
209
	public void testGetSequences() throws SQLException
210
	{
211
		DatabaseMetaData metaData = EasyMock.createStrictMock(DatabaseMetaData.class);
212
		ResultSet resultSet = EasyMock.createStrictMock(ResultSet.class);
213
		
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);
222
		
223
		resultSet.close();
224
		
225
		EasyMock.replay(metaData, resultSet);
226
		
227
		Collection<QualifiedName> results = this.getSequences(metaData);
228
		
229
		EasyMock.verify(metaData, resultSet);
230
		
231
		assert results.size() == 2 : results;
232
		
233
		Iterator<QualifiedName> iterator = results.iterator();
234
		QualifiedName sequence = iterator.next();
235
		String schema = sequence.getSchema();
236
		String name = sequence.getName();
237
		
238
		assert schema.equals("schema1") : schema;
239
		assert name.equals("sequence1") : name;
240
		
241
		sequence = iterator.next();
242
		schema = sequence.getSchema();
243
		name = sequence.getName();
244
		
245
		assert schema.equals("schema2") : schema;
246
		assert name.equals("sequence2") : name;
247
	}
248
	
249
	@Override
250
	public Collection<QualifiedName> getSequences(DatabaseMetaData metaData) throws SQLException
251
	{
252
		return this.dialect.getSequences(metaData);
253
	}
254
	
255
	public void testGetSimpleSQL() throws SQLException
256
	{
257
		String result = this.getSimpleSQL();
258
		
259
		assert result.equals("SELECT CURRENT_TIMESTAMP") : result;
260
	}
261
	
262
	@Override
263
	public String getSimpleSQL() throws SQLException
264
	{
265
		return this.dialect.getSimpleSQL();
266
	}
267
268
	public void testGetTruncateTableSQL() throws SQLException
269
	{
270
		TableProperties table = EasyMock.createStrictMock(TableProperties.class);
271
		
272
		EasyMock.expect(table.getName()).andReturn("table");
273
		
274
		EasyMock.replay(table);
275
		
276
		String result = this.getTruncateTableSQL(table);
277
		
278
		EasyMock.verify(table);
279
		
280
		assert result.equals("DELETE FROM table") : result;
281
	}
282
	
283
	@Override
284
	public String getTruncateTableSQL(TableProperties properties) throws SQLException
285
	{
286
		return this.dialect.getTruncateTableSQL(properties);
287
	}
288
289
	@DataProvider(name = "select-for-update-sql")
290
	Object[][] selectForUpdateProvider()
291
	{
292
		return new Object[][] {
293
			new Object[] { "SELECT * FROM success FOR UPDATE" },
294
			new Object[] { "SELECT * FROM failure" },
295
		};
296
	}
297
	
298
	@Test(dataProvider = "select-for-update-sql")
299
	public void testIsSelectForUpdate(String sql) throws SQLException
300
	{
301
		boolean result = this.isSelectForUpdate(sql);
302
		
303
		assert result == sql.contains("success");
304
	}
305
	
306
	@Override
307
	public boolean isSelectForUpdate(String sql) throws SQLException
308
	{
309
		return this.dialect.isSelectForUpdate(sql);
310
	}
311
312
	@DataProvider(name = "sequence-sql")
313
	Object[][] sequenceSQLProvider()
314
	{
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" },
321
		};
322
	}
323
324
	@Test(dataProvider = "sequence-sql")
325
	public void testParseSequence(String sql) throws SQLException
326
	{
327
		String result = this.parseSequence(sql);
328
		
329
		if (sql.contains("success"))
330
		{
331
			assert (result != null);
332
			assert result.equals("success") : result;
333
		}
334
		else
335
		{
336
			assert (result == null) : result;
337
		}
338
	}
339
	
340
	@Override
341
	public String parseSequence(String sql) throws SQLException
342
	{
343
		return this.dialect.parseSequence(sql);
344
	}
345
346
	public void testGetDefaultSchemas() throws SQLException
347
	{
348
		DatabaseMetaData metaData = EasyMock.createStrictMock(DatabaseMetaData.class);
349
		
350
		String user = "user";
351
		
352
		EasyMock.expect(metaData.getUserName()).andReturn(user);
353
		
354
		EasyMock.replay(metaData);
355
		
356
		List<String> result = this.getDefaultSchemas(metaData);
357
		
358
		EasyMock.verify(metaData);
359
		
360
		assert result.size() == 1 : result.size();
361
		
362
		String schema = result.get(0);
363
		
364
		assert schema.equals(user) : schema;
365
	}
366
	
367
	@Override
368
	public List<String> getDefaultSchemas(DatabaseMetaData metaData) throws SQLException
369
	{
370
		return this.dialect.getDefaultSchemas(metaData);
371
	}
372
373
	@DataProvider(name = "insert-table-sql")
374
	Object[][] insertTableProvider()
375
	{
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" },
387
		};
388
	}
389
	
390
	@Test(dataProvider = "insert-table-sql")
391
	public void testParseInsertTable(String sql) throws SQLException
392
	{
393
		String result = this.parseInsertTable(sql);
394
		
395
		if (sql.contains("success"))
396
		{
397
			assert result != null;
398
			assert result.equals("success");
399
		}
400
		else
401
		{
402
			assert result == null : result;
403
		}
404
	}
405
	
406
	@Override
407
	public String parseInsertTable(String sql) throws SQLException
408
	{
409
		return this.dialect.parseInsertTable(sql);
410
	}
411
	
412
	public void testGetIdentifierPattern() throws SQLException
413
	{
414
		DatabaseMetaData metaData = EasyMock.createStrictMock(DatabaseMetaData.class);
415
		
416
		EasyMock.expect(metaData.getExtraNameCharacters()).andReturn("$");
417
		
418
		EasyMock.replay(metaData);
419
		
420
		String result = this.getIdentifierPattern(metaData).pattern();
421
		
422
		EasyMock.verify(metaData);
423
		
424
		assert result.equals("[a-zA-Z][\\w\\Q$\\E]*") : result;
425
	}
426
	
427
	@Override
428
	public Pattern getIdentifierPattern(DatabaseMetaData metaData) throws SQLException
429
	{
430
		return this.dialect.getIdentifierPattern(metaData);
431
	}
432
433
	@DataProvider(name = "current-date")
434
	Object[][] currentDateProvider()
435
	{
436
		java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
437
		
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 },
443
		};
444
	}
445
	
446
	@Test(dataProvider = "current-date")
447
	public void testEvaluateCurrentDate(String sql, java.sql.Date date)
448
	{
449
		String expected = sql.contains("success") ? String.format("SELECT DATE '%s' FROM success", date.toString()) : sql;
450
		
451
		String result = this.evaluateCurrentDate(sql, date);
452
		
453
		assert result.equals(expected) : result;
454
	}
455
	
456
	@Override
457
	public String evaluateCurrentDate(String sql, java.sql.Date date)
458
	{
459
		return this.dialect.evaluateCurrentDate(sql, date);
460
	}
461
462
	@DataProvider(name = "current-time")
463
	Object[][] currentTimeProvider()
464
	{
465
		java.sql.Time date = new java.sql.Time(System.currentTimeMillis());
466
		
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 },
479
		};
480
	}
481
482
	@Test(dataProvider = "current-time")
483
	public void testEvaluateCurrentTime(String sql, java.sql.Time date)
484
	{
485
		String expected = sql.contains("success") ? String.format("SELECT TIME '%s' FROM success", date.toString()) : sql;
486
		
487
		String result = this.evaluateCurrentTime(sql, date);
488
		
489
		assert result.equals(expected) : result;
490
	}
491
	
492
	@Override
493
	public String evaluateCurrentTime(String sql, java.sql.Time date)
494
	{
495
		return this.dialect.evaluateCurrentTime(sql, date);
496
	}
497
498
	@DataProvider(name = "current-timestamp")
499
	Object[][] currentTimestampProvider()
500
	{
501
		java.sql.Timestamp date = new java.sql.Timestamp(System.currentTimeMillis());
502
		
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 },
515
		};
516
	}
517
518
	@Test(dataProvider = "current-timestamp")
519
	public void testEvaluateCurrentTimestamp(String sql, java.sql.Timestamp date)
520
	{
521
		String expected = sql.contains("success") ? String.format("SELECT TIMESTAMP '%s' FROM success", date.toString()) : sql;
522
		
523
		String result = this.evaluateCurrentTimestamp(sql, date);
524
		
525
		assert result.equals(expected) : result;
526
	}
527
	
528
	@Override
529
	public String evaluateCurrentTimestamp(String sql, java.sql.Timestamp date)
530
	{
531
		return this.dialect.evaluateCurrentTimestamp(sql, date);
532
	}
533
534
	@DataProvider(name = "random")
535
	Object[][] randomProvider()
536
	{
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" },
543
		};
544
	}
545
	
546
	@Test(dataProvider = "random")
547
	public void testEvaluateRand(String sql)
548
	{
549
		String result = this.evaluateRand(sql);
550
		
551
		if (sql.contains("success"))
552
		{
553
			assert Pattern.matches("SELECT ((0\\.\\d+)|([1-9]\\.\\d+E\\-\\d+)) FROM success", result) : result;
554
		}
555
		else
556
		{
557
			assert result.equals(sql) : result;
558
		}
559
	}
560
	
561
	@Override
562
	public String evaluateRand(String sql)
563
	{
564
		return this.dialect.evaluateRand(sql);
565
	}
566
567
	public void testGetAlterIdentityColumnSQL() throws SQLException
568
	{
569
		TableProperties table = EasyMock.createStrictMock(TableProperties.class);
570
		ColumnProperties column = EasyMock.createStrictMock(ColumnProperties.class);
571
		
572
		EasyMock.expect(table.getName()).andReturn("table");
573
		EasyMock.expect(column.getName()).andReturn("column");
574
		
575
		EasyMock.replay(table, column);
576
		
577
		String result = this.getAlterIdentityColumnSQL(table, column, 1000L);
578
		
579
		EasyMock.verify(table, column);
580
		
581
		assert result.equals("ALTER TABLE table ALTER COLUMN column RESTART WITH 1000") : result;
582
	}
583
	
584
	@Override
585
	public String getAlterIdentityColumnSQL(TableProperties table, ColumnProperties column, long value) throws SQLException
586
	{
587
		return this.dialect.getAlterIdentityColumnSQL(table, column, value);
588
	}
589
}