001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
005: *
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common Development
009: * and Distribution License("CDDL") (collectively, the "License"). You
010: * may not use this file except in compliance with the License. You can obtain
011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
013: * language governing permissions and limitations under the License.
014: *
015: * When distributing the software, include this License Header Notice in each
016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
017: * Sun designates this particular file as subject to the "Classpath" exception
018: * as provided by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the License
020: * Header, with the fields enclosed by brackets [] replaced by your own
021: * identifying information: "Portions Copyrighted [year]
022: * [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * If you wish your version of this file to be governed by only the CDDL or
027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
028: * elects to include this software in this distribution under the [CDDL or GPL
029: * Version 2] license." If you don't indicate a single choice of license, a
030: * recipient has the option to distribute your version of this file under
031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
032: * its licensees as provided above. However, if you add GPL Version 2 code
033: * and therefore, elected the GPL Version 2 license, then the option applies
034: * only if the new code is made subject to such option by the copyright
035: * holder.
036: */
037: package oracle.toplink.essentials.platform.database;
038:
039: import oracle.toplink.essentials.internal.databaseaccess.FieldTypeDefinition;
040: import oracle.toplink.essentials.internal.sessions.AbstractSession;
041: import oracle.toplink.essentials.internal.helper.DatabaseTable;
042: import oracle.toplink.essentials.exceptions.ValidationException;
043: import oracle.toplink.essentials.queryframework.ValueReadQuery;
044:
045: import java.util.Vector;
046: import java.io.Writer;
047: import java.io.IOException;
048: import java.sql.SQLException;
049: import java.util.Hashtable;
050: import java.util.Collection;
051: import java.util.Iterator;
052: import oracle.toplink.essentials.internal.helper.DatabaseField;
053:
054: /**
055: * <p><b>Purpose</b>: Provides Derby DBMS specific behaviour.
056: *
057: * @since TOPLink Essentials 1.0
058: */
059: public class DerbyPlatform extends DB2Platform {
060:
061: /**
062: * INTERNAL:
063: * TODO: Need to find out how can byte arrays be inlined in Derby
064: */
065: protected void appendByteArray(byte[] bytes, Writer writer)
066: throws IOException {
067: super .appendByteArray(bytes, writer);
068: }
069:
070: /**
071: * INTERNAL:
072: * This method returns the query to select the timestamp from the server
073: * for Derby.
074: */
075: public ValueReadQuery getTimestampQuery() {
076: if (timestampQuery == null) {
077: timestampQuery = new ValueReadQuery();
078: timestampQuery.setSQLString("VALUES CURRENT_TIMESTAMP");
079: }
080: return timestampQuery;
081:
082: }
083:
084: //TODO: check with reviewer. This method should be made private in DB2platform
085: public Vector getNativeTableInfo(String table, String creator,
086: AbstractSession session) {
087: throw new RuntimeException("Should never reach here");
088: }
089:
090: /**
091: * Used for stored procedure defs.
092: */
093: public String getProcedureEndString() {
094: return getBatchEndString();
095: }
096:
097: /**
098: * Used for stored procedure defs.
099: */
100: public String getProcedureBeginString() {
101: return getBatchBeginString();
102: }
103:
104: /**
105: * This method is used to print the output parameter token when stored
106: * procedures are called
107: */
108: public String getInOutputProcedureToken() {
109: return "INOUT";
110: }
111:
112: /**
113: * This is required in the construction of the stored procedures with
114: * output parameters
115: */
116: public boolean shouldPrintOutputTokenAtStart() {
117: //TODO: Check with the reviewer where this is used
118: return false;
119: }
120:
121: /**
122: * INTERNAL:
123: * Answers whether platform is Derby
124: */
125: public boolean isDerby() {
126: return true;
127: }
128:
129: public boolean isDB2() {
130: //This class inhertits from DB2. But it is not DB2
131: return false;
132: }
133:
134: /**
135: * Allow for the platform to ignore exceptions.
136: */
137: public boolean shouldIgnoreException(SQLException exception) {
138: // Nothing is ignored.
139: return false;
140: }
141:
142: /**
143: * INTERNAL:
144: */
145: protected String getCreateTempTableSqlSuffix() {
146: return " ON COMMIT DELETE ROWS NOT LOGGED";
147: }
148:
149: public boolean supportsNativeSequenceNumbers() {
150: return true;
151: }
152:
153: /**
154: * INTERNAL:
155: * Indicates whether NativeSequence should retrieve
156: * sequence value after the object has been inserted into the db
157: * This method is to be used *ONLY* by sequencing classes
158: */
159: public boolean shouldNativeSequenceAcquireValueAfterInsert() {
160: return true;
161: }
162:
163: /**
164: * INTERNAL:
165: * Build the identity query for native sequencing.
166: */
167: public ValueReadQuery buildSelectQueryForNativeSequence() {
168: ValueReadQuery selectQuery = new ValueReadQuery();
169: selectQuery.setSQLString("values IDENTITY_VAL_LOCAL()");
170: return selectQuery;
171: }
172:
173: /**
174: * INTERNAL:
175: * Indicates whether temporary table can specify primary keys (some platforms don't allow that).
176: * Used by writeCreateTempTableSql method.
177: */
178: protected boolean shouldTempTableSpecifyPrimaryKeys() {
179: return false;
180: }
181:
182: /**
183: * INTERNAL:
184: */
185: protected String getCreateTempTableSqlBodyForTable(
186: DatabaseTable table) {
187: // returning null includes fields of the table in body
188: // see javadoc of DatabasePlatform#getCreateTempTableSqlBodyForTable(DataBaseTable)
189: // for details
190: return null;
191: }
192:
193: /**
194: * INTERNAL:
195: * May need to override this method if the platform supports temporary tables
196: * and the generated sql doesn't work.
197: * Write an sql string for updating the original table from the temporary table.
198: * Precondition: supportsTempTables() == true.
199: * Precondition: pkFields and assignFields don't intersect.
200: * @parameter Writer writer for writing the sql
201: * @parameter DatabaseTable table is original table for which temp table is created.
202: * @parameter Collection pkFields - primary key fields for the original table.
203: * @parameter Collection assignedFields - fields to be assigned a new value.
204: */
205: public void writeUpdateOriginalFromTempTableSql(Writer writer,
206: DatabaseTable table, Collection pkFields,
207: Collection assignedFields) throws IOException {
208: writer.write("UPDATE ");
209: String tableName = table.getQualifiedName();
210: writer.write(tableName);
211: writer.write(" SET ");
212:
213: String tempTableName = getTempTableForTable(table)
214: .getQualifiedName();
215: boolean isFirst = true;
216: Iterator itFields = assignedFields.iterator();
217: while (itFields.hasNext()) {
218: if (isFirst) {
219: isFirst = false;
220: } else {
221: writer.write(", ");
222: }
223: DatabaseField field = (DatabaseField) itFields.next();
224: String fieldName = field.getName();
225: writer.write(fieldName);
226: writer.write(" = (SELECT ");
227: writer.write(fieldName);
228: writer.write(" FROM ");
229: writer.write(tempTableName);
230: writeAutoJoinWhereClause(writer, null, tableName, pkFields);
231: writer.write(")");
232: }
233:
234: writer.write(" WHERE EXISTS(SELECT ");
235: writer.write(((DatabaseField) pkFields.iterator().next())
236: .getName());
237: writer.write(" FROM ");
238: writer.write(tempTableName);
239: writeAutoJoinWhereClause(writer, null, tableName, pkFields);
240: writer.write(")");
241: }
242:
243: /**
244: * INTERNAL:
245: * Append the receiver's field 'identity' constraint clause to a writer.
246: */
247: public void printFieldIdentityClause(Writer writer)
248: throws ValidationException {
249: try {
250: writer.write(" GENERATED ALWAYS AS IDENTITY");
251: } catch (IOException ioException) {
252: throw ValidationException.fileError(ioException);
253: }
254: }
255:
256: protected Hashtable buildFieldTypes() {
257: Hashtable fieldTypeMapping = new Hashtable();
258:
259: fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition(
260: "SMALLINT DEFAULT 0", false));
261:
262: fieldTypeMapping.put(Integer.class, new FieldTypeDefinition(
263: "INTEGER", false));
264: fieldTypeMapping.put(Long.class, new FieldTypeDefinition(
265: "BIGINT", false));
266: fieldTypeMapping.put(Float.class, new FieldTypeDefinition(
267: "FLOAT"));
268: fieldTypeMapping.put(Double.class, new FieldTypeDefinition(
269: "FLOAT", false));
270: fieldTypeMapping.put(Short.class, new FieldTypeDefinition(
271: "SMALLINT", false));
272: fieldTypeMapping.put(Byte.class, new FieldTypeDefinition(
273: "SMALLINT", false));
274: fieldTypeMapping.put(java.math.BigInteger.class,
275: new FieldTypeDefinition("BIGINT", false));
276: fieldTypeMapping.put(java.math.BigDecimal.class,
277: new FieldTypeDefinition("DECIMAL"));
278: fieldTypeMapping.put(Number.class, new FieldTypeDefinition(
279: "DECIMAL"));
280:
281: fieldTypeMapping.put(String.class, new FieldTypeDefinition(
282: "VARCHAR", 255));
283: fieldTypeMapping.put(Character.class, new FieldTypeDefinition(
284: "CHAR", 1));
285: fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition(
286: "BLOB", 64000));
287: fieldTypeMapping.put(Character[].class,
288: new FieldTypeDefinition("CLOB", 64000));
289: fieldTypeMapping.put(byte[].class, new FieldTypeDefinition(
290: "BLOB", 64000));
291: fieldTypeMapping.put(char[].class, new FieldTypeDefinition(
292: "CLOB", 64000));
293: fieldTypeMapping.put(java.sql.Blob.class,
294: new FieldTypeDefinition("BLOB", 64000));
295: fieldTypeMapping.put(java.sql.Clob.class,
296: new FieldTypeDefinition("CLOB", 64000));
297:
298: fieldTypeMapping.put(java.sql.Date.class,
299: new FieldTypeDefinition("DATE", false));
300: fieldTypeMapping.put(java.sql.Time.class,
301: new FieldTypeDefinition("TIME", false));
302: fieldTypeMapping.put(java.sql.Timestamp.class,
303: new FieldTypeDefinition("TIMESTAMP", false));
304:
305: return fieldTypeMapping;
306: }
307:
308: }
|