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

SybasePlatform

public class SybasePlatform extends DatabasePlatform

Purpose: Provides Sybase specific behaviour.

Responsibilities:

  • Native SQL for byte[], Date, Time, & Timestamp.
  • Native sequencing using @@IDENTITY.
since
TOPLink/Java 1.0

Fields Summary
protected Hashtable
typeStrings
Constructors Summary
Methods Summary
protected voidappendByteArray(byte[] bytes, java.io.Writer writer)
INTERNAL: If using native SQL then print a byte[] as '0xFF...'

        if (usesNativeSQL() && (!usesByteArrayBinding())) {
            writer.write("0x");
            Helper.writeHexString(bytes, writer);
        } else {
            super.appendByteArray(bytes, writer);
        }
    
protected voidappendCalendar(java.util.Calendar calendar, java.io.Writer writer)
INTERNAL: Answer a platform correct string representation of a Calendar, suitable for SQL generation. The date is printed in the ODBC platform independent format {d'YYYY-MM-DD'}.

        if (usesNativeSQL()) {
            appendSybaseCalendar(calendar, writer);
        } else {
            super.appendCalendar(calendar, writer);
        }
    
protected voidappendDate(java.sql.Date date, java.io.Writer writer)
INTERNAL: Answer a platform correct string representation of a Date, suitable for SQL generation. Native format: 'yyyy-mm-dd

        if (usesNativeSQL()) {
            writer.write("'");
            writer.write(Helper.printDate(date));
            writer.write("'");
        } else {
            super.appendDate(date, writer);
        }
    
protected voidappendSybaseCalendar(java.util.Calendar calendar, java.io.Writer writer)
INTERNAL: Write a timestamp in Sybase specific format ( yyyy-mm-dd-hh.mm.ss.fff)

        writer.write("'");
        writer.write(Helper.printCalendar(calendar));
        writer.write("'");
    
