FileDocCategorySizeDatePackage
DB2Platform.javaAPI DocGlassfish v2 API23153Tue May 22 16:54:48 BST 2007oracle.toplink.essentials.platform.database

DB2Platform

public class DB2Platform extends DatabasePlatform

Purpose: Provides DB2 specific behaviour.

Responsibilities:

  • Native SQL for byte[], Date, Time, & Timestamp.
  • Support for table qualified names.
since
TOPLink/Java 1.0

Fields Summary
Constructors Summary
Methods Summary
protected voidappendByteArray(byte[] bytes, java.io.Writer writer)
INTERNAL: Append a byte[] in native DB@ format BLOB(hexString) if usesNativeSQL(), otherwise use ODBC format from DatabasePLatform.

        if (usesNativeSQL()) {
            writer.write("BLOB(x'");
            Helper.writeHexString(bytes, writer);
            writer.write("')");
        } else {
            super.appendByteArray(bytes, writer);
        }
    
protected voidappendCalendar(java.util.Calendar calendar, java.io.Writer writer)
INTERNAL: Append the Timestamp in native format if usesNativeSQL() is true otherwise use ODBC format from DatabasePlatform. Native format: 'YYYY-MM-DD-hh.mm.ss.SSSSSS'

        if (usesNativeSQL()) {
            writer.write("'");
            appendDB2Calendar(calendar, writer);
            writer.write("'");
        } else {
            super.appendCalendar(calendar, writer);
        }
    
