All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.SQLDecFloat34 Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
//
//JTOpen (IBM Toolbox for Java - OSS version)
//
//Filename: SQLDecFloat34.java
//
//The source code contained herein is licensed under the IBM Public License
//Version 1.0, which has been approved by the Open Source Initiative.
//Copyright (C) 2006 International Business Machines Corporation and
//others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Date;
/* ifdef JDBC40 
import java.sql.NClob;
import java.sql.RowId;
endif */ 
import java.sql.SQLException;
/*ifdef JDBC40 
import java.sql.SQLXML;
endif */ 
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;

//@DFA new class
final class SQLDecFloat34 extends SQLDataBase {
    static final String copyright = "Copyright (C) 2006 International Business Machines Corporation and others.";

    private static final BigDecimal default_ = BigDecimal.valueOf(0);  

    //various min/max values used for comparisons in calculating truncation etc
    private static final BigDecimal BYTE_MAX_VALUE = BigDecimal.valueOf(Byte.MAX_VALUE);

    private static final BigDecimal BYTE_MIN_VALUE = BigDecimal.valueOf(Byte.MIN_VALUE);

    private static final BigDecimal SHORT_MAX_VALUE = BigDecimal.valueOf(Short.MAX_VALUE);

    private static final BigDecimal SHORT_MIN_VALUE = BigDecimal.valueOf(Short.MIN_VALUE);

    private static final BigDecimal INTEGER_MAX_VALUE = BigDecimal.valueOf(Integer.MAX_VALUE);

    private static final BigDecimal INTEGER_MIN_VALUE = BigDecimal.valueOf(Integer.MIN_VALUE);

    private static final BigDecimal LONG_MAX_VALUE = BigDecimal.valueOf(Long.MAX_VALUE);

