KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > databaseaccess > DatabasePlatform


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.databaseaccess;
23
24 import java.sql.*;
25 import java.util.*;
26 import java.math.*;
27 import java.io.*;
28 import oracle.toplink.essentials.exceptions.*;
29 import oracle.toplink.essentials.queryframework.*;
30 import oracle.toplink.essentials.internal.helper.*;
31 import oracle.toplink.essentials.sessions.SessionProfiler;
32 import oracle.toplink.essentials.sequencing.*;
33 import oracle.toplink.essentials.internal.sequencing.Sequencing;
34 import oracle.toplink.essentials.internal.sessions.AbstractSession;
35 import oracle.toplink.essentials.internal.expressions.ParameterExpression;
36 import oracle.toplink.essentials.descriptors.ClassDescriptor;
37 import oracle.toplink.essentials.tools.schemaframework.TableDefinition;
38 import oracle.toplink.essentials.tools.schemaframework.FieldDefinition;
39
40 /**
41  * DatabasePlatform is private to TopLink. It encapsulates behavior specific to a database platform
42  * (eg. Oracle, Sybase, DBase), and provides protocol for TopLink to access this behavior. The behavior categories
43  * which require platform specific handling are SQL generation and sequence behavior. While database platform
44  * currently provides sequence number retrieval behaviour, this will move to a sequence manager (when it is
45  * implemented).
46  *
47  * @see AccessPlatform
48  * @see DB2Platform
49  * @see DBasePlatform
50  * @see OraclePlatform
51  * @see SybasePlatform
52  *
53  * @since TOPLink/Java 1.0
54  */