protected voidappendDB2Calendar(java.util.Calendar calendar, java.io.Writer writer)
INTERNAL: Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff).

        int hour;
        int minute;
        int second;
        if (!Helper.getDefaultTimeZone().equals(calendar.getTimeZone())) {
            // Must convert the calendar to the local timezone if different, as dates have no timezone (always local).
            Calendar localCalendar = Helper.allocateCalendar();
            JavaPlatform.setTimeInMillis(localCalendar, JavaPlatform.getTimeInMillis(calendar));
            hour = calendar.get(Calendar.HOUR_OF_DAY);
            minute = calendar.get(Calendar.MINUTE);
            second = calendar.get(Calendar.SECOND);
            Helper.releaseCalendar(localCalendar);
        } else {
            hour = calendar.get(Calendar.HOUR_OF_DAY);
            minute = calendar.get(Calendar.MINUTE);
            second = calendar.get(Calendar.SECOND);
        }
        writer.write(Helper.printDate(calendar));
        writer.write('-");
        if (hour < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(hour));
        writer.write('.");
        if (minute < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(minute));
        writer.write('.");
        if (second < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(second));
        writer.write('.");

        // Must truncate the nanos to six decimal places,
        // it is actually a complex algorithm...
        String millisString = Integer.toString(calendar.get(Calendar.MILLISECOND));
        int numberOfZeros = 0;
        for (int num = Math.min(3 - millisString.length(), 3); num > 0; num--) {
            writer.write('0");
            numberOfZeros++;
        }
        if ((millisString.length() + numberOfZeros) > 3) {
            millisString = millisString.substring(0, (3 - numberOfZeros));
        }
        writer.write(millisString);
    
protected voidappendDB2Date(java.sql.Date date, java.io.Writer writer)
INTERNAL: Write a timestamp in DB2 specific format (mm/dd/yyyy).

        writer.write("'");
        // PERF: Avoid deprecated get methods, that are now very inefficient and used from toString.
        Calendar calendar = Helper.allocateCalendar();
        calendar.setTime(date);

        if ((calendar.get(Calendar.MONTH) + 1) < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(calendar.get(Calendar.MONTH) + 1));
        writer.write('/");
        if (calendar.get(Calendar.DATE) < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(calendar.get(Calendar.DATE)));
        writer.write('/");
        writer.write(Integer.toString(calendar.get(Calendar.YEAR)));
        writer.write("'");

        Helper.releaseCalendar(calendar);
    
protected voidappendDB2Timestamp(java.sql.Timestamp timestamp, java.io.Writer writer)
INTERNAL: Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff).

        // PERF: Avoid deprecated get methods, that are now very inefficient and used from toString.
        Calendar calendar = Helper.allocateCalendar();
        calendar.setTime(timestamp);

        writer.write(Helper.printDate(calendar));
        writer.write('-");
        if (calendar.get(Calendar.HOUR_OF_DAY) < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)));
        writer.write('.");
        if (calendar.get(Calendar.MINUTE) < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(calendar.get(Calendar.MINUTE)));
        writer.write('.");
        if (calendar.get(Calendar.SECOND) < 10) {
            writer.write('0");
        }
        writer.write(Integer.toString(calendar.get(Calendar.SECOND)));
        writer.write('.");

        Helper.releaseCalendar(calendar);

        // Must truncate the nanos to six decimal places,
        // it is actually a complex algorithm...
        String nanoString = Integer.toString(timestamp.getNanos());
        int numberOfZeros = 0;
        for (int num = Math.min(9 - nanoString.length(), 6); num > 0; num--) {
            writer.write('0");
            numberOfZeros++;
        }
        if ((nanoString.length() + numberOfZeros) > 6) {
            nanoString = nanoString.substring(0, (6 - numberOfZeros));
        }
        writer.write(nanoString);
    
protected voidappendDate(java.sql.Date date, java.io.Writer writer)
INTERNAL: Appends the Date in native format if usesNativeSQL() otherwise use ODBC format from DatabasePlatform. Native format: 'mm/dd/yyyy'

        if (usesNativeSQL()) {
            appendDB2Date(date, writer);
        } else {
            super.appendDate(date, writer);
        }
    
protected voidappendTime(java.sql.Time time, java.io.Writer writer)
INTERNAL: Append the Time in Native format if usesNativeSQL() otherwise use ODBC format from DAtabasePlatform. Native Format: 'hh:mm:ss'

        if (usesNativeSQL()) {
            writer.write("'");
            writer.write(Helper.printTime(time));
            writer.write("'");
        } else {
            super.appendTime(time, writer);
        }
    
protected voidappendTimestamp(java.sql.Timestamp timestamp, java.io.Writer writer)
INTERNAL: Append the Timestamp in native format if usesNativeSQL() is true otherwise use ODBC format from DatabasePlatform. Native format: 'YYYY-MM-DD-hh.mm.ss.SSSSSS'

        if (usesNativeSQL()) {
            writer.write("'");
            appendDB2Timestamp(timestamp, writer);
            writer.write("'");
        } else {
            super.appendTimestamp(timestamp, writer);
        }
    
protected java.util.HashtablebuildFieldTypes()

        Hashtable fieldTypeMapping = new Hashtable();

        fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("SMALLINT DEFAULT 0", false));

        fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false));
        fieldTypeMapping.put(Long.class, new FieldTypeDefinition("INTEGER", false));
        fieldTypeMapping.put(Float.class, new FieldTypeDefinition("FLOAT", false));
        fieldTypeMapping.put(Double.class, new FieldTypeDefinition("FLOAT", false));
        fieldTypeMapping.put(Short.class, new FieldTypeDefinition("SMALLINT", false));
        fieldTypeMapping.put(Byte.class, new FieldTypeDefinition("SMALLINT", false));
        fieldTypeMapping.put(java.math.BigInteger.class, new FieldTypeDefinition("BIGINT", false));
        fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("DECIMAL", 15));
        fieldTypeMapping.put(Number.class, new FieldTypeDefinition("DECIMAL", 15));

        fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", 255));
        fieldTypeMapping.put(Character.class, new FieldTypeDefinition("CHAR", 1));
        fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition("BLOB", 64000));
        fieldTypeMapping.put(Character[].class, new FieldTypeDefinition("CLOB", 64000));
        fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("BLOB", 64000));
        fieldTypeMapping.put(char[].class, new FieldTypeDefinition("CLOB", 64000));        
        fieldTypeMapping.put(java.sql.Blob.class, new FieldTypeDefinition("BLOB", 64000));
        fieldTypeMapping.put(java.sql.Clob.class, new FieldTypeDefinition("CLOB", 64000));  

        fieldTypeMapping.put(java.sql.Date.class, new FieldTypeDefinition("DATE", false));
        fieldTypeMapping.put(java.sql.Time.class, new FieldTypeDefinition("TIME", false));
        fieldTypeMapping.put(java.sql.Timestamp.class, new FieldTypeDefinition("TIMESTAMP", false));

        return fieldTypeMapping;
    
public oracle.toplink.essentials.queryframework.ValueReadQuerybuildSelectQueryForNativeSequence()
INTERNAL: Build the identity query for native sequencing.

        ValueReadQuery selectQuery = new ValueReadQuery();
        StringWriter writer = new StringWriter();
        writer.write("SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1");

        selectQuery.setSQLString(writer.toString());
        return selectQuery;
    
private oracle.toplink.essentials.expressions.ExpressionOperatorconcatOperator()
The Concat operator is of the form .... VARCHAR ( || )

        ExpressionOperator exOperator = new ExpressionOperator();
        exOperator.setType(ExpressionOperator.FunctionOperator);
        exOperator.setSelector(ExpressionOperator.Concat);
        Vector v = new Vector(5);
        v.addElement("VARCHAR(");
        v.addElement(" || ");
        v.addElement(")");
        exOperator.printsAs(v);
        exOperator.bePrefix();
        exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
        return exOperator;
    
protected java.lang.StringgetCreateTempTableSqlBodyForTable(oracle.toplink.essentials.internal.helper.DatabaseTable table)
INTERNAL:

         return " LIKE " + table.getQualifiedName();
     
protected java.lang.StringgetCreateTempTableSqlPrefix()
INTERNAL:

         return "DECLARE GLOBAL TEMPORARY TABLE ";
     
protected java.lang.StringgetCreateTempTableSqlSuffix()
INTERNAL:

        return " ON COMMIT DELETE ROWS NOT LOGGED";
    
public intgetMaxFieldNameSize()
INTERNAL: returns the maximum number of characters that can be used in a field name on this platform.

        return 128;
    
public intgetMaxForeignKeyNameSize()
INTERNAL: returns the maximum number of characters that can be used in a foreign key name on this platform.

        return 18;
    
public java.util.VectorgetNativeTableInfo(java.lang.String table, java.lang.String creator, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return the catalog information through using the native SQL catalog selects. This is required because many JDBC driver do not support meta-data. Willcards can be passed as arguments.

        String query = "SELECT * FROM SYSIBM.SYSTABLES WHERE TBCREATOR NOT IN ('SYS', 'SYSTEM')";
        if (table != null) {
            if (table.indexOf('%") != -1) {
                query = query + " AND TBNAME LIKE " + table;
            } else {
                query = query + " AND TBNAME = " + table;
            }
        }
        if (creator != null) {
            if (creator.indexOf('%") != -1) {
                query = query + " AND TBCREATOR LIKE " + creator;
            } else {
                query = query + " AND TBCREATOR = " + creator;
            }
        }
        return session.executeSelectingCall(new oracle.toplink.essentials.queryframework.SQLCall(query));
    
public java.lang.StringgetProcedureAsString()
INTERNAL: Used for stored procedure defs.

        return "";
    
public java.lang.StringgetProcedureBeginString()
INTERNAL: Used for stored procedure defs.

        return "BEGIN";
    
public java.lang.StringgetProcedureCallHeader()
INTERNAL: Used for sp calls.

        return "CALL ";
    
public java.lang.StringgetProcedureEndString()
INTERNAL: Used for stored procedure defs.

        return "END";
    
public java.lang.StringgetSelectForUpdateString()
INTERNAL:

        return " FOR UPDATE";
    
public oracle.toplink.essentials.internal.helper.DatabaseTablegetTempTableForTable(oracle.toplink.essentials.internal.helper.DatabaseTable table)
INTERNAL:

         DatabaseTable tempTable =  super.getTempTableForTable(table);
         tempTable.setTableQualifier("session");
         return tempTable;
     
public oracle.toplink.essentials.queryframework.ValueReadQuerygetTimestampQuery()
INTERNAL: This method returns the query to select the timestamp from the server for DB2.

        if (timestampQuery == null) {
            timestampQuery = new ValueReadQuery();
            timestampQuery.setSQLString("SELECT DISTINCT CURRENT TIMESTAMP FROM SYSIBM.SYSTABLES");
        }
        return timestampQuery;
    
protected voidinitializePlatformOperators()
INTERNAL: Initialize any platform-specific operators

        super.initializePlatformOperators();

        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToUpperCase, "UCASE"));
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToLowerCase, "LCASE"));
        addOperator(concatOperator());
        addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Instring, "Locate"));
        //CR#2811076 some missing DB2 functions added.
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToNumber, "DECIMAL"));
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToChar, "CHAR"));
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.DateToString, "CHAR"));
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToDate, "DATE"));
    
