KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derbyTesting > functionTests > tests > junitTests > compatibility > JDBCDriverTest


1 /*
2
3    Derby - Class org.apache.derbyTesting.functionTests.tests.compatibility.JDBCDriverTest
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21 /**
22  * <p>
23  * This JUnit test verifies the compatibility of Derby clients and
24  * servers across Derby version levels and supported VMs.
25  * </p>
26  *
27  * @author Rick
28  */

29
30 package org.apache.derbyTesting.functionTests.tests.junitTests.compatibility;
31
32 import java.io.*;
33 import java.math.*;
34 import java.sql.*;
35 import java.util.*;
36
37 import junit.framework.*;
38
39 import org.apache.derbyTesting.functionTests.util.DerbyJUnitTest;
40
41 public class JDBCDriverTest extends CompatibilitySuite
42 {
43     /////////////////////////////////////////////////////////////
44
//
45
// CONSTANTS
46
//
47
/////////////////////////////////////////////////////////////
48

49     private static final String JavaDoc ALL_TYPES_TABLE = "allTypesTable";
50     private static final String JavaDoc KEY_COLUMN = "keyCol";
51
52     //
53
// Data values to be stuffed into columns of ALL_TYPES_TABLE.
54
//
55
private static final byte[] SAMPLE_BYTES =
56         new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5 };
57     private static final String JavaDoc SAMPLE_STRING = "hello";
58
59     //
60
// These funny constants are defined this way to make the salient
61
// facts of the COERCIONS table leap out at you.
62
//
63
private static final boolean Y = true;
64     private static final boolean _ = false;
65
66     //
67
// This table declares the datatypes supported by Derby and the earliest
68
// versions of the Derby and the db2jcc client which support these
69
// datatypes.
70
//
71
// If you add a type to this table, make sure you add a corresponding
72
// column to the following row table. Also add a corresponding row to the
73
// COERCIONS table.
74
//
75
private static final TypeDescriptor[] ALL_TYPES =
76     {
77         // 10.0 types
78

79         new TypeDescriptor
80         ( Types.BIGINT, "bigint", IBM_2_4, DRB_10_0, VM_1_3 ),
81         new TypeDescriptor
82         ( Types.BLOB, "blob", IBM_2_4, DRB_10_0, VM_1_3 ),
83         new TypeDescriptor
84         ( Types.CHAR, "char(5)", IBM_2_4, DRB_10_0, VM_1_3 ),
85         new TypeDescriptor
86         ( Types.BINARY, "char(5) for bit data", IBM_2_4, DRB_10_0, VM_1_3 ),
87         new TypeDescriptor
88         ( Types.CLOB, "clob", IBM_2_4, DRB_10_0, VM_1_3 ),
89         new TypeDescriptor
90         ( Types.DATE, "date", IBM_2_4, DRB_10_0, VM_1_3 ),
91         new TypeDescriptor
92         ( Types.DECIMAL, "decimal", IBM_2_4, DRB_10_0, VM_1_3 ),
93         new TypeDescriptor
94         ( Types.DOUBLE, "double", IBM_2_4, DRB_10_0, VM_1_3 ),
95         new TypeDescriptor
96         ( Types.DOUBLE, "double precision", IBM_2_4, DRB_10_0, VM_1_3 ),
97         new TypeDescriptor
98         ( Types.REAL, "float(23)", IBM_2_4, DRB_10_0, VM_1_3 ),
99         new TypeDescriptor
100         ( Types.DOUBLE, "float", IBM_2_4, DRB_10_0, VM_1_3 ),
101         new TypeDescriptor
102         ( Types.INTEGER, "integer", IBM_2_4, DRB_10_0, VM_1_3 ),
103         new TypeDescriptor
104         ( Types.LONGVARCHAR, "long varchar", IBM_2_4, DRB_10_0, VM_1_3 ),
105         new TypeDescriptor
106         ( Types.LONGVARBINARY, "long varchar for bit data", IBM_2_4, DRB_10_0, VM_1_3 ),
107         new TypeDescriptor
108         ( Types.NUMERIC, "numeric", IBM_2_4, DRB_10_0, VM_1_3 ),
109         new TypeDescriptor
110         ( Types.REAL, "real", IBM_2_4, DRB_10_0, VM_1_3 ),
111         new TypeDescriptor
112         ( Types.SMALLINT, "smallint", IBM_2_4, DRB_10_0, VM_1_3 ),
113         new TypeDescriptor
114         ( Types.TIME, "time", IBM_2_4, DRB_10_0, VM_1_3 ),
115         new TypeDescriptor
116         ( Types.TIMESTAMP, "timestamp", IBM_2_4, DRB_10_0, VM_1_3 ),
117         new TypeDescriptor
118         ( Types.VARCHAR, "varchar(5)", IBM_2_4, DRB_10_0, VM_1_3 ),
119         new TypeDescriptor
120         ( Types.VARBINARY, "varchar(5) for bit data", IBM_2_4, DRB_10_0, VM_1_3 ),
121     };
122
123     //
124
// This table needs to have the same number of entries as ALL_TYPES.
125
// The testSanity() test case enforces this at run time.
126
//
127
private static final Object JavaDoc[] ROW_1 =
128     {
129         // 10.0 columns
130

131         new Long JavaDoc( 1L ),
132         new MyBlob( SAMPLE_BYTES ),
133         SAMPLE_STRING,
134         SAMPLE_BYTES,
135         new MyClob( SAMPLE_STRING ),
136         new java.sql.Date JavaDoc( 1L ),
137         new BigDecimal( 1.0 ),
138         new Double JavaDoc( 1.0 ),
139         new Double JavaDoc( 1.0 ),
140         new Float JavaDoc( (float) 1.0 ),
141         new Double JavaDoc( 1.0 ),
142         new Integer JavaDoc( 1 ),
143         SAMPLE_STRING,
144         SAMPLE_BYTES,
145         new BigDecimal( 1.0 ),
146         new Float JavaDoc( (float) 1.0 ),
147         new Short JavaDoc( (short) 1 ),
148         new Time( 1L ),
149         new Timestamp( 1L ),
150         SAMPLE_STRING,
151         SAMPLE_BYTES,
152     };
153
154     //
155
// This table needs to have the same number of rows as ALL_TYPES.
156
// Each row in this table needs to have the same number of columns as
157
// rows in ALL_TYPES. The testSanity() test case enforces this at run time.
158
// Note how the funny synonyms for true and false
159
// make the salient facts of this table leap out at you.
160
//
161
// The ugly class name T_CN is an abbreviation which makes it possible to
162
// squeeze this table onto a readable screen.
163
//
164
// Please read the introductory comment top-to-bottom. 'Y' means a coercion
165
// is legal; '_' means it isn't.
166
//
167
private static final T_CN[] COERCIONS =
168     {
169         // B|B|C|B|C|D|D|D|R|I|L|L|N|R|S|T|T|V|V
170
// I|L|H|I|L|A|E|O|E|N|O|O|U|E|M|I|I|A|A
171
// G|O|A|N|O|T|C|U|A|T|N|N|M|A|A|M|M|R|R
172
// I|B|R|A|B|E|I|B|L|E|G|G|E|L|L|E|E|C|B
173
// N|-|-|R|-|-|M|L|-|G|V|V|R|-|L|-|S|H|I
174
// T|-|-|Y|-|-|A|E|-|E|A|A|I|-|I|-|T|A|N
175
// -|-|-|-|-|-|L|-|-|R|R|R|C|-|N|-|A|R|A
176
// -|-|-|-|-|-|-|-|-|-|C|B|-|-|T|-|M|-|R
177
// -|-|-|-|-|-|-|-|-|-|H|I|-|-|-|-|P|-|Y
178
// -|-|-|-|-|-|-|-|-|-|A|N|-|-|-|-|-|-|-
179
// -|-|-|-|-|-|-|-|-|-|R|A|-|-|-|-|-|-|-
180
// -|-|-|-|-|-|-|-|-|-|-|R|-|-|-|-|-|-|-
181
// -|-|-|-|-|-|-|-|-|-|-|Y|-|-|-|-|-|-|-
182
new T_CN( Types.BIGINT, new boolean[] { Y,_,Y,_,_,_,_,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
183         new T_CN( Types.BLOB, new boolean[] { _,Y,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ } ),
184         new T_CN( Types.CHAR, new boolean[] { _,_,Y,_,_,_,_,_,_,_,Y,_,_,_,_,_,_,Y,_ } ),
185         new T_CN( Types.BINARY, new boolean[] { _,_,_,Y,_,_,_,_,_,_,_,Y,_,_,_,_,_,_,Y } ),
186         new T_CN( Types.CLOB, new boolean[] { _,_,_,_,Y,_,_,_,_,_,_,_,_,_,_,_,_,_,_ } ),
187         new T_CN( Types.DATE, new boolean[] { _,_,_,_,_,Y,_,_,_,_,_,_,_,_,_,_,_,_,_ } ),
188         new T_CN( Types.DECIMAL, new boolean[] { Y,_,_,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
189         new T_CN( Types.DOUBLE, new boolean[] { Y,_,_,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
190         new T_CN( Types.REAL, new boolean[] { Y,_,Y,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
191         new T_CN( Types.INTEGER, new boolean[] { Y,_,Y,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
192         new T_CN( Types.LONGVARCHAR, new boolean[] { _,_,Y,_,_,_,_,_,_,_,Y,_,_,_,_,_,_,Y,_ } ),
193         new T_CN( Types.LONGVARBINARY, new boolean[] { _,_,_,_,_,_,_,_,_,_,_,Y,_,_,_,_,_,_,Y } ),
194         new T_CN( Types.NUMERIC, new boolean[] { Y,_,Y,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
195         new T_CN( Types.REAL, new boolean[] { Y,_,Y,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
196         new T_CN( Types.SMALLINT, new boolean[] { Y,_,Y,_,_,_,Y,Y,Y,Y,Y,_,Y,Y,Y,_,_,Y,_ } ),
197         new T_CN( Types.TIME, new boolean[] { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,Y,_,_,_ } ),
198         new T_CN( Types.TIMESTAMP, new boolean[] { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,Y,_,_ } ),
199         new T_CN( Types.VARCHAR, new boolean[] { _,_,Y,_,_,_,_,_,_,_,Y,_,_,_,_,_,_,Y,_ } ),
200         new T_CN( Types.VARBINARY, new boolean[] { _,_,_,_,_,_,_,_,_,_,_,Y,_,_,_,_,_,_,Y } ),
201     };
202
203     /////////////////////////////////////////////////////////////
204
//
205
// STATE
206
//
207
/////////////////////////////////////////////////////////////
208

209     // map derby type name to type descriptor
210
private static HashMap _types = new HashMap(); // maps Derby type names to TypeDescriptors
211

212     // map jdbc type to index into COERCIONS
213
private static HashMap _coercionIndex = new HashMap(); // maps jdbc types to legal coercions
214

215     /////////////////////////////////////////////////////////////
216
//
217
// CONSTRUCTOR
218
//
219
/////////////////////////////////////////////////////////////
220

221     public JDBCDriverTest() {}
222
223     /////////////////////////////////////////////////////////////
224
//
225
// TEST ENTRY POINTS
226
//
227
/////////////////////////////////////////////////////////////
228

229     /**
230      * <p>
231      * Sanity check the integrity of this test suite.
232      * </p>
233      */

234     public void testSanity()
235     {
236         assertEquals
237             ( "ALL_TYPES.length == ROW_1.length", ALL_TYPES.length, ROW_1.length );
238
239         // make sure there we completely describe the coercibility of every jdbc type
240
int coercionCount = COERCIONS.length;
241         for ( int i = 0; i < coercionCount; i++ )
242         { assertEquals( "Coercion " + i, coercionCount, COERCIONS[ i ].getCoercions().length ); }
243     }
244
245     /**
246      * <p>
247      * Main test of jdbc drivers.
248      * </p>
249      */

250     public void testJDBCDriver()
251         throws Exception JavaDoc
252     {
253         Connection conn = getConnection();
254         
255         dropSchema( conn );
256         createSchema( conn );
257
258         datatypesTest( conn );
259
260         close( conn );
261     }
262     
263     /////////////////////////////////////////////////////////////
264
//
265
// TEST DATATYPES
266
//
267
/////////////////////////////////////////////////////////////
268

269     //
270
// Test that we can declare, insert, and select all datatypes that
271
// are legal on the server. Test the metadata for these datatypes.
272
//
273
private void datatypesTest( Connection conn )
274         throws Exception JavaDoc
275     {
276         TypeDescriptor[] types = ALL_TYPES;
277         String JavaDoc tableName = ALL_TYPES_TABLE;
278         Object JavaDoc[][] rows = new Object JavaDoc[][] { makeNullRow( types.length ), ROW_1 };
279         
280         checkDBMetadata( conn, tableName );
281         stuffTable( conn, tableName, types, rows );
282         readTable( conn, tableName, types, rows, null );
283     }
284     
285     //
286
// Verify that we get the correct DatabaseMetaData for a table.
287
//
288
private void checkDBMetadata( Connection conn, String JavaDoc tableName )
289         throws Exception JavaDoc
290     {
291         String JavaDoc normalizedSchema = DEFAULT_USER_NAME.toUpperCase();
292         String JavaDoc normalizedTable = tableName.toUpperCase();
293         DatabaseMetaData dbmd = conn.getMetaData();
294
295         ResultSet rs = dbmd.getColumns
296             ( null, normalizedSchema, normalizedTable, "%" );
297
298         println( "Pawing through database metadata for " + normalizedSchema + '.' + normalizedTable );
299
300         while( rs.next() )
301         {
302             String JavaDoc columnName = rs.getString( "COLUMN_NAME" );
303             int actualJdbcType = rs.getInt( "DATA_TYPE" );
304             TypeDescriptor typeDesc = getType( columnName );
305
306             if ( columnName.equals( KEY_COLUMN ) ) { continue; }
307
308             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
309
310             buffer.append( "[ " );
311             buffer.append( rs.getString( "COLUMN_NAME" ) );
312             buffer.append( ",\t" );
313             buffer.append( "type( " + rs.getInt( "DATA_TYPE" ) + " ),\t" );
314             buffer.append( rs.getString( "TYPE_NAME" ) );
315             buffer.append( " ]" );
316
317             println( buffer.toString() );
318             
319             assertEquals( columnName, ddmdTypeKludge( typeDesc.getJdbcType() ), actualJdbcType );
320         }
321
322         close( rs );
323     }
324
325     //
326
// Verify that we get the correct DatabaseMetaData for a procedure
327
//
328
private void checkProcMetadata( Connection conn, String JavaDoc procName, TypeDescriptor[] signature )
329         throws Exception JavaDoc
330     {
331         String JavaDoc normalizedSchema = DEFAULT_USER_NAME.toUpperCase();
332         String JavaDoc normalizedProc = procName.toUpperCase();
333         DatabaseMetaData dbmd = conn.getMetaData();
334
335         ResultSet rs = dbmd.getProcedureColumns
336             ( null, normalizedSchema, normalizedProc, "%" );
337
338         println( "Pawing through database metadata for " + normalizedSchema + '.' + normalizedProc );
339
340         while( rs.next() )
341         {
342             String JavaDoc columnName = rs.getString( "COLUMN_NAME" );
343             int actualJdbcType = rs.getInt( "DATA_TYPE" );
344             TypeDescriptor typeDesc = getType( signature, columnName );
345
346             if ( columnName.equals( KEY_COLUMN ) ) { continue; }
347
348             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
349
350             buffer.append( "[ " );
351             buffer.append( rs.getString( "COLUMN_NAME" ) );
352             buffer.append( ",\t" );
353             buffer.append( "type( " + rs.getInt( "DATA_TYPE" ) + " ),\t" );
354             buffer.append( rs.getString( "TYPE_NAME" ) );
355             buffer.append( " ]" );
356
357             println( buffer.toString() );
358             
359             assertEquals( columnName, ddmdTypeKludge( typeDesc.getJdbcType() ), actualJdbcType );
360         }
361
362         close( rs );
363     }
364
365     //
366
// Stuff a table with rows
367
//
368
private void stuffTable
369         ( Connection conn, String JavaDoc tableName, TypeDescriptor[] types, Object JavaDoc[][] rows )
370         throws Exception JavaDoc
371     {
372         PreparedStatement ps = makeInsert( conn, tableName, types );
373         int rowCount = rows.length;
374
375         for ( int i = 0; i < rowCount; i++ )
376         {
377             setRow( ps, i + 1, types, rows[ i ] );
378         }
379         
380         close( ps );
381     }
382
383     private PreparedStatement makeInsert
384         ( Connection conn, String JavaDoc tableName, TypeDescriptor[] types )
385         throws Exception JavaDoc
386     {
387         StringBuffer JavaDoc masterBuffer = new StringBuffer JavaDoc();
388         StringBuffer JavaDoc columnBuffer = new StringBuffer JavaDoc();
389         StringBuffer JavaDoc valuesBuffer = new StringBuffer JavaDoc();
390         int columnNumber = 0;
391         int valuesNumber = 0;
392         int typeCount = types.length;
393
394         beginColumnList( columnBuffer );
395         beginColumnList( valuesBuffer );
396
397         addColumn( columnBuffer, columnNumber++, doubleQuote( KEY_COLUMN ) );
398         addColumn( valuesBuffer, valuesNumber++, "?" );
399         
400         for ( int i = 0; i < typeCount; i++ )
401         {
402             TypeDescriptor type = types[ i ];
403             
404             if ( getServerVersion().atLeast( type.getDerbyVersion() ) )
405             {
406                 String JavaDoc typeName = type.getDerbyTypeName();
407                 String JavaDoc columnDesc = doubleQuote( typeName );
408                 
409                 addColumn( columnBuffer, columnNumber++, columnDesc );
410                 addColumn( valuesBuffer, valuesNumber++, "?" );
411             }
412         }
413
414         endColumnList( columnBuffer );
415         endColumnList( valuesBuffer );
416
417         masterBuffer.append( "insert into " + tableName + "\n" );
418         masterBuffer.append( columnBuffer.toString() );
419         masterBuffer.append( "values\n" );
420         masterBuffer.append( valuesBuffer.toString() );
421
422         PreparedStatement ps = prepare( conn, masterBuffer.toString() );
423
424         return ps;
425     }
426
427     //
428
// Verify that we can select all legal datatypes in a table.
429
//
430
private void readTable
431         ( Connection conn, String JavaDoc tableName, TypeDescriptor[] types, Object JavaDoc[][] rows, List casts )
432         throws Exception JavaDoc
433     {
434         PreparedStatement ps = readTableQuery( conn, tableName, types );
435         ResultSet rs = ps.executeQuery();
436
437         checkRSMD( rs );
438         checkRows( rs, types, rows, casts );
439         
440         close( rs );
441         close( ps );
442     }
443
444     //
445
// Make the select query
446
//
447
private PreparedStatement readTableQuery
448         ( Connection conn, String JavaDoc tableName, TypeDescriptor[] types )
449         throws Exception JavaDoc
450     {
451         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
452         int columnNumber = 0;
453         int typeCount = types.length;
454
455         buffer.append( "select \n" );
456
457         addColumn( buffer, columnNumber++, doubleQuote( KEY_COLUMN ) );
458         
459         for ( int i = 0; i < typeCount; i++ )
460         {
461             TypeDescriptor type = types[ i ];
462             
463             if ( getServerVersion().atLeast( type.getDerbyVersion() ) )
464             {
465                 String JavaDoc typeName = type.getDerbyTypeName();
466                 String JavaDoc columnDesc = doubleQuote( typeName );
467                 
468                 addColumn( buffer, columnNumber++, columnDesc );
469             }
470         }
471
472         buffer.append( "\nfrom " + tableName + "\n" );
473         buffer.append( "order by " + doubleQuote( KEY_COLUMN ) );
474
475         PreparedStatement ps = prepare( conn, buffer.toString() );
476
477         return ps;
478     }
479     
480     //
481
// Verify that we get the correct ResultSetMetaData for all datatypes
482
// which are legal on the server.
483
//
484
private void checkRSMD( ResultSet rs )
485         throws Exception JavaDoc
486     {
487         ResultSetMetaData rsmd = rs.getMetaData();
488         int columnCount = rsmd.getColumnCount();
489         int firstTastyColumn = 0;
490
491         println( "ResultSetMetaData:\n" );
492         
493         firstTastyColumn++; // skip uninteresting key column
494

495         for ( int i = firstTastyColumn; i < columnCount; i++ )
496         {
497             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
498             int columnID = i + 1;
499             String JavaDoc columnName = rsmd.getColumnName( columnID );
500             TypeDescriptor typeDesc = getType( columnName );
501             int expectedType = rsmdTypeKludge( typeDesc.getJdbcType() );
502             int actualType = rsmd.getColumnType( columnID );
503
504             buffer.append( "[ " );
505             buffer.append( columnName );
506             buffer.append( ", type( " );
507             buffer.append( actualType );
508             buffer.append( " ), " );
509             buffer.append( rsmd.getColumnTypeName( columnID ) );
510             buffer.append( " ]\n" );
511             
512             println( buffer.toString() );
513
514             assertEquals( columnName, expectedType, actualType );
515         }
516
517     }
518
519     //
520
// Verify that we select the values we
521
// originally inserted into a table.
522
//
523
private void checkRows( ResultSet rs, TypeDescriptor[] types, Object JavaDoc[][] rows, List casts )
524         throws Exception JavaDoc
525     {
526         int rowCount = rows.length;
527
528         for ( int i = 0; i < rowCount; i++ )
529         {
530             rs.next();
531             checkRow( rs, types, rows[ i ], casts );
532         }
533     }
534
535     //
536
// Verify that we select the values we
537
// originally inserted into a row.
538
//
539
private void checkRow( ResultSet rs, TypeDescriptor[] types, Object JavaDoc[] row, List casts )
540         throws Exception JavaDoc
541     {
542         int typeCount = types.length;
543
544         for ( int i = 0; i < typeCount; i++ )
545         {
546             TypeDescriptor type = types[ i ];
547             
548             if ( getServerVersion().atLeast( type.getDerbyVersion() ) )
549             {
550                 String JavaDoc columnName = type.getDerbyTypeName();
551                 Object JavaDoc expectedValue = row[ i ];
552                 Object JavaDoc actualValue = getColumn( rs, columnName, type );
553
554                 println( "Comparing column " + columnName + ": " + expectedValue + " to " + actualValue );
555                 compareObjects( columnName, expectedValue, actualValue );
556
557                 checkCoercions( rs, columnName, type, casts );
558             }
559         }
560     }
561
562     //
563
// Verify all legal jdbc coercions of a data value.
564
//
565
private void checkCoercions( ResultSet rs, String JavaDoc columnName, TypeDescriptor type, List casts )
566         throws Exception JavaDoc
567     {
568         T_CN coercionDesc = COERCIONS[ getCoercionIndex( type.getJdbcType() ) ];
569         boolean[] coercions = coercionDesc.getCoercions();
570         int count = coercions.length;
571         int legalCoercions = 0;
572
573         println( "Checking coercions for " + columnName );
574         
575         for ( int i = 0; i < count; i++ )
576         {
577             if ( coercions[ i ] )
578             {
579                 legalCoercions++;
580
581                 int jdbcType = COERCIONS[ i ].getJdbcType();
582                 Object JavaDoc retval = getColumn( rs, columnName, jdbcType );
583
584                 if ( casts != null ) { casts.add( retval ); }
585
586                 println( "\t" + jdbcType + ":\t" + retval );
587             }
588
589         }
590         // finally, try getObject()
591

592         Object JavaDoc objval = rs.getObject( columnName );
593         if ( objval == null ) { println( "\tgetObject() = null" ); }
594         else
595         {
596             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
597             buffer.append( "\tgetObject() = " );
598             buffer.append( objval.getClass().getName() );
599             buffer.append( "( " );
600             buffer.append( objval );
601             buffer.append( " )" );
602             println( buffer.toString() );
603         }
604     }
605     
606     //
607
// This kludge compensates for the fact that the DRDA clients report
608
// that NUMERIC columns are DECIMAL. See bug 584.
609
//
610
// In addition, booleans are handled oddly by down-rev clients.
611
//
612
private int rsmdTypeKludge( int originalJDbcType )
613     {
614         // The embedded client does the right thing.
615
if ( usingEmbeddedClient() && getServerVMVersion().atLeast( VM_1_4 ) ) { return originalJDbcType; }
616         
617         switch( originalJDbcType )
618         {
619             //This kludge compensates for the fact that the DRDA clients report
620
// that NUMERIC columns are DECIMAL. See bug 584.
621
case Types.NUMERIC:
622                 if ( usingEmbeddedClient() ) { return originalJDbcType; }
623                 else { return Types.DECIMAL; }
624
625             default: return originalJDbcType;
626         }
627     }
628
629     //
630
// This kludge compensates for the fact that servers return
631
// different jdbc types depending on their vm.
632
//
633
private int ddmdTypeKludge( int originalJDbcType )
634     {
635         switch( originalJDbcType )
636         {
637             case JDBC_BOOLEAN:
638                 if ( getServerVMVersion().atLeast( VM_1_4 ) ) { return originalJDbcType; }
639                 else { return Types.BIT; }
640
641             default: return originalJDbcType;
642         }
643     }
644
645     //
646
// Insert a row into the ALL_TYPES table. The row contains all datatypes
647
// that are legal on the server.
648
//
649
private void setRow( PreparedStatement ps, int keyValue, TypeDescriptor[] types, Object JavaDoc[] row )
650         throws Exception JavaDoc
651     {
652         int param = 1;
653         int typeCount = types.length;
654
655         ps.setInt( param++, keyValue );
656
657         for ( int i = 0; i < typeCount; i++ )
658         {
659             TypeDescriptor type = types[ i ];
660             Object JavaDoc value = row[ i ];
661             
662             if ( getServerVersion().atLeast( type.getDerbyVersion() ) )
663             {
664                 setParameter( ps, param++, type, value );
665             }
666         }
667
668         ps.execute();
669     }
670
671     //
672
// Add a row of null columns.
673
//
674
private Object JavaDoc[][] makeRows( Object JavaDoc[][] rows )
675     {
676         int count = rows.length;
677         int columns = rows[0].length;
678         Object JavaDoc[][] result = new Object JavaDoc[ count + 1 ][];
679         int idx = 0;
680
681         result[ idx++ ] = makeNullRow( columns );
682         
683         for ( int i = 0; i < count; i++ )
684         {
685             result[ idx++ ] = rows[ i ];
686         }
687
688         return result;
689     }
690
691     private Object JavaDoc[] makeNullRow( int rowLength )
692     {
693         return new Object JavaDoc[ rowLength ];
694     }
695
696     //
697
// Index the TypeDescriptors by Derby type name.
698
//
699
private void buildTypeMap()
700     {
701         int typeCount = ALL_TYPES.length;
702
703         for ( int i = 0; i < typeCount; i++ ) { putType( ALL_TYPES[ i ] ); }
704     }
705     private void putType( TypeDescriptor type )
706     {
707         _types.put( type.getDerbyTypeName(), type );
708     }
709
710     //
711
// Lookup TypeDescriptors by Derby type name.
712
//
713
private TypeDescriptor getType( String JavaDoc typeName )
714     {
715         if ( _types.size() == 0 ) { buildTypeMap(); }
716         
717         return (TypeDescriptor) _types.get( typeName );
718     }
719
720     //
721
// Lookup TypeDescriptors by jdbc type
722
//
723
private TypeDescriptor getType( int jdbcType )
724     {
725         int count = ALL_TYPES.length;
726
727         for ( int i = 0; i < count; i++ )
728         {
729             TypeDescriptor type = ALL_TYPES[ i ];
730
731             if ( type.getJdbcType() == jdbcType ) { return type; }
732         }
733
734         return null;
735     }
736
737     //
738
// Lookup TypeDescriptors by column name in an array of types
739
//
740
private TypeDescriptor getType( TypeDescriptor[] types, String JavaDoc typeName )
741     {
742         int count = types.length;
743
744         for ( int i = 0; i < count; i++ )
745         {
746             TypeDescriptor type = types[ i ];
747
748             if ( type.getDerbyTypeName().equals( typeName ) ) { return type; }
749         }
750         
751         return null;
752     }
753
754     //
755
// Index legal coercions by jdbc type.
756
//
757
private void buildCoercionMap()
758     {
759         int count = COERCIONS.length;
760
761         for ( int i = 0; i < count; i++ ) { putCoercionIndex( i ); }
762     }
763     private void putCoercionIndex( int index )
764     {
765         _coercionIndex.put( new Integer JavaDoc( COERCIONS[ index ].getJdbcType() ), new Integer JavaDoc( index ) );
766     }
767
768     //
769
// Lookup the legal coercions for a given jdbc type.
770
//
771
private int getCoercionIndex( int jdbcType )
772     {
773         if ( _coercionIndex.size() == 0 ) { buildCoercionMap(); }
774         
775         return ((Integer JavaDoc) _coercionIndex.get( new Integer JavaDoc( jdbcType ) )).intValue();
776     }
777     
778     /////////////////////////////////////////////////////////////
779
//
780
// MINIONS
781
//
782
/////////////////////////////////////////////////////////////
783

784     ///////////////////
785
//
786
// TYPE MANAGEMENT
787
//
788
///////////////////
789

790     //////////////////
791
//
792
// SCHEMA MINIONS
793
//
794
//////////////////
795

796     //
797
// Create all the tables needed by our test cases.
798
//
799
private void createSchema( Connection conn )
800         throws Exception JavaDoc
801     {
802         createTable( conn, ALL_TYPES_TABLE, ALL_TYPES );
803     }
804
805     //
806
// Create a table modelling an array of datatypes.
807
//
808
private void createTable( Connection conn, String JavaDoc tableName, TypeDescriptor[] types )
809         throws Exception JavaDoc
810     {
811         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
812         int columnNumber = 0;
813         int typeCount = types.length;
814
815         buffer.append( "create table " + tableName + "\n" );
816         beginColumnList( buffer );
817
818         addColumn( buffer, columnNumber++, doubleQuote( KEY_COLUMN ) + "\tint" );
819         
820         for ( int i = 0; i < typeCount; i++ )
821         {
822             TypeDescriptor type = types[ i ];
823             
824             if ( getServerVersion().atLeast( type.getDerbyVersion() ) )
825             {
826                 String JavaDoc typeName = type.getDerbyTypeName();
827                 String JavaDoc columnDesc = doubleQuote( typeName ) + '\t' + typeName;
828                 
829                 addColumn( buffer, columnNumber++, columnDesc );
830             }
831         }
832
833         endColumnList( buffer );
834
835         PreparedStatement ps = prepare( conn, buffer.toString() );
836
837         ps.execute();
838
839         close( ps );
840     }
841
842
843     //
844
// Helper methods for declaring a table.
845
//
846
private void beginColumnList( StringBuffer JavaDoc buffer )
847     {
848         buffer.append( "(\n" );
849     }
850     private void endColumnList( StringBuffer JavaDoc buffer )
851     {
852         buffer.append( "\n)\n" );
853     }
854     private void addColumn( StringBuffer JavaDoc buffer, int columnNumber, String JavaDoc text )
855     {
856         if ( columnNumber > 0 ) { buffer.append( "," ); }
857
858         buffer.append( "\n\t" );
859         buffer.append( text );
860     }
861     
862     //
863
// Drop the tables used by our test cases.
864
//
865
private void dropSchema( Connection conn )
866     {
867         dropTable( conn, ALL_TYPES_TABLE );
868     }
869
870     //
871
// Logic for stuffing a data value into a column, given its type.
872
//
873
private void setParameter( PreparedStatement ps, int param, TypeDescriptor type, Object JavaDoc value )
874         throws Exception JavaDoc
875     {
876         int jdbcType = type.getJdbcType();
877
878         if ( value != null )
879         {
880             setParameter( ps, param, jdbcType, value );
881             return;
882         }
883         else if ( clientSupports( type ) )
884         {
885             ps.setNull( param, jdbcType );
886
887             return;
888         }
889
890         // client does not support nulls of this type.
891

892         fail( "Unsupported Derby type: " + type.getDerbyTypeName() );
893     }
894
895     //
896
// Logic for verifying that a value was stuffed correctly.
897
//
898
private void checkParameter( ResultSet rs, int param, Object JavaDoc value )
899         throws Exception JavaDoc
900     {
901         Object JavaDoc actualValue;
902
903         if ( value == null )
904         {
905             return;
906         }
907
908         println( "Checking " + value.getClass().getName() );
909
910         if ( value instanceof Boolean JavaDoc ) { actualValue = new Boolean JavaDoc( rs.getBoolean( param ) ); }
911         else if ( value instanceof Byte JavaDoc ) { actualValue = new Byte JavaDoc( rs.getByte( param ) ); }
912         else if ( value instanceof Short JavaDoc ) { actualValue = new Short JavaDoc( rs.getShort( param ) ); }
913         else if ( value instanceof Integer JavaDoc ) { actualValue = new Integer JavaDoc( rs.getInt( param ) ); }
914         else if ( value instanceof Long JavaDoc ) { actualValue = new Long JavaDoc( rs.getLong( param ) ); }
915         else if ( value instanceof Float JavaDoc ) { actualValue = new Float JavaDoc( rs.getFloat( param ) ); }
916         else if ( value instanceof Double JavaDoc ) { actualValue = new Double JavaDoc( rs.getDouble( param ) ); }
917         else if ( value instanceof String JavaDoc ) { actualValue = rs.getString( param ); }
918         else if ( value instanceof BigDecimal ) { actualValue = rs.getBigDecimal( param ); }
919         else
920         {
921             actualValue = rs.getObject( param );
922         }
923
924         assertTrue( value.equals( actualValue ) );
925     }
926
927
928     // return true if the client supports this datatype
929
private boolean clientSupports( TypeDescriptor type )
930     {
931         Version firstSupportedVersion;
932
933         if ( usingDB2Client() ) { firstSupportedVersion = type.getDb2jccVersion(); }
934         else { firstSupportedVersion = type.getDerbyVersion(); }
935
936         if ( firstSupportedVersion == null ) { return false; }
937         else { return getDriverVersion().atLeast( firstSupportedVersion ); }
938     }
939     
940     //
941
// Get a data value from a column, given its type.
942
//
943
private Object JavaDoc getColumn( ResultSet rs, String JavaDoc columnName, TypeDescriptor type )
944         throws Exception JavaDoc
945     {
946         int jdbcType = type.getJdbcType();
947
948         return getColumn( rs, columnName, jdbcType );
949     }
950     //
951
// Get a data value from a procedure's output arg, given its type.
952
//
953
private Object JavaDoc getOutArg( CallableStatement cs, int arg, TypeDescriptor type )
954         throws Exception JavaDoc
955     {
956         int jdbcType = type.getJdbcType();
957
958         return getOutArg( cs, arg, jdbcType );
959     }
960     //
961
// SQL code generation minions
962
//
963
private String JavaDoc doubleQuote( String JavaDoc text )
964     {
965         return '"' + text + '"';
966     }
967
968     /////////////////////////////////////////////////////////////
969
//
970
// INNER CLASSES
971
//
972
/////////////////////////////////////////////////////////////
973

974     /**
975      * <p>
976      * This helper class describes a legal datatype and the version of Derby
977      * and db2jcc where the datatype first appears.
978      * </p>
979      */

980     public static final class TypeDescriptor
981     {
982         private int _jdbcType;
983         private String JavaDoc _derbyTypeName;
984         private Version _db2jccVersion; // first db2jcc version which supports this type
985
private Version _derbyVersion; // first derby version which supports this type
986
private Version _vmVersion; // first vm (jdbc) version which supports this type
987

988         public TypeDescriptor
989         (
990             int jdbcType,
991             String JavaDoc derbyTypeName,
992             Version db2jccVersion,
993             Version derbyVersion,
994             Version vmVersion
995         )
996         {
997             _jdbcType = jdbcType;
998             _derbyTypeName = derbyTypeName;
999             _db2jccVersion = db2jccVersion;
1000            _derbyVersion = derbyVersion;
1001            _vmVersion = vmVersion;
1002        }
1003
1004        public int getJdbcType() { return _jdbcType; }
1005        public String JavaDoc getDerbyTypeName() { return _derbyTypeName; }
1006        public Version getDb2jccVersion() { return _db2jccVersion; }
1007        public Version getDerbyVersion() { return _derbyVersion; }
1008        public Version getVMVersion() { return _vmVersion; }
1009    }
1010
1011    /**
1012     * <p>
1013     * This helper class captures TypeCoercion logic. I have abbreviated it to
1014     * this ugly class name so that the COERCIONS table will fit on a readable screen.
1015     * </p>
1016     */

1017    public static final class T_CN
1018    {
1019        private int _jdbcType;
1020        private boolean[] _coercions;
1021
1022        public T_CN( int jdbcType, boolean[] coercions )
1023        {
1024            _jdbcType = jdbcType;
1025            _coercions = coercions;
1026        }
1027
1028        public int getJdbcType() { return _jdbcType; }
1029        public boolean[] getCoercions() { return _coercions; }
1030    }
1031    
1032    /**
1033     * <p>
1034     * A crude Blob implementation for datatype testing.
1035     * </p>
1036     */

1037    public static final class MyBlob implements Blob
1038    {
1039        private byte[] _bytes;
1040
1041        public MyBlob( byte[] bytes )
1042        {
1043            _bytes = bytes;
1044        }
1045
1046        public InputStream getBinaryStream()
1047        {
1048            return new ByteArrayInputStream( _bytes );
1049        }
1050
1051        public byte[] getBytes( long position, int length ) { return _bytes; }
1052
1053        public long length() { return (long) _bytes.length; }
1054
1055        public long position( Blob pattern, long start ) { return 0L; }
1056        public long position( byte[] pattern, long start ) { return 0L; }
1057
1058        public boolean equals( Object JavaDoc other )
1059        {
1060            if ( other == null ) { return false; }
1061            if ( !( other instanceof Blob ) ) { return false; }
1062
1063            Blob that = (Blob) other;
1064
1065            try {
1066                if ( this.length() != that.length() ) { return false; }
1067
1068                InputStream thisStream = this.getBinaryStream();
1069                InputStream thatStream = that.getBinaryStream();
1070
1071                while( true )
1072                {
1073                    int nextByte = thisStream.read();
1074
1075                    if ( nextByte < 0 ) { break; }
1076                    if ( nextByte != thatStream.read() ) { return false; }
1077                }
1078            }
1079            catch (Exception JavaDoc e)
1080            {
1081                System.err.println( e.getMessage() );
1082                e.printStackTrace();
1083                return false;
1084            }
1085
1086            return true;
1087        }
1088
1089    }
1090
1091    /**
1092     * <p>
1093     * A crude Clob implementation for datatype testing.
1094     * </p>
1095     */

1096    public static final class MyClob implements Clob
1097    {
1098        private String JavaDoc _contents;
1099
1100        public MyClob( String JavaDoc contents )
1101        {
1102            _contents = contents;
1103        }
1104
1105        public InputStream getAsciiStream()
1106        {
1107            try {
1108                return new ByteArrayInputStream( _contents.getBytes( "UTF-8" ) );
1109            }
1110            catch (Exception JavaDoc e) { return null; }
1111        }
1112
1113        public Reader getCharacterStream()
1114        {
1115            return new CharArrayReader( _contents.toCharArray() );
1116        }
1117
1118        public String JavaDoc getSubString( long position, int length )
1119        {
1120            return _contents.substring( (int) position, length );
1121        }
1122        
1123        public long length() { return (long) _contents.length(); }
1124
1125        public long position( Clob searchstr, long start ) { return 0L; }
1126        public long position( String JavaDoc searchstr, long start ) { return 0L; }
1127
1128        public boolean equals( Object JavaDoc other )
1129        {
1130            if ( other == null ) { return false; }
1131            if ( !( other instanceof Clob ) ) { return false; }
1132
1133            Clob that = (Clob) other;
1134
1135            try {
1136                if ( this.length() != that.length() ) { return false; }
1137            
1138                InputStream thisStream = this.getAsciiStream();
1139                InputStream thatStream = that.getAsciiStream();
1140
1141                while( true )
1142                {
1143                    int nextByte = thisStream.read();
1144
1145                    if ( nextByte < 0 ) { break; }
1146                    if ( nextByte != thatStream.read() ) { return false; }
1147                }
1148            }
1149            catch (Exception JavaDoc e)
1150            {
1151                System.err.println( e.getMessage() );
1152                e.printStackTrace();
1153                return false;
1154            }
1155
1156            return true;
1157        }
1158
1159    }
1160
1161}
1162
Popular Tags