55 public class DatabasePlatform extends DatasourcePlatform {
56
57     /** Holds a hashtable of values used to map JAVA types to database types for table creation */
58     protected transient Hashtable fieldTypes;
59
60     /** Indicates that native SQL should be used for literal values instead of ODBC esacpe format
61     Only used with Oracle, Sybase & DB2 */

62     protected boolean usesNativeSQL;
63
64     /** Indicates that binding will be used for BLOB data. NOTE: does not work well with ODBC. */
65     protected boolean usesByteArrayBinding;
66
67     /** Bind all arguments to any SQL statement. */
68     protected boolean shouldBindAllParameters;
69
70     /** Cache all prepared statements, this requires full parameter binding as well. */
71     protected boolean shouldCacheAllStatements;
72
73     /** The statement cache size for prepare parameterized statements. */
74     protected int statementCacheSize;
75
76     /** Can be used if the app expects upper case but the database is not return consistent case, i.e. different databases. */
77     protected boolean shouldForceFieldNamesToUpperCase;
78
79     /** Indicates (if true) to remove blanks characters from the right of CHAR strings. */
80     protected boolean shouldTrimStrings;
81
82     /** Indicates that streams will be used to store BLOB data. NOTE: does not work with ODBC */
83     protected boolean usesStreamsForBinding;
84
85     /** Indicates the size above which strings will be bound NOTE: does not work with ODBC */
86     protected int stringBindingSize;
87
88     /** Indicates that strings will above the stringBindingSize will be bound NOTE: does not work with ODBC */
89     protected boolean usesStringBinding;
90
91     /** Allow for the code that is used for preparing cursored outs for a storedprocedure to be settable. **/
92     protected int cursorCode;
93
94     /** The transaction isolation level to be set on the connection (optional). */
95     protected int transactionIsolation;
96
97     /** Some JDBC drivers do not support AutoCommit in the way TopLink expects. (e.g. Attunity Connect, JConnect) */
98     protected boolean supportsAutoCommit;
99
100     /**
101      * Allow for driver level data conversion optimization to be disabled,
102      * required because some drivers can loose precision.
103      */

104     protected boolean shouldOptimizeDataConversion;
105
106     /** Stores mapping of class types to database types for schema creation. */
107     protected transient Hashtable classTypes;
108
109     /** Allow for case in field names to be ignored as some databases are not case sensitive and when using custom this can be an issue. */
110     protected static boolean shouldIgnoreCaseOnFieldComparisons = false;
111
112     public DatabasePlatform() {
113         this.tableQualifier = "";
114         this.usesNativeSQL = false;
115         this.usesByteArrayBinding = true;
116         this.usesStringBinding = false;
117         this.stringBindingSize = 255;
118         this.shouldTrimStrings = true;
119         this.shouldBindAllParameters = false;
120         this.shouldCacheAllStatements = false;
121         this.shouldOptimizeDataConversion = true;
122         this.statementCacheSize = 50;
123         this.shouldForceFieldNamesToUpperCase = false;
124         this.transactionIsolation = -1;
125         this.cursorCode = -10;
126         this.supportsAutoCommit = true;
127     }
128
129     /**
130      * Used for sp defs.
131      */

132     public boolean allowsSizeInProcedureArguments() {
133         return true;
134     }
135
136     /**
137      * Appends a Boolean value as a number
138      */

139     protected void appendBoolean(Boolean JavaDoc bool, Writer writer) throws IOException {
140         if (bool.booleanValue()) {
141             writer.write("1");
142         } else {
143             writer.write("0");
144         }
145     }
146
147     /**
148      * Append the ByteArray in ODBC literal format ({b hexString}).
149      * This limits the amount of Binary data by the length of the SQL. Binding should increase this limit.
150      */

151     protected void appendByteArray(byte[] bytes, Writer writer) throws IOException {
152         writer.write("{b '");
153         Helper.writeHexString(bytes, writer);
154         writer.write("'}");
155     }
156
157     /**
158      * Answer a platform correct string representation of a Date, suitable for SQL generation.
159      * The date is printed in the ODBC platform independent format {d 'yyyy-mm-dd'}.
160      */

161     protected void appendDate(java.sql.Date JavaDoc date, Writer writer) throws IOException {
162         writer.write("{d '");
163         writer.write(Helper.printDate(date));
164         writer.write("'}");
165     }
166
167     /**
168      * Write number to SQL string. This is provided so that database which do not support
169      * Exponential format can customize their printing.
170      */

171     protected void appendNumber(Number JavaDoc number, Writer writer) throws IOException {
172         writer.write(number.toString());
173     }
174
175     /**
176      * INTERNAL
177      * Allows platform to override adding a literal to a call.
178      */

179     public void appendLiteralToCall(Call call, Writer writer, Object JavaDoc literal) {
180         ((DatabaseCall)call).appendLiteral(writer, literal);
181     }
182     
183     /**
184      * Write a database-friendly representation of the given parameter to the writer.
185      * Determine the class of the object to be written, and invoke the appropriate print method
186      * for that object. The default is "toString".
187      * The platform may decide to bind some types, such as byte arrays and large strings.
188      * Should only be called in case binding is not used.
189      */

190     public void appendParameter(Call call, Writer writer, Object JavaDoc parameter) {
191         appendParameterInternal(call, writer, parameter);
192     }
193     
194     /**
195      * Returns the number of parameters that used binding.
196      * Should only be called in case binding is not used.
197      */

198     public int appendParameterInternal(Call call, Writer writer, Object JavaDoc parameter) {
199         int nBoundParameters = 0;
200         DatabaseCall databaseCall = (DatabaseCall)call;
201         try {
202             // PERF: Print Calendars directly avoiding timestamp conversion,
203
// Must be before conversion as you cannot bind calendars.
204
if (parameter instanceof Calendar) {
205                 appendCalendar((Calendar)parameter, writer);
206                 return nBoundParameters;
207             }
208             Object JavaDoc dbValue = convertToDatabaseType(parameter);
209
210             if (dbValue instanceof String JavaDoc) {// String and number first as they are most common.
211
if (usesStringBinding() && (((String JavaDoc)dbValue).length() >= getStringBindingSize())) {
212                     databaseCall.bindParameter(writer, dbValue);
213                     nBoundParameters = 1;
214                 } else {
215                     appendString((String JavaDoc)dbValue, writer);
216                 }
217             } else if (dbValue instanceof Number JavaDoc) {
218                 appendNumber((Number JavaDoc)dbValue, writer);
219             } else if (dbValue instanceof java.sql.Time JavaDoc) {
220                 appendTime((java.sql.Time JavaDoc)dbValue, writer);
221             } else if (dbValue instanceof java.sql.Timestamp JavaDoc) {
222                 appendTimestamp((java.sql.Timestamp JavaDoc)dbValue, writer);
223             } else if (dbValue instanceof java.sql.Date JavaDoc) {
224                 appendDate((java.sql.Date JavaDoc)dbValue, writer);
225             } else if (dbValue == null) {
226                 writer.write("NULL");
227             } else if (dbValue instanceof Boolean JavaDoc) {
228                 appendBoolean((Boolean JavaDoc)dbValue, writer);
229             } else if (dbValue instanceof byte[]) {
230                 if (usesByteArrayBinding()) {
231                     databaseCall.bindParameter(writer, dbValue);
232                     nBoundParameters = 1;
233                 } else {
234                     appendByteArray((byte[])dbValue, writer);
235                 }
236             } else if (dbValue instanceof Vector) {
237                 nBoundParameters = printValuelist((Vector)dbValue, databaseCall, writer);
238             } else if ((parameter instanceof Struct) || (parameter instanceof Array) || (parameter instanceof Ref)) {
239                 databaseCall.bindParameter(writer, parameter);
240                 nBoundParameters = 1;
241             } else if (oracle.toplink.essentials.internal.helper.Helper.isCollection(dbValue)) {
242                 nBoundParameters = printValuelist(Helper.makeVectorFromObject(dbValue), databaseCall, writer);
243             } else if (dbValue.getClass() == int[].class) {
244                 nBoundParameters = printValuelist((int[])dbValue, databaseCall, writer);
245             } else if (dbValue instanceof AppendCallCustomParameter) {
246                 // custom append is required (example BLOB, CLOB on Oracle8)
247
((AppendCallCustomParameter)dbValue).append(writer);
248                 nBoundParameters = 1;
249             } else if (dbValue instanceof BindCallCustomParameter) {
250                 // custom binding is required, object to be bound is wrapped (example NCHAR, NVARCHAR2, NCLOB on Oracle9)
251
databaseCall.bindParameter(writer, dbValue);
252                 nBoundParameters = 1;
253             } else if ((dbValue instanceof Struct) || (dbValue instanceof Array) || (dbValue instanceof Ref)) {
254                 databaseCall.bindParameter(writer, dbValue);
255                 nBoundParameters = 1;
256             } else {
257                 // Assume database driver primitive that knows how to print itself, this is required for drivers
258
// such as Oracle JDBC, Informix JDBC and others, as well as client specific classes.
259
writer.write(dbValue.toString());
260             }
261         } catch (IOException exception) {
262             throw ValidationException.fileError(exception);
263         }
264         
265         return nBoundParameters;
266     }
267
268     /**
269      * Write the string. Quotes must be double quoted.
270      */

271     protected void appendString(String JavaDoc string, Writer writer) throws IOException {
272         writer.write('\'');
273         for (int position = 0; position < string.length(); position++) {
274             if (string.charAt(position) == '\'') {
275                 writer.write("''");
276             } else {
277                 writer.write(string.charAt(position));
278             }
279         }
280         writer.write('\'');
281     }
282
283     /**
284      * Answer a platform correct string representation of a Time, suitable for SQL generation.
285      * The time is printed in the ODBC platform independent format {t'hh:mm:ss'}.
286      */

287     protected void appendTime(java.sql.Time JavaDoc time, Writer writer) throws IOException {
288         writer.write("{t '");
289         writer.write(Helper.printTime(time));
290         writer.write("'}");
291     }
292
293     /**
294      * Answer a platform correct string representation of a Timestamp, suitable for SQL generation.
295      * The timestamp is printed in the ODBC platform independent timestamp format {ts'YYYY-MM-DD HH:MM:SS.NNNNNNNNN'}.
296      */

297     protected void appendTimestamp(java.sql.Timestamp JavaDoc timestamp, Writer writer) throws IOException {
298         writer.write("{ts '");
299         writer.write(Helper.printTimestamp(timestamp));
300         writer.write("'}");
301     }
302
303     /**
304      * Answer a platform correct string representation of a Calendar as a Timestamp, suitable for SQL generation.
305      * The calendar is printed in the ODBC platform independent timestamp format {ts'YYYY-MM-DD HH:MM:SS.NNNNNNNNN'}.
306      */

307     protected void appendCalendar(Calendar calendar, Writer writer) throws IOException {
308         writer.write("{ts '");
309         writer.write(Helper.printCalendar(calendar));
310         writer.write("'}");
311     }
312
313     /**
314      * Used by JDBC drivers that do not support autocommit so simulate an autocommit.
315      */

316     public void autoCommit(DatabaseAccessor accessor) throws SQLException {
317         if (!supportsAutoCommit()) {
318             accessor.getConnection().commit();
319         }
320     }
321
322     /**
323      * Used for jdbc drivers which do not support autocommit to explicitly begin a transaction
324      * This method is a no-op for databases which implement autocommit as expected.
325      */

326     public void beginTransaction(DatabaseAccessor accessor) throws SQLException {
327         if (!supportsAutoCommit()) {
328             Statement statement = accessor.getConnection().createStatement();
329             try {
330                 statement.executeUpdate("BEGIN TRANSACTION");
331             } finally {
332                 statement.close();
333             }
334         }
335     }
336
337     /**
338      * INTERNAL
339      * Returns null unless the platform supports call with returning
340      */

341     public DatabaseCall buildCallWithReturning(SQLCall sqlCall, Vector returnFields) {
342         throw ValidationException.platformDoesNotSupportCallWithReturning(Helper.getShortClassName(this));
343     }
344
345     /**
346      * Return the mapping of class types to database types for the schema framework.
347      */

348     protected Hashtable buildClassTypes() {
349         Hashtable classTypeMapping;
350
351         classTypeMapping = new Hashtable();
352         //Key the dictionary the other way for table creation
353
classTypeMapping.put("NUMBER", java.math.BigInteger JavaDoc.class);
354         classTypeMapping.put("DECIMAL", java.math.BigDecimal JavaDoc.class);
355         classTypeMapping.put("INTEGER", Integer JavaDoc.class);
356         classTypeMapping.put("INT", Integer JavaDoc.class);
357         classTypeMapping.put("NUMERIC", Long JavaDoc.class);
358         classTypeMapping.put("FLOAT(16)", Float JavaDoc.class);
359         classTypeMapping.put("FLOAT(32)", Double JavaDoc.class);
360         classTypeMapping.put("NUMBER(1) default 0", Boolean JavaDoc.class);
361         classTypeMapping.put("SHORT", Short JavaDoc.class);
362         classTypeMapping.put("BYTE", Byte JavaDoc.class);
363         classTypeMapping.put("DOUBLE", Double JavaDoc.class);
364         classTypeMapping.put("FLOAT", Float JavaDoc.class);
365         classTypeMapping.put("SMALLINT", Short JavaDoc.class);
366
367         classTypeMapping.put("BIT", Boolean JavaDoc.class);
368         classTypeMapping.put("SMALLINT DEFAULT 0", Boolean JavaDoc.class);
369
370         classTypeMapping.put("VARCHAR", String JavaDoc.class);
371         classTypeMapping.put("CHAR", Character JavaDoc.class);
372         classTypeMapping.put("LONGVARBINARY", Byte JavaDoc[].class);
373         classTypeMapping.put("TEXT", Character JavaDoc[].class);
374         classTypeMapping.put("LONGTEXT", Character JavaDoc[].class);
375         // classTypeMapping.put("BINARY", Byte[].class);
376
classTypeMapping.put("MEMO", Character JavaDoc[].class);
377         classTypeMapping.put("VARCHAR2", String JavaDoc.class);
378         classTypeMapping.put("LONG RAW", Byte JavaDoc[].class);
379         classTypeMapping.put("LONG", Character JavaDoc[].class);
380
381         classTypeMapping.put("DATE", java.sql.Date JavaDoc.class);
382         classTypeMapping.put("TIMESTAMP", java.sql.Timestamp JavaDoc.class);
383         classTypeMapping.put("TIME", java.sql.Time JavaDoc.class);
384         classTypeMapping.put("DATETIME", java.sql.Timestamp JavaDoc.class);
385
386         classTypeMapping.put("BIGINT", java.math.BigInteger JavaDoc.class);
387         classTypeMapping.put("DOUBLE PRECIS", Double JavaDoc.class);
388         classTypeMapping.put("IMAGE", Byte JavaDoc[].class);
389         classTypeMapping.put("LONGVARCHAR", Character JavaDoc[].class);
390         classTypeMapping.put("REAL", Float JavaDoc.class);
391         classTypeMapping.put("TINYINT", Short JavaDoc.class);
392         // classTypeMapping.put("VARBINARY", Byte[].class);
393

394         classTypeMapping.put("BLOB", Byte JavaDoc[].class);
395         classTypeMapping.put("CLOB", Character JavaDoc[].class);
396
397         return classTypeMapping;
398     }
399
400     /**
401      * Return the mapping of class types to database types for the schema framework.
402      */

403     protected Hashtable buildFieldTypes() {
404         Hashtable fieldTypeMapping;
405
406         fieldTypeMapping = new Hashtable();
407         fieldTypeMapping.put(Boolean JavaDoc.class, new FieldTypeDefinition("NUMBER", 1));
408
409         fieldTypeMapping.put(Integer JavaDoc.class, new FieldTypeDefinition("NUMBER", 10));
410         fieldTypeMapping.put(Long JavaDoc.class, new FieldTypeDefinition("NUMBER", 19));
411         fieldTypeMapping.put(Float JavaDoc.class, new FieldTypeDefinition("NUMBER", 12, 5).setLimits(19, 0, 19));
412         fieldTypeMapping.put(Double JavaDoc.class, new FieldTypeDefinition("NUMBER", 10, 5).setLimits(19, 0, 19));
413         fieldTypeMapping.put(Short JavaDoc.class, new FieldTypeDefinition("NUMBER", 5));
414         fieldTypeMapping.put(Byte JavaDoc.class, new FieldTypeDefinition("NUMBER", 3));
415         fieldTypeMapping.put(java.math.BigInteger JavaDoc.class, new FieldTypeDefinition("NUMBER", 19));
416         fieldTypeMapping.put(java.math.BigDecimal JavaDoc.class, new FieldTypeDefinition("NUMBER", 19, 0).setLimits(19, 0, 19));
417
418         fieldTypeMapping.put(String JavaDoc.class, new FieldTypeDefinition("VARCHAR"));
419         fieldTypeMapping.put(Character JavaDoc.class, new FieldTypeDefinition("CHAR"));
420
421         fieldTypeMapping.put(Byte JavaDoc[].class, new FieldTypeDefinition("BLOB"));
422         fieldTypeMapping.put(Character JavaDoc[].class, new FieldTypeDefinition("CLOB"));
423         fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("BLOB"));
424         fieldTypeMapping.put(char[].class, new FieldTypeDefinition("CLOB"));
425         fieldTypeMapping.put(java.sql.Blob JavaDoc.class, new FieldTypeDefinition("BLOB"));
426         fieldTypeMapping.put(java.sql.Clob JavaDoc.class, new FieldTypeDefinition("CLOB"));
427         
428         fieldTypeMapping.put(java.sql.Date JavaDoc.class, new FieldTypeDefinition("DATE"));
429         fieldTypeMapping.put(java.sql.Timestamp JavaDoc.class, new FieldTypeDefinition("TIMESTAMP"));
430         fieldTypeMapping.put(java.sql.Time JavaDoc.class, new FieldTypeDefinition("TIME"));
431
432         return fieldTypeMapping;
433     }
434
435     /**
436      * INTERNAL
437      * Indicates whether the platform can build call with returning.
438      * In case this method returns true, buildCallWithReturning method
439      * may be called.
440      */

