KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > platform > database > oracle > OraclePlatform


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.platform.database.oracle;
23
24 import java.util.*;
25 import java.io.*;
26 import java.sql.*;
27 import oracle.toplink.essentials.exceptions.*;
28 import oracle.toplink.essentials.queryframework.*;
29 import oracle.toplink.essentials.internal.helper.*;
30 import oracle.toplink.essentials.expressions.*;
31 import oracle.toplink.essentials.internal.expressions.*;
32 import oracle.toplink.essentials.internal.databaseaccess.*;
33 import oracle.toplink.essentials.internal.sessions.AbstractSession;
34
35 /**
36  * <p><b>Purpose</b>: Provides Oracle specific behaviour.
37  * <p><b>Responsibilities</b>:<ul>
38  * <li> Native SQL for byte[], Date, Time, & Timestamp.
39  * <li> Native sequencing named sequences.
40  * </ul>
41  *
42  * @since TOPLink/Java 1.0
43  */

44 public class OraclePlatform extends oracle.toplink.essentials.platform.database.DatabasePlatform {
45
46     /**
47      * INTERNAL:
48      * Used for sp defs.
49      */

50     public boolean allowsSizeInProcedureArguments() {
51         return false;
52     }
53
54     /**
55      * INTERNAL:
56      * If using native SQL then print a byte[] literally as a hex string otherwise use ODBC format
57      * as provided in DatabasePlatform.
58      */

59     protected void appendByteArray(byte[] bytes, Writer writer) throws IOException {
60         if (usesNativeSQL()) {
61             writer.write('\'');
62             Helper.writeHexString(bytes, writer);
63             writer.write('\'');
64         } else {
65             super.appendByteArray(bytes, writer);
66         }
67     }
68
69     /**
70      * INTERNAL:
71      * Appends an Oracle specific date if usesNativeSQL is true otherwise use the ODBC format.
72      * Native FORMAT: to_date('1997-11-06','yyyy-mm-dd')
73      */

74     protected void appendDate(java.sql.Date JavaDoc date, Writer writer) throws IOException {
75         if (usesNativeSQL()) {
76             writer.write("to_date('");
77             writer.write(Helper.printDate(date));
78             writer.write("','yyyy-mm-dd')");
79         } else {
80             super.appendDate(date, writer);
81         }
82     }
83
84     /**
85      * INTERNAL:
86      * Appends an Oracle specific time if usesNativeSQL is true otherwise use the ODBC format.
87      * Native FORMAT: to_date(#####, 'sssss').
88      */

89     protected void appendTime(java.sql.Time JavaDoc time, Writer writer) throws IOException {
90         if (usesNativeSQL()) {
91             writer.write("to_date('");
92             writer.write(Helper.printTime(time));
93             writer.write("','hh24:mi:ss')");
94         } else {
95             super.appendTime(time, writer);
96         }
97     }
98
99     /**
100      * INTERNAL:
101      * Appends an Oracle specific Timestamp, if usesNativeSQL is true otherwise use the ODBC format.
102      * Native Format: to_date ('1997-11-06 10:35:45.0' , 'yyyy-mm-dd hh:mm:ss.n')
103      */

104     protected void appendTimestamp(java.sql.Timestamp JavaDoc timestamp, Writer writer) throws IOException {
105         if (usesNativeSQL()) {
106             writer.write("to_date('");
107             writer.write(Helper.printTimestampWithoutNanos(timestamp));
108             writer.write("','yyyy-mm-dd hh24:mi:ss')");
109         } else {
110             super.appendTimestamp(timestamp, writer);
111         }
112     }
113
114     /**
115      * INTERNAL:
116      * Appends an Oracle specific Timestamp, if usesNativeSQL is true otherwise use the ODBC format.
117      * Native Format: to_date ('1997-11-06 10:35:45.0' , 'yyyy-mm-dd hh:mm:ss.n')
118      */

119     protected void appendCalendar(Calendar calendar, Writer writer) throws IOException {
120         if (usesNativeSQL()) {
121             writer.write("to_date('");
122             writer.write(Helper.printCalendarWithoutNanos(calendar));
123             writer.write("','yyyy-mm-dd hh24:mi:ss')");
124         } else {
125             super.appendCalendar(calendar, writer);
126         }
127     }
128
129     /**
130      * INTERNAL:
131      * Build operator.
132      */

133     public ExpressionOperator atan2Operator() {
134         return ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATAN2");
135     }
136
137     protected Hashtable buildFieldTypes() {
138         Hashtable fieldTypeMapping;
139
140         fieldTypeMapping = new Hashtable();
141         fieldTypeMapping.put(Boolean JavaDoc.class, new FieldTypeDefinition("NUMBER(1) default 0", false));
142
143         fieldTypeMapping.put(Integer JavaDoc.class, new FieldTypeDefinition("NUMBER", 10));
144         fieldTypeMapping.put(Long JavaDoc.class, new FieldTypeDefinition("NUMBER", 19));
145         fieldTypeMapping.put(Float JavaDoc.class, new FieldTypeDefinition("NUMBER", 19, 4));
146         fieldTypeMapping.put(Double JavaDoc.class, new FieldTypeDefinition("NUMBER", 19, 4));
147         fieldTypeMapping.put(Short JavaDoc.class, new FieldTypeDefinition("NUMBER", 5));
148         fieldTypeMapping.put(Byte JavaDoc.class, new FieldTypeDefinition("NUMBER", 3));
149         fieldTypeMapping.put(java.math.BigInteger JavaDoc.class, new FieldTypeDefinition("NUMBER", 38));
150         fieldTypeMapping.put(java.math.BigDecimal JavaDoc.class, new FieldTypeDefinition("NUMBER", 38).setLimits(38, -38, 38));
151         fieldTypeMapping.put(Number JavaDoc.class, new FieldTypeDefinition("NUMBER", 38).setLimits(38, -38, 38));
152
153         fieldTypeMapping.put(String JavaDoc.class, new FieldTypeDefinition("VARCHAR2", 255));
154         fieldTypeMapping.put(Character JavaDoc.class, new FieldTypeDefinition("CHAR", 1));
155
156         fieldTypeMapping.put(Byte JavaDoc[].class, new FieldTypeDefinition("LONG RAW", false));
157         fieldTypeMapping.put(Character JavaDoc[].class, new FieldTypeDefinition("LONG", false));
158         fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("LONG RAW", false));
159         fieldTypeMapping.put(char[].class, new FieldTypeDefinition("LONG", false));
160         fieldTypeMapping.put(java.sql.Blob JavaDoc.class, new FieldTypeDefinition("BLOB", false));
161         fieldTypeMapping.put(java.sql.Clob JavaDoc.class, new FieldTypeDefinition("CLOB", false));
162
163         fieldTypeMapping.put(java.sql.Date JavaDoc.class, new FieldTypeDefinition("DATE", false));
164         fieldTypeMapping.put(java.sql.Time JavaDoc.class, new FieldTypeDefinition("TIMESTAMP", false));
165         fieldTypeMapping.put(java.sql.Timestamp JavaDoc.class, new FieldTypeDefinition("TIMESTAMP", false));
166
167         return fieldTypeMapping;
168     }
169
170     /**
171      * INTERNAL
172      * Returns null unless the platform supports call with returning
173      */