    private static final BigDecimal LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);

    private static final BigDecimal FLOAT_MAX_VALUE = new BigDecimal(Float.MAX_VALUE);

    private static final BigDecimal FLOAT_MIN_VALUE = new BigDecimal(-Float.MAX_VALUE); //@PDC MIN_VALUE is positive

    private static final BigDecimal DOUBLE_MAX_VALUE = new BigDecimal(Double.MAX_VALUE);

    private static final BigDecimal DOUBLE_MIN_VALUE = new BigDecimal(-Double.MAX_VALUE); //@PDC MIN_VALUE is positive
    
    private static final BigDecimal DECFLOAT34_MAX_VALUE = new BigDecimal("9.999999999999999999999999999999999E6144"); 
    
    private static final BigDecimal DECFLOAT34_MIN_VALUE = new BigDecimal("-9.999999999999999999999999999999999E6144"); 
    
    static final int DECFLOAT34_MIN_EXP = -6143;  
    

    private int precision_;  //34
       
    
    String specialValue_ = null; //since BigDecimal cannot hold "Infinity", "-Infinity" or "NaN", store them here as string

    private AS400DecFloat typeConverter_;

    private BigDecimal value_;

    private JDProperties properties_;

    private int roundingMode;
    
    private String roundingModeStr;
    
    private int vrm_;

    SQLDecFloat34( SQLConversionSettings settings, int vrm, JDProperties properties) {
      super(settings); 
      
        precision_ = 34;
        roundingModeStr = properties.getString(JDProperties.DECFLOAT_ROUNDING_MODE);
        typeConverter_ = new AS400DecFloat(precision_);
        value_ = default_;  
        vrm_ = vrm;  
        properties_ = properties;  
     
        //parse property rounding mode and save its value as int (needed for BigDecimal, MathContext etc)
        // valid rounding modes are:
        //"half even" 
        //"half up" 
        //"down" 
        //"ceiling" 
        //"floor" 
        //"half down" 
        //"up" 
        
        if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_UP))
            roundingMode = BigDecimal.ROUND_UP;
        else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_DOWN))
            roundingMode = BigDecimal.ROUND_DOWN;
        else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_CEILING))
            roundingMode = BigDecimal.ROUND_CEILING;
        else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_FLOOR))
            roundingMode = BigDecimal.ROUND_FLOOR;
        else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_HALF_UP))
            roundingMode = BigDecimal.ROUND_HALF_UP;
        else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_HALF_DOWN))
            roundingMode = BigDecimal.ROUND_HALF_DOWN;
        else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_HALF_EVEN))
            roundingMode = BigDecimal.ROUND_HALF_EVEN;
        
       
        //for MathContext, methods take strings which are same as JDProperties rounding modes with "round" added.
        roundingModeStr = "ROUND_" + roundingModeStr.toUpperCase().replace(' ', '_');
    }

    public Object clone() {
        return new SQLDecFloat34( settings_, vrm_, properties_); 
    }

    //---------------------------------------------------------//
    //                                                         //
    // CONVERSION TO AND FROM RAW BYTES //
    //                                                         //
    //---------------------------------------------------------//

    public void convertFromRawBytes(byte[] rawBytes, int offset, ConvTable ccisdConverter, boolean ignoreConversionErrors) 
            throws SQLException {
        try{
            value_ = ((BigDecimal) typeConverter_.toObject(rawBytes, offset));
            specialValue_ = null;
        } catch (ExtendedIllegalArgumentException e) {
          
            //check for NAN and INF flag exception
            if ( (specialValue_ = getSpecialValue( e.toString())) == null ) {
              if (!ignoreConversionErrors) { /*@Q2C*/
                throw e;
            }
          }
        }
    }

    public void convertToRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter) 
            throws SQLException {
        try{
            if ( specialValue_ == null)
                typeConverter_.toBytes(value_, rawBytes, offset);
            else
                typeConverter_.toBytes(specialValue_, rawBytes, offset); //Nan, Infinity, -Infinity
        } catch (ExtendedIllegalArgumentException e) {
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH, e);
        }
    }

    //---------------------------------------------------------//
    //                                                         //
    // SET METHODS //
    //                                                         //
    //---------------------------------------------------------//

    public void set(Object object, Calendar calendar, int scale) throws SQLException {
        BigDecimal bigDecimal = null;
        specialValue_ = null;
        
        if (object instanceof String) {
            try {
                if ( (specialValue_ = getSpecialValue( (String)object)) == null ) {
                    //not one of the special values, just store as BigDecimal
                    // Because the string may be using a comma for the decimal separator and we are going to
                    // store the object as a Java Bigdec, we much check and change to the default '.' notation.
                    if (((String)object).indexOf(',')!=-1) { 
                      bigDecimal = new BigDecimal (((String)object).replace(',', '.'));
                    } else { 
                      bigDecimal = new BigDecimal((String)object);
                    }
                }
            } catch (NumberFormatException e) {
                JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH, e);
            } catch (StringIndexOutOfBoundsException e) // jdk 1.3.x throws this
                                                        // instead of a NFE
            {
                JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
            }
        }

        else if (object instanceof Number) {
            if ( (specialValue_ = getSpecialValue( object.toString())) == null ) {
                //not one of the special values, just store as BigDecimal
                bigDecimal = new BigDecimal(object.toString());  //convert to string so all Number types can be passed in
            }
        }

        else if (object instanceof Boolean)
            bigDecimal = (((Boolean) object).booleanValue() == true) ? BigDecimal.valueOf(1) : BigDecimal.valueOf(0);

        else {
          if (JDTrace.isTraceOn()) {
              if (object == null) { 
                  JDTrace.logInformation(this, "Unable to assign null object");
                } else { 
                    JDTrace.logInformation(this, "Unable to assign object("+object+") of class("+object.getClass().toString()+")");
                }
          }

        
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }

        //Round by mode if necessary.         
        truncated_ = 0; outOfBounds_ = false; 
        
        //if one of the special values, then no need to check truncation
        if(specialValue_ != null)
        {
            //Nan, Infinity, -Infinity
            value_ = null;
            return;
        }
        
        //follow native and allow rounding mode to handle
        //@pdd int otherScale = bigDecimal.scale();
        //@pdd if(otherScale > ((-1) * DECFLOAT34_MIN_EXP)) //absolute of min_exp is max scale
        //@pdd    truncated_ += otherScale + DECFLOAT34_MIN_EXP; //diff in scales
    
        //get precision from bigDecimal without 0's on right side      
        //@pdd int otherPrecision =  SQLDataFactory.getPrecisionForTruncation(bigDecimal, 34);
        
        //follow native and allow rounding mode to handle
        //@pdd if(otherPrecision > precision_)
        //@pdd {
        //@pdd    int digits = otherPrecision - precision_;
        //@pdd     truncated_ += digits;
        //@pdd }
        //@pdd else                                                             
        //@pdd     truncated_ = 0; outOfBounds_ = false;   // No left side truncation, report nothing       
        //@pdd                      // (even if there was right side truncation).     
 
        value_ = AS400DecFloat.roundByMode(bigDecimal, 34, roundingModeStr);

    
        // Check the value is within range
        if (value_.compareTo(DECFLOAT34_MAX_VALUE) > 0) {
          truncated_ = 1;  outOfBounds_ = true; value_ = DECFLOAT34_MAX_VALUE;
        } else if (value_.compareTo(DECFLOAT34_MIN_VALUE) < 0) {
          truncated_ = 1;  outOfBounds_ = true; value_ = DECFLOAT34_MIN_VALUE;
        }

    
    
    }

    //---------------------------------------------------------//
    //                                                         //
    // DESCRIPTION OF SQL TYPE //
    //                                                         //
    //---------------------------------------------------------//

    public int getSQLType() {
        return SQLData.DECFLOAT;
    }

    public String getCreateParameters() {
        return null;
    }

    public int getDisplaySize() {
        return 42; //@pdc same as native
    }

    
    public String getJavaClassName() {
        return "java.math.BigDecimal";
    }

    public String getLiteralPrefix() {
        return null;
    }

    public String getLiteralSuffix() {
        return null;
    }

    public String getLocalName() {
        return "DECFLOAT";
    }

    public int getMaximumPrecision() {
        return precision_;
    }

    public int getMaximumScale() {
        return 0;
    }

    public int getMinimumScale() {
        return 0;
    }

    public int getNativeType() {
        return 996;
    }

    public int getPrecision() {
        return precision_;
    }

    public int getRadix() {
        return 10;  //decimal base (4 bits per digit)
    }

    public int getScale() {
        return 0;
    }

    public int getType() {
        return java.sql.Types.OTHER;  //decfloat is not sql type right now.
    }

    public String getTypeName() {
        return "DECFLOAT";
    }

    public boolean isSigned() {
        return true;
    }

    public boolean isText() {
        return false;
    }

    public int getActualSize() {
        if(specialValue_ == null)
            return SQLDataFactory.getPrecision( value_ );
        else
            return specialValue_.length();
    }

    public int getTruncated() {
        return truncated_;
    }
    public boolean getOutOfBounds() {
      return outOfBounds_; 
    }

    //---------------------------------------------------------//
    //                                                         //
    // CONVERSIONS TO JAVA TYPES //
    //                                                         //
    //---------------------------------------------------------//


    public BigDecimal getBigDecimal(int scale) throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        //remove this when BigDecimal supports Nan, Inf, -Inf
        if(specialValue_ != null){
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
            return null;
        }
        
        if(scale >= 0)
        {
            if(scale >= value_.scale())
            {
                return value_.setScale(scale);
            }
            else
            {
                truncated_ = value_.scale() - scale;
                return value_.setScale(scale, roundingMode);
            }
        }
        else
            return value_;
    }

    public InputStream getBinaryStream() throws SQLException {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }

    public Blob getBlob() throws SQLException {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }

    public boolean getBoolean() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
            return false; //false seems logical here
        }
        
        return (value_.compareTo(BigDecimal.valueOf(0)) != 0);
    }

    public byte getByte() throws SQLException {
        //this code is similar to SQLDouble, and then in inner iff, it is like
        // SQLDecimal
        truncated_ = 0; outOfBounds_ = false; 

        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
          //@snan snan is not yet supported, return as regular nan
            if(specialValue_.indexOf("-SNaN") != -1)  //@snan
                return (new Double("-NaN")).byteValue();
            else if(specialValue_.indexOf("SNaN") != -1)  //@snan
                return (new Double("NaN")).byteValue();
            else 
                return (new Double(specialValue_)).byteValue();
        }
        
        if (value_.compareTo(BYTE_MAX_VALUE) > 0 || value_.compareTo(BYTE_MIN_VALUE) < 0) {
            if (value_.compareTo(SHORT_MAX_VALUE) > 0 || value_.compareTo(SHORT_MIN_VALUE) < 0) {
                if (value_.compareTo(INTEGER_MAX_VALUE) > 0 || value_.compareTo(INTEGER_MIN_VALUE) < 0) {
                    if (value_.compareTo(LONG_MAX_VALUE) > 0 || value_.compareTo(LONG_MIN_VALUE) < 0) {
                        truncated_ = 15;  //16 bytes - 1;
                        outOfBounds_=true;
                    } else {
                        truncated_ = 7; outOfBounds_=true;
                    }
                } else {
                    truncated_ = 3; outOfBounds_=true;
                }
            } else {
                truncated_ = 1; outOfBounds_=true;
            }
        }
        return value_.byteValue();
    }

    public byte[] getBytes() throws SQLException {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }


    public Date getDate(Calendar calendar) throws SQLException {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }

    public double getDouble() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 

        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
            //@snan snan is not yet supported, return as regular nan
            if(specialValue_.indexOf("-SNaN") != -1)  //@snan
                return (new Double("-NaN")).doubleValue();
            else if(specialValue_.indexOf("SNaN") != -1)  //@snan
                return (new Double("NaN")).doubleValue();
            else 
                return (new Double(specialValue_)).doubleValue();
        }
        
        if (value_.compareTo(DOUBLE_MAX_VALUE) > 0 || value_.compareTo(DOUBLE_MIN_VALUE) < 0) {
            truncated_ = 8;  //16 bytes - 8;
            outOfBounds_=true;
        }

        return value_.doubleValue();
    }

    public float getFloat() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
            //@snan snan is not yet supported, return as regular nan
            if(specialValue_.indexOf("-SNaN") != -1)  //@snan
                return (new Float("-NaN")).floatValue();
            else if(specialValue_.indexOf("SNaN") != -1)  //@snan
                return (new Float("NaN")).floatValue();
            else
                return (new Float(specialValue_)).floatValue();
        }
        
        if (value_.compareTo(FLOAT_MAX_VALUE) > 0 || value_.compareTo(FLOAT_MIN_VALUE) < 0) {
            if (value_.compareTo(DOUBLE_MAX_VALUE) > 0 || value_.compareTo(DOUBLE_MIN_VALUE) < 0) {
                truncated_ = 12;  //16 bytes - 4;
                outOfBounds_=true;
            } else {
                truncated_ = 4; outOfBounds_=true;
            }
        }
        return value_.floatValue();
    }

    public int getInt() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 

        //NaN, Infinity, -Infinity
        //remove this when Integer supports Nan, Inf, -Inf
        if(specialValue_ != null){
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
        
        if (value_.compareTo(INTEGER_MAX_VALUE) > 0 || value_.compareTo(INTEGER_MIN_VALUE) < 0) {
            if (value_.compareTo(LONG_MAX_VALUE) > 0 || value_.compareTo(LONG_MIN_VALUE) < 0) {
                truncated_ = 12;  //16 bytes - 4;
                outOfBounds_=true;
            } else {
                truncated_ = 4; outOfBounds_=true;
            }
        }

        return value_.intValue();
    }

    public long getLong() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        //remove this when Long supports Nan, Inf, -Inf
        if(specialValue_ != null){
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
        
        if( value_.compareTo(LONG_MAX_VALUE) > 0 || value_.compareTo(LONG_MIN_VALUE) < 0)
        {
            truncated_ = 8;  //16 bytes - 8;
            outOfBounds_=true;
        }
        return value_.longValue();
    }

    public Object getObject() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        //in this case, return String object instead of throwing exception
        //remove this when BigDecimal supports Nan, Inf, -Inf
        if(specialValue_ != null){
            return specialValue_;
        }
        
        return value_;
    }

    public short getShort() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 

        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
        
        if (value_.compareTo(SHORT_MAX_VALUE) > 0 || value_.compareTo(SHORT_MIN_VALUE) < 0) {
            if (value_.compareTo(INTEGER_MAX_VALUE) > 0 || value_.compareTo(INTEGER_MIN_VALUE) < 0) {
                if (value_.compareTo(LONG_MAX_VALUE) > 0 || value_.compareTo(LONG_MIN_VALUE) < 0) {
                    truncated_ = 14;  //16 bytes - 2;
                    outOfBounds_=true;
                } else {
                    truncated_ = 6;
                    outOfBounds_=true;
                }
            } else {
                truncated_ = 2;
                outOfBounds_=true;
            }
        }

        return value_.shortValue();
    }

    public String getString() throws SQLException {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
            return specialValue_;
        }
        
        String stringRep = value_.toString();
        int decimal = stringRep.indexOf('.');
        if(decimal == -1)
            return stringRep;
        else
            return stringRep.substring(0, decimal)
            + settings_.getDecimalSeparator()
            + stringRep.substring(decimal+1);
     }

    public Time getTime(Calendar calendar) throws SQLException {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }

    public Timestamp getTimestamp(Calendar calendar) throws SQLException {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }

    
    /** Helper method to return string value of special values that
     *  cannot be held in current BigDecimal objects.
     *  Valid inputs = "NaN", "NAN", "+NaN", "-NaN", "QNaN", "+QNaN", "-QNaN", "SNaN", "+SNaN", "-SNaN", "INF", "+INF", 
     *  "-INF", "Infinity", "+Infinity", "-Infinity"
     */
    private String getSpecialValue(String number){
        //use indexOf() so that we can use this method for exception text from AS400DecFloat also
        int startOfValue = -1;
        //@snan
        if ( (startOfValue = number.toUpperCase().indexOf("SNAN")) != -1 ){ 
            //check for sign
            if ( ((startOfValue > 0 ) && (number.charAt(startOfValue - 1) == '-') ) )
                return "-SNaN"; //no representaion in Double
            else
                return "SNaN"; //no representaion in Double
        }
        else if ( (startOfValue = number.toUpperCase().indexOf("NAN")) != -1 ){ 
            //check for sign
            if ( ((startOfValue > 0 ) && (number.charAt(startOfValue - 1) == '-') )
                    || ((startOfValue > 1 ) && (number.charAt(startOfValue - 2) == '-')) )
                return "-NaN"; //no representaion in Double
            return String.valueOf(Double.NaN);
        }
        else if ( (startOfValue = number.toUpperCase().indexOf("INF")) != -1){
            //check for sign
            if ( (startOfValue != 0 ) && (number.charAt(startOfValue - 1) == '-'))
                return String.valueOf(Double.NEGATIVE_INFINITY);
            else
                return String.valueOf(Double.POSITIVE_INFINITY);
        }
        else
            return null; //not a special value
    }

    
    
    //@pda jdbc40
    public String getNString() throws SQLException
    {
        truncated_ = 0; outOfBounds_ = false; 
        
        //NaN, Infinity, -Infinity
        if(specialValue_ != null){
            return specialValue_;
        }
        
        String stringRep = value_.toString();
        int decimal = stringRep.indexOf('.');
        if(decimal == -1)
            return stringRep;
        else
            return stringRep.substring(0, decimal)
            + settings_.getDecimalSeparator()
            + stringRep.substring(decimal+1);
    }

    //@pda jdbc40
    /* ifdef JDBC40
    public RowId getRowId() throws SQLException
    {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }
   endif */ 
    //@pda jdbc40
    /* ifdef JDBC40 
    public SQLXML getSQLXML() throws SQLException
    {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }
    endif */ 
    
    
    public void saveValue() {
      savedValue_ = value_; 
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy