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

de.bytefish.pgbulkinsert.pgsql.handlers.BigDecimalValueHandler Maven / Gradle / Ivy

There is a newer version: 7.0.1
Show newest version
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package de.bytefish.pgbulkinsert.pgsql.handlers;

import de.bytefish.pgbulkinsert.util.BigDecimalUtils;

import java.io.DataOutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * The Algorithm for turning a BigDecimal into a Postgres Numeric is heavily inspired by the Intermine Implementation:
 * 

* https://github.com/intermine/intermine/blob/master/intermine/objectstore/main/src/org/intermine/sql/writebatch/BatchWriterPostgresCopyImpl.java */ public class BigDecimalValueHandler extends BaseValueHandler { private static final int DECIMAL_DIGITS = 4; private static final BigInteger TEN_THOUSAND = new BigInteger("10000"); @Override protected void internalHandle(final DataOutputStream buffer, final T value) throws Exception { final BigDecimal tmpValue = getNumericAsBigDecimal(value); // Number of fractional digits: final int fractionDigits = tmpValue.scale(); // Number of Fraction Groups: final int fractionGroups = (fractionDigits + 3) / 4; final List digits = digits(tmpValue); buffer.writeInt(8 + (2 * digits.size())); buffer.writeShort(digits.size()); buffer.writeShort(digits.size() - fractionGroups - 1); buffer.writeShort(tmpValue.signum() == 1 ? 0x0000 : 0x4000); buffer.writeShort(fractionDigits); // Now write each digit: for (int pos = digits.size() - 1; pos >= 0; pos--) { final int valueToWrite = digits.get(pos); buffer.writeShort(valueToWrite); } } @Override public int getLength(final T value) { final List digits = digits(getNumericAsBigDecimal(value)); return (8 + (2 * digits.size())); } private static BigDecimal getNumericAsBigDecimal(final Number source) { if (!(source instanceof BigDecimal)) { return BigDecimalUtils.toBigDecimal(source.doubleValue()); } return (BigDecimal) source; } private List digits(final BigDecimal value) { BigInteger unscaledValue = value.unscaledValue(); if (value.signum() == -1) { unscaledValue = unscaledValue.negate(); } final List digits = new ArrayList<>(); // The scale needs to be a multiple of 4: int scaleRemainder = value.scale() % 4; // Scale the first value: if (scaleRemainder != 0) { final BigInteger[] result = unscaledValue.divideAndRemainder(BigInteger.TEN.pow(scaleRemainder)); final int digit = result[1].intValue() * (int) Math.pow(10, DECIMAL_DIGITS - scaleRemainder); digits.add(digit); unscaledValue = result[0]; } while (!unscaledValue.equals(BigInteger.ZERO)) { final BigInteger[] result = unscaledValue.divideAndRemainder(TEN_THOUSAND); digits.add(result[1].intValue()); unscaledValue = result[0]; } return digits; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy