Changeset: 3bde6392aa91 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3bde6392aa91 Modified Files: java/ChangeLog.Feb2013 java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java Branch: Feb2013 Log Message:
setBigDecimal: improve way we "round" BigDecimals Use BigDecimal rounding to "shave off" digits from the input BigDecimal to try and make it fit for the DECIMAL(x,y) type the server expects. Slightly modified patch by Ben Reilly from bug #3290. diffs (69 lines): diff --git a/java/ChangeLog.Feb2013 b/java/ChangeLog.Feb2013 --- a/java/ChangeLog.Feb2013 +++ b/java/ChangeLog.Feb2013 @@ -1,6 +1,10 @@ # ChangeLog file for java # This file is updated with Maddlog +* Sun Jun 9 2013 Fabian Groffen <fab...@monetdb.org> +- Further improved setBigDecimal() method, based on patch by Ben Reilly + in bug #3290 + * Thu May 23 2013 Fabian Groffen <fab...@monetdb.org> - Fixed bug where PreparedStatement.setBigDecimal() wouldn't format its input well enough for the server causing odd errors. diff --git a/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java b/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java --- a/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java +++ b/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java @@ -951,25 +951,37 @@ public class MonetPreparedStatement * The driver converts this to an SQL NUMERIC value when it sends it to the * database. * - * @param i the first parameter is 1, the second is 2, ... + * @param idx the first parameter is 1, the second is 2, ... * @param x the parameter value * @throws SQLException if a database access error occurs */ - public void setBigDecimal(int i, BigDecimal x) + public void setBigDecimal(int idx, BigDecimal x) throws SQLException { - // if we don't give the server the exact digits/scale thing, it - // barfs at us that we don't give it a correct value, so... - String ps = x.toPlainString(); - // chop off excess "precision" - int di = ps.indexOf("."); - if (di >= 0 && ps.length() - di - 1 > scale[i]) - ps = ps.substring(0, di + scale[i] + (scale[i] == 0 ? 0 : 1)); - if (di < 0) - di = ps.length(); - if (di > (digits[i] - scale[i])) - throw new SQLDataException("DECIMAL value exceeds allowed digits/scale: " + ps + " (" + digits[i] + "/" + scale[i] + ")", "22003"); - setValue(i, ps); + // get array position + int i = getParamIdx(idx); + + // We need to shave off enough digits to bring ourselves to an + // acceptable precision if we currently have too many digits. + int digitsToShave = Math.max(0, x.precision() - digits[i]); + int targetScale = Math.min(scale[i], x.scale() - digitsToShave); + + // However, if we need to shave off more digits than we have available + // to the right of the decimal point, then this is impossible. + if (targetScale < 0) + throw new SQLDataException("DECIMAL value exceeds allowed digits/scale: " + x.toPlainString() + " (" + digits[i] + "/" + scale[i] + ")", "22003"); + + // Reduction is possible via rounding; do it and we're good to go. + x = x.round(new MathContext(targetScale, RoundingMode.HALF_UP)); + x = x.stripTrailingZeros(); + + // MonetDB doesn't like leading 0's, since it counts them as part of + // the precision, so let's strip them off. (But be careful not to do + // this to the exact number "0".) + String xStr = x.toPlainString(); + while (xStr.startsWith("0") && xStr.length() > 1) + xStr = xStr.substring(1); + setValue(idx, xStr); } /** _______________________________________________ checkin-list mailing list checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list