db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r179254 - in /incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types: BigIntegerDecimal.java BinaryDecimal.java CDCDataValueFactory.java NumberDataType.java SQLDecimal.java
Date Tue, 31 May 2005 18:28:58 GMT
Author: djd
Date: Tue May 31 11:28:57 2005
New Revision: 179254

URL: http://svn.apache.org/viewcvs?rev=179254&view=rev
Log:
Add the initial implementations of a DECIMAL data value
factory and DECIMAL data type for J2ME/CDC/Foundation.
BigIntegerDecimal is basically working but some additional
work is needed to pass the floattypes test.
Not enabled as a running module yet.

Added:
    incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BigIntegerDecimal.java
  (with props)
    incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BinaryDecimal.java
  (with props)
Modified:
    incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CDCDataValueFactory.java
    incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/NumberDataType.java
    incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLDecimal.java

Added: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BigIntegerDecimal.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BigIntegerDecimal.java?rev=179254&view=auto
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BigIntegerDecimal.java
(added)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BigIntegerDecimal.java
Tue May 31 11:28:57 2005
@@ -0,0 +1,501 @@
+/*
+
+   Derby - Class org.apache.derby.iapi.types.BigIntegerDecimal
+
+   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.iapi.types;
+
+import java.math.BigInteger;
+import java.sql.Types;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+/**
+ * DECIMAL support using the immutable java.math.BigInteger to perform arithmetic
+ * and conversions. Extends BinaryDecimal to use the base
+ * support of that class. J2ME/CDC/Foundation includes BigInteger.
+ * 
+ * A BigInteger is used in calculations etc. to represent the integral unscaled value.
+ * It is simply created from new BigInteger(data2c). No additional instance fields
+ * are used by this class, a possible enhancement would be to keep the BigInteger around
+ * but would require calls from the parent class to reset state etc.
+ */
+
+public final class BigIntegerDecimal extends BinaryDecimal
+{
+	private static final BigInteger TEN = BigInteger.valueOf(10L);
+	private static final BigInteger MAXLONG_PLUS_ONE = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
+	private static final BigInteger MINLONG_MINUS_ONE = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE);
+	
+	public BigIntegerDecimal() {
+	}
+
+	public DataValueDescriptor getNewNull()
+	{
+		return new BigIntegerDecimal();
+	}	
+	
+	public long getLong() throws StandardException
+	{
+		if (isNull())
+			return 0L;
+		
+		BigInteger bi = new BigInteger(data2c);
+		
+		boolean rangeOk = false;
+		if ((bi.compareTo(BigIntegerDecimal.MAXLONG_PLUS_ONE) < 0)
+			&& (bi.compareTo(BigIntegerDecimal.MINLONG_MINUS_ONE) > 0))
+			rangeOk = true;
+			
+		
+		for (int i = 0; i < sqlScale; i++)
+		{
+			bi = bi.divide(BigIntegerDecimal.TEN);
+			if (rangeOk)
+				continue;
+			
+			if ((bi.compareTo(BigIntegerDecimal.MAXLONG_PLUS_ONE) < 0)
+					&& (bi.compareTo(BigIntegerDecimal.MINLONG_MINUS_ONE) > 0))
+					rangeOk = true;
+			}
+		
+		// TODO Range checking
+		if (!rangeOk)
+			throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "BIGINT");
+		
+		return bi.longValue();
+	}
+
+	public float getFloat() throws StandardException
+    {
+		if (isNull())
+			return 0.0f;
+		return Float.parseFloat(getString());
+
+		// TODO - correct implementation
+	}
+	public double getDouble() throws StandardException
+    {
+		if (isNull())
+			return 0.0;
+		return Double.parseDouble(getString());
+		// TODO - correct implementation
+	}	
+	
+
+	/**
+	 * Set the value from a String, the format is
+	 * nnnn
+	 * 
+	 * Scale always set to zero.
+	 */
+	public void setValue(String theValue) throws StandardException
+	{
+		if (theValue == null)
+		{
+			restoreToNull();
+			return;
+		}
+		
+		theValue = theValue.trim();
+		
+		int dot = theValue.indexOf('.');
+		int ePosition = theValue.indexOf('e');
+		if (ePosition == -1)
+			ePosition = theValue.indexOf('E');
+		
+		
+		int scale = 0;
+		try
+		{
+			// handle the exponent
+			if (ePosition != -1)
+			{
+				if (dot > ePosition)
+					throw invalidFormat();
+				
+				//	TODO Need to handle a + sign in the exponent
+				scale = -1 * Integer.parseInt(theValue.substring(ePosition + 1));
+				theValue = theValue.substring(0, ePosition);
+			}
+			
+			if (dot != -1)
+			{
+				// remove the dot from the string
+				String leading = theValue.substring(0, dot);
+				
+				scale += (theValue.length() - (dot + 1));
+				
+				theValue = leading.concat(theValue.substring(dot + 1, theValue.length()));
+			}
+			
+			if (scale < 0)
+			{
+				for (int i = scale; i < 0; i++)
+					theValue = theValue.concat("0");
+				scale = 0;
+			}
+			
+			BigInteger bi = new BigInteger(theValue);		
+			data2c = bi.toByteArray();
+			sqlScale = scale;
+			
+			//System.out.println("setValue unscaled " + bi + "scale " + sqlScale);
+
+		} catch (NumberFormatException nfe) 
+		{
+		    throw invalidFormat();
+		}		
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see org.apache.derby.iapi.types.DataValueDescriptor#getString()
+	 */
+	public String getString() {
+		
+		if (isNull())
+			return null;
+		
+		// TODO - correct impl
+		String unscaled = new BigInteger(data2c).toString();
+		//System.out.println("Scale" + sqlScale + " unv " + unscaled);
+		
+		if (sqlScale == 0)
+			return unscaled;
+
+		boolean isNegative = this.isNegative();
+		
+		if (sqlScale >= (unscaled.length() - (isNegative ? 1 : 0)))
+		{	
+			if (isNegative)
+				unscaled = unscaled.substring(1);
+
+			String val = isNegative ? "-0." : "0.";
+			for (int i = sqlScale - unscaled.length(); i > 0; i--)
+				val = val.concat("0");
+			return val.concat(unscaled);
+		}
+		
+		String val = unscaled.substring(0, unscaled.length() - sqlScale);
+		val = val.concat(".");
+		return val.concat(unscaled.substring(unscaled.length() - sqlScale, unscaled.length()));
+	}
+	
+	/**
+	 * Return the SQL precision of this value.
+	 */
+	public int getDecimalValuePrecision()
+	{
+		if (isNull())
+			return 0;
+		
+		BigInteger bi = new BigInteger(data2c);
+		
+		if (BigInteger.ZERO.equals(bi))
+			return 0;
+		
+		int precision = bi.toString().length();
+		
+		if (this.isNegative())
+			precision--;
+		
+		return precision;
+	}
+	
+
+	/**
+	 * Compare two non-null NumberDataValues using DECIMAL arithmetic.
+	 * Uses add() to perform the calculation.
+	 */
+	protected int typeCompare(DataValueDescriptor arg) throws StandardException {
+		
+		BigIntegerDecimal obid = getBID(arg);
+		
+		// need to align scales to perform comparisions
+		int tscale = getDecimalValueScale();
+		int oscale = obid.getDecimalValueScale();
+		
+		BigInteger tbi = new BigInteger(data2c);
+		BigInteger obi = new BigInteger(obid.data2c);
+		
+		if (tscale < oscale)
+			tbi = BigIntegerDecimal.rescale(tbi, oscale - tscale);
+		else if (oscale < tscale)
+			obi = BigIntegerDecimal.rescale(obi, tscale - oscale);
+		
+		return tbi.compareTo(obi);
+	}
+
+	/**
+	 * Add two non-null NumberDataValues using DECIMAL arithmetic.
+	 * Uses add() to perform the calculation.
+	 */
+	public NumberDataValue plusNN(NumberDataValue left, NumberDataValue right, NumberDataValue
result)
+	throws StandardException {
+		
+		BinaryDecimal resultBid = (BinaryDecimal) result;
+		if (resultBid == null)
+			resultBid = new BigIntegerDecimal();
+				
+		BigIntegerDecimal lbid = getBID(left);
+		BigIntegerDecimal rbid = getBID(right);
+		
+		// need to align scales to perform plus
+		int lscale = lbid.getDecimalValueScale();
+		int rscale = rbid.getDecimalValueScale();
+		
+		BigInteger bi1 = new BigInteger(lbid.data2c);
+		BigInteger bi2 = new BigInteger(rbid.data2c);
+		
+		int tscale = lscale;
+		if (lscale < rscale)
+		{
+			bi1 = BigIntegerDecimal.rescale(bi1, rscale - lscale);
+			tscale = rscale;
+		}
+		else if (rscale < lscale)
+		{
+			bi2 = BigIntegerDecimal.rescale(bi2, lscale - rscale);
+		}
+			
+		
+
+		bi1 = bi1.add(bi2);
+		
+		resultBid.data2c = bi1.toByteArray();
+		resultBid.sqlScale = tscale;
+		
+		return resultBid;
+	}
+
+	/**
+	 * Negate the number.
+	 * @see org.apache.derby.iapi.types.NumberDataValue#minus(org.apache.derby.iapi.types.NumberDataValue)
+	 */
+	public NumberDataValue minus(NumberDataValue result) throws StandardException {
+		
+		if (result == null)
+			result = (NumberDataValue) getNewNull();
+
+		if (isNull())
+			result.setToNull();
+		else
+		{
+			BinaryDecimal rbd = (BinaryDecimal) result;
+			
+			BigInteger bi = new BigInteger(data2c);
+			// scale remains unchanged.
+			rbd.data2c = bi.negate().toByteArray();
+			rbd.sqlScale = sqlScale;
+		
+		}
+			
+		return result;
+	}
+
+
+	/**
+	 * Multiple two non-null NumberDataValues using DECIMAL arithmetic.
+	 * Uses BigInteger.multipy() to perform the calculation.
+	 * Simply multiply the unscaled values and add the scales, proof:
+	 
+	 <code>
+	 left * right
+	 = (left_unscaled * 10^-left_scale) * (right_unscaled * 10^-right_scale)
+	 = (left_unscaled * 10^-left_scale) * (right_unscaled * 10^-right_scale)
+	 = (left_unscaled * right_unscaled) * 10^-(left_scale + right_scale)
+	 </code>
+	 */
+	public NumberDataValue timesNN(NumberDataValue left, NumberDataValue right, NumberDataValue
result)
+	throws StandardException
+	{
+		BigIntegerDecimal resultBid = (BigIntegerDecimal) result;
+		if (resultBid == null)
+			resultBid = new BigIntegerDecimal();
+				
+		BigIntegerDecimal lbid = getBID(left);
+		BigIntegerDecimal rbid = getBID(right);
+
+		BigInteger lbi = new BigInteger(lbid.data2c);
+		BigInteger rbi = new BigInteger(rbid.data2c);
+		
+		rbi = lbi.multiply(rbi);	
+		resultBid.data2c = rbi.toByteArray();
+		resultBid.sqlScale = lbid.getDecimalValueScale() + rbid.getDecimalValueScale();
+		
+		return resultBid;
+	}
+
+	/**
+	 * Divide two non-null NumberDataValues using DECIMAL arithmetic.
+	 * Uses divide() to perform the calculation.
+	 * Simply multiply the unscaled values and subtract the scales, proof:
+	 
+	 <code>
+		left / right
+		= (left_unscaled * 10^-left_scale) / (right_unscaled * 10^-right_scale)
+		= (left_unscaled / right_unscaled) * (10^-left_scale / 10^-right_scale)
+		= (left_unscaled / right_unscaled) * (10^-(left_scale-right_scale))
+	</code>
+	 */
+	public NumberDataValue divideNN(NumberDataValue left, NumberDataValue right,
+			NumberDataValue result, int scale)
+	throws StandardException
+	{
+		BinaryDecimal resultBid = (BinaryDecimal) result;
+		if (resultBid == null)
+			resultBid = new BigIntegerDecimal();
+				
+		BigIntegerDecimal lbid = getBID(left);
+		BigIntegerDecimal rbid = getBID(right);
+
+		BigInteger lbi = new BigInteger(lbid.data2c);
+		BigInteger rbi = new BigInteger(rbid.data2c);
+		
+		if (BigInteger.ZERO.equals(rbi))
+			throw  StandardException.newException(SQLState.LANG_DIVIDE_BY_ZERO);
+				
+		int lscale = lbid.getDecimalValueScale();
+		int rscale = rbid.getDecimalValueScale();
+				
+		if (scale >= 0)
+		{
+			if (lscale < (scale + rscale)) {
+				lbi = BigIntegerDecimal.rescale(lbi, scale + rscale - lscale);
+				lscale = scale + rscale;
+			}
+		}
+		
+		rbi = lbi.divide(rbi);
+		resultBid.sqlScale = lscale - rscale;
+		
+		if (resultBid.sqlScale < 0)
+		{
+			rbi = BigIntegerDecimal.rescale(rbi, -resultBid.sqlScale);
+			resultBid.sqlScale = 0;
+		}
+			
+		resultBid.data2c = rbi.toByteArray();
+		
+		return resultBid;
+	}	
+
+	public void normalize(
+			DataTypeDescriptor desiredType,
+			DataValueDescriptor source)
+					throws StandardException
+	{
+		int desiredScale = desiredType.getScale();
+		int desiredPrecision = desiredType.getPrecision();
+
+		setFrom(source);
+		setWidth(desiredPrecision, desiredScale, true);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.apache.derby.iapi.types.VariableSizeDataValue#setWidth(int, int, boolean)
+	 */
+	public DataValueDescriptor setWidth(int desiredPrecision, int desiredScale,
+			boolean errorOnTrunc) throws StandardException
+	{
+		if (isNull())
+			return this;
+			
+		int deltaScale = desiredScale - sqlScale;
+		if (desiredPrecision != IGNORE_PRECISION)
+		{
+			int currentPrecision = getDecimalValuePrecision();
+	
+			int futurePrecision = currentPrecision + deltaScale;
+			
+			if (futurePrecision > desiredPrecision)
+				throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, 
+						("DECIMAL/NUMERIC("+desiredPrecision+","+desiredScale+")"));
+		}
+		
+		if (deltaScale == 0)
+			return this;
+		
+		BigInteger bi = new BigInteger(data2c);
+		
+		bi = BigIntegerDecimal.rescale(bi, deltaScale);
+
+		data2c = bi.toByteArray();
+		sqlScale = desiredScale;		
+     	return this;
+	}
+	
+	/**
+	 * Obtain a BinaryDecimal that represents the passed in value.
+	 */
+	private BigIntegerDecimal getBID(DataValueDescriptor value)
+	throws StandardException
+	 {
+		switch (value.typeToBigDecimal()) {
+		case Types.DECIMAL:
+			return (BigIntegerDecimal) value;
+		case Types.CHAR: {
+			BigIntegerDecimal bid = new BigIntegerDecimal();
+			bid.setValue(value.getString());
+			return bid;
+		}
+
+		case Types.BIGINT: {
+			BigIntegerDecimal bid = new BigIntegerDecimal();
+			bid.setValue(value.getLong());
+			return bid;
+		}
+		default:
+			if (SanityManager.DEBUG)
+				SanityManager.THROWASSERT("invalid return from "
+						+ value.getClass() + ".typeToBigDecimal() "
+						+ value.typeToBigDecimal());
+			return null;
+		}
+	}	
+	/**
+	 * Rescale a BigInteger, a positive delta means the scale is increased, zero
+	 * no change and negative decrease of scale. It is up to the caller to
+	 * manage the actual scale of the value, e.g. don't allow the scale to go
+	 * negative.
+	 * 
+	 * @param bi
+	 *            value to be rescaled
+	 * @param deltaScale
+	 *            change of scale
+	 * @return rescaled value
+	 */
+	private static BigInteger rescale(BigInteger bi, int deltaScale) {
+		if (deltaScale == 0)
+			return bi;
+		if (deltaScale > 0) {
+			// scale increasing, e.g. 10.23 to 10.2300		
+			for (int i = 0; i < deltaScale; i++)
+				bi = bi.multiply(BigIntegerDecimal.TEN);
+
+		} else if (deltaScale < 0) {
+			// scale decreasing, e.g. 10.2345 to 10.23
+			for (int i = deltaScale; i < 0; i++)
+				bi = bi.divide(BigIntegerDecimal.TEN);
+		}
+		return bi;
+	}
+}

Propchange: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BigIntegerDecimal.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BinaryDecimal.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BinaryDecimal.java?rev=179254&view=auto
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BinaryDecimal.java
(added)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BinaryDecimal.java
Tue May 31 11:28:57 2005
@@ -0,0 +1,686 @@
+/*
+
+   Derby - Class org.apache.derby.iapi.types.BinaryDecimal
+
+   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.iapi.types;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.io.ArrayInputStream;
+import org.apache.derby.iapi.services.io.StoredFormatIds;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+/**
+ * SQL DECIMAL using raw data. Provides the basis for the
+ * CDCDecimal implementation.
+ * <P>
+ * The on-disk format must match the SQLDecimal format so that
+ * databases are portable across J2ME and J2SE environments.
+ * <P>
+ * The format of the byte array is defined by the return of the
+ * java.math.BigInteger.toByteArray:, extracted here.
+ * 
+ * Returns a byte array containing the two's-complement representation of this BigInteger.
+ * The byte array will be in big-endian byte-order: the most significant byte is in the zeroth
element.
+ *
+ * This is the format for DECIMAL even if BigINteger is not available, e.g. OSGi ee.minimum.
+ */
+
+abstract class BinaryDecimal extends NumberDataType
+	implements VariableSizeDataValue
+{
+	/**
+	 * An unscaled value of 1 in two's complement
+	 */
+	private static final byte[] ONE_2C = {(byte) 0x01};
+	
+	/**
+	 * The unscaled value as a binary two's complement array.
+	*/
+	protected byte[]		data2c;
+
+	/**
+	 * The SQL scale, zero or positive, of the value
+	 */
+	protected int			sqlScale;
+	
+	
+	BinaryDecimal() {
+	}
+	
+	/*
+	** Methods about the DECIMAL type itself.
+	*/
+
+	/**
+	 * DECIMAL implementation.
+	 * Use DECIMAL to indicate to self that another
+	 * passed in value is an instance of this type.
+	 */
+	public final int typeToBigDecimal()
+	{
+		return java.sql.Types.DECIMAL;
+	}
+
+	/** @see DataValueDescriptor#typePrecedence */
+	public final int typePrecedence()
+	{
+		return TypeId.DECIMAL_PRECEDENCE;
+	}
+	
+	/* Return DECIMAL as the type name.
+	 * @see org.apache.derby.iapi.types.DataValueDescriptor#getTypeName()
+	 */
+	public final String getTypeName() {
+		return TypeId.DECIMAL_NAME;
+	}
+
+	/**
+	 * Return my format identifier.
+	 * 
+	 * @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
+	 */
+	public final int getTypeFormatId() {
+		return StoredFormatIds.SQL_DECIMAL_ID;
+	}	
+	
+	/*
+	** NULL handling.
+	*/
+
+	/**
+	 * see if the decimal value is null.
+	 */
+	public boolean isNull()
+	{
+		return data2c == null;
+	}	
+
+	public void restoreToNull()
+	{
+		data2c = null;
+	}
+
+	/* Check the leftmost bit, if set the value is negative.
+	 * NULL values return false.
+	 * @see org.apache.derby.iapi.types.NumberDataType#isNegative()
+	 */
+	protected boolean isNegative() {
+		return !isNull() && ((data2c[0] & 0x80) != 0);
+	}
+	
+	
+	/*
+	** Methods to convert values into this DECIMAL
+	*/
+	
+	/**
+	 * Set the value from a long.
+	 */
+	public void setValue(long theValue)
+	{
+		byte[] rd = data2c;
+		if (rd == null || rd.length < 8)
+			rd = new byte[8];
+		
+		rd[0] = (byte)(theValue >>> 56);
+		rd[1] = (byte)(theValue >>> 48);
+		rd[2] = (byte)(theValue >>> 40);
+		rd[3] = (byte)(theValue >>> 32);
+		rd[4] = (byte)(theValue >>> 24);
+		rd[5] = (byte)(theValue >>> 16);
+		rd[6] = (byte)(theValue >>> 8);
+		rd[7] = (byte) theValue;
+		
+		if (SanityManager.DEBUG)
+		{
+			data2c = rd;
+			sqlScale = 0;
+			try {
+			if (theValue != getLong())
+				SanityManager.THROWASSERT("BinaryDecimal invalid long conversion before reduce in "
+						+ theValue + " out " + getLong());
+			}
+			catch (StandardException se)
+			{
+				SanityManager.THROWASSERT(se.toString());
+			}
+		}
+		
+		data2c = BinaryDecimal.reduceBytes2c(rd, 0, 8);
+		sqlScale = 0;
+		
+		if (SanityManager.DEBUG)
+		{
+			try {
+			if (theValue != getLong())
+				SanityManager.THROWASSERT("BinaryDecimal invalid long conversion after reduce in "
+						+ theValue + " out " + getLong());
+			}
+			catch (StandardException se)
+			{
+				SanityManager.THROWASSERT(se.toString());
+			}
+		}	
+	}
+
+	/**
+	 * Set the value from an int, just copy 'byte-by-byte'
+	 * from the int to a four byte array. Then reduce.
+	 * @see NumberDataValue#setValue
+	 */
+	public final void setValue(int theValue)
+	{
+		byte[] rd = data2c;
+		if (rd == null || rd.length < 4)
+			rd = new byte[4];
+		
+		rd[0] = (byte)(theValue >>> 24);
+		rd[1] = (byte)(theValue >>> 16);
+		rd[2] = (byte)(theValue >>> 8);
+		rd[3] = (byte) theValue;
+			
+		data2c = BinaryDecimal.reduceBytes2c(rd, 0, 4);
+		sqlScale = 0;
+	}
+	
+	/**
+	 * Convert from a double, normalize and then convert as a String.
+	 *
+	 * @exception StandardException		Thrown on error
+	 */
+	public final void setValue(double theValue) throws StandardException
+	{
+		setCoreValue(NumberDataType.normalizeDOUBLE(theValue));
+	}
+
+	/**
+	 * Convert from a float, normalize and then convert as a String.
+	 *
+	 */
+	public final void setValue(float theValue)
+		throws StandardException
+	{
+		setCoreValue((double)NumberDataType.normalizeREAL(theValue));
+	}
+	
+	private void setCoreValue(double theValue) throws StandardException {
+		setValue(Double.toString(theValue));
+	}
+	
+	/**
+	Called when setting a DECIMAL value internally or from
+	through a procedure or function.
+	Handles long in addition to BigDecimal to handle
+	identity being stored as a long but returned as a DECIMAL.
+	*/
+	public void setValue(Number theValue) throws StandardException
+	{
+		if (SanityManager.ASSERT)
+		{
+			if (theValue != null &&
+				!(theValue instanceof java.lang.Long))
+				SanityManager.THROWASSERT("BinaryDecimal.setValue(Number) passed a " + theValue.getClass());
+		}
+	
+		if (theValue == null)
+			setToNull();
+		else
+			setValue(theValue.longValue());
+	}
+	
+	/**
+	 * Set this DECIMAL value from another DataValueDescriptor
+	 */
+	protected void setFrom(DataValueDescriptor dvd) throws StandardException
+	{
+	
+		switch (dvd.typeToBigDecimal())
+		{
+			case Types.CHAR:
+			case Types.DECIMAL: // TODO : direct copy
+				
+				setValue(dvd.getString());
+				break;
+			case Types.BIGINT:
+				setValue(dvd.getLong());
+			    break;
+			default:
+				super.setFrom(dvd);
+		}
+	}
+	/*
+	** Methods to get a value from this DECIMAL
+	*/
+
+	/**
+	 * Return a int from this value.
+	 * 
+	 * @exception StandardException
+	 *                this value is out of range for an int
+	 */
+	public final int getInt() throws StandardException
+	{
+		if (isNull())
+			return 0;
+
+		try {
+			long lv = getLong();
+
+			if ((lv >= Integer.MIN_VALUE) && (lv <= Integer.MAX_VALUE))
+				return (int) lv;
+
+		} catch (StandardException se) {
+			// out of range error but with incorrect messgae (BIGINT)
+			// fall through to correct message
+		}
+
+		throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER");
+	}
+
+	/**
+	 * Return a byte from this value.
+	 * 
+	 * @exception StandardException
+	 *                this value is out of range for a short
+	 */
+	public final byte getByte() throws StandardException {
+		if (isNull())
+			return (byte) 0;
+
+		try {
+			long lv = getLong();
+
+			if ((lv >= Byte.MIN_VALUE) && (lv <= Byte.MAX_VALUE))
+				return (byte) lv;
+
+		} catch (StandardException se) {
+			// out of range error but with incorrect messgae (BIGINT)
+			// fall through to correct message
+		}
+
+		throw StandardException.newException(
+				SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "TINYINT");
+	}
+
+	/**
+	 * Return a short from this value.
+	 * @exception StandardException this value is out of range for a short
+	 */
+	public final short getShort() throws StandardException	
+	{
+		if (isNull())
+			return (short)0;
+
+		try {
+			long lv = getLong();
+
+			if ((lv >= Short.MIN_VALUE) && (lv <= Short.MAX_VALUE))
+				return (short) lv;
+
+		} catch (StandardException se) {
+			// out of range error but with incorrect messgae (BIGINT)
+			// fall through to correct message
+		}
+
+		throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "SMALLINT");
+	}
+	
+	
+	/*
+	** DECIMAL arithmetic methods.
+	*/
+	
+	/**
+	 * This method implements the + operator for DECIMAL.
+	 *
+	 * @param addend1	One of the addends
+	 * @param addend2	The other addend
+	 * @param result	The result of a previous call to this method, null
+	 *					if not called yet
+	 *
+	 * @return	A SQLDecimal containing the result of the addition
+	 *
+	 * @exception StandardException		Thrown on error
+	 */
+
+	public final NumberDataValue plus(NumberDataValue addend1,
+							NumberDataValue addend2,
+							NumberDataValue result)
+				throws StandardException
+	{
+		if (result == null)
+		{
+			result = (NumberDataValue) getNewNull();
+		}
+
+		if (addend1.isNull() || addend2.isNull())
+		{
+			result.setToNull();
+			return result;
+		}
+
+		return plusNN(addend1, addend2, result);
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.apache.derby.iapi.types.NumberDataValue#times(org.apache.derby.iapi.types.NumberDataValue,
org.apache.derby.iapi.types.NumberDataValue, org.apache.derby.iapi.types.NumberDataValue)
+	 */
+	public final NumberDataValue times(NumberDataValue left, NumberDataValue right, NumberDataValue
result)
+	throws StandardException
+	{
+		if (result == null)
+		{
+			result = (NumberDataValue) getNewNull();
+		}
+
+		if (left.isNull() || right.isNull())
+		{
+			result.setToNull();
+			return result;
+		}		
+		return timesNN(left, right, result);
+	}
+	public NumberDataValue divide(NumberDataValue dividend,
+			 NumberDataValue divisor,
+			 NumberDataValue result)
+throws StandardException
+{
+return divide(dividend, divisor, result, -1);
+}
+
+	/**
+	 * This method implements the / operator for BigDecimal/BigDecimal
+	 *
+	 * @param dividend	The numerator
+	 * @param divisor	The denominator
+	 * @param result	The result of a previous call to this method, null
+	 *					if not called yet
+	 * @param scale		The result scale, if < 0, calculate the scale according
+	 *					to the actual values' sizes
+	 *
+	 * @return	A SQLDecimal containing the result of the division
+	 *
+	 * @exception StandardException		Thrown on error
+	 */
+
+	public final NumberDataValue divide(NumberDataValue dividend,
+							 NumberDataValue divisor,
+							 NumberDataValue result,
+							 int scale)
+				throws StandardException
+	{
+		if (result == null)
+		{
+			result = (NumberDataValue) getNewNull();
+		}
+
+		if (dividend.isNull() || divisor.isNull())
+		{
+			result.setToNull();
+			return result;
+		}
+		
+		return divideNN(dividend, divisor, result, scale);
+	}	
+	public final NumberDataValue minus(NumberDataValue left, NumberDataValue right, NumberDataValue
result)
+	throws StandardException
+	{
+		if (result == null)
+		{
+			result = (NumberDataValue) getNewNull();
+		}
+
+		if (left.isNull() || right.isNull())
+		{
+			result.setToNull();
+			return result;
+		}
+		
+		return minusNN(left, right, result);
+	}
+	
+	/**
+	 * Implement subtraction using addition and negation of the right value.
+	 */
+	public NumberDataValue minusNN(NumberDataValue left, NumberDataValue right, NumberDataValue
result)
+		throws StandardException
+	{
+		// Requires plusNN() correctly handles that its right argument and
+		// result can be references to the same object.
+		return plusNN(left, right.minus(result), result);
+	}
+		
+	/*
+	** Abstract methods for handling non-null arithmetic.
+	** Eventually move these methods into NumberDataType
+	** and directly compile to them when arguments cannot
+	** be null. A performance optimization.
+	*/
+	
+	
+	/**
+	 * Multiple two non-nullable values using DECIMAL arithmetic.
+	 */
+	public abstract NumberDataValue timesNN(NumberDataValue left,
+			NumberDataValue right, NumberDataValue result)
+			throws StandardException;
+
+	/**
+	 * Add two non-nullable values using DECIMAL arithmetic.
+	 * For subclasses of BinaryDecimal, any implementation
+	 * must handle the result and addend2 (right) being references
+	 * to the same object.
+	 */
+	public abstract NumberDataValue plusNN(NumberDataValue addend1,
+			NumberDataValue addend2, NumberDataValue result)
+			throws StandardException;
+
+	/**
+	 * Divide two non-nullable values using DECIMAL arithmetic.
+	 */
+	public abstract NumberDataValue divideNN(NumberDataValue dividend,
+			NumberDataValue divisor, NumberDataValue result, int scale)
+			throws StandardException;
+	
+	/*
+	** Methods that act directly on twos complement byte arrays.
+	*/
+
+	/**
+	 * Compress the passed in byte array so that leading
+	 * 0x00 and 0xff are removed when possible.
+	 * E.g.
+	 * 0x00000453 ->>> 0x0453
+	 * 0xfffffff2 ->>> 0xf2
+	 * 0xff192312 ->>> 0xff192312 (unchanged)
+	 * 0xffff8039 ->>> 0x8039
+	 * data2c is set to the compressed value.
+	 * @param dataLength Valid length of data in data2c.
+	 */
+	private static byte[] reduceBytes2c(byte[] rd, int offset, int dataLength)
+	{
+		// look for leading zeros, if the value
+		// is dataLength bytes long then look
+		// at up to the first (dataLength - 1) bytes
+		// to see if leading 0x00 can be removed.
+
+		int leading;
+		for (leading = 0; leading < (dataLength - 1); leading++)
+		{
+			if (rd[offset + leading] != (byte) 0)
+				break;
+			
+			// if the hi bit of the next byte is set
+			// then we cannot strip this 0x00 otherwise
+			// the number will turn negative.
+			if ((rd[offset + leading + 1] & 0x80) != 0)
+				break;
+		}
+
+		if (leading == 0)
+		{
+			// now a similar trick with 0xff, but a slight
+			// complication.
+			for (; leading < (dataLength - 1); leading++)
+			{
+				// Need to check the highest byte of the
+				// would-be remaining significant byte is
+				// set to indicate this is still a negative number
+				
+				if ((rd[offset + leading] == (byte) 0xff) && ((rd[offset + leading+1] & (byte)
0x80) != 0))
+					continue;
+				break;
+			}
+		}
+		
+		if ((leading != 0) || (rd.length != dataLength))
+		{
+			byte[] reduced = new byte[dataLength - leading];
+			System.arraycopy(rd, offset + leading, reduced, 0, reduced.length);
+			return reduced;
+		}
+		
+		return rd;
+	}
+
+	/**
+	 * Return the SQL scale of this value, number of digits after the
+	 * decimal point, or zero for a whole number.
+	 */
+	public int getDecimalValueScale()
+	{
+		if (isNull())
+			return 0;
+		
+		return sqlScale;
+	}	
+	
+	/*
+	** I/O handling
+	*/
+
+	/** 
+	 * Distill the Decimal to a byte array and
+	 * Write out: <UL>
+	 *	<LI> scale (unsigned byte) </LI>
+	 *	<LI> length of byte array </LI>
+	 *	<LI> the byte array </LI> </UL>
+	 *
+	 */
+	public void writeExternal(ObjectOutput out) throws IOException 
+	{
+		// never called when value is null
+		if (SanityManager.DEBUG)
+			SanityManager.ASSERT(! isNull());
+
+		out.writeByte(sqlScale);
+		out.writeByte(data2c.length);
+		out.write(data2c);
+	}
+	
+	/** 
+	 * Note the use of data2c: we reuse the array if the
+	 * incoming array is the same length or smaller than
+	 * the array length.  
+	 * 
+	 * @see java.io.Externalizable#readExternal 
+	 */
+	public void readExternal(ObjectInput in) throws IOException 
+	{
+		sqlScale = in.readUnsignedByte();
+		int size = in.readUnsignedByte();
+
+		/*
+		** Allocate a new array if the data to read
+		** is larger than the existing array, or if
+		** we don't have an array yet.
+
+        Need to use readFully below and NOT just read because read does not
+        guarantee getting size bytes back, whereas readFully does (unless EOF).
+        */
+		if ((data2c == null) || size != data2c.length)
+		{
+			data2c = new byte[size];
+		}
+		in.readFully(data2c);
+
+	}
+	public void readExternalFromArray(ArrayInputStream in) throws IOException 
+	{
+		sqlScale = in.readUnsignedByte();
+		int size = in.readUnsignedByte();
+
+		/*
+		** Allocate a new array if the data to read
+		** is larger than the existing array, or if
+		** we don't have an array yet.
+
+        Need to use readFully below and NOT just read because read does not
+        guarantee getting size bytes back, whereas readFully does (unless EOF).
+        */
+		if ((data2c == null) || size != data2c.length)
+		{
+			data2c = new byte[size];
+		}
+		in.readFully(data2c);
+	}
+
+
+
+	public final int getLength()
+	{
+		return getDecimalValuePrecision();
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.derby.iapi.types.DataValueDescriptor#getClone()
+	 */
+	public DataValueDescriptor getClone() {
+		BinaryDecimal dvd = (BinaryDecimal) getNewNull();
+		
+		dvd.data2c = this.data2c;
+		dvd.sqlScale = this.sqlScale;
+		return dvd;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.derby.iapi.types.DataValueDescriptor#setValueFromResultSet(java.sql.ResultSet,
int, boolean)
+	 */
+	public void setValueFromResultSet(ResultSet resultSet, int colNumber, boolean isNullable)
throws StandardException, SQLException {
+		// TODO Auto-generated method stub
+		throw StandardException.newException(SQLState.NOT_IMPLEMENTED);
+		
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.derby.iapi.types.DataValueDescriptor#estimateMemoryUsage()
+	 */
+	public int estimateMemoryUsage() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+}

Propchange: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/BinaryDecimal.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CDCDataValueFactory.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CDCDataValueFactory.java?rev=179254&r1=179253&r2=179254&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CDCDataValueFactory.java
(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CDCDataValueFactory.java
Tue May 31 11:28:57 2005
@@ -26,13 +26,9 @@
 import org.apache.derby.iapi.error.StandardException;
 
 /**
-/**
  * DataValueFactory implementation for J2ME/CDC/Foundation.
  * Cannot use SQLDecimal since that requires java.math.BigDecimal.
- * 
- * THIS IS A TEMPORARY IMPLEMENTATION THAT USES SQLDouble for DECIMAL
- * WHICH IS NOT PRECISE. IS IT A STEP IN THE WAY TO A COMPLETE IMPLEMENTAION
- * FOR J2ME.
+ * Uses BigIntegerDecimal for DECIMAL support.
  *
  * @see DataValueFactory
  */
@@ -62,7 +58,7 @@
 	public NumberDataValue getDecimalDataValue(Long value,
 			NumberDataValue previous) throws StandardException {
 		if (previous == null)
-			previous = new SQLDouble(); // CDCDecimal();
+			previous = new BigIntegerDecimal();
 
 		previous.setValue(value);
 		return previous;
@@ -70,7 +66,7 @@
 
 	public NumberDataValue getDecimalDataValue(String value)
 			throws StandardException {
-		NumberDataValue ndv = new SQLDouble(); // CDCDecimal();
+		NumberDataValue ndv = new BigIntegerDecimal();
 
 		ndv.setValue(value);
 		return ndv;
@@ -78,7 +74,7 @@
 
 	public NumberDataValue getNullDecimal(NumberDataValue dataValue) {
 		if (dataValue == null) {
-			return new SQLDouble(); // CDCDecimal();
+			return new BigIntegerDecimal();
 		} else {
 			dataValue.setToNull();
 			return dataValue;

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/NumberDataType.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/NumberDataType.java?rev=179254&r1=179253&r2=179254&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/NumberDataType.java
(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/NumberDataType.java
Tue May 31 11:28:57 2005
@@ -63,16 +63,16 @@
      * @return this object's absolute value.  Null if object is null.
      * @exception StandardException thrown on error.
      */
-    public NumberDataValue absolute(NumberDataValue result) 
+    public final NumberDataValue absolute(NumberDataValue result) 
                         throws StandardException
-    {
+    {   		
         if(isNegative())
             return minus(result);
 
         if(result == null)
             result = (NumberDataType)getNewNull();
-
-        result.setValue(this.getObject());
+        
+        result.setValue(this);
         return result;
     }
 

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLDecimal.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLDecimal.java?rev=179254&r1=179253&r2=179254&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLDecimal.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLDecimal.java Tue
May 31 11:28:57 2005
@@ -770,7 +770,7 @@
 		int desiredScale = desiredType.getScale();
 		int desiredPrecision = desiredType.getPrecision();
 
-		setCoreValue(SQLDecimal.getBigDecimal(source));
+		setFrom(source);
 		setWidth(desiredPrecision, desiredScale, true);
 	}
 
@@ -781,7 +781,7 @@
 
 
 	/**
-	 * This method implements the + operator for "double + double".
+	 * This method implements the + operator for DECIMAL.
 	 *
 	 * @param addend1	One of the addends
 	 * @param addend2	The other addend
@@ -939,7 +939,7 @@
 			throw  StandardException.newException(SQLState.LANG_DIVIDE_BY_ZERO);
 		}
 		BigDecimal dividendBigDecimal = SQLDecimal.getBigDecimal(dividend);
-
+		
 		/*
 		** Set the result scale to be either the passed in scale, whcih was
 		** calculated at bind time to be max(ls+rp-rs+1, 4), where ls,rp,rs
@@ -955,6 +955,7 @@
 											1), 
 										NumberDataValue.MIN_DECIMAL_DIVIDE_SCALE),
 									BigDecimal.ROUND_DOWN));
+		
 		return result;
 	}
 



Mime
View raw message