KickJava   Java API By Example, From Geeks To Geeks.

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


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

42 public class SQLServerPlatform extends oracle.toplink.essentials.platform.database.DatabasePlatform {
43
44     /**
45      * INTERNAL:
46      * If using native SQL then print a byte[] as '0xFF...'
47      */

48     protected void appendByteArray(byte[] bytes, Writer writer) throws IOException {
49         if (usesNativeSQL() && (!usesByteArrayBinding())) {
50             writer.write("0x");
51             Helper.writeHexString(bytes, writer);
52         } else {
53             super.appendByteArray(bytes, writer);
54         }
55     }
56
57     /**
58      * INTERNAL:
59      * Answer a platform correct string representation of a Date, suitable for SQL generation.
60      * Native format: 'yyyy-mm-dd
61      */

62     protected void appendDate(java.sql.Date JavaDoc date, Writer writer) throws IOException {
63         if (usesNativeSQL()) {
64             writer.write("'");
65             writer.write(Helper.printDate(date));
66             writer.write("'");
67         } else {
68             super.appendDate(date, writer);
69         }
70     }
71
72     /**
73      * INTERNAL:
74      * Write a timestamp in Sybase specific format ( yyyy-mm-dd-hh.mm.ss.fff)
75      */

76     protected void appendSybaseTimestamp(java.sql.Timestamp JavaDoc timestamp, Writer writer) throws IOException {
77         writer.write("'");
78         writer.write(Helper.printTimestampWithoutNanos(timestamp));
79         writer.write(':');
80
81         // Must truncate the nanos to three decimal places,
82
// it is actually a complex algorithm...
83
String JavaDoc nanoString = Integer.toString(timestamp.getNanos());
84         int numberOfZeros = 0;
85         for (int num = Math.min(9 - nanoString.length(), 3); num > 0; num--) {
86             writer.write('0');
87             numberOfZeros++;
88         }
89         if ((nanoString.length() + numberOfZeros) > 3) {
90             nanoString = nanoString.substring(0, (3 - numberOfZeros));
91         }
92         writer.write(nanoString);
93         writer.write("'");
94     }
95
96     /**
97      * INTERNAL:
98      * Write a timestamp in Sybase specific format ( yyyy-mm-dd-hh.mm.ss.fff)
99      */

100     protected void appendSybaseCalendar(Calendar calendar, Writer writer) throws IOException {
101         writer.write("'");
102         writer.write(Helper.printCalendar(calendar));
103         writer.write("'");
104     }
105
106     /**
107      * INTERNAL:
108      * Answer a platform correct string representation of a Time, suitable for SQL generation.
109      * The time is printed in the ODBC platform independent format {t'hh:mm:ss'}.
110      */

111     protected void appendTime(java.sql.Time JavaDoc time, Writer writer) throws IOException {
112         if (usesNativeSQL()) {
113             writer.write("'");
114             writer.write(Helper.printTime(time));
115             writer.write("'");
116         } else {
117             super.appendTime(time, writer);
118         }
119     }
120
121     /**
122      * INTERNAL:
123      * Answer a platform correct string representation of a Timestamp, suitable for SQL generation.
124      * The date is printed in the ODBC platform independent format {d'YYYY-MM-DD'}.
125      */

126     protected void appendTimestamp(java.sql.Timestamp JavaDoc timestamp, Writer writer) throws IOException {
127         if (usesNativeSQL()) {
128             appendSybaseTimestamp(timestamp, writer);
129         } else {
130             super.appendTimestamp(timestamp, writer);
131         }
132     }
133
134     /**
135      * INTERNAL:
136      * Answer a platform correct string representation of a Calendar, suitable for SQL generation.
137      * The date is printed in the ODBC platform independent format {d'YYYY-MM-DD'}.
138      */

139     protected void appendCalendar(Calendar calendar, Writer writer) throws IOException {
140         if (usesNativeSQL()) {
141             appendSybaseCalendar(calendar, writer);
142         } else {
143             super.appendCalendar(calendar, writer);
144         }
145     }
146
147     protected Hashtable buildFieldTypes() {
148         Hashtable fieldTypeMapping;
149
150         fieldTypeMapping = new Hashtable();
151         fieldTypeMapping.put(Boolean JavaDoc.class, new FieldTypeDefinition("BIT default 0", false));
152
153         fieldTypeMapping.put(Integer JavaDoc.class, new FieldTypeDefinition("INTEGER", false));
154         fieldTypeMapping.put(Long JavaDoc.class, new FieldTypeDefinition("NUMERIC", 19));
155         fieldTypeMapping.put(Float JavaDoc.class, new FieldTypeDefinition("FLOAT(16)", false));
156         fieldTypeMapping.put(Double JavaDoc.class, new FieldTypeDefinition("FLOAT(32)", false));
157         fieldTypeMapping.put(Short JavaDoc.class, new FieldTypeDefinition("SMALLINT", false));
158         fieldTypeMapping.put(Byte JavaDoc.class, new FieldTypeDefinition("SMALLINT", false));
159         fieldTypeMapping.put(java.math.BigInteger JavaDoc.class, new FieldTypeDefinition("NUMERIC", 28));
160         fieldTypeMapping.put(java.math.BigDecimal JavaDoc.class, new FieldTypeDefinition("NUMERIC", 28).setLimits(28, -19, 19));
161         fieldTypeMapping.put(Number JavaDoc.class, new FieldTypeDefinition("NUMERIC", 28).setLimits(28, -19, 19));
162
163         fieldTypeMapping.put(String JavaDoc.class, new FieldTypeDefinition("VARCHAR", 255));
164         fieldTypeMapping.put(Character JavaDoc.class, new FieldTypeDefinition("CHAR", 1));
165         
166         fieldTypeMapping.put(Byte JavaDoc[].class, new FieldTypeDefinition("IMAGE", false));
167         fieldTypeMapping.put(Character JavaDoc[].class, new FieldTypeDefinition("TEXT", false));
168         fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("IMAGE", false));
169         fieldTypeMapping.put(char[].class, new FieldTypeDefinition("TEXT", false));
170         fieldTypeMapping.put(java.sql.Blob JavaDoc.class, new FieldTypeDefinition("IMAGE", false));
171         fieldTypeMapping.put(java.sql.Clob JavaDoc.class, new FieldTypeDefinition("TEXT", false));
172         
173         fieldTypeMapping.put(java.sql.Date JavaDoc.class, new FieldTypeDefinition("DATETIME", false));
174         fieldTypeMapping.put(java.sql.Time JavaDoc.class, new FieldTypeDefinition("DATETIME", false));
175         fieldTypeMapping.put(java.sql.Timestamp JavaDoc.class, new FieldTypeDefinition("DATETIME", false));
176
177         return fieldTypeMapping;
178     }
179
180     /**
181      * INTERNAL:
182      * Build the identity query for native sequencing.
183      */

184     public ValueReadQuery buildSelectQueryForNativeSequence() {
185         ValueReadQuery selectQuery = new ValueReadQuery();
186         StringWriter writer = new StringWriter();
187         writer.write("SELECT @@IDENTITY");
188         selectQuery.setSQLString(writer.toString());
189         return selectQuery;
190     }
191
192     /**
193      * INTERNAL:
194      * Used for batch writing and sp defs.
195      */

196     public String JavaDoc getBatchDelimiterString() {
197         return "";
198     }
199
200     /**
201      * INTERNAL:
202      * This method is used to print the required output parameter token for the
203      * specific platform. Used when stored procedures are created.
204      */

205     public String JavaDoc getCreationInOutputProcedureToken() {
206         return getInOutputProcedureToken();
207     }
208
209     /**
210      * INTERNAL:
211      * This method is used to print the required output parameter token for the
212      * specific platform. Used when stored procedures are created.
213      */

214     public String JavaDoc getCreationOutputProcedureToken() {
215         return "OUTPUT";
216     }
217
218     /**
219      * INTERNAL:
220      * This method is used to print the output parameter token when stored
221      * procedures are called
222      */

223     public String JavaDoc getInOutputProcedureToken() {
224         return "OUT";
225     }
226
227     /**
228      * INTERNAL:
229      * returns the maximum number of characters that can be used in a field
230      * name on this platform.
231      */