441     public boolean canBuildCallWithReturning() {
442         return false;
443     }
444
445     /**
446      * Used for jdbc drivers which do not support autocommit to explicitly commit a transaction
447      * This method is a no-op for databases which implement autocommit as expected.
448      */

449     public void commitTransaction(DatabaseAccessor accessor) throws SQLException {
450         if (!supportsAutoCommit()) {
451             accessor.getConnection().commit();
452         }
453     }
454
455     /**
456      * INTERNAL
457      * We support more primitive than JDBC does so we must do conversion before printing or binding.
458      * 2.0p22: protected->public INTERNAL
459      */

460     public Object JavaDoc convertToDatabaseType(Object JavaDoc value) {
461         if (value == null) {
462             return null;
463         }
464         if (value.getClass() == ClassConstants.UTILDATE) {
465             return Helper.timestampFromDate((java.util.Date JavaDoc)value);
466         } else if (value instanceof Character JavaDoc) {
467             return ((Character JavaDoc)value).toString();
468         } else if (value instanceof Calendar) {
469             return Helper.timestampFromDate(((Calendar)value).getTime());
470         } else if (value instanceof BigInteger) {
471             return new BigDecimal((BigInteger)value);
472         } else if (value instanceof char[]) {
473             return new String JavaDoc((char[])value);
474         } else if (value instanceof Character JavaDoc[]) {
475             return convertObject(value, ClassConstants.STRING);
476         } else if (value instanceof Byte JavaDoc[]) {
477             return convertObject(value, ClassConstants.APBYTE);
478         }
479         return value;
480     }
481
482     /**
483      * Copy the state into the new platform.
484      */

485     public void copyInto(Platform platform) {
486         super.copyInto(platform);
487         if (!(platform instanceof DatabasePlatform)) {
488             return;
489         }
490         DatabasePlatform databasePlatform = (DatabasePlatform)platform;
491         databasePlatform.setShouldTrimStrings(shouldTrimStrings());
492         databasePlatform.setUsesNativeSQL(usesNativeSQL());
493         databasePlatform.setUsesByteArrayBinding(usesByteArrayBinding());
494         databasePlatform.setUsesStringBinding(usesStringBinding());
495         databasePlatform.setShouldBindAllParameters(shouldBindAllParameters());
496         databasePlatform.setShouldCacheAllStatements(shouldCacheAllStatements());
497         databasePlatform.setStatementCacheSize(getStatementCacheSize());
498         databasePlatform.setTransactionIsolation(getTransactionIsolation());
499         databasePlatform.setShouldForceFieldNamesToUpperCase(shouldForceFieldNamesToUpperCase());
500         databasePlatform.setShouldOptimizeDataConversion(shouldOptimizeDataConversion());
501         databasePlatform.setStringBindingSize(getStringBindingSize());
502         databasePlatform.setUsesStreamsForBinding(usesStreamsForBinding());
503     }
504
505     /**
506      * Used for batch writing and sp defs.
507      */

508     public String JavaDoc getBatchBeginString() {
509         return "";
510     }
511
512     /**
513      * Used for batch writing and sp defs.
514      */

515     public String JavaDoc getBatchDelimiterString() {
516         return "; ";
517     }
518
519     /**
520      * Used for batch writing and sp defs.
521      */

522     public String JavaDoc getBatchEndString() {
523         return "";
524     }
525     
526     /**
527      * Used for constraint deletion.
528      */

529     public String JavaDoc getConstraintDeletionString() {
530         return " DROP CONSTRAINT ";
531     }
532     
533     /**
534      * Used for view creation.
535      */

536     public String JavaDoc getCreateViewString() {
537         return "CREATE VIEW ";
538     }
539     
540     /**
541      * Used for stored procedure defs.
542      */

543     public String JavaDoc getProcedureEndString() {
544         return getBatchEndString();
545     }
546     
547     /**
548      * Used for stored procedure defs.
549      */

550     public String JavaDoc getProcedureBeginString() {
551         return getBatchBeginString();
552     }
553     
554     /**
555      * Used for stored procedure defs.
556      */

557     public String JavaDoc getProcedureAsString() {
558         return " AS";
559     }
560
561     /**
562      * Return the class type to database type mapping for the schema framework.
563      */

564     public Hashtable getClassTypes() {
565         if (classTypes == null) {
566             classTypes = buildClassTypes();
567         }
568         return classTypes;
569     }
570
571     /**
572      * Used for stored function calls.
573      */

574     public String JavaDoc getAssignmentString() {
575         return "= ";
576     }
577
578     /**
579      * This method is used to print the required output parameter token for the
580      * specific platform. Used when stored procedures are created.
581      */

582     public String JavaDoc getCreationInOutputProcedureToken() {
583         return getInOutputProcedureToken();
584     }
585
586     /**
587      * This method is used to print the required output parameter token for the
588      * specific platform. Used when stored procedures are created.
589      */

590     public String JavaDoc getCreationOutputProcedureToken() {
591         return getOutputProcedureToken();
592     }
593
594     /**
595      * ADVANCED:
596      * Return the code for preparing cursored output
597      * parameters in a stored procedure
598      */

599     public int getCursorCode() {
600         return cursorCode;
601     }
602
603     /**
604      * Return the field type object describing this databases platform specific representation
605      * of the Java primitive class name.
606      */

607     public FieldTypeDefinition getFieldTypeDefinition(Class JavaDoc javaClass) {
608         return (FieldTypeDefinition)getFieldTypes().get(javaClass);
609     }
610
611     /**
612      * Return the class type to database type mappings for the schema framework.
613      */

614     public Hashtable getFieldTypes() {
615         if (fieldTypes == null) {
616             fieldTypes = buildFieldTypes();
617         }
618         return fieldTypes;
619     }
620
621     /**
622      * Used for stored function calls.
623      */

624     public String JavaDoc getFunctionCallHeader() {
625         return getProcedureCallHeader() + "? " + getAssignmentString();
626     }
627
628     /**
629      * This method is used to print the output parameter token when stored
630      * procedures are called
631      */

632     public String JavaDoc getInOutputProcedureToken() {
633         return "IN OUT";
634     }
635
636     /**
637      * Returns the JDBC outer join operator for SELECT statements.
638      */

639     public String JavaDoc getJDBCOuterJoinString() {
640         return "{oj ";
641     }
642
643     /**
644      * Return the JDBC type for the given database field.
645      */

646     public int getJDBCType(DatabaseField field) {
647         if (field != null) {
648             // If the field has a specified JDBC type, use it,
649
// otherwise compute the type from the Java class type.
650
if (field.getSqlType() != -1) {
651                 return field.getSqlType();
652             } else {
653                 return getJDBCType(ConversionManager.getObjectClass(field.getType()));
654             }
655         } else {
656             return getJDBCType((Class JavaDoc)null);
657         }
658     }
659
660     /**
661      * Return the JDBC type for the Java type.
662      */

663     public int getJDBCType(Class JavaDoc javaType) {
664         if (javaType == null) {
665             return Types.VARCHAR;// Best guess, sometimes we cannot determine type from mapping, this may fail on some drivers, other dont care what type it is.
666
} else if (javaType == ClassConstants.STRING) {
667             return Types.VARCHAR;
668         } else if (javaType == ClassConstants.BIGDECIMAL) {
669             return Types.DECIMAL;
670         } else if (javaType == ClassConstants.BIGINTEGER) {
671             return Types.BIGINT;
672         } else if (javaType == ClassConstants.BOOLEAN) {
673             return Types.BIT;
674         } else if (javaType == ClassConstants.BYTE) {
675             return Types.TINYINT;
676         } else if (javaType == ClassConstants.CHAR) {
677             return Types.CHAR;
678         } else if (javaType == ClassConstants.DOUBLE) {
679             return Types.DOUBLE;
680         } else if (javaType == ClassConstants.FLOAT) {
681             return Types.FLOAT;
682         } else if (javaType == ClassConstants.INTEGER) {
683             return Types.INTEGER;
684         } else if (javaType == ClassConstants.LONG) {
685             return Types.INTEGER;
686         } else if (javaType == ClassConstants.NUMBER) {
687             return Types.DECIMAL;
688         } else if (javaType == ClassConstants.SHORT ) {
689             return Types.SMALLINT;
690         } else if (javaType == ClassConstants.CALENDAR ) {
691             return Types.TIMESTAMP;
692         } else if (javaType == ClassConstants.UTILDATE ) {
693             return Types.TIMESTAMP;
694         } else if (javaType == ClassConstants.TIME) {
695             return Types.TIME;
696         } else if (javaType == ClassConstants.SQLDATE) {
697             return Types.DATE;
698         } else if (javaType == ClassConstants.TIMESTAMP) {
699             return Types.TIMESTAMP;
700         } else if (javaType == ClassConstants.ABYTE) {
701             return Types.LONGVARBINARY;
702         } else if (javaType == ClassConstants.APBYTE) {
703             return Types.LONGVARBINARY;
704         } else if (javaType == ClassConstants.BLOB) {
705             return Types.BLOB;
706         } else if (javaType == ClassConstants.ACHAR) {
707             return Types.LONGVARCHAR;
708         } else if (javaType == ClassConstants.APCHAR) {
709             return Types.LONGVARCHAR;
710         } else if (javaType == ClassConstants.CLOB) {
711             return Types.CLOB;
712         } else {
713             return Types.VARCHAR;// Best guess, sometimes we cannot determine type from mapping, this may fail on some drivers, other dont care what type it is.
714
}
715     }
716
717     /**
718      * INTERNAL:
719      * Returns the type name corresponding to the jdbc type
720      */

721     public String JavaDoc getJdbcTypeName(int jdbcType) {
722         return null;
723     }
724
725     /**
726      * INTERNAL:
727      * returns the maximum number of characters that can be used in a field
728      * name on this platform.
729      */

730     public int getMaxFieldNameSize() {
731         return 50;
732     }
733
734     /**
735      * INTERNAL:
736      * returns the maximum number of characters that can be used in a foreign key
737      * name on this platform.
738      */

739     public int getMaxForeignKeyNameSize() {
740         return getMaxFieldNameSize();
741     }
742
743     /**
744      * INTERNAL:
745      * returns the maximum number of characters that can be used in a unique key
746      * name on this platform.
747      */

748     public int getMaxUniqueKeyNameSize() {
749         return getMaxFieldNameSize();
750     }
751
752     /**
753      * INTERNAL:
754      * Get the object from the JDBC Result set. Added to allow other platforms to
755      * override.
756      * @see oracle.toplink.essentials.oraclespecific.Oracle9Platform
757      */

758     public Object JavaDoc getObjectFromResultSet(ResultSet resultSet, int columnNumber, int type) throws java.sql.SQLException JavaDoc {
759         return resultSet.getObject(columnNumber);
760     }
761
762     /**
763      * This method is used to print the output parameter token when stored
764      * procedures are called
765      */

766     public String JavaDoc getOutputProcedureToken() {
767         return "OUT";
768     }
769
770     /**
771      * Used for sp calls.
772      */

773     public String JavaDoc getProcedureArgumentSetter() {
774         return " = ";
775     }
776
777     /**
778      * Used for sp defs.
779      */

780     public String JavaDoc getProcedureArgumentString() {
781         return "";
782     }
783
784     /**
785      * Used for sp calls.
786      */

787     public String JavaDoc getProcedureCallHeader() {
788         return "EXECUTE PROCEDURE ";
789     }
790
791     /**
792      * Used for sp calls.
793      */

794     public String JavaDoc getProcedureCallTail() {
795         return "";
796     }
797
798     public String JavaDoc getQualifiedSequenceTableName() {
799         if (getDefaultSequence() instanceof TableSequence) {
800             String JavaDoc sequenceTableName = ((TableSequence)getDefaultSequence()).getTableName();
801             if (getTableQualifier().equals("")) {
802                 return sequenceTableName;
803             } else {
804                 return getTableQualifier() + "." + sequenceTableName;
805             }
806         } else {
807             throw ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "getTableName");
808         }
809     }
810
811     /**
812      * This syntax does no wait on the lock.
813      * (i.e. In Oracle adding NOWAIT to the end will accomplish this)
814      */

815     public String JavaDoc getSelectForUpdateNoWaitString() {
816         return " NOWAIT";
817     }
818
819     /**
820      * For fine-grained pessimistic locking the column names can be
821      * specified individually.
822      */

823     public String JavaDoc getSelectForUpdateOfString() {
824         return " FOR UPDATE OF ";
825     }
826
827     /**
828      * Most database support a syntax. although don't actually lock the row.
829      * Some require the OF some don't like it.
830      */

831     public String JavaDoc getSelectForUpdateString() {
832         return " FOR UPDATE OF *";
833     }
834
835     public String JavaDoc getSequenceCounterFieldName() {
836         if (getDefaultSequence() instanceof TableSequence) {
837             return ((TableSequence)getDefaultSequence()).getCounterFieldName();
838         } else {
839             throw ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "getCounterFieldName");
840         }
841     }
842
843     public String JavaDoc getSequenceNameFieldName() {
844         if (getDefaultSequence() instanceof TableSequence) {
845             return ((TableSequence)getDefaultSequence()).getNameFieldName();
846         } else {
847             throw ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "getNameFieldName");
848         }
849     }
850
851     public int getSequencePreallocationSize() {
852         return getDefaultSequence().getPreallocationSize();
853     }
854
855     public String JavaDoc getSequenceTableName() {
856         if (getDefaultSequence() instanceof TableSequence) {
857             return ((TableSequence)getDefaultSequence()).getTableName();
858         } else {
859             throw ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "getTableName");
860         }
861     }
862
863     /**
864      * The statement cache size for prepare parameterized statements.
865      */

866     public int getStatementCacheSize() {
867         return statementCacheSize;
868     }
869
870     public String JavaDoc getStoredProcedureParameterPrefix() {
871         return "";
872     }
873
874     public String JavaDoc getStoredProcedureTerminationToken() {
875         return ";";
876     }
877
878     public int getStringBindingSize() {
879         return stringBindingSize;
880     }
881
882     /**
883      * Returns the transaction isolation setting for a connection.
884      * Return -1 if it has not been set.
885      */

886     public int getTransactionIsolation() {
887         return transactionIsolation;
888     }
889
890     /**
891      * Some database require outer joins to be given in the where clause, others require it in the from clause.
892      * Informix requires it in the from clause with no ON expression.
893      */

894     public boolean isInformixOuterJoin() {
895         return false;
896     }
897
898     /**
899      * Builds a table of maximum numeric values keyed on java class. This is used for type testing but
900      * might also be useful to end users attempting to sanitize values.
901      * <p><b>NOTE</b>: BigInteger & BigDecimal maximums are dependent upon their precision & Scale
902      */

903     public Hashtable maximumNumericValues() {
904         Hashtable values = new Hashtable();
905
906         values.put(Integer JavaDoc.class, new Integer JavaDoc(Integer.MAX_VALUE));
907         values.put(Long JavaDoc.class, new Long JavaDoc(Long.MAX_VALUE));
908         values.put(Double JavaDoc.class, new Double JavaDoc(Double.MAX_VALUE));
909         values.put(Short JavaDoc.class, new Short JavaDoc(Short.MAX_VALUE));
910         values.put(Byte JavaDoc.class, new Byte JavaDoc(Byte.MAX_VALUE));
911         values.put(Float JavaDoc.class, new Float JavaDoc(Float.MAX_VALUE));
912         values.put(java.math.BigInteger JavaDoc.class, new java.math.BigInteger JavaDoc("999999999999999999999999999999999999999"));
913         values.put(java.math.BigDecimal JavaDoc.class, new java.math.BigDecimal JavaDoc("99999999999999999999.9999999999999999999"));
914         return values;
915     }
916
917     /**
918      * Builds a table of minimum numeric values keyed on java class. This is used for type testing but
919      * might also be useful to end users attempting to sanitize values.
920      * <p><b>NOTE</b>: BigInteger & BigDecimal minimums are dependent upon their precision & Scale
921      */

922     public Hashtable minimumNumericValues() {
923         Hashtable values = new Hashtable();
924
925         values.put(Integer JavaDoc.class, new Integer JavaDoc(Integer.MIN_VALUE));
926         values.put(Long JavaDoc.class, new Long JavaDoc(Long.MIN_VALUE));
927         values.put(Double JavaDoc.class, new Double JavaDoc(Double.MIN_VALUE));
928         values.put(Short JavaDoc.class, new Short JavaDoc(Short.MIN_VALUE));
929         values.put(Byte JavaDoc.class, new Byte JavaDoc(Byte.MIN_VALUE));
930         values.put(Float JavaDoc.class, new Float JavaDoc(Float.MIN_VALUE));
931         values.put(java.math.BigInteger JavaDoc.class, new java.math.BigInteger JavaDoc("-99999999999999999999999999999999999999"));
932         values.put(java.math.BigDecimal JavaDoc.class, new java.math.BigDecimal JavaDoc("-9999999999999999999.9999999999999999999"));
933         return values;
934     }
935
936     /**
937      * Append the receiver's field 'identity' constraint clause to a writer.
938      */

939     public void printFieldIdentityClause(Writer writer, AbstractSession session, String JavaDoc qualifiedFieldName) throws ValidationException {
940         if (shouldAcquireSequenceValueAfterInsert(session, qualifiedFieldName)) {
941             printFieldIdentityClause(writer);
942         }
943     }
944
945     /**
946      * Append the receiver's field 'identity' constraint clause to a writer.
947      */

948     public void printFieldIdentityClause(Writer writer) throws ValidationException {
949         //The default is to do nothing.
950
}
951
952     /**
953      * Append the receiver's field 'NOT NULL' constraint clause to a writer.
954      */

955     public void printFieldNotNullClause(Writer writer) throws ValidationException {
956         try {
957             writer.write(" NOT NULL");
958         } catch (IOException ioException) {
959             throw ValidationException.fileError(ioException);
960         }
961     }
962
963     /**
964      * Append the receiver's field 'NULL' constraint clause to a writer.
965      */

966     public void printFieldNullClause(Writer writer) throws ValidationException {
967         // The default is to do nothing
968
}
969
970     /**
971      * Added November 7, 2000 JED
972      * Prs reference: 24501
973      * Tracker reference: 14111
974      * Print the int array on the writer. Added to handle int[] passed as parameters to named queries
975      * Returns the number of objects using binding.
976      */

977     public int printValuelist(int[] theObjects, DatabaseCall call, Writer writer) throws IOException {
978         int nBoundParameters = 0;
979         writer.write("(");
980
981         for (int i = 0; i < theObjects.length; i++) {
982             nBoundParameters = nBoundParameters + appendParameterInternal(call, writer, new Integer JavaDoc(theObjects[i]));
983             if (i < (theObjects.length - 1)) {
984                 writer.write(", ");
985             }
986         }
987
988         writer.write(")");
989         return nBoundParameters;
990     }
991
992     /**
993      * Returns the number of objects using binding.
994      */