protected voidappendSybaseTimestamp(java.sql.Timestamp timestamp, java.io.Writer writer)
INTERNAL: Write a timestamp in Sybase specific format (yyyy-mm-dd-hh.mm.ss.fff).

        writer.write("'");
        writer.write(Helper.printTimestampWithoutNanos(timestamp));
        writer.write(':");

        // Must truncate the nanos to three 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(), 3); num > 0; num--) {
            writer.write('0");
            numberOfZeros++;
        }
        if ((nanoString.length() + numberOfZeros) > 3) {
            nanoString = nanoString.substring(0, (3 - numberOfZeros));
        }
        writer.write(nanoString);
        writer.write("'");
    
protected voidappendTime(java.sql.Time time, java.io.Writer writer)
INTERNAL: Answer a platform correct string representation of a Time, suitable for SQL generation. The time is printed in the ODBC platform independent format {t'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: Answer a platform correct string representation of a Timestamp, suitable for SQL generation. The date is printed in the ODBC platform independent format {d'YYYY-MM-DD'}.

        if (usesNativeSQL()) {
            appendSybaseTimestamp(timestamp, writer);
        } else {
            super.appendTimestamp(timestamp, writer);
        }
    
public oracle.toplink.essentials.expressions.ExpressionOperatoratan2Operator()
INTERNAL: Build operator.

        return ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATN2");
    
protected java.util.HashtablebuildFieldTypes()

        Hashtable fieldTypeMapping;

        fieldTypeMapping = new Hashtable();
        fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("BIT default 0", false, false));

        fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false));
        fieldTypeMapping.put(Long.class, new FieldTypeDefinition("NUMERIC", 19));
        fieldTypeMapping.put(Float.class, new FieldTypeDefinition("FLOAT(16)", false));
        fieldTypeMapping.put(Double.class, new FieldTypeDefinition("FLOAT(32)", 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("NUMERIC", 38));
        fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("NUMERIC", 38).setLimits(38, -19, 19));
        fieldTypeMapping.put(Number.class, new FieldTypeDefinition("NUMERIC", 38).setLimits(38, -19, 19));

        fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", 255));
        fieldTypeMapping.put(Character.class, new FieldTypeDefinition("CHAR", 1));
        
        fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition("IMAGE", false));
        fieldTypeMapping.put(Character[].class, new FieldTypeDefinition("TEXT", false));
        fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("IMAGE", false));
        fieldTypeMapping.put(char[].class, new FieldTypeDefinition("TEXT", false));
        fieldTypeMapping.put(java.sql.Blob.class, new FieldTypeDefinition("IMAGE", false));
        fieldTypeMapping.put(java.sql.Clob.class, new FieldTypeDefinition("TEXT", false));        
        
        fieldTypeMapping.put(java.sql.Date.class, new FieldTypeDefinition("DATETIME", false));
        fieldTypeMapping.put(java.sql.Time.class, new FieldTypeDefinition("DATETIME", false));
        fieldTypeMapping.put(java.sql.Timestamp.class, new FieldTypeDefinition("DATETIME", 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");
        selectQuery.setSQLString(writer.toString());
        return selectQuery;
    
public java.lang.ObjectexecuteStoredProcedure(oracle.toplink.essentials.internal.databaseaccess.DatabaseCall dbCall, java.sql.PreparedStatement statement, oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor accessor, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Because each platform has different requirements for accessing stored procedures and the way that we can combine resultsets and output params the stored procedure call is being executed on the platform. This entire process needs some serious refactoring to eliminate the chance of bugs.

        Object result = null;
        ResultSet resultSet = null;
        if (!dbCall.getReturnsResultSet()) {
            accessor.executeDirectNoSelect(statement, dbCall, session);
            result = accessor.buildOutputRow((CallableStatement)statement, dbCall, session);

            //ReadAllQuery may be returning just output params, or they may be executing a DataReadQuery, which also
            //assumes a vector
            if (dbCall.areManyRowsReturned()) {
                Vector tempResult = new Vector();
                ((Vector)tempResult).add(result);
                result = tempResult;
            }
        } else {
            // start the process of procesing the result set and the output params.  this is specific to Sybase JConnect 5.5
            // as we must process the result set before the output params.
            session.startOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
            try {
                resultSet = statement.executeQuery();
            } finally {
                session.endOperationProfile(SessionProfiler.STATEMENT_EXECUTE);
            }
            dbCall.matchFieldOrder(resultSet, accessor, session);

            // cursored result set and output params not supported because of database limitation
            if (dbCall.isCursorReturned()) {
                dbCall.setStatement(statement);
                dbCall.setResult(resultSet);
                return dbCall;
            }
            result = processResultSet(resultSet, dbCall, statement, accessor, session);

            if (dbCall.shouldBuildOutputRow()) {
                AbstractRecord outputRow = accessor.buildOutputRow((CallableStatement)statement, dbCall, session);
                dbCall.getQuery().setProperty("output", outputRow);
                session.getEventManager().outputParametersDetected(outputRow, dbCall);
            }
            return result;
            // end special sybase behaviour.
        }
        return result;
    
public java.lang.StringgetBatchDelimiterString()
INTERNAL: Used for batch writing and sp defs.

        return "";
    
protected java.lang.StringgetCreateTempTableSqlPrefix()
INTERNAL:

        return "CREATE TABLE ";
    
public java.lang.StringgetCreationInOutputProcedureToken()
INTERNAL: This method is used to print the required output parameter token for the specific platform. Used when stored procedures are created.

        return getInOutputProcedureToken();
    
public java.lang.StringgetCreationOutputProcedureToken()
INTERNAL: This method was added because SQLServer requires the output paramater token to be set on creation but not on execution.

        return getOutputProcedureToken();
    
public java.lang.StringgetInOutputProcedureToken()
INTERNAL: This method is used to print the output parameter token when stored procedures are called

        return "OUT";
    
public java.lang.StringgetJdbcTypeName(int jdbcType)
INTERNAL: Returns the type name corresponding to the jdbc type

        return (String)getTypeStrings().get(new Integer(jdbcType));
    
public intgetMaxFieldNameSize()
INTERNAL: returns the maximum number of characters that can be used in a field name on this platform.

        return 22;
    
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.

        // need to filter only tables / views
        String query = "SELECT * FROM sysobjects WHERE table_type <> 'SYSTEM_TABLE'";
        if (table != null) {
            if (table.indexOf('%") != -1) {
                query = query + " AND table_name LIKE " + table;
            } else {
                query = query + " AND table_name = " + table;
            }
        }
        if (creator != null) {
            if (creator.indexOf('%") != -1) {
                query = query + " AND table_owner LIKE " + creator;
            } else {
                query = query + " AND table_owner = " + creator;
            }
        }
        return session.executeSelectingCall(new oracle.toplink.essentials.queryframework.SQLCall(query));
    
public java.lang.StringgetOutputProcedureToken()
INTERNAL: This method is used to print the output parameter token when stored procedures are called

        return "OUTPUT";
    
public java.lang.StringgetProcedureArgumentString()
INTERNAL: Used for sp defs.

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

        return "EXECUTE ";
    
public java.lang.StringgetStoredProcedureParameterPrefix()
INTERNAL:

        return "@";
    
public java.lang.StringgetStoredProcedureTerminationToken()
INTERNAL: This method returns the delimiter between stored procedures in multiple stored procedure calls.

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

        return new DatabaseTable("#" + table.getName(), table.getTableQualifier());
    
public oracle.toplink.essentials.queryframework.ValueReadQuerygetTimestampQuery()
INTERNAL: This method returns the query to select the timestamp from the server for Sybase.

        if (timestampQuery == null) {
            timestampQuery = new ValueReadQuery();
            timestampQuery.setSQLString("SELECT GETDATE()");
        }
        return timestampQuery;
    
protected java.util.HashtablegetTypeStrings()

        if (typeStrings == null) {
            initializeTypeStrings();
        }
        return typeStrings;
    
protected voidinitializePlatformOperators()
INTERNAL: Initialize any platform-specific operators

        super.initializePlatformOperators();
        addOperator(operatorOuterJoin());
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Today, "GETDATE"));
        // GETDATE returns both date and time. It is not the perfect match for 
        // ExpressionOperator.currentDate and ExpressionOperator.currentTime
        // However, there is no known function on sql server that returns just 
        // the date or just the time.
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.CurrentDate, "GETDATE"));
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.CurrentTime, "GETDATE"));
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Length, "CHAR_LENGTH"));
        addOperator(ExpressionOperator.sybaseLocateOperator());
        addOperator(ExpressionOperator.simpleThreeArgumentFunction(ExpressionOperator.Substring, "SUBSTRING"));
        addOperator(ExpressionOperator.addDate());
        addOperator(ExpressionOperator.dateName());
        addOperator(ExpressionOperator.datePart());
        addOperator(ExpressionOperator.dateDifference());
        addOperator(ExpressionOperator.difference());
        addOperator(ExpressionOperator.charIndex());
        addOperator(ExpressionOperator.charLength());
        addOperator(ExpressionOperator.reverse());
        addOperator(ExpressionOperator.replicate());
        addOperator(ExpressionOperator.right());
        addOperator(ExpressionOperator.cot());
        addOperator(ExpressionOperator.sybaseAtan2Operator());
        addOperator(ExpressionOperator.sybaseAddMonthsOperator());
        addOperator(ExpressionOperator.sybaseInStringOperator());
        // bug 3061144
        addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "ISNULL"));
        // CR### TO_NUMBER, TO_CHAR, TO_DATE is CONVERT(type, ?)
        addOperator(ExpressionOperator.sybaseToNumberOperator());
        addOperator(ExpressionOperator.sybaseToDateToStringOperator());
        addOperator(ExpressionOperator.sybaseToDateOperator());
        addOperator(ExpressionOperator.sybaseToCharOperator());
        addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Ceil, "CEILING"));
        addOperator(modOperator());
    
protected synchronized voidinitializeTypeStrings()

        if (typeStrings == null) {
            typeStrings = new Hashtable(30);
            typeStrings.put(new Integer(Types.ARRAY), "ARRAY");
            typeStrings.put(new Integer(Types.BIGINT), "BIGINT");
            typeStrings.put(new Integer(Types.BINARY), "BINARY");
            typeStrings.put(new Integer(Types.BIT), "BIT");
            typeStrings.put(new Integer(Types.BLOB), "BLOB");
            typeStrings.put(new Integer(Types.CHAR), "CHAR");
            typeStrings.put(new Integer(Types.CLOB), "CLOB");
            typeStrings.put(new Integer(Types.DATE), "DATE");
            typeStrings.put(new Integer(Types.DECIMAL), "DECIMAL");
            typeStrings.put(new Integer(Types.DOUBLE), "DOUBLE");
            typeStrings.put(new Integer(Types.FLOAT), "FLOAT");
            typeStrings.put(new Integer(Types.INTEGER), "INTEGER");
            typeStrings.put(new Integer(Types.JAVA_OBJECT), "JAVA_OBJECT");
            typeStrings.put(new Integer(Types.LONGVARBINARY), "LONGVARBINARY");
            typeStrings.put(new Integer(Types.LONGVARCHAR), "LONGVARCHAR");
            typeStrings.put(new Integer(Types.NULL), "NULL");
            typeStrings.put(new Integer(Types.NUMERIC), "NUMERIC");
            typeStrings.put(new Integer(Types.OTHER), "OTHER");
            typeStrings.put(new Integer(Types.REAL), "REAL");
            typeStrings.put(new Integer(Types.REF), "REF");
            typeStrings.put(new Integer(Types.SMALLINT), "SMALLINT");
            typeStrings.put(new Integer(Types.STRUCT), "STRUCT");
            typeStrings.put(new Integer(Types.TIME), "TIME");
            typeStrings.put(new Integer(Types.TIMESTAMP), "TIMESTAMP");
            typeStrings.put(new Integer(Types.TINYINT), "TINYINT");
            typeStrings.put(new Integer(Types.VARBINARY), "VARBINARY");
            typeStrings.put(new Integer(Types.VARCHAR), "VARCHAR");
        }
    