232     public int getMaxFieldNameSize() {
233         return 22;
234     }
235
236     /**
237      * INTERNAL:
238      * Return the catalog information through using the native SQL catalog selects.
239      * This is required because many JDBC driver do not support meta-data.
240      * Willcards can be passed as arguments.
241      */

242     public Vector getNativeTableInfo(String JavaDoc table, String JavaDoc creator, AbstractSession session) {
243         // need to filter only tables / views
244
String JavaDoc query = "SELECT * FROM sysobjects WHERE table_type <> 'SYSTEM_TABLE'";
245         if (table != null) {
246             if (table.indexOf('%') != -1) {
247                 query = query + " AND table_name LIKE " + table;
248             } else {
249                 query = query + " AND table_name = " + table;
250             }
251         }
252         if (creator != null) {
253             if (creator.indexOf('%') != -1) {
254                 query = query + " AND table_owner LIKE " + creator;
255             } else {
256                 query = query + " AND table_owner = " + creator;
257             }
258         }
259         return session.executeSelectingCall(new SQLCall(query));
260     }
261
262     /**
263      * INTERNAL:
264      * This method is used to print the output parameter token when stored
265      * procedures are called
266      */

267     public String JavaDoc getOutputProcedureToken() {
268         return "";
269     }
270
271     /**
272      * INTERNAL:
273      * Used for sp defs.
274      */

275     public String JavaDoc getProcedureArgumentString() {
276         return "@";
277     }
278     
279     /**
280      * INTERNAL:
281      */

282     public String JavaDoc getSelectForUpdateString() {
283         return " FOR UPDATE";
284     }
285
286     /**
287      * INTERNAL:
288      * Used for sp calls.
289      */

290     public String JavaDoc getProcedureCallHeader() {
291         return "EXECUTE ";
292     }
293     
294     /**
295      * INTERNAL:
296      */

297     public String JavaDoc getStoredProcedureParameterPrefix() {
298         return "@";
299     }
300
301     /**
302      * INTERNAL:
303      * This method returns the delimiter between stored procedures in multiple stored procedure calls.
304      */

305     public String JavaDoc getStoredProcedureTerminationToken() {
306         return " go";
307     }
308
309     /**
310      * INTERNAL:
311      * This method returns the query to select the timestamp
312      * from the server for SQLServer.
313      */

314     public ValueReadQuery getTimestampQuery() {
315         if (timestampQuery == null) {
316             timestampQuery = new ValueReadQuery();
317             timestampQuery.setSQLString("SELECT GETDATE()");
318         }
319         return timestampQuery;
320     }
321
322     /**
323      * INTERNAL:
324      * Initialize any platform-specific operators
325      */

326     protected void initializePlatformOperators() {
327         super.initializePlatformOperators();
328         addOperator(operatorOuterJoin());
329         addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Today, "GETDATE"));
330         // GETDATE retuens both date and time. It is not the perfect match for ExpressionOperator.currentDate
331
// However, there is no known function on sql server that returns just the date
332
addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.currentDate, "GETDATE"));
333         addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Length, "CHAR_LENGTH"));
334         addOperator(ExpressionOperator.simpleThreeArgumentFunction(ExpressionOperator.Substring, "SUBSTRING"));
335         addOperator(ExpressionOperator.addDate());
336         addOperator(ExpressionOperator.dateName());
337         addOperator(ExpressionOperator.datePart());
338         addOperator(ExpressionOperator.dateDifference());
339         addOperator(ExpressionOperator.difference());
340         addOperator(ExpressionOperator.charIndex());
341         addOperator(ExpressionOperator.charLength());
342         addOperator(ExpressionOperator.reverse());
343         addOperator(ExpressionOperator.replicate());
344         addOperator(ExpressionOperator.right());
345         addOperator(ExpressionOperator.cot());
346         addOperator(ExpressionOperator.sybaseAtan2Operator());
347         addOperator(ExpressionOperator.sybaseAddMonthsOperator());
348         addOperator(ExpressionOperator.sybaseInStringOperator());
349         // bug 3061144
350
addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "ISNULL"));
351         // CR### TO_NUMBER, TO_CHAR, TO_DATE is CONVERT(type, ?)
352
addOperator(ExpressionOperator.sybaseToNumberOperator());
353         addOperator(ExpressionOperator.sybaseToDateToStringOperator());
354         addOperator(ExpressionOperator.sybaseToDateOperator());
355         addOperator(ExpressionOperator.sybaseToCharOperator());
356         addOperator(ExpressionOperator.sybaseLocateOperator());
357         addOperator(locate2Operator());
358         addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Ceil, "CEILING"));
359         addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Length, "LEN"));
360         addOperator(modOperator());
361     }
362
363     public boolean isSQLServer() {
364         return true;
365     }
366
367     /**
368      * INTERNAL:
369      * Builds a table of maximum numeric values keyed on java class. This is used for type testing but
370      * might also be useful to end users attempting to sanitize values.
371      * <p><b>NOTE</b>: BigInteger & BigDecimal maximums are dependent upon their precision & Scale
372      */

