You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@avro.apache.org by "opwvhk (via GitHub)" <gi...@apache.org> on 2023/06/16 12:32:13 UTC

[GitHub] [avro] opwvhk commented on a diff in pull request #2282: AVRO-3779: [java] any big decimal conversion

opwvhk commented on code in PR #2282:
URL: https://github.com/apache/avro/pull/2282#discussion_r1232188780


##########
lang/java/avro/src/main/java/org/apache/avro/Conversions.java:
##########
@@ -146,6 +154,65 @@ private static BigDecimal validate(final LogicalTypes.Decimal decimal, BigDecima
     }
   }
 
+  public static class BigDecimalConversion extends Conversion<BigDecimal> {
+
+    @Override
+    public Class<BigDecimal> getConvertedType() {
+      return BigDecimal.class;
+    }
+
+    @Override
+    public String getLogicalTypeName() {
+      return "bigdecimal";
+    }
+
+    @Override
+    public BigDecimal fromBytes(final ByteBuffer value, final Schema schema, final LogicalType type) {
+      BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(value.array(), null);
+
+      try {
+        BigInteger bg = null;
+        ByteBuffer buffer = decoder.readBytes(null);
+        byte[] array = buffer.array();
+        if (array != null && array.length > 0) {
+          bg = new BigInteger(array);
+        }
+
+        int scale = decoder.readInt();
+        return new BigDecimal(bg, scale);
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    @Override
+    public ByteBuffer toBytes(final BigDecimal value, final Schema schema, final LogicalType type) {
+      try {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(out, null);
+
+        BigInteger unscaledValue = value.unscaledValue();
+        if (unscaledValue != null) {
+          encoder.writeBytes(unscaledValue.toByteArray());
+        } else {
+          encoder.writeBytes(new byte[] {});
+        }
+        encoder.writeInt(value.scale());
+        encoder.flush();
+        return ByteBuffer.wrap(out.toByteArray());
+
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }

Review Comment:
   This is overkill: the result is going to be encoded as well...
   
   Given that the scale is usually small, and that we'd like to limit the number of bytes written, this would work as well:
   
   ```
   byte[] unscaled = value.unscaledValue().toByteArray();
   ByteBuffer buffer = ByteBuffer.allocate(unscaled.length + 5);
   int scaleSize = org.apache.avro.io.BinaryData.encodeInt(value.scale(), buffer.array(), buffer.position());
   buffer.position(buffer.position() + scaleSize);
   buffer.put(unscaled);
   buffer.flip();
   return buffer;
   ```
   
   An even better solution would be to add a 2nd version of `org.apache.avro.io.BinaryData#encodeInt` and `org.apache.avro.io.BinaryData#decodeInt` that operate on a ByteBuffer (removing the need to reposition the buffer).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@avro.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org