Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 18156 invoked from network); 2 May 2005 23:58:33 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 2 May 2005 23:58:33 -0000 Received: (qmail 45895 invoked by uid 500); 3 May 2005 00:00:06 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 45824 invoked by uid 500); 3 May 2005 00:00:05 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 45809 invoked by uid 500); 3 May 2005 00:00:05 -0000 Delivered-To: apmail-incubator-derby-cvs@incubator.apache.org Received: (qmail 45804 invoked by uid 99); 3 May 2005 00:00:05 -0000 X-ASF-Spam-Status: No, hits=0.2 required=10.0 tests=NO_REAL_NAME X-Spam-Check-By: apache.org Received: from minotaur.apache.org (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.28) with SMTP; Mon, 02 May 2005 17:00:05 -0700 Received: (qmail 18116 invoked by uid 65534); 2 May 2005 23:58:30 -0000 Message-ID: <20050502235830.18113.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: svn commit: r167832 - in /incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types: NumberDataValue.java SQLDecimal.java Date: Mon, 02 May 2005 23:58:30 -0000 To: derby-cvs@incubator.apache.org From: djd@apache.org X-Mailer: svnmailer-1.0.0-dev X-Virus-Checked: Checked X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: djd Date: Mon May 2 16:58:30 2005 New Revision: 167832 URL: http://svn.apache.org/viewcvs?rev=3D167832&view=3Drev Log: Fix Derby-225 - Handle negative scale values for BigDecimal values introduc= ed in J2SE 5.0. Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Numb= erDataValue.java incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLD= ecimal.java Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/type= s/NumberDataValue.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/o= rg/apache/derby/iapi/types/NumberDataValue.java?rev=3D167832&r1=3D167831&r2= =3D167832&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Numb= erDataValue.java (original) +++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/Numb= erDataValue.java Mon May 2 16:58:30 2005 @@ -196,14 +196,18 @@ public void setValue(Number theValue) throws StandardException; =20 /** - Return the precision of this specific DECIMAL value. + Return the SQL precision of this specific DECIMAL value. + This does not match the return from BigDecimal.precision() + added in J2SE 5.0, which represents the precision of the unscaled value. If the value does not represent a SQL DECIMAL then the return is undefined. */ public int getDecimalValuePrecision(); =20 /** - Return the scale of this specific DECIMAL value. + Return the SQL scale of this specific DECIMAL value. + This does not match the return from BigDecimal.scale() + since in J2SE 5.0 onwards that can return negative scales. If the value does not represent a SQL DECIMAL then the return is undefined. */ Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/type= s/SQLDecimal.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/o= rg/apache/derby/iapi/types/SQLDecimal.java?rev=3D167832&r1=3D167831&r2=3D16= 7832&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLD= ecimal.java (original) +++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLD= ecimal.java Mon May 2 16:58:30 2005 @@ -343,6 +343,7 @@ } =20 private static final Method toPlainString; + private static final Method bdPrecision; static { Method m; try { @@ -351,6 +352,12 @@ m =3D null; } toPlainString =3D m; + try { + m =3D BigDecimal.class.getMethod("precision", null); + } catch (NoSuchMethodException e) { + m =3D null; + } + bdPrecision =3D m; } =20 public Object getObject() @@ -425,8 +432,8 @@ /**=20 * Distill the BigDecimal to a byte array and * write out:
    - *
  • scale (int)
  • - *
  • length of byte array
  • + *
  • scale (zero or positive) as a byte
  • + *
  • length of byte array as a byte
  • *
  • the byte array
* */ @@ -441,12 +448,43 @@ =20 if (value !=3D null) { scale =3D value.scale(); + =09 + // J2SE 5.0 introduced negative scale value for BigDecimals. + // In previouse Java releases a negative scale was not allowed + // (threw an exception on setScale and the constructor that took + // a scale). + // + // Thus the Derby format for DECIMAL implictly assumed a + // positive or zero scale value, and thus now must explicitly + // be positive. This is to allow databases created under J2SE 5.0 + // to continue to be supported under JDK 1.3/JDK 1.4, ie. to continue + // the platform independence, independent of OS/cpu and JVM. + // + // If the scale is negative set the scale to be zero, this results + // in an unchanged value with a new scale. A BigDecimal with a + // negative scale by definition is a whole number. + // e.g. 1000 can be represented by: + // a BigDecimal with scale -3 (unscaled value of 1) + // or a BigDecimal with scale 0 (unscaled value of 1000) + =09 + if (scale < 0) { =09 + scale =3D 0; + value =3D value.setScale(0); + } + BigInteger bi =3D value.unscaledValue(); byteArray =3D bi.toByteArray(); } else { scale =3D rawScale; byteArray =3D rawData; } + =09 + if (SanityManager.DEBUG) + { + if (scale < 0) + SanityManager.THROWASSERT("DECIMAL scale at writeExternal is negative " + + scale + " value " + toString()); + } =20 out.writeByte(scale); out.writeByte(byteArray.length); @@ -1051,11 +1089,9 @@ { if (isNull()) return this; - =09 - // the getWholeDigits() call will ensure via getBigDecimal() - // that the rawData is translated into the BigDecimal in value. + =09 if (desiredPrecision !=3D IGNORE_PRECISION && - ((desiredPrecision - desiredScale) < getWholeDigits())) + ((desiredPrecision - desiredScale) < SQLDecimal.getWholeDigits(getBigD= ecimal()))) { throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DA= TATYPE,=20 ("DECIMAL/NUMERIC("+desiredPrecision+","+desiredScale+")")); @@ -1065,31 +1101,43 @@ return this; } =20 - public int getDecimalValuePrecision() - { - return getPrecision(getBigDecimal()); - } /** - * - * @param decimalValue the big decimal - * - * @return the precision - */=09 - private static int getPrecision(BigDecimal decimalValue) + * Return the SQL scale of this value, number of digits after the + * decimal point, or zero for a whole number. This does not match the + * return from BigDecimal.scale() since in J2SE 5.0 onwards that can retu= rn + * negative scales. + */ + public int getDecimalValuePrecision() { - if ((decimalValue =3D=3D null) || - decimalValue.equals(ZERO)) - { + if (isNull()) return 0; - }=09 + =09 + BigDecimal localValue =3D getBigDecimal(); =20 - return SQLDecimal.getWholeDigits(decimalValue) + decimalValue.scale(); + return SQLDecimal.getWholeDigits(localValue) + getDecimalValueScale(); } =20 + /** + * Return the SQL scale of this value, number of digits after the + * decimal point, or zero for a whole number. This does not match the + * return from BigDecimal.scale() since in J2SE 5.0 onwards that can retu= rn + * negative scales. + */ public int getDecimalValueScale() { - BigDecimal localValue =3D getBigDecimal(); - return (localValue =3D=3D null) ? 0 : localValue.scale(); + if (isNull()) + return 0; + =09 + if (value =3D=3D null) + return rawScale; +=09 + int scale =3D value.scale(); + if (scale >=3D 0) + return scale; + =09 + // BigDecimal scale is negative, so number must have no fractional + // part as its value is the unscaled value * 10^-scale + return 0; } =09 /** @@ -1125,19 +1173,14 @@ } } =20 - private int getWholeDigits() - { - return SQLDecimal.getWholeDigits(getBigDecimal()); - } - + /** + * Calculate the number of digits to the left of the decimal point + * of the passed in value. + * @param decimalValue Value to get whole digits from, never null. + * @return number of whole digits. + */ private static int getWholeDigits(BigDecimal decimalValue) { - if ((decimalValue =3D=3D null) || - decimalValue.equals(ZERO)) - { - return 0; - } - /** * if ONE > abs(value) then the number of whole digits is 0 */ @@ -1146,7 +1189,36 @@ { return 0; } - + =20 + if (JVMInfo.JDK_ID >=3D JVMInfo.J2SE_15) + { + // use reflection so we can still compile using JDK1.4 + // if we are prepared to require 1.5 to compile then this can be a + // direct call + try { + // precision is the number of digits in the unscaled value, + // subtracting the scale (positive or negative) will give the + // number of whole digits. + int precision =3D ((Integer) bdPrecision.invoke(decimalValue, + null)).intValue(); + return precision - decimalValue.scale(); + } catch (IllegalAccessException e) { + // can't happen based on the JDK spec + throw new IllegalAccessError("precision"); + } catch (InvocationTargetException e) { + Throwable t =3D e.getTargetException(); + if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else if (t instanceof Error) { + throw (Error) t; + } else { + // can't happen + throw new IncompatibleClassChangeError("precision"); + } + } + =20 + } + =20 String s =3D decimalValue.toString(); return (decimalValue.scale() =3D=3D 0) ? s.length() : s.indexOf('.= '); }