public booleanisSybase()

        return true;
    
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.MAX_VALUE));
        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(Float.class, new Float(Float.MAX_VALUE));
        values.put(java.math.BigInteger.class, new java.math.BigInteger("99999999999999999999999999999999999999"));
        values.put(java.math.BigDecimal.class, new java.math.BigDecimal("9999999999999999999.9999999999999999999"));
        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.MIN_VALUE));
        values.put(Double.class, new Double((double)1.4012984643247149E-44));// The double values are weird. They lose precision at E-45
        values.put(Short.class, new Short(Short.MIN_VALUE));
        values.put(Byte.class, new Byte(Byte.MIN_VALUE));
        values.put(Float.class, new Float(Float.MIN_VALUE));
        values.put(java.math.BigInteger.class, new java.math.BigInteger("-99999999999999999999999999999999999999"));
        values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-9999999999999999999.9999999999999999999"));
        return values;
    
public oracle.toplink.essentials.expressions.ExpressionOperatormodOperator()
INTERNAL: Override the default MOD operator.

        ExpressionOperator result = new ExpressionOperator();
        result.setSelector(ExpressionOperator.Mod);
        Vector v = new Vector();
        v.addElement(" % ");
        result.printsAs(v);
        result.bePostfix();
        result.setNodeClass(oracle.toplink.essentials.internal.expressions.FunctionExpression.class);
        return result;
    
protected oracle.toplink.essentials.expressions.ExpressionOperatoroperatorOuterJoin()
INTERNAL: Create the outer join operator for this platform

        ExpressionOperator result = new ExpressionOperator();
        result.setSelector(ExpressionOperator.EqualOuterJoin);
        Vector v = new Vector();
        v.addElement(" =* ");
        result.printsAs(v);
        result.bePostfix();
        result.setNodeClass(RelationExpression.class);
        return result;
    
public voidprintFieldIdentityClause(java.io.Writer writer)
INTERNAL: Append the receiver's field 'identity' constraint clause to a writer.

        try {
            writer.write(" IDENTITY");
        } catch (IOException ioException) {
            throw ValidationException.fileError(ioException);
        }
    
public voidprintFieldNullClause(java.io.Writer writer)
INTERNAL: Append the receiver's field 'NULL' constraint clause to a writer.

        try {
            writer.write(" NULL");
        } catch (IOException ioException) {
            throw ValidationException.fileError(ioException);
        }
    
public voidregisterOutputParameter(java.sql.CallableStatement statement, int index, int jdbcType)
INTERNAL: This method is used to register output parameter on Callable Statements for Stored Procedures as each database seems to have a different method.

        statement.registerOutParameter(index, jdbcType, (String)getTypeStrings().get(new Integer(jdbcType)));
    
public booleanrequiresProcedureCallBrackets()
INTERNAL: USed for sp calls.

        return false;
    
public booleanrequiresProcedureCallOuputToken()
INTERNAL: Used for sp calls. Sybase must print output after output params.

        return true;
    
public booleanrequiresTypeNameToRegisterOutputParameter()
INTERNAL: Indicates whether the version of CallableStatement.registerOutputParameter method that takes type name should be used.

        return true;
    
public booleanshouldNativeSequenceAcquireValueAfterInsert()
INTERNAL: If native sequencing is being used on Sybase then the values must be retrieved after the insert. This method is to be used *ONLY* by sequencing classes

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

        return false;
    
public booleanshouldPrintOuterJoinInWhereClause()
INTERNAL: Some database require outer joins to be given in the where clause, others require it in the from clause.

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

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

        return false;
    
public booleansupportsLocalTempTables()
INTERNAL:

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

        return true;
    
public voidwriteUpdateOriginalFromTempTableSql(java.io.Writer writer, oracle.toplink.essentials.internal.helper.DatabaseTable table, java.util.Collection pkFields, java.util.Collection assignedFields)
INTERNAL:

        writer.write("UPDATE ");
        String tableName = table.getQualifiedName();
        writer.write(tableName);
        String tempTableName = getTempTableForTable(table).getQualifiedName();
        writeAutoAssignmentSetClause(writer, null, tempTableName, assignedFields);
        writer.write(" FROM ");
        writer.write(tableName);
        writer.write(", ");
        writer.write(tempTableName);
        writeAutoJoinWhereClause(writer, tableName, tempTableName, pkFields);