174     public DatabaseCall buildCallWithReturning(SQLCall sqlCall, Vector returnFields) {
175         SQLCall call = new SQLCall();
176         call.setParameters(sqlCall.getParameters());
177         call.setParameterTypes(sqlCall.getParameterTypes());
178
179         Writer writer = new CharArrayWriter(200);
180         try {
181             writer.write("BEGIN ");
182             writer.write(sqlCall.getSQLString());
183             writer.write(" RETURNING ");
184
185             for (int i = 0; i < returnFields.size(); i++) {
186                 DatabaseField field = (DatabaseField)returnFields.elementAt(i);
187                 writer.write(field.getName());
188                 if ((i + 1) < returnFields.size()) {
189                     writer.write(", ");
190                 }
191             }
192
193             writer.write(" INTO ");
194
195             for (int i = 0; i < returnFields.size(); i++) {
196                 DatabaseField field = (DatabaseField)returnFields.elementAt(i);
197                 call.appendOut(writer, field);
198                 if ((i + 1) < returnFields.size()) {
199                     writer.write(", ");
200                 }
201             }
202
203             writer.write("; END;");
204
205             call.setQueryString(writer.toString());
206
207         } catch (IOException exception) {
208             throw ValidationException.fileError(exception);
209         }
210
211         return call;
212     }
213
214     /**
215      * INTERNAL
216      * Indicates whether the platform can build call with returning.
217      * In case this method returns true, buildCallWithReturning method
218      * may be called.
219      */

220     public boolean canBuildCallWithReturning() {
221         return true;
222     }
223
224     /**
225      * INTERNAL
226      * Used for stored function calls.
227      */

228     public String JavaDoc getAssignmentString() {
229         return ":= ";
230     }
231
232     /**
233      * INTERNAL:
234      * Used for batch writing and sp defs.
235      */

236     public String JavaDoc getBatchBeginString() {
237         return "BEGIN ";
238     }
239
240     /**
241      * INTERNAL:
242      * Used for batch writing and sp defs.
243      */

244     public String JavaDoc getBatchEndString() {
245         return "END;";
246     }
247
248     /**
249      * Returns the JDBC outer join operator for SELECT statements.
250      * Overwrites the default implementation, as some Oracle versions
251      * seem to require the syntax given here.
252      */

253     public String JavaDoc getJDBCOuterJoinString() {
254         return "{'oj ";
255     }
256
257     /**
258      * INTERNAL:
259      * returns the maximum number of characters that can be used in a field
260      * name on this platform.
261      */

262     public int getMaxFieldNameSize() {
263         return 30;
264     }
265
266     /**
267      * INTERNAL:
268      * Return the catalog information through using the native SQL catalog selects.
269      * This is required because many JDBC driver do not support meta-data.
270      * Willcards can be passed as arguments.
271      */

272     public Vector getNativeTableInfo(String JavaDoc table, String JavaDoc creator, AbstractSession session) {
273         String JavaDoc query = "SELECT * FROM ALL_TABLES WHERE OWNER NOT IN ('SYS', 'SYSTEM')";
274         if (table != null) {
275             if (table.indexOf('%') != -1) {
276                 query = query + " AND TABLE_NAME LIKE " + table;
277             } else {
278                 query = query + " AND TABLE_NAME = " + table;
279             }
280         }
281         if (creator != null) {
282             if (creator.indexOf('%') != -1) {
283                 query = query + " AND OWNER LIKE " + creator;
284             } else {
285                 query = query + " AND OWNER = " + creator;
286             }
287         }
288         return session.executeSelectingCall(new oracle.toplink.essentials.queryframework.SQLCall(query));
289     }
290
291     /**
292      * INTERNAL:
293      * Used for sp calls.
294      */

295     public String JavaDoc getProcedureArgumentSetter() {
296         return "=>";
297     }
298
299     /**
300      * INTERNAL:
301      * Used for sp calls.
302      */

303     public String JavaDoc getProcedureCallHeader() {
304         return "BEGIN ";
305     }
306
307     /**
308      * INTERNAL:
309      * Used for sp calls.
310      */

311     public String JavaDoc getProcedureCallTail() {
312         return "; END;";
313     }
314
315     /**
316      * INTERNAL:
317      */

318     public String JavaDoc getSelectForUpdateString() {
319         return " FOR UPDATE";
320     }
321
322     /**
323      * INTERNAL:
324      */

325     public String JavaDoc getStoredProcedureParameterPrefix() {
326         return "P_";
327     }
328     
329     /**
330      * INTERNAL:
331      */

332     public String JavaDoc getStoredProcedureTerminationToken() {
333         return "";
334     }
335
336     /**
337      * INTERNAL:
338      * The query to select the current system change number
339      * from Oracle.
340      * In order to execute this query a database administrator may need
341      * to grant execute permission on pl/sql package DBMS_FLASHBACK.
342      */

343     public ValueReadQuery getSystemChangeNumberQuery() {
344         ValueReadQuery sCNQuery = new ValueReadQuery();
345         sCNQuery.setSQLString("SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM DUAL");
346         return sCNQuery;
347     }
348
349     /**
350      * INTERNAL:
351      * This method returns the query to select the timestamp
352      * from the server for Oracle.
353      */

354     public ValueReadQuery getTimestampQuery() {
355         if (timestampQuery == null) {
356             timestampQuery = new ValueReadQuery();
357             timestampQuery.setSQLString("SELECT SYSDATE FROM DUAL");
358         }
359         return timestampQuery;
360     }
361     
362     /**
363      * INTERNAL:
364      * Get a timestamp value from a result set.
365      * Overrides the default behavior to specifically return a timestamp. Added
366      * to overcome an issue with the oracle 9.0.1.4 JDBC driver.
367      */

368     public Object JavaDoc getObjectFromResultSet(ResultSet resultSet, int columnNumber, int type) throws java.sql.SQLException JavaDoc {
369         //Bug#3381652 10G Drivers return sql.Date instead of timestamp on DATE field
370
if ((type == Types.TIMESTAMP) || (type == Types.DATE)) {
371             return resultSet.getTimestamp(columnNumber);
372         } else {
373             return resultSet.getObject(columnNumber);
374         }
375     }
376
377     /**
378      * INTERNAL:
379      * Initialize any platform-specific operators
380      */

381     protected void initializePlatformOperators() {
382         super.initializePlatformOperators();
383         addOperator(operatorOuterJoin());
384         addOperator(logOperator());
385         addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Concat, "CONCAT"));
386         addOperator(todayOperator());
387         addOperator(currentDateOperator());
388         addOperator(ExpressionOperator.truncateDate());
389         addOperator(ExpressionOperator.newTime());
390         addOperator(ExpressionOperator.ifNull());
391         addOperator(atan2Operator());
392         addOperator(ExpressionOperator.oracleDateName());
393         addOperator(operatorLocate());
394         addOperator(operatorLocate2());
395     }
396
397     public boolean isOracle() {
398         return true;
399     }
400
401     /**
402      * INTERNAL:
403      * Create the log operator for this platform
404      */

405     protected ExpressionOperator logOperator() {
406         ExpressionOperator result = new ExpressionOperator();
407         result.setSelector(ExpressionOperator.Log);
408         Vector v = new Vector(2);
409         v.addElement("LOG(");
410         v.addElement(", 10)");
411         result.printsAs(v);
412         result.bePrefix();
413         result.setNodeClass(FunctionExpression.class);
414         return result;
415
416     }
417
418     /**
419      * INTERNAL:
420      * Builds a table of maximum numeric values keyed on java class. This is used for type testing but
421      * might also be useful to end users attempting to sanitize values.
422      * <p><b>NOTE</b>: BigInteger & BigDecimal maximums are dependent upon their precision & Scale
423      */

424     public Hashtable maximumNumericValues() {
425         Hashtable values = new Hashtable();
426
427         values.put(Integer JavaDoc.class, new Integer JavaDoc(Integer.MAX_VALUE));
428         values.put(Long JavaDoc.class, new Long JavaDoc(Long.MAX_VALUE));
429         values.put(Double JavaDoc.class, new Double JavaDoc((double)9.9999E125));
430         values.put(Short JavaDoc.class, new Short JavaDoc(Short.MAX_VALUE));
431         values.put(Byte JavaDoc.class, new Byte JavaDoc(Byte.MAX_VALUE));
432         values.put(Float JavaDoc.class, new Float JavaDoc(Float.MAX_VALUE));
433         values.put(java.math.BigInteger JavaDoc.class, new java.math.BigInteger JavaDoc("0"));
434         values.put(java.math.BigDecimal JavaDoc.class, new java.math.BigDecimal JavaDoc(new java.math.BigInteger JavaDoc("0"), 38));
435         return values;
436     }
437
438     /**
439      * INTERNAL:
440      * Builds a table of minimum numeric values keyed on java class. This is used for type testing but
441      * might also be useful to end users attempting to sanitize values.
442      * <p><b>NOTE</b>: BigInteger & BigDecimal minimums are dependent upon their precision & Scale
443      */

444     public Hashtable minimumNumericValues() {
445         Hashtable values = new Hashtable();
446
447         values.put(Integer JavaDoc.class, new Integer JavaDoc(Integer.MIN_VALUE));
448         values.put(Long JavaDoc.class, new Long JavaDoc(Long.MIN_VALUE));
449         values.put(Double JavaDoc.class, new Double JavaDoc((double)-1E-129));
450         values.put(Short JavaDoc.class, new Short JavaDoc(Short.MIN_VALUE));
451         values.put(Byte JavaDoc.class, new Byte JavaDoc(Byte.MIN_VALUE));
452         values.put(Float JavaDoc.class, new Float JavaDoc(Float.MIN_VALUE));
453         values.put(java.math.BigInteger JavaDoc.class, new java.math.BigInteger JavaDoc("0"));
454         values.put(java.math.BigDecimal JavaDoc.class, new java.math.BigDecimal JavaDoc(new java.math.BigInteger JavaDoc("0"), 38));
455         return values;
456     }
457
458     /**
459      * INTERNAL:
460      * Produce a DataReadQuery which updates(!) the sequence number in the db
461      * and returns it. Currently implemented on Oracle only.
462      * @param sequenceName Name known by Oracle to be a defined sequence
463      */