995     public int printValuelist(Vector theObjects, DatabaseCall call, Writer writer) throws IOException {
996         int nBoundParameters = 0;
997         Enumeration enumtr = theObjects.elements();
998         while (enumtr.hasMoreElements()) {
999             nBoundParameters = nBoundParameters + appendParameterInternal(call, writer, enumtr.nextElement());
1000            if (enumtr.hasMoreElements()) {
1001                writer.write(", ");
1002            }
1003        }
1004        return nBoundParameters;
1005    }
1006
1007    protected Object JavaDoc processResultSet(ResultSet resultSet, DatabaseCall dbCall, PreparedStatement statement, DatabaseAccessor accessor, AbstractSession session) throws SQLException {
1008        Object JavaDoc result = null;
1009        ResultSetMetaData metaData = resultSet.getMetaData();
1010
1011        session.startOperationProfile(SessionProfiler.ROW_FETCH);
1012        try {
1013            if (dbCall.isOneRowReturned()) {
1014                if (resultSet.next()) {
1015                    result = accessor.fetchRow(dbCall.getFields(), resultSet, metaData, session);
1016                    if (resultSet.next()) {
1017                        // Raise more rows event, some apps may interpret as error or warning.
1018
session.getEventManager().moreRowsDetected(dbCall);
1019                    }
1020                } else {
1021                    result = null;
1022                }
1023            } else {
1024                Vector results = new Vector(20);
1025                while (resultSet.next()) {
1026                    results.addElement(accessor.fetchRow(dbCall.getFields(), resultSet, metaData, session));
1027                }
1028                result = results;
1029            }
1030            resultSet.close();// This must be closed incase the statement is cached and not closed.
1031
} finally {
1032            session.endOperationProfile(SessionProfiler.ROW_FETCH);
1033        }
1034        return result;
1035    }
1036
1037    /**
1038     * This method is used to register output parameter on Callable Statements for Stored Procedures
1039     * as each database seems to have a different method.
1040     */

1041    public void registerOutputParameter(CallableStatement statement, int index, int jdbcType) throws SQLException {
1042        statement.registerOutParameter(index, jdbcType);
1043    }
1044
1045    /**
1046     * This is used as some databases create the primary key constraint differently, i.e. Access.
1047     */

1048    public boolean requiresNamedPrimaryKeyConstraints() {
1049        return false;
1050    }
1051
1052    /**
1053     * USed for sp calls.
1054     */

1055    public boolean requiresProcedureCallBrackets() {
1056        return true;
1057    }
1058
1059    /**
1060     * Used for sp calls. Sybase must print output after output params.
1061     */

1062    public boolean requiresProcedureCallOuputToken() {
1063        return false;
1064    }
1065
1066    /**
1067     * INTERNAL:
1068     * Indicates whether the version of CallableStatement.registerOutputParameter method
1069     * that takes type name should be used.
1070     */

1071    public boolean requiresTypeNameToRegisterOutputParameter() {
1072        return false;
1073    }
1074
1075    /**
1076     * Used for jdbc drivers which do not support autocommit to explicitly rollback a transaction
1077     * This method is a no-op for databases which implement autocommit as expected.
1078     */

1079    public void rollbackTransaction(DatabaseAccessor accessor) throws SQLException {
1080        if (!supportsAutoCommit()) {
1081            accessor.getConnection().rollback();
1082        }
1083    }
1084
1085    protected void setClassTypes(Hashtable classTypes) {
1086        this.classTypes = classTypes;
1087    }
1088
1089    /**
1090     * ADVANCED:
1091     * Set the code for preparing cursored output
1092     * parameters in a stored procedure
1093     */

1094    public void setCursorCode(int cursorCode) {
1095        this.cursorCode = cursorCode;
1096    }
1097
1098    protected void setFieldTypes(Hashtable theFieldTypes) {
1099        fieldTypes = theFieldTypes;
1100    }
1101
1102    public void setSequenceCounterFieldName(String JavaDoc name) {
1103        if (getDefaultSequence() instanceof TableSequence) {
1104            ((TableSequence)getDefaultSequence()).setCounterFieldName(name);
1105        } else {
1106            if (!name.equals((new TableSequence()).getCounterFieldName())) {
1107                ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "setCounterFieldName");
1108            }
1109        }
1110    }
1111
1112    public void setSequenceNameFieldName(String JavaDoc name) {
1113        if (getDefaultSequence() instanceof TableSequence) {
1114            ((TableSequence)getDefaultSequence()).setNameFieldName(name);
1115        } else {
1116            if (!name.equals((new TableSequence()).getNameFieldName())) {
1117                throw ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "setNameFieldName");
1118            }
1119        }
1120    }
1121
1122    public void setSequenceTableName(String JavaDoc name) {
1123        if (getDefaultSequence() instanceof TableSequence) {
1124            ((TableSequence)getDefaultSequence()).setTableName(name);
1125        } else {
1126            if (!name.equals((new TableSequence()).getTableName())) {
1127                throw ValidationException.wrongSequenceType(Helper.getShortClassName(getDefaultSequence()), "setTableName");
1128            }
1129        }
1130    }
1131
1132    /**
1133     * Bind all arguments to any SQL statement.
1134     */

1135    public void setShouldBindAllParameters(boolean shouldBindAllParameters) {
1136        this.shouldBindAllParameters = shouldBindAllParameters;
1137    }
1138
1139    /**
1140     * Cache all prepared statements, this requires full parameter binding as well.
1141     */

1142    public void setShouldCacheAllStatements(boolean shouldCacheAllStatements) {
1143        this.shouldCacheAllStatements = shouldCacheAllStatements;
1144    }
1145
1146    /**
1147     * Can be used if the app expects upper case but the database is not return consistent case, i.e. different databases.
1148     */

1149    public void setShouldForceFieldNamesToUpperCase(boolean shouldForceFieldNamesToUpperCase) {
1150        this.shouldForceFieldNamesToUpperCase = shouldForceFieldNamesToUpperCase;
1151    }
1152
1153    /**
1154     * Allow for case in field names to be ignored as some databases are not case sensitive and when using custom this can be an issue.
1155     */

1156    public static void setShouldIgnoreCaseOnFieldComparisons(boolean newShouldIgnoreCaseOnFieldComparisons) {
1157        shouldIgnoreCaseOnFieldComparisons = newShouldIgnoreCaseOnFieldComparisons;
1158    }
1159
1160    /**
1161     * PUBLIC:
1162     * Set if our driver level data conversion optimization is enabled.
1163     * This can be disabled as some drivers perform data conversion themselves incorrectly.
1164     */

1165    public void setShouldOptimizeDataConversion(boolean value) {
1166        this.shouldOptimizeDataConversion = value;
1167    }
1168
1169    public void setShouldTrimStrings(boolean aBoolean) {
1170        shouldTrimStrings = aBoolean;
1171    }
1172
1173    /**
1174     * The statement cache size for prepare parameterized statements.
1175     */

1176    public void setStatementCacheSize(int statementCacheSize) {
1177        this.statementCacheSize = statementCacheSize;
1178    }
1179
1180    public void setStringBindingSize(int aSize) {
1181        stringBindingSize = aSize;
1182    }
1183
1184    /**
1185     * supportsAutoCommit can be set to false for JDBC drivers which do not support autocommit
1186     * @return boolean
1187     */

1188    public void setSupportsAutoCommit(boolean supportsAutoCommit) {
1189        this.supportsAutoCommit = supportsAutoCommit;
1190    }
1191
1192    /**
1193     * Set the transaction isolation setting for a connection.
1194     */

1195    public void setTransactionIsolation(int isolationLevel) {
1196        transactionIsolation = isolationLevel;
1197    }
1198
1199    public void setUsesByteArrayBinding(boolean usesByteArrayBinding) {
1200        this.usesByteArrayBinding = usesByteArrayBinding;
1201    }
1202
1203    public void setUsesNativeSQL(boolean usesNativeSQL) {
1204        this.usesNativeSQL = usesNativeSQL;
1205    }
1206
1207    public void setUsesStreamsForBinding(boolean usesStreamsForBinding) {
1208        this.usesStreamsForBinding = usesStreamsForBinding;
1209    }
1210
1211    public void setUsesStringBinding(boolean aBool) {
1212        usesStringBinding = aBool;
1213    }
1214
1215    /**
1216     * Bind all arguments to any SQL statement.
1217     */

1218    public boolean shouldBindAllParameters() {
1219        return shouldBindAllParameters;
1220    }
1221
1222    /**
1223     * Cache all prepared statements, this requires full parameter binding as well.
1224     */

1225    public boolean shouldCacheAllStatements() {
1226        return shouldCacheAllStatements;
1227    }
1228
1229    /**
1230     * Can be used if the app expects upper case but the database is not return consistent case, i.e. different databases.
1231     */

1232    public boolean shouldForceFieldNamesToUpperCase() {
1233        return shouldForceFieldNamesToUpperCase;
1234    }
1235
1236    /**
1237     * Allow for case in field names to be ignored as some databases are not case sensitive and when using custom this can be an issue.
1238     */

1239    public static boolean shouldIgnoreCaseOnFieldComparisons() {
1240        return shouldIgnoreCaseOnFieldComparisons;
1241    }
1242
1243    /**
1244     * Allow for the platform to ignore exceptions.
1245     * This is required for DB2 which throws no-data modified as an exception.
1246     */

1247    public boolean shouldIgnoreException(SQLException exception) {
1248        // By default nothing is ignored.
1249
return false;
1250    }
1251
1252    /**
1253     * Return if our driver level data conversion optimization is enabled.
1254     * This can be disabled as some drivers perform data conversion themselves incorrectly.
1255     */

1256    public boolean shouldOptimizeDataConversion() {
1257        return shouldOptimizeDataConversion;
1258    }
1259
1260    /**
1261    * Some Platforms want the constraint name after the constraint definition.
1262    */

1263    public boolean shouldPrintConstraintNameAfter() {
1264        return false;
1265    }
1266
1267    /**
1268     * This is required in the construction of the stored procedures with
1269     * output parameters
1270     */

1271    public boolean shouldPrintInOutputTokenBeforeType() {
1272        return true;
1273    }
1274
1275    /**
1276     * Some database require outer joins to be given in the where clause, others require it in the from clause.
1277     */

1278    public boolean shouldPrintOuterJoinInWhereClause() {
1279        return false;
1280    }
1281
1282    /**
1283     * This is required in the construction of the stored procedures with
1284     * output parameters
1285     */

1286    public boolean shouldPrintOutputTokenBeforeType() {
1287        return true;
1288    }
1289    
1290    /**
1291     * This is required in the construction of the stored procedures with
1292     * output parameters
1293     */

1294    public boolean shouldPrintOutputTokenAtStart() {
1295        return false;
1296    }
1297    
1298    public boolean shouldTrimStrings() {
1299        return shouldTrimStrings;
1300    }
1301
1302    /**
1303     * JDBC defines and outer join syntax, many drivers do not support this. So we normally avoid it.
1304     */

1305    public boolean shouldUseJDBCOuterJoinSyntax() {
1306        return true;
1307    }
1308
1309    /**
1310     * supportsAutoCommit must sometimes be set to false for JDBC drivers which do not
1311     * support autocommit. Used to determine how to handle transactions properly.
1312     */

1313    public boolean supportsAutoCommit() {
1314        return supportsAutoCommit;
1315    }
1316
1317    public boolean supportsForeignKeyConstraints() {
1318        return true;
1319    }
1320
1321    public boolean supportsUniqueKeyConstraints() {
1322        return true;
1323    }
1324
1325    public boolean supportsNativeSequenceNumbers() {
1326        return false;
1327    }
1328
1329    public boolean supportsPrimaryKeyConstraint() {
1330        return true;
1331    }
1332
1333    public boolean supportsStoredFunctions() {
1334        return false;
1335    }
1336
1337    /**
1338     * because each platform has different requirements for accessing stored procedures and
1339     * the way that we can combine resultsets and output params the stored procedure call
1340     * is being executed on the platform
1341     */

1342    public Object JavaDoc executeStoredProcedure(DatabaseCall dbCall, PreparedStatement statement, DatabaseAccessor accessor, AbstractSession session) throws SQLException {
1343        Object JavaDoc result = null;
1344        ResultSet resultSet = null;
1345        if (!dbCall.getReturnsResultSet()) {// no result set is expected
1346
if (dbCall.isCursorOutputProcedure()) {
1347                result = accessor.executeNoSelect(dbCall, statement, session);
1348                resultSet = (ResultSet)((CallableStatement)statement).getObject(dbCall.getCursorOutIndex());
1349            } else {
1350                accessor.executeDirectNoSelect(statement, dbCall, session);
1351                result = accessor.buildOutputRow((CallableStatement)statement, dbCall, session);
1352
1353                //ReadAllQuery may be returning just output params, or they may be executing a DataReadQuery, which also
1354
//assumes a vector
1355
if (dbCall.areManyRowsReturned()) {
1356                    Vector tempResult = new Vector();
1357                    ((Vector)tempResult).add(result);
1358                    result = tempResult;
1359                }
1360            }
1361        } else {
1362            // so specifically in Sybase JConnect 5.5 we must create the result vector before accessing the
1363
// output params in the case where the user is returning both. this is a driver limitation
1364
resultSet = accessor.executeSelect(dbCall, statement, session);
1365        }
1366        if (resultSet != null) {
1367            dbCall.matchFieldOrder(resultSet, accessor, session);
1368
1369            if (dbCall.isCursorReturned()) {
1370                dbCall.setStatement(statement);
1371                dbCall.setResult(resultSet);
1372                return dbCall;
1373            }
1374            result = processResultSet(resultSet, dbCall, statement, accessor, session);
1375
1376        }
1377        return result;
1378    }
1379
1380    /**
1381     * INTERNAL
1382     * Note that index (not index+1) is used in statement.setObject(index, parameter)
1383     * Binding starts with a 1 not 0, so make sure that index > 0.
1384     */

1385    public void setParameterValueInDatabaseCall(Object JavaDoc parameter, PreparedStatement statement, int index, AbstractSession session) throws SQLException {
1386        // 2.0p22: Added the following conversion before binding into prepared statement
1387
parameter = convertToDatabaseType(parameter);
1388        if (! setComplexParameterValue(session, statement, index, parameter)) {
1389            setPrimitiveParameterValue(statement, index, parameter);
1390        }
1391    }
1392    
1393    /**
1394     * Set a primitive parameter.
1395     * Database platforms that need customised behavior would override this method
1396     */

1397    protected void setPrimitiveParameterValue(final PreparedStatement statement, final int index,
1398            final Object JavaDoc parameter) throws SQLException {
1399        statement.setObject(index, parameter);
1400    }
1401
1402    /**
1403     * Set a complex parameter.
1404     * @return true if parameter was successfully set by this method, false otherwise.
1405     */

1406    private boolean setComplexParameterValue(final AbstractSession session, final PreparedStatement statement, final int index, final Object JavaDoc parameter) throws SQLException {
1407        if (parameter == null) {
1408            // no DatabaseField available
1409
statement.setNull(index, getJDBCType((Class JavaDoc)null));
1410        } else if (parameter instanceof DatabaseField) {
1411            // Substituted null value for the corresponding DatabaseField.
1412
// Cannot bind null through set object, so we must compute to type.
1413
int jdbcType = getJDBCType((DatabaseField)parameter);
1414            statement.setNull(index, jdbcType);
1415        } else if ((parameter instanceof byte[]) && (usesStreamsForBinding())) {
1416            ByteArrayInputStream inputStream = new ByteArrayInputStream((byte[])parameter);
1417            statement.setBinaryStream(index, inputStream, ((byte[])parameter).length);
1418        } else if ((parameter instanceof String JavaDoc) && usesStringBinding() && (((String JavaDoc)parameter).length() > getStringBindingSize())) {
1419            CharArrayReader reader = new CharArrayReader(((String JavaDoc)parameter).toCharArray());
1420            statement.setCharacterStream(index, reader, ((String JavaDoc)parameter).length());
1421        } else if (parameter instanceof BindCallCustomParameter) {
1422            ((BindCallCustomParameter)(parameter)).set(this, statement, index, session);
1423        } else {
1424            return false;
1425        }
1426        return true;
1427    }
1428
1429    /**
1430     * INTERNAL
1431     * Used by SQLCall.prepareStatement(..)
1432     * Note that parameterIndex corresponds to parameters vector and
1433     * index corresponds to statement:
1434     * statement.setObject(parameterIndex + 1, parameters.elementAt(parameterIndex))
1435     * Therefore parameterIndex may be 0.
1436     */

1437    public void setParameterValueInDatabaseCall(Vector parameters, PreparedStatement statement, int parameterIndex, AbstractSession session) throws SQLException {
1438        setParameterValueInDatabaseCall(parameters, statement, parameterIndex, parameterIndex + 1, session);
1439    }
1440
1441    /**
1442     * INTERNAL
1443     * Used by StoredProcedureCall.prepareStatement(..)
1444     * Note that parameterIndex corresponds to parameters vector and
1445     * index corresponds to statement:
1446     * statement.setObject(index, parameters.elementAt(parameterIndex))
1447     * Therefore parameterIndex may be 0, but index > 0.
1448     */

1449    public void setParameterValueInDatabaseCall(Vector parameters, PreparedStatement statement, int parameterIndex, int index, AbstractSession session) throws SQLException {
1450        setParameterValueInDatabaseCall(parameters.elementAt(parameterIndex), statement, index, session);
1451    }
1452
1453    public boolean usesByteArrayBinding() {
1454        return usesByteArrayBinding;
1455    }
1456
1457    public boolean usesSequenceTable() {
1458        return getDefaultSequence() instanceof TableSequence;
1459    }
1460
1461    public boolean usesNativeSQL() {
1462        return usesNativeSQL;
1463    }
1464
1465    public boolean usesStreamsForBinding() {
1466        return usesStreamsForBinding;
1467    }
1468
1469    public boolean usesStringBinding() {
1470        return usesStringBinding;
1471    }
1472
1473    /**
1474     * INTERNAL:
1475     * Write LOB value - only on Oracle8 and up
1476     */

1477    public void writeLOB(DatabaseField field, Object JavaDoc value, ResultSet resultSet, AbstractSession session) throws SQLException {
1478        // used by Oracle8Platform
1479
}
1480
1481    /**
1482     * INTERNAL
1483     * Indicates whether a separate transaction is required for NativeSequence.
1484     * This method is to be used *ONLY* by sequencing classes
1485     */

1486    public boolean shouldNativeSequenceUseTransaction() {
1487        return false;
1488    }
1489
1490    /**
1491     * INTERNAL:
1492     * Indicates whether NativeSequence should retrieve
1493     * sequence value after the object has been inserted into the db
1494     * This method is to be used *ONLY* by sequencing classes
1495     */

1496    public boolean shouldNativeSequenceAcquireValueAfterInsert() {
1497        return false;
1498    }
1499
1500
1501    /**
1502     * INTERNAL:
1503     */

1504    public ValueReadQuery buildSelectQueryForNativeSequence() {
1505        return null;
1506    }
1507
1508    /**
1509     * INTERNAL:
1510     */

1511    public ValueReadQuery buildSelectQueryForNativeSequence(String JavaDoc seqName, Integer JavaDoc size) {
1512        return null;
1513    }
1514
1515    /**
1516     * INTERNAL:
1517     * Create platform-default Sequence
1518     */

1519    protected Sequence createPlatformDefaultSequence() {
1520        return new TableSequence();
1521    }
1522
1523    /**
1524     * INTERNAL:
1525     * Indicates whether the platform supports temporary tables.
1526     * Temporary tables may be used by UpdateAllQueries:
1527     * though attempt is always made to perform UpdateAll without using temporary
1528     * storage there are some scenarios that can't be fulfilled without it.
1529     * Don't override this method.
1530     * If the platform support temorary tables then override
1531     * either supportsLocalTempTables() or supportsGlobalTempTables()
1532     * method.
1533     */

1534     public boolean supportsTempTables() {
1535         return supportsLocalTempTables() || supportsGlobalTempTables();
1536     }
1537
1538    /**
1539     * INTERNAL:
1540     * Indicates whether the platform supports local temporary tables.
1541     * "Local" means that several threads may create
1542     * temporary tables with the same name.
1543     * Local temporary table is created in the beginning of UpdateAllQuery
1544     * execution and dropped in the end of it.
1545     * Override this method if the platform supports local temporary tables.
1546     */

1547     public boolean supportsLocalTempTables() {
1548         return false;
1549     }
1550
1551    /**
1552     * INTERNAL:
1553     * Indicates whether the platform supports global temporary tables.
1554     * "Global" means that an attempt to create temporary table with the same
1555     * name for the second time results in exception.
1556     * TopLink attempts to create global temporary table in the beginning of UpdateAllQuery,
1557     * execution and assumes that it already exists in case SQLException results.
1558     * In the end of UpdateAllQuery execution all rows are removed from the temporary table -
1559     * it is necessary in case the same temporary table will be used by another UpdateAllQuery
1560     * in the same transaction.
1561     * Override this method if the platform supports global temporary tables.
1562     * Note that this method is ignored in case supportsLocalTempTables() returns true.
1563     */

1564     public boolean supportsGlobalTempTables() {
1565         return false;
1566     }
1567     
1568    /**
1569     * INTERNAL:
1570     * Override this method if the platform supports temporary tables.
1571     * This should contain the beginning of sql string for
1572     * creating temporary table - the sql statement name, for instance:
1573     * "CREATE GLOBAL TEMPORARY TABLE ".
1574     * Don't forget to end it with a space.
1575     */

1576     protected String JavaDoc getCreateTempTableSqlPrefix() {
1577         throw ValidationException.platformDoesNotOverrideGetCreateTempTableSqlPrefix(Helper.getShortClassName(this));
1578     }
1579
1580    /**
1581     * INTERNAL:
1582     * May override this method if the platform support temporary tables.
1583     * @parameter DatabaseTable table is original table for which temp table is created.
1584     * @return DatabaseTable temorary table
1585     */

1586     public DatabaseTable getTempTableForTable(DatabaseTable table) {
1587         return new DatabaseTable("TL_" + table.getName(), table.getTableQualifier());
1588     }
1589
1590    /**
1591     * INTERNAL:
1592     * May override this method if the platform support temporary tables.
1593     * This should contain the ending of sql string for
1594     * creating temporary table, for instance:
1595     * " ON COMMIT DELETE ROWS"
1596     * Don't forget to begin it with a space.
1597     */

1598     protected String JavaDoc getCreateTempTableSqlSuffix() {
1599         return "";
1600     }
1601
1602    /**
1603     * INTERNAL:
1604     * May override this method if the platform supports temporary tables.
1605     * With this method not overridden the sql string for temporary table creation
1606     * will include a list of database fields extracted from descriptor:
1607     * getCreateTempTableSqlPrefix() + getTempTableForTable(table).getQualifiedName() +
1608     * (list of database fields) + getCreateTempTableSqlSuffix().
1609     * If this method is overridden its output will be used instead of fields' list:
1610     * getCreateTempTableSqlPrefix() + getTempTableForTable(table).getQualifiedName() +
1611     * getCreateTempTableSqlBodyForTable(table) + getCreateTempTableSqlSuffix().
1612     * Don't forget to begin it with a space.
1613     * Example: " LIKE " + table.getQualifiedName();
1614     * @parameter DatabaseTable table is original table for which temp table is created.
1615     * @result String
1616     */

1617     protected String JavaDoc getCreateTempTableSqlBodyForTable(DatabaseTable table) {
1618         return null;
1619     }
1620
1621    /**
1622     * INTERNAL:
1623     * Don't override this method.
1624     * Write an sql string for creation of the temporary table.
1625     * Note that in case of local temp table support it's possible to limit
1626     * the fields in the temp table to those needed for the operation it supports (usedFields) -
1627     * the temp table will be dropped in the end of query execution.
1628     * Alternatively, in global temp table case the table with a given name is created just once
1629     * and will be potentially used by various operations with various sets of used fields,
1630     * therefore global temp table should contain all mapped fields (allFields).
1631     * Precondition: supportsTempTables() == true.
1632     * Precondition: pkFields contained in usedFields contained in allFields
1633     * @parameter Writer writer for writing the sql
1634     * @parameter DatabaseTable table is original table for which temp table is created.
1635     * @parameter AbstractSession session.
1636     * @parameter Collection pkFields - primary key fields for the original table.
1637     * @parameter Collection usedFields - fields that will be used by operation for which temp table is created.
1638     * @parameter Collection allFields - all mapped fields for the original table.
1639     */

1640     public void writeCreateTempTableSql(Writer writer, DatabaseTable table, AbstractSession session,
1641                                        Collection pkFields,
1642                                        Collection usedFields,
1643                                        Collection allFields) throws IOException
1644    {
1645        String JavaDoc body = getCreateTempTableSqlBodyForTable(table);
1646        if(body == null) {
1647            TableDefinition tableDef = new TableDefinition();
1648            Collection fields;
1649            if(supportsLocalTempTables()) {
1650                fields = usedFields;
1651            } else {
1652                // supportsGlobalTempTables() == true
1653
fields = allFields;
1654            }
1655            Iterator itFields = fields.iterator();
1656            while(itFields.hasNext()) {
1657                DatabaseField field = (DatabaseField)itFields.next();
1658                FieldDefinition fieldDef = new FieldDefinition(field.getName(), ConversionManager.getObjectClass(field.getType()));
1659                if(pkFields.contains(field)) {
1660                    fieldDef.setIsPrimaryKey(true);
1661                }
1662                tableDef.addField(fieldDef);
1663            }
1664            tableDef.setCreationPrefix(getCreateTempTableSqlPrefix());
1665            tableDef.setName(getTempTableForTable(table).getQualifiedName());
1666            tableDef.setCreationSuffix(getCreateTempTableSqlSuffix());
1667            tableDef.buildCreationWriter(session, writer);
1668        } else {
1669            writer.write(getCreateTempTableSqlPrefix());
1670            writer.write(getTempTableForTable(table).getQualifiedName());
1671            writer.write(body);
1672            writer.write(getCreateTempTableSqlSuffix());
1673        }
1674    }
1675
1676    /**
1677     * INTERNAL:
1678     * May need to override this method if the platform supports temporary tables
1679     * and the generated sql doesn't work.
1680     * Write an sql string for insertion into the temporary table.
1681     * Precondition: supportsTempTables() == true.
1682     * @parameter Writer writer for writing the sql
1683     * @parameter DatabaseTable table is original table for which temp table is created.
1684     * @parameter Collection usedFields - fields that will be used by operation for which temp table is created.
1685     */

1686     public void writeInsertIntoTableSql(Writer writer, DatabaseTable table, Collection usedFields) throws IOException {
1687        writer.write("INSERT INTO ");
1688        writer.write(getTempTableForTable(table).getQualifiedName());
1689
1690        writer.write(" (");
1691        writeFieldsList(writer, usedFields);
1692        writer.write(") ");
1693    }
1694
1695    /**
1696     * INTERNAL:
1697     * May need to override this method if the platform supports temporary tables
1698     * and the generated sql doesn't work.
1699     * Write an sql string for updating the original table from the temporary table.
1700     * Precondition: supportsTempTables() == true.
1701     * Precondition: pkFields and assignFields don't intersect.
1702     * @parameter Writer writer for writing the sql
1703     * @parameter DatabaseTable table is original table for which temp table is created.
1704     * @parameter Collection pkFields - primary key fields for the original table.
1705     * @parameter Collection assignedFields - fields to be assigned a new value.
1706     */

1707     public void writeUpdateOriginalFromTempTableSql(Writer writer, DatabaseTable table,
1708                                                     Collection pkFields,
1709                                                     Collection assignedFields) throws IOException
1710    {
1711        writer.write("UPDATE ");
1712        String JavaDoc tableName = table.getQualifiedName();
1713        writer.write(tableName);
1714        writer.write(" SET (");
1715        writeFieldsList(writer, assignedFields);
1716        writer.write(") = (SELECT ");
1717        writeFieldsList(writer, assignedFields);
1718        writer.write(" FROM ");
1719        String JavaDoc tempTableName = getTempTableForTable(table).getQualifiedName();
1720        writer.write(tempTableName);
1721        writeAutoJoinWhereClause(writer, null, tableName, pkFields);
1722        writer.write(") WHERE EXISTS(SELECT ");
1723        writer.write(((DatabaseField)pkFields.iterator().next()).getName());
1724        writer.write(" FROM ");
1725        writer.write(tempTableName);
1726        writeAutoJoinWhereClause(writer, null, tableName, pkFields);
1727        writer.write(")");
1728    }
1729
1730    /**
1731     * INTERNAL:
1732     * Write an sql string for deletion from target table using temporary table.
1733     * At this point temporary table should contains pks for the rows that should be
1734     * deleted from target table.
1735     * Temporary tables are not required for DeleteAllQuery, however will be used if
1736     * shouldAlwaysUseTempStorageForModifyAll()==true
1737     * May need to override this method in case it generates sql that doesn't work on the platform.
1738     * Precondition: supportsTempTables() == true.
1739     * @parameter Writer writer for writing the sql
1740     * @parameter DatabaseTable table is original table for which temp table is created.
1741     * @parameter DatabaseTable targetTable is a table from which to delete.
1742     * @parameter Collection pkFields - primary key fields for the original table.
1743     * @parameter Collection targetPkFields - primary key fields for the target table.
1744     * @parameter Collection assignedFields - fields to be assigned a new value.
1745     */

1746     public void writeDeleteFromTargetTableUsingTempTableSql(Writer writer, DatabaseTable table, DatabaseTable targetTable,
1747                                                     Collection pkFields,
1748                                                     Collection targetPkFields) throws IOException
1749    {
1750        writer.write("DELETE FROM ");
1751        String JavaDoc targetTableName = targetTable.getQualifiedName();
1752        writer.write(targetTableName);
1753        writer.write(" WHERE EXISTS(SELECT ");
1754        writer.write(((DatabaseField)pkFields.iterator().next()).getName());
1755        writer.write(" FROM ");
1756        String JavaDoc tempTableName = getTempTableForTable(table).getQualifiedName();
1757        writer.write(tempTableName);
1758        writeJoinWhereClause(writer, null, targetTableName, pkFields, targetPkFields);
1759        writer.write(")");
1760    }
1761
1762    /**
1763     * INTERNAL:
1764     * Don't override this method.
1765     * Write an sql string for clean up of the temporary table.
1766     * Drop a local temp table or delete all from a global temp table (so that it's
1767     * ready to be used again in the same transaction).
1768     * Precondition: supportsTempTables() == true.
1769     * @parameter Writer writer for writing the sql
1770     * @parameter DatabaseTable table is original table for which temp table is created.
1771     */

1772     public void writeCleanUpTempTableSql(Writer writer, DatabaseTable table) throws IOException {
1773        if(supportsLocalTempTables()) {
1774            writer.write("DROP TABLE ");
1775        } else {
1776            // supportsGlobalTempTables() == true
1777
writer.write("DELETE FROM ");
1778        }
1779        writer.write(getTempTableForTable(table).getQualifiedName());
1780    }
1781
1782    /**
1783     * INTERNAL:
1784     * That method affects UpdateAllQuery and DeleteAllQuery execution.
1785     * In case it returns false modify all queries would attempt to proceed
1786     * without using temporary storage if it is possible.
1787     * In case it returns true modify all queries would use temporary storage unless
1788     * each modify statement doesn't reference any other tables.
1789     * May need to override this method if the platform can't handle the sql
1790     * generated for modify all queries without using temporary storage.
1791     */

1792    public boolean shouldAlwaysUseTempStorageForModifyAll() {
1793        return false;
1794    }
1795    
1796   /**
1797    * INTERNAL:
1798    * May need to override this method if the sql generated for UpdateAllQuery
1799    * using temp tables fails in case parameter binding is used.
1800    */

1801    public boolean dontBindUpdateAllQueryUsingTempTables() {
1802        return false;
1803    }
1804    
1805    /**
1806     * INTERNAL:
1807     * helper method, don't override.
1808     */

1809    protected static void writeFieldsList(Writer writer, Collection fields) throws IOException {
1810        boolean isFirst = true;
1811        Iterator itFields = fields.iterator();
1812        while(itFields.hasNext()) {
1813            if(isFirst) {
1814                isFirst = false;
1815            } else {
1816                writer.write(", ");
1817            }
1818            DatabaseField field = (DatabaseField)itFields.next();
1819            writer.write(field.getName());
1820        }
1821    }
1822    
1823    /**
1824     * INTERNAL:
1825     * helper method, don't override.
1826     */

1827    protected static void writeAutoAssignmentSetClause(Writer writer, String JavaDoc tableName1, String JavaDoc tableName2, Collection fields) throws IOException {
1828        writer.write(" SET ");
1829        writeFieldsAutoClause(writer, tableName1, tableName2, fields, ", ");
1830    }
1831
1832    /**
1833     * INTERNAL:
1834     * helper method, don't override.
1835     */

1836    protected static void writeAutoJoinWhereClause(Writer writer, String JavaDoc tableName1, String JavaDoc tableName2, Collection pkFields) throws IOException {
1837        writer.write(" WHERE ");
1838        writeFieldsAutoClause(writer, tableName1, tableName2, pkFields, " AND ");
1839    }
1840
1841    /**
1842     * INTERNAL:
1843     * helper method, don't override.
1844     */

1845    protected static void writeFieldsAutoClause(Writer writer, String JavaDoc tableName1, String JavaDoc tableName2, Collection fields, String JavaDoc separator) throws IOException {
1846        writeFields(writer, tableName1, tableName2, fields, fields, separator);
1847    }
1848    /**
1849     * INTERNAL:
1850     * helper method, don't override.
1851     */

1852    protected static void writeJoinWhereClause(Writer writer, String JavaDoc tableName1, String JavaDoc tableName2, Collection pkFields1, Collection pkFields2) throws IOException {
1853        writer.write(" WHERE ");
1854        writeFields(writer, tableName1, tableName2, pkFields1, pkFields2, " AND ");
1855    }
1856
1857    /**
1858     * INTERNAL:
1859     * helper method, don't override.
1860     */

1861    protected static void writeFields(Writer writer, String JavaDoc tableName1, String JavaDoc tableName2, Collection fields1, Collection fields2, String JavaDoc separator) throws IOException {
1862        boolean isFirst = true;
1863        Iterator itFields1 = fields1.iterator();
1864        Iterator itFields2 = fields2.iterator();
1865        while(itFields1.hasNext()) {
1866            if(isFirst) {
1867                isFirst = false;
1868            } else {
1869                writer.write(separator);
1870            }
1871            if(tableName1 != null) {
1872                writer.write(tableName1);
1873                writer.write(".");
1874            }
1875            String JavaDoc fieldName1 = ((DatabaseField)itFields1.next()).getName();
1876            writer.write(fieldName1);
1877            writer.write(" = ");
1878            if(tableName2 != null) {
1879                writer.write(tableName2);
1880                writer.write(".");
1881            }
1882            String JavaDoc fieldName2 = ((DatabaseField)itFields2.next()).getName();
1883            writer.write(fieldName2);
1884        }
1885    }
1886    
1887    public boolean shouldAcquireSequenceValueAfterInsert(AbstractSession session, String JavaDoc qualifiedFieldName) {
1888        if (!supportsNativeSequenceNumbers() || !shouldNativeSequenceAcquireValueAfterInsert()) {
1889            return false;
1890        }
1891        if ((session.getSequencing() == null) || (session.getSequencing().whenShouldAcquireValueForAll() == Sequencing.BEFORE_INSERT)) {
1892            return false;
1893        }
1894
1895        boolean shouldAcquireSequenceValueAfterInsert = false;
1896        DatabaseField field = new DatabaseField(qualifiedFieldName);
1897        Iterator descriptors = session.getDescriptors().values().iterator();
1898        while (descriptors.hasNext()) {
1899            ClassDescriptor descriptor = (ClassDescriptor)descriptors.next();
1900            if (!descriptor.usesSequenceNumbers()) {
1901                continue;
1902            }
1903            if (descriptor.getSequenceNumberField().equals(field)) {
1904                String JavaDoc seqName = descriptor.getSequenceNumberName();
1905                Sequence sequence = getSequence(seqName);
1906                shouldAcquireSequenceValueAfterInsert = sequence.shouldAcquireValueAfterInsert();
1907                break;
1908            }
1909        }
1910        return shouldAcquireSequenceValueAfterInsert;
1911    }
1912    
1913    public void printFieldTypeSize(Writer writer, FieldDefinition field,
1914            FieldTypeDefinition fieldType, AbstractSession session, String JavaDoc qualifiedFieldName) throws IOException {
1915        writer.write(fieldType.getName());
1916        if ((fieldType.isSizeAllowed()) && ((field.getSize() != 0) || (fieldType.isSizeRequired()))) {
1917            writer.write("(");
1918            if (field.getSize() == 0) {
1919                writer.write(new Integer JavaDoc(fieldType.getDefaultSize()).toString());
1920            } else {
1921                writer.write(new Integer JavaDoc(field.getSize()).toString());
1922            }
1923            if (field.getSubSize() != 0) {
1924                writer.write(",");
1925                writer.write(new Integer JavaDoc(field.getSubSize()).toString());
1926            } else if (fieldType.getDefaultSubSize() != 0) {
1927                writer.write(",");
1928                writer.write(new Integer JavaDoc(fieldType.getDefaultSubSize()).toString());
1929            }
1930            writer.write(")");
1931        }
1932    }
1933    
1934    public void printFieldUnique(Writer writer, boolean isUnique,
1935            AbstractSession session, String JavaDoc qualifiedFieldName) throws IOException {
1936        if (isUnique) {
1937            if (supportsPrimaryKeyConstraint()) {
1938                writer.write(" UNIQUE");
1939            }
1940        }
1941    }
1942
1943    public void writeParameterMarker(Writer writer, ParameterExpression expression) throws IOException {
1944        writer.write("?");
1945    }
1946}
1947
Popular Tags