public booleanisDB2()

        return true;
    
public booleanisNullAllowedInSelectClause()
INTERNAL: Override this if the platform cannot handle NULL in select clause.

        return false;
    
public java.util.HashtablemaximumNumericValues()
INTERNAL: Builds a table of maximum numeric values keyed on java class. This is used for type testing but might also be useful to end users attempting to sanitize values.

NOTE: BigInteger & BigDecimal maximums are dependent upon their precision & Scale

        Hashtable values = new Hashtable();

        values.put(Integer.class, new Integer(Integer.MAX_VALUE));
        values.put(Long.class, new Long((long)Integer.MAX_VALUE));
        values.put(Float.class, new Float(123456789));
        values.put(Double.class, new Double((double)Float.MAX_VALUE));
        values.put(Short.class, new Short(Short.MAX_VALUE));
        values.put(Byte.class, new Byte(Byte.MAX_VALUE));
        values.put(java.math.BigInteger.class, new java.math.BigInteger("999999999999999"));
        values.put(java.math.BigDecimal.class, new java.math.BigDecimal("0.999999999999999"));
        return values;
    
public java.util.HashtableminimumNumericValues()
INTERNAL: Builds a table of minimum numeric values keyed on java class. This is used for type testing but might also be useful to end users attempting to sanitize values.