464     public ValueReadQuery buildSelectQueryForNativeSequence(String JavaDoc seqName, Integer JavaDoc size) {
465         return new ValueReadQuery("SELECT " + getQualifiedSequenceName(seqName) + ".NEXTVAL FROM DUAL");
466     }
467
468     /**
469      * INTERNAL:
470      * Prepend sequence name with table qualifier (if any)
471      */

472     protected String JavaDoc getQualifiedSequenceName(String JavaDoc seqName) {
473         if (getTableQualifier().equals("")) {
474             return seqName;
475         } else {
476             return getTableQualifier() + "." + seqName;
477         }
478     }
479
480     /**
481      * INTERNAL:
482      * Create the outer join operator for this platform
483      */

484     protected ExpressionOperator operatorOuterJoin() {
485         ExpressionOperator result = new ExpressionOperator();
486         result.setSelector(ExpressionOperator.EqualOuterJoin);
487         Vector v = new Vector(2);
488         v.addElement(" (+) = ");
489         result.printsAs(v);
490         result.bePostfix();
491         result.setNodeClass(RelationExpression.class);
492         return result;
493
494     }
495
496     /**
497      * INTERNAL:
498      * Override the default locate operator
499      */

500     protected ExpressionOperator operatorLocate() {
501         ExpressionOperator result = new ExpressionOperator();
502         result.setSelector(ExpressionOperator.Locate);
503         Vector v = new Vector(3);
504         v.addElement("INSTR(");
505         v.addElement(", ");
506         v.addElement(")");
507         result.printsAs(v);
508         result.bePrefix();
509         result.setNodeClass(RelationExpression.class);
510         return result;
511     }
512
513     /**
514      * INTERNAL:
515      * Override the default locate operator
516      */

517     protected ExpressionOperator operatorLocate2() {
518         ExpressionOperator result = new ExpressionOperator();
519         result.setSelector(ExpressionOperator.Locate2);
520         Vector v = new Vector(4);
521         v.addElement("INSTR(");
522         v.addElement(", ");
523         v.addElement(", ");
524         v.addElement(")");
525         result.printsAs(v);
526         result.bePrefix();
527         result.setNodeClass(RelationExpression.class);
528         return result;
529     }
530
531     /**
532      * INTERNAL:
533      * Append the receiver's field 'NULL' constraint clause to a writer.
534      */

535     public void printFieldNullClause(Writer writer) throws ValidationException {
536         try {
537             writer.write(" NULL");
538         } catch (IOException ioException) {
539             throw ValidationException.fileError(ioException);
540         }
541     }
542
543     /**
544      * INTERNAL:
545      * Return the current date and time from the server.
546      */

547     public String JavaDoc serverTimestampString() {
548         return "SYSDATE";
549     }
550
551     /**
552      * INTERNAL:
553      * Some database require outer joins to be given in the where clause, others require it in the from clause.
554      */

555     public boolean shouldPrintOuterJoinInWhereClause() {
556         return true;
557     }
558
559     /**
560      * INTERNAL:
561      * JDBC defines and outer join syntax, many drivers do not support this. So we normally avoid it.
562      */

563     public boolean shouldUseJDBCOuterJoinSyntax() {
564         return false;
565     }
566
567     /**
568      * INTERNAL:
569      * Return true if the receiver uses host sequence numbers, generated on the database.
570      * Oracle does through global sequence objects.
571      */

572     public boolean supportsNativeSequenceNumbers() {
573         return true;
574     }
575
576     /**
577      * INTERNAL:
578      */

579     public boolean supportsStoredFunctions() {
580         return true;
581     }
582
583     /**
584      * INTERNAL:
585      * Returns true if the database supports SQL syntax not to wait on a SELECT..FOR UPADTE
586      * (i.e. In Oracle adding NOWAIT to the end will accomplish this)
587      */

588     public boolean supportsSelectForUpdateNoWait() {
589         return true;
590     }
591
592     /**
593      * INTERNAL:
594      * Create the sysdate operator for this platform
595      */

596     protected ExpressionOperator todayOperator() {
597         return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.Today, "SYSDATE");
598     }
599
600     protected ExpressionOperator currentDateOperator() {
601         return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.currentDate, "TO_DATE(CURRENT_DATE)");
602     }
603
604 }
605
Popular Tags