373     public Hashtable maximumNumericValues() {
374         Hashtable values = new Hashtable();
375
376         values.put(Integer JavaDoc.class, new Integer JavaDoc(Integer.MAX_VALUE));
377         values.put(Long JavaDoc.class, new Long JavaDoc(Long.MAX_VALUE));
378         values.put(Double JavaDoc.class, new Double JavaDoc(0));
379         values.put(Short JavaDoc.class, new Short JavaDoc(Short.MAX_VALUE));
380         values.put(Byte JavaDoc.class, new Byte JavaDoc(Byte.MAX_VALUE));
381         values.put(Float JavaDoc.class, new Float JavaDoc(0));
382         values.put(java.math.BigInteger JavaDoc.class, new java.math.BigInteger JavaDoc("9999999999999999999999999999"));
383         values.put(java.math.BigDecimal JavaDoc.class, new java.math.BigDecimal JavaDoc("999999999.9999999999999999999"));
384         return values;
385     }
386
387     /**
388      * INTERNAL:
389      * Builds a table of minimum numeric values keyed on java class. This is used for type testing but
390      * might also be useful to end users attempting to sanitize values.
391      * <p><b>NOTE</b>: BigInteger & BigDecimal minimums are dependent upon their precision & Scale
392      */

393     public Hashtable minimumNumericValues() {
394         Hashtable values = new Hashtable();
395
396         values.put(Integer JavaDoc.class, new Integer JavaDoc(Integer.MIN_VALUE));
397         values.put(Long JavaDoc.class, new Long JavaDoc(Long.MIN_VALUE));
398         values.put(Double JavaDoc.class, new Double JavaDoc((double)-9));
399         values.put(Short JavaDoc.class, new Short JavaDoc(Short.MIN_VALUE));
400         values.put(Byte JavaDoc.class, new Byte JavaDoc(Byte.MIN_VALUE));
401         values.put(Float JavaDoc.class, new Float JavaDoc((float)-9));
402         values.put(java.math.BigInteger JavaDoc.class, new java.math.BigInteger JavaDoc("-9999999999999999999999999999"));
403         values.put(java.math.BigDecimal JavaDoc.class, new java.math.BigDecimal JavaDoc("-999999999.9999999999999999999"));
404         return values;
405     }
406
407     /**
408      * INTERNAL:
409      * Override the default MOD operator.
410      */

411     public ExpressionOperator modOperator() {
412         ExpressionOperator result = new ExpressionOperator();
413         result.setSelector(ExpressionOperator.Mod);
414         Vector v = new Vector();
415         v.addElement(" % ");
416         result.printsAs(v);
417         result.bePostfix();
418         result.setNodeClass(oracle.toplink.essentials.internal.expressions.FunctionExpression.class);
419         return result;
420     }
421
422     /**
423      * INTERNAL:
424      * Create the outer join operator for this platform.
425      */

426     protected ExpressionOperator operatorOuterJoin() {
427         ExpressionOperator result = new ExpressionOperator();
428         result.setSelector(ExpressionOperator.EqualOuterJoin);
429         Vector v = new Vector();
430         v.addElement(" =* ");
431         result.printsAs(v);
432         result.bePostfix();
433         result.setNodeClass(RelationExpression.class);
434         return result;
435     }
436
437     /**
438      * INTERNAL:
439      * create the Locate2 Operator for this platform
440      */