NOTE: BigInteger & BigDecimal minimums are dependent upon their precision & Scale

        Hashtable values = new Hashtable();

        values.put(Integer.class, new Integer(Integer.MIN_VALUE));
        values.put(Long.class, new Long((long)Integer.MIN_VALUE));
        values.put(Float.class, new Float(-123456789));
        values.put(Double.class, new Double((double)Float.MIN_VALUE));
        values.put(Short.class, new Short(Short.MIN_VALUE));
        values.put(Byte.class, new Byte(Byte.MIN_VALUE));
        values.put(java.math.BigInteger.class, new java.math.BigInteger("-999999999999999"));
        values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-0.999999999999999"));
        return values;
    
public voidprintFieldIdentityClause(java.io.Writer writer)
INTERNAL: Append the receiver's field 'identity' constraint clause to a writer

        try {
            writer.write(" GENERATED ALWAYS AS IDENTITY");
        } catch (IOException ioException) {
            throw ValidationException.fileError(ioException);
        }
    
public booleanshouldBindLiterals()
INTERNAL Allows platform to choose whether to bind literals in DatabaseCalls or not.

        return false;
    
public booleanshouldIgnoreException(java.sql.SQLException exception)
INTERNAL: Allow for the platform to ignore exceptions. This is required for DB2 which throws no-data modified as an exception.

        if (exception.getMessage().equals("No data found") || exception.getMessage().equals("No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table") || (exception.getErrorCode() == 100)) {
            return true;
        }
        return super.shouldIgnoreException(exception);
    
public booleanshouldNativeSequenceAcquireValueAfterInsert()
INTERNAL: If native sequencing is being used on DB2 then the values must be retrieved after the insert. This method is to be used *ONLY* by sequencing classes

        return true;
    
public booleanshouldPrintOutputTokenAtStart()
INTERNAL: This is required in the construction of the stored procedures with output parameters

        return true;
    
public booleanshouldUseJDBCOuterJoinSyntax()
INTERNAL: JDBC defines and outer join syntax, many drivers do not support this. So we normally avoid it.

        return false;
    
public booleansupportsGlobalTempTables()
INTERNAL:

         return true;
     
public booleansupportsNativeSequenceNumbers()
Return true if the receiver uses host sequence numbers, generated on the database. DB2 does through AS IDENTITY field types.

        return true;
    
public voidwriteParameterMarker(java.io.Writer writer, oracle.toplink.essentials.internal.expressions.ParameterExpression parameter)

        // DB2 requires cast around parameter markers if both operands of certian
        // operators are parameter markers
        // This method generates CAST for parameter markers whose type is correctly
        // identified by the query compiler
        String paramaterMarker = "?";
        Object type = parameter.getType();
        if(type != null) {
            BasicTypeHelperImpl typeHelper = BasicTypeHelperImpl.getInstance();
            String castType = null;
            if (typeHelper.isBooleanType(type) || typeHelper.isByteType(type) || typeHelper.isShortType(type)) {
                castType = "SMALLINT";
            } else if (typeHelper.isIntType(type)) {
                castType = "INTEGER";
            } else if (typeHelper.isLongType(type)) {
                castType = "BIGINT";
            } else if (typeHelper.isFloatType(type)) {
                castType = "REAL";
            } else if (typeHelper.isDoubleType(type)) {
                castType = "DOUBLE";
            } else if (typeHelper.isStringType(type)) {
                castType = "VARCHAR(32672)";
            }

            if(castType != null){
                paramaterMarker = "CAST (? AS " + castType + " )";
            }
        }
        writer.write(paramaterMarker);