441     public static ExpressionOperator locate2Operator() {
442         ExpressionOperator result = ExpressionOperator.simpleThreeArgumentFunction(ExpressionOperator.Locate2, "CHARINDEX");
443         int[] argumentIndices = new int[3];
444         argumentIndices[0] = 1;
445         argumentIndices[1] = 0;
446         argumentIndices[2] = 2;
447         result.setArgumentIndices(argumentIndices);
448         return result;
449     }
450
451
452
453     /**
454      * INTERNAL:
455      * Append the receiver's field 'identity' constraint clause to a writer.
456      */

457     public void printFieldIdentityClause(Writer writer) throws ValidationException {
458         try {
459             writer.write(" IDENTITY");
460         } catch (IOException ioException) {
461             throw ValidationException.fileError(ioException);
462         }
463     }
464
465     /**
466      * INTERNAL:
467      * Append the receiver's field 'NULL' constraint clause to a writer.
468      */

469     public void printFieldNullClause(Writer writer) throws ValidationException {
470         try {
471             writer.write(" NULL");
472         } catch (IOException ioException) {
473             throw ValidationException.fileError(ioException);
474         }
475     }
476
477     /**
478      * INTERNAL:
479      * Used for sp calls.
480      */

481     public boolean requiresProcedureCallBrackets() {
482         return false;
483     }
484
485     /**
486      * INTERNAL:
487      * Used for sp calls. Sybase must print output after output params.
488      */

489     public boolean requiresProcedureCallOuputToken() {
490         return true;
491     }
492
493     /**
494      * INTERNAL:
495      * This is required in the construction of the stored procedures with
496      * output parameters
497      */

498     public boolean shouldPrintInOutputTokenBeforeType() {
499         return false;
500     }
501
502     /**
503      * INTERNAL:
504      * Some database require outer joins to be given in the where clause, others require it in the from clause.
505      */

506     public boolean shouldPrintOuterJoinInWhereClause() {
507         return false;
508     }
509
510     /**
511      * INTERNAL:
512      * This is required in the construction of the stored procedures with
513      * output parameters
514      */

515     public boolean shouldPrintOutputTokenBeforeType() {
516         return false;
517     }
518
519     /**
520      * INTERNAL:
521      * If native sequencing is being used on Sybase then the values must be
522      * retrieved after the insert.
523      * This method is to be used *ONLY* by sequencing classes
524      */

525     public boolean shouldNativeSequenceAcquireValueAfterInsert() {
526         return true;
527     }
528
529     /**
530      * INTERNAL:
531      * JDBC defines and outer join syntax, many drivers do not support this. So we normally avoid it.
532      */

533     public boolean shouldUseJDBCOuterJoinSyntax() {
534         return false;
535     }
536
537     /**
538      * INTERNAL:
539      * Return true if the receiver uses host sequence numbers, generated on the database.
540      * Sybase does through IDENTITY field types.
541      */

542     public boolean supportsNativeSequenceNumbers() {
543         return true;
544     }
545
546     /**
547      * INTERNAL:
548      */

549     public boolean supportsLocalTempTables() {
550         return true;
551     }
552      
553     /**
554      * INTERNAL:
555      */

556     protected String JavaDoc getCreateTempTableSqlPrefix() {
557         return "CREATE TABLE ";
558     }
559
560     /**
561      * INTERNAL:
562      */

563     public DatabaseTable getTempTableForTable(DatabaseTable table) {
564         return new DatabaseTable("#" + table.getName(), table.getTableQualifier());
565     }
566
567     /**
568      * INTERNAL:
569      */

570     public void writeUpdateOriginalFromTempTableSql(Writer writer, DatabaseTable table,
571                                                     Collection pkFields,
572                                                     Collection assignedFields) throws IOException
573     {
574         writer.write("UPDATE ");
575         String JavaDoc tableName = table.getQualifiedName();
576         writer.write(tableName);
577         String JavaDoc tempTableName = getTempTableForTable(table).getQualifiedName();
578         writeAutoAssignmentSetClause(writer, null, tempTableName, assignedFields);
579         writer.write(" FROM ");
580         writer.write(tableName);
581         writer.write(", ");
582         writer.write(tempTableName);
583         writeAutoJoinWhereClause(writer, tableName, tempTableName, pkFields);
584     }
585 }
586
Popular Tags