You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by pr...@apache.org on 2020/03/06 11:19:36 UTC
[arrow] branch master updated: ARROW-7993: [Java] Support decimal
type in ComplexCopier
This is an automated email from the ASF dual-hosted git repository.
praveenbingo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new 88e3267 ARROW-7993: [Java] Support decimal type in ComplexCopier
88e3267 is described below
commit 88e3267ad09ca62643b7fe5ffd98eb03b29728fc
Author: Projjal Chanda <ia...@pchanda.com>
AuthorDate: Fri Mar 6 16:49:09 2020 +0530
ARROW-7993: [Java] Support decimal type in ComplexCopier
Closes #6523 from projjal/decimalcomplexcopier and squashes the following commits:
105e94eb0 <Projjal Chanda> added missing methods
0f0bb2646 <Projjal Chanda> added test
b523e957e <Projjal Chanda> added fix
45a2c0720 <Projjal Chanda> Added more tests
574f13c49 <Projjal Chanda> added (some) review comments
dc849c139 <Projjal Chanda> Support DecimalType in ComplexCopier
Authored-by: Projjal Chanda <ia...@pchanda.com>
Signed-off-by: Praveen <pr...@dremio.com>
---
.../codegen/templates/AbstractFieldWriter.java | 8 +
.../templates/AbstractPromotableFieldWriter.java | 20 ++-
.../src/main/codegen/templates/ComplexCopier.java | 17 ++-
.../src/main/codegen/templates/ComplexWriters.java | 55 ++++++-
.../main/codegen/templates/DenseUnionReader.java | 4 +-
.../main/codegen/templates/DenseUnionVector.java | 16 +-
.../main/codegen/templates/DenseUnionWriter.java | 18 ++-
.../src/main/codegen/templates/StructWriters.java | 2 +-
.../templates/UnionFixedSizeListWriter.java | 4 +-
.../main/codegen/templates/UnionListWriter.java | 5 +
.../src/main/codegen/templates/UnionReader.java | 4 +-
.../src/main/codegen/templates/UnionVector.java | 49 +++++--
.../src/main/codegen/templates/UnionWriter.java | 49 +++++--
.../org/apache/arrow/vector/DecimalVector.java | 7 +
.../vector/complex/impl/PromotableWriter.java | 48 +++---
.../apache/arrow/vector/util/DecimalUtility.java | 18 +++
.../vector/complex/impl/TestComplexCopier.java | 162 ++++++++++++++++++++-
17 files changed, 402 insertions(+), 84 deletions(-)
diff --git a/java/vector/src/main/codegen/templates/AbstractFieldWriter.java b/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
index c4ac32c..4f6d5ea 100644
--- a/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
+++ b/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
@@ -81,9 +81,17 @@ abstract class AbstractFieldWriter extends AbstractBaseWriter implements FieldWr
fail("${name}");
}
+ public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list><#if minor.class == "Decimal">, ArrowType arrowType</#if>) {
+ fail("${name}");
+ }
+
public void writeBigEndianBytesToDecimal(byte[] value) {
fail("${name}");
}
+
+ public void writeBigEndianBytesToDecimal(byte[] value, ArrowType arrowType) {
+ fail("${name}");
+ }
</#if>
</#list></#list>
diff --git a/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java b/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
index 77ac5ba..92b9cd2 100644
--- a/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
+++ b/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
@@ -75,6 +75,7 @@ abstract class AbstractPromotableFieldWriter extends AbstractFieldWriter {
<#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
+ <#if minor.class != "Decimal">
@Override
public void write(${name}Holder holder) {
getWriter(MinorType.${name?upper_case}).write(holder);
@@ -84,7 +85,24 @@ abstract class AbstractPromotableFieldWriter extends AbstractFieldWriter {
getWriter(MinorType.${name?upper_case}).write${minor.class}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
}
- <#if minor.class == "Decimal">
+ <#else>
+ @Override
+ public void write(DecimalHolder holder) {
+ getWriter(MinorType.DECIMAL).write(holder);
+ }
+
+ public void writeDecimal(int start, ArrowBuf buffer, ArrowType arrowType) {
+ getWriter(MinorType.DECIMAL).writeDecimal(start, buffer, arrowType);
+ }
+
+ public void writeDecimal(int start, ArrowBuf buffer) {
+ getWriter(MinorType.DECIMAL).writeDecimal(start, buffer);
+ }
+
+ public void writeBigEndianBytesToDecimal(byte[] value, ArrowType arrowType) {
+ getWriter(MinorType.DECIMAL).writeBigEndianBytesToDecimal(value, arrowType);
+ }
+
public void writeBigEndianBytesToDecimal(byte[] value) {
getWriter(MinorType.DECIMAL).writeBigEndianBytesToDecimal(value);
}
diff --git a/java/vector/src/main/codegen/templates/ComplexCopier.java b/java/vector/src/main/codegen/templates/ComplexCopier.java
index ebf6c0f..270be08 100644
--- a/java/vector/src/main/codegen/templates/ComplexCopier.java
+++ b/java/vector/src/main/codegen/templates/ComplexCopier.java
@@ -96,14 +96,14 @@ public class ComplexCopier {
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class?starts_with("Decimal") >
case ${name?upper_case}:
if (reader.isSet()) {
Nullable${name}Holder ${uncappedName}Holder = new Nullable${name}Holder();
reader.read(${uncappedName}Holder);
if (${uncappedName}Holder.isSet == 1) {
- writer.write${name}(<#list fields as field>${uncappedName}Holder.${field.name}<#if field_has_next>, </#if></#list>);
+ writer.write${name}(<#list fields as field>${uncappedName}Holder.${field.name}<#if field_has_next>, </#if></#list><#if minor.class == "Decimal">, new ArrowType.Decimal(decimalHolder.precision, decimalHolder.scale)</#if>);
}
}
break;
@@ -118,10 +118,19 @@ public class ComplexCopier {
<#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams??>
case ${name?upper_case}:
return (FieldWriter) writer.<#if name == "Int">integer<#else>${uncappedName}</#if>(name);
</#if>
+ <#if minor.class == "Decimal">
+ case ${name?upper_case}:
+ if (reader.getField().getType() instanceof ArrowType.Decimal) {
+ ArrowType.Decimal type = (ArrowType.Decimal) reader.getField().getType();
+ return (FieldWriter) writer.${uncappedName}(name, type.getScale(), type.getPrecision());
+ } else {
+ return (FieldWriter) writer.${uncappedName}(name);
+ }
+ </#if>
</#list></#list>
case STRUCT:
return (FieldWriter) writer.struct(name);
@@ -139,7 +148,7 @@ public class ComplexCopier {
<#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class?starts_with("Decimal") >
case ${name?upper_case}:
return (FieldWriter) writer.<#if name == "Int">integer<#else>${uncappedName}</#if>();
</#if>
diff --git a/java/vector/src/main/codegen/templates/ComplexWriters.java b/java/vector/src/main/codegen/templates/ComplexWriters.java
index 9d943e4..ab99ac3 100644
--- a/java/vector/src/main/codegen/templates/ComplexWriters.java
+++ b/java/vector/src/main/codegen/templates/ComplexWriters.java
@@ -99,6 +99,7 @@ public class ${eName}WriterImpl extends AbstractFieldWriter {
<#else>
+ <#if minor.class != "Decimal">
public void write(${minor.class}Holder h) {
vector.setSafe(idx(), h);
vector.setValueCount(idx()+1);
@@ -113,9 +114,9 @@ public class ${eName}WriterImpl extends AbstractFieldWriter {
vector.setSafe(idx(), 1<#list fields as field><#if field.include!true >, ${field.name}</#if></#list>);
vector.setValueCount(idx()+1);
}
+ </#if>
- <#if minor.class == "Decimal" ||
- minor.class == "VarChar">
+ <#if minor.class == "VarChar">
public void write${minor.class}(${friendlyType} value) {
vector.setSafe(idx(), value);
vector.setValueCount(idx()+1);
@@ -123,9 +124,49 @@ public class ${eName}WriterImpl extends AbstractFieldWriter {
</#if>
<#if minor.class == "Decimal">
- public void writeBigEndianBytesToDecimal(byte[] value) {
+
+ public void write(DecimalHolder h){
+ DecimalUtility.checkPrecisionAndScale(h.precision, h.scale, vector.getPrecision(), vector.getScale());
+ vector.setSafe(idx(), h);
+ vector.setValueCount(idx() + 1);
+ }
+
+ public void write(NullableDecimalHolder h){
+ if (h.isSet == 1) {
+ DecimalUtility.checkPrecisionAndScale(h.precision, h.scale, vector.getPrecision(), vector.getScale());
+ }
+ vector.setSafe(idx(), h);
+ vector.setValueCount(idx() + 1);
+ }
+
+ public void writeDecimal(int start, ArrowBuf buffer){
+ vector.setSafe(idx(), 1, start, buffer);
+ vector.setValueCount(idx() + 1);
+ }
+
+ public void writeDecimal(int start, ArrowBuf buffer, ArrowType arrowType){
+ DecimalUtility.checkPrecisionAndScale(((ArrowType.Decimal) arrowType).getPrecision(),
+ ((ArrowType.Decimal) arrowType).getScale(), vector.getPrecision(), vector.getScale());
+ vector.setSafe(idx(), 1, start, buffer);
+ vector.setValueCount(idx() + 1);
+ }
+
+ public void writeDecimal(BigDecimal value){
+ // vector.setSafe already does precision and scale checking
+ vector.setSafe(idx(), value);
+ vector.setValueCount(idx() + 1);
+ }
+
+ public void writeBigEndianBytesToDecimal(byte[] value, ArrowType arrowType){
+ DecimalUtility.checkPrecisionAndScale(((ArrowType.Decimal) arrowType).getPrecision(),
+ ((ArrowType.Decimal) arrowType).getScale(), vector.getPrecision(), vector.getScale());
vector.setBigEndianSafe(idx(), value);
- vector.setValueCount(idx()+1);
+ vector.setValueCount(idx() + 1);
+ }
+
+ public void writeBigEndianBytesToDecimal(byte[] value){
+ vector.setBigEndianSafe(idx(), value);
+ vector.setValueCount(idx() + 1);
}
</#if>
@@ -149,11 +190,17 @@ package org.apache.arrow.vector.complex.writer;
public interface ${eName}Writer extends BaseWriter {
public void write(${minor.class}Holder h);
+ <#if minor.class == "Decimal">@Deprecated</#if>
public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>);
<#if minor.class == "Decimal">
+ public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>, ArrowType arrowType);
+
public void write${minor.class}(${friendlyType} value);
+ public void writeBigEndianBytesToDecimal(byte[] value, ArrowType arrowType);
+
+ @Deprecated
public void writeBigEndianBytesToDecimal(byte[] value);
</#if>
}
diff --git a/java/vector/src/main/codegen/templates/DenseUnionReader.java b/java/vector/src/main/codegen/templates/DenseUnionReader.java
index 6e3d19b..51bd7d1 100644
--- a/java/vector/src/main/codegen/templates/DenseUnionReader.java
+++ b/java/vector/src/main/codegen/templates/DenseUnionReader.java
@@ -92,7 +92,7 @@ public class DenseUnionReader extends AbstractFieldReader {
<#list type.minor as minor>
<#assign name = minor.class?cap_first />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
case ${name?upper_case}:
reader = (FieldReader) get${name}(typeId);
break;
@@ -165,7 +165,7 @@ public class DenseUnionReader extends AbstractFieldReader {
<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
<#assign safeType=friendlyType />
<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
private ${name}ReaderImpl get${name}(byte typeId) {
${name}ReaderImpl reader = (${name}ReaderImpl) readers[typeId];
diff --git a/java/vector/src/main/codegen/templates/DenseUnionVector.java b/java/vector/src/main/codegen/templates/DenseUnionVector.java
index 31ffd78..9efab95 100644
--- a/java/vector/src/main/codegen/templates/DenseUnionVector.java
+++ b/java/vector/src/main/codegen/templates/DenseUnionVector.java
@@ -239,6 +239,10 @@ public class DenseUnionVector implements FieldVector {
return internalStruct.addOrGet(fieldName(typeId, minorType), fieldType(minorType), c);
}
+ private <T extends FieldVector> T addOrGet(byte typeId, MinorType minorType, ArrowType arrowType, Class<T> c) {
+ return internalStruct.addOrGet(fieldName(typeId, minorType), FieldType.nullable(arrowType), c);
+ }
+
@Override
public long getOffsetBufferAddress() {
return offsetBuffer.memoryAddress();
@@ -285,13 +289,13 @@ public class DenseUnionVector implements FieldVector {
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
<#assign lowerCaseName = name?lower_case/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
- public ${name}Vector get${name}Vector(byte typeId) {
+ public ${name}Vector get${name}Vector(byte typeId<#if minor.class == "Decimal">, ArrowType arrowType</#if>) {
ValueVector vector = childVectors[typeId];
if (vector == null) {
int vectorCount = internalStruct.size();
- vector = addOrGet(typeId, MinorType.${name?upper_case}, ${name}Vector.class);
+ vector = addOrGet(typeId, MinorType.${name?upper_case}<#if minor.class == "Decimal">, arrowType</#if>, ${name}Vector.class);
childVectors[typeId] = vector;
if (internalStruct.size() > vectorCount) {
vector.allocateNew();
@@ -820,7 +824,7 @@ public class DenseUnionVector implements FieldVector {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
case ${name?upper_case}:
Nullable${name}Holder ${uncappedName}Holder = new Nullable${name}Holder();
reader.read(${uncappedName}Holder);
@@ -844,7 +848,7 @@ public class DenseUnionVector implements FieldVector {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
public void setSafe(int index, Nullable${name}Holder holder) {
while (index >= getOffsetBufferValueCapacity()) {
reallocOffsetBuffer();
@@ -854,7 +858,7 @@ public class DenseUnionVector implements FieldVector {
}
BitVectorHelper.setBit(validityBuffer, index);
byte typeId = getTypeId(index);
- ${name}Vector vector = get${name}Vector(typeId);
+ ${name}Vector vector = get${name}Vector(typeId<#if minor.class == "Decimal">, new ArrowType.Decimal(holder.precision, holder.scale)</#if>);
int offset = vector.getValueCount();
vector.setValueCount(offset + 1);
vector.setSafe(offset, holder);
diff --git a/java/vector/src/main/codegen/templates/DenseUnionWriter.java b/java/vector/src/main/codegen/templates/DenseUnionWriter.java
index 41c1c49..ee6f614 100644
--- a/java/vector/src/main/codegen/templates/DenseUnionWriter.java
+++ b/java/vector/src/main/codegen/templates/DenseUnionWriter.java
@@ -123,7 +123,7 @@ public class DenseUnionWriter extends AbstractFieldWriter implements FieldWriter
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams??>
+ <#if !minor.typeParams?? || minor.class == "Decimal">
case ${name?upper_case}:
return get${name}Writer(typeId);
</#if>
@@ -138,7 +138,7 @@ public class DenseUnionWriter extends AbstractFieldWriter implements FieldWriter
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
private ${name}Writer get${name}Writer(byte typeId) {
${name}Writer writer = (${name}Writer) writers[typeId];
@@ -159,10 +159,10 @@ public class DenseUnionWriter extends AbstractFieldWriter implements FieldWriter
throw new UnsupportedOperationException();
}
- public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>, byte typeId) {
+ public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>, byte typeId<#if minor.class == "Decimal">, ArrowType arrowType</#if>) {
data.setTypeId(idx(), typeId);
get${name}Writer(typeId).setPosition(data.getOffset(idx()));
- get${name}Writer(typeId).write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
+ get${name}Writer(typeId).write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list><#if minor.class == "Decimal">, arrowType</#if>);
}
</#if>
</#list>
@@ -208,7 +208,7 @@ public class DenseUnionWriter extends AbstractFieldWriter implements FieldWriter
<#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
<#assign upperName = minor.class?upper_case />
<#assign capName = minor.class?cap_first />
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
@Override
public ${capName}Writer ${lowerName}(String name) {
byte typeId = data.getTypeId(idx());
@@ -225,6 +225,14 @@ public class DenseUnionWriter extends AbstractFieldWriter implements FieldWriter
return getListWriter(typeId).${lowerName}();
}
</#if>
+ <#if minor.class == "Decimal">
+ public ${capName}Writer ${lowerName}(String name<#list minor.typeParams as typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
+ byte typeId = data.getTypeId(idx());
+ data.setTypeId(idx(), typeId);
+ getStructWriter(typeId).setPosition(data.getOffset(idx()));
+ return getStructWriter(typeId).${lowerName}(name<#list minor.typeParams as typeParam>, ${typeParam.name}</#list>);
+ }
+ </#if>
</#list></#list>
@Override
diff --git a/java/vector/src/main/codegen/templates/StructWriters.java b/java/vector/src/main/codegen/templates/StructWriters.java
index 8861a41..9b88924 100644
--- a/java/vector/src/main/codegen/templates/StructWriters.java
+++ b/java/vector/src/main/codegen/templates/StructWriters.java
@@ -265,7 +265,7 @@ public class ${mode}StructWriter extends AbstractFieldWriter {
} else {
if (writer instanceof PromotableWriter) {
// ensure writers are initialized
- ((PromotableWriter)writer).getWriter(MinorType.${upperName});
+ ((PromotableWriter)writer).getWriter(MinorType.${upperName}<#if minor.class == "Decimal">, new ${minor.arrowType}(precision, scale)</#if>);
}
}
return writer;
diff --git a/java/vector/src/main/codegen/templates/UnionFixedSizeListWriter.java b/java/vector/src/main/codegen/templates/UnionFixedSizeListWriter.java
index 64ce120..ef6fd0c 100644
--- a/java/vector/src/main/codegen/templates/UnionFixedSizeListWriter.java
+++ b/java/vector/src/main/codegen/templates/UnionFixedSizeListWriter.java
@@ -181,11 +181,11 @@ public class UnionFixedSizeListWriter extends AbstractFieldWriter {
writer.setPosition(writer.idx() + 1);
}
- public void writeDecimal(int start, ArrowBuf buffer) {
+ public void writeDecimal(int start, ArrowBuf buffer, ArrowType arrowType) {
if (writer.idx() >= (idx() + 1) * listSize) {
throw new IllegalStateException(String.format("values at index %s is greater than listSize %s", idx(), listSize));
}
- writer.writeDecimal(start, buffer);
+ writer.writeDecimal(start, buffer, arrowType);
writer.setPosition(writer.idx() + 1);
}
diff --git a/java/vector/src/main/codegen/templates/UnionListWriter.java b/java/vector/src/main/codegen/templates/UnionListWriter.java
index 810dc05..16c1f3b 100644
--- a/java/vector/src/main/codegen/templates/UnionListWriter.java
+++ b/java/vector/src/main/codegen/templates/UnionListWriter.java
@@ -178,6 +178,11 @@ public class UnionListWriter extends AbstractFieldWriter {
writer.setPosition(writer.idx()+1);
}
+ public void writeDecimal(int start, ArrowBuf buffer, ArrowType arrowType) {
+ writer.writeDecimal(start, buffer, arrowType);
+ writer.setPosition(writer.idx()+1);
+ }
+
public void writeDecimal(int start, ArrowBuf buffer) {
writer.writeDecimal(start, buffer);
writer.setPosition(writer.idx()+1);
diff --git a/java/vector/src/main/codegen/templates/UnionReader.java b/java/vector/src/main/codegen/templates/UnionReader.java
index bfb6f19..20fdb41 100644
--- a/java/vector/src/main/codegen/templates/UnionReader.java
+++ b/java/vector/src/main/codegen/templates/UnionReader.java
@@ -88,7 +88,7 @@ public class UnionReader extends AbstractFieldReader {
<#list type.minor as minor>
<#assign name = minor.class?cap_first />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal">
case ${name?upper_case}:
return (FieldReader) get${name}();
</#if>
@@ -157,7 +157,7 @@ public class UnionReader extends AbstractFieldReader {
<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
<#assign safeType=friendlyType />
<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
private ${name}ReaderImpl ${uncappedName}Reader;
diff --git a/java/vector/src/main/codegen/templates/UnionVector.java b/java/vector/src/main/codegen/templates/UnionVector.java
index 8bf5d8a..177ef33 100644
--- a/java/vector/src/main/codegen/templates/UnionVector.java
+++ b/java/vector/src/main/codegen/templates/UnionVector.java
@@ -20,6 +20,7 @@ import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.ReferenceManager;
import org.apache.arrow.memory.util.hash.ArrowBufHasher;
import org.apache.arrow.util.Preconditions;
+import org.apache.arrow.vector.FieldVector;
import org.apache.arrow.vector.ValueVector;
import org.apache.arrow.vector.complex.StructVector;
import org.apache.arrow.vector.compare.VectorVisitor;
@@ -188,6 +189,10 @@ public class UnionVector implements FieldVector {
return internalStruct.addOrGet(fieldName(minorType), fieldType(minorType), c);
}
+ private <T extends FieldVector> T addOrGet(MinorType minorType, ArrowType arrowType, Class<T> c) {
+ return internalStruct.addOrGet(fieldName(minorType), FieldType.nullable(arrowType), c);
+ }
+
@Override
public long getValidityBufferAddress() {
return typeBuffer.memoryAddress();
@@ -231,14 +236,14 @@ public class UnionVector implements FieldVector {
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
<#assign lowerCaseName = name?lower_case/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
private ${name}Vector ${uncappedName}Vector;
- public ${name}Vector get${name}Vector() {
+ public ${name}Vector get${name}Vector(<#if minor.class == "Decimal">ArrowType arrowType</#if>) {
if (${uncappedName}Vector == null) {
int vectorCount = internalStruct.size();
- ${uncappedName}Vector = addOrGet(MinorType.${name?upper_case}, ${name}Vector.class);
+ ${uncappedName}Vector = addOrGet(MinorType.${name?upper_case},<#if minor.class == "Decimal"> arrowType,</#if> ${name}Vector.class);
if (internalStruct.size() > vectorCount) {
${uncappedName}Vector.allocateNew();
if (callBack != null) {
@@ -248,6 +253,14 @@ public class UnionVector implements FieldVector {
}
return ${uncappedName}Vector;
}
+ <#if minor.class == "Decimal">
+ public ${name}Vector get${name}Vector() {
+ if (${uncappedName}Vector == null) {
+ throw new IllegalArgumentException("No Decimal Vector present. Provide ArrowType argument to create a new vector");
+ }
+ return ${uncappedName}Vector;
+ }
+ </#if>
</#if>
</#list>
</#list>
@@ -554,11 +567,19 @@ public class UnionVector implements FieldVector {
}
public ValueVector getVector(int index) {
+ return getVector(index, null);
+ }
+
+ public ValueVector getVector(int index, ArrowType arrowType) {
int type = typeBuffer.getByte(index * TYPE_WIDTH);
- return getVectorByType(type);
+ return getVectorByType(type, arrowType);
}
- public ValueVector getVectorByType(int typeId) {
+ public ValueVector getVectorByType(int typeId) {
+ return getVectorByType(typeId, null);
+ }
+
+ public ValueVector getVectorByType(int typeId, ArrowType arrowType) {
switch (MinorType.values()[typeId]) {
case NULL:
return null;
@@ -567,9 +588,9 @@ public class UnionVector implements FieldVector {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
case ${name?upper_case}:
- return get${name}Vector();
+ return get${name}Vector(<#if minor.class == "Decimal">arrowType</#if>);
</#if>
</#list>
</#list>
@@ -641,6 +662,10 @@ public class UnionVector implements FieldVector {
}
public void setSafe(int index, UnionHolder holder) {
+ setSafe(index, holder, null);
+ }
+
+ public void setSafe(int index, UnionHolder holder, ArrowType arrowType) {
FieldReader reader = holder.reader;
if (writer == null) {
writer = new UnionWriter(UnionVector.this);
@@ -653,11 +678,11 @@ public class UnionVector implements FieldVector {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
case ${name?upper_case}:
Nullable${name}Holder ${uncappedName}Holder = new Nullable${name}Holder();
reader.read(${uncappedName}Holder);
- setSafe(index, ${uncappedName}Holder);
+ setSafe(index, ${uncappedName}Holder<#if minor.class == "Decimal">, arrowType</#if>);
break;
</#if>
</#list>
@@ -679,10 +704,10 @@ public class UnionVector implements FieldVector {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
- public void setSafe(int index, Nullable${name}Holder holder) {
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
+ public void setSafe(int index, Nullable${name}Holder holder<#if minor.class == "Decimal">, ArrowType arrowType</#if>) {
setType(index, MinorType.${name?upper_case});
- get${name}Vector().setSafe(index, holder);
+ get${name}Vector(<#if minor.class == "Decimal">arrowType</#if>).setSafe(index, holder);
}
</#if>
diff --git a/java/vector/src/main/codegen/templates/UnionWriter.java b/java/vector/src/main/codegen/templates/UnionWriter.java
index 82e7f6d..0aa2347 100644
--- a/java/vector/src/main/codegen/templates/UnionWriter.java
+++ b/java/vector/src/main/codegen/templates/UnionWriter.java
@@ -16,6 +16,7 @@
*/
import org.apache.arrow.vector.complex.impl.NullableStructWriterFactory;
+import org.apache.arrow.vector.types.Types;
<@pp.dropOutputFile />
<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/UnionWriter.java" />
@@ -110,6 +111,10 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
}
BaseWriter getWriter(MinorType minorType) {
+ return getWriter(minorType, null);
+ }
+
+ BaseWriter getWriter(MinorType minorType, ArrowType arrowType) {
switch (minorType) {
case STRUCT:
return getStructWriter();
@@ -120,9 +125,9 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams??>
+ <#if !minor.typeParams?? || minor.class == "Decimal">
case ${name?upper_case}:
- return get${name}Writer();
+ return get${name}Writer(<#if minor.class == "Decimal" >arrowType</#if>);
</#if>
</#list>
</#list>
@@ -135,36 +140,46 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
<#assign name = minor.class?cap_first />
<#assign fields = minor.fields!type.fields />
<#assign uncappedName = name?uncap_first/>
- <#if !minor.typeParams?? >
+ <#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
private ${name}Writer ${name?uncap_first}Writer;
- private ${name}Writer get${name}Writer() {
+ private ${name}Writer get${name}Writer(<#if minor.class == "Decimal">ArrowType arrowType</#if>) {
if (${uncappedName}Writer == null) {
- ${uncappedName}Writer = new ${name}WriterImpl(data.get${name}Vector());
+ ${uncappedName}Writer = new ${name}WriterImpl(data.get${name}Vector(<#if minor.class == "Decimal">arrowType</#if>));
${uncappedName}Writer.setPosition(idx());
writers.add(${uncappedName}Writer);
}
return ${uncappedName}Writer;
}
- public ${name}Writer as${name}() {
+ public ${name}Writer as${name}(<#if minor.class == "Decimal">ArrowType arrowType</#if>) {
data.setType(idx(), MinorType.${name?upper_case});
- return get${name}Writer();
+ return get${name}Writer(<#if minor.class == "Decimal">arrowType</#if>);
}
@Override
public void write(${name}Holder holder) {
data.setType(idx(), MinorType.${name?upper_case});
- get${name}Writer().setPosition(idx());
- get${name}Writer().write${name}(<#list fields as field>holder.${field.name}<#if field_has_next>, </#if></#list>);
+ <#if minor.class == "Decimal">ArrowType arrowType = new ArrowType.Decimal(holder.precision, holder.scale);</#if>
+ get${name}Writer(<#if minor.class == "Decimal">arrowType</#if>).setPosition(idx());
+ get${name}Writer(<#if minor.class == "Decimal">arrowType</#if>).write${name}(<#list fields as field>holder.${field.name}<#if field_has_next>, </#if></#list><#if minor.class == "Decimal">, arrowType</#if>);
}
- public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>) {
+ public void write${minor.class}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list><#if minor.class == "Decimal">, ArrowType arrowType</#if>) {
data.setType(idx(), MinorType.${name?upper_case});
- get${name}Writer().setPosition(idx());
- get${name}Writer().write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
+ get${name}Writer(<#if minor.class == "Decimal">arrowType</#if>).setPosition(idx());
+ get${name}Writer(<#if minor.class == "Decimal">arrowType</#if>).write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list><#if minor.class == "Decimal">, arrowType</#if>);
+ }
+ <#if minor.class == "Decimal">
+ public void write${minor.class}(${friendlyType} value) {
+ data.setType(idx(), MinorType.DECIMAL);
+ ArrowType arrowType = new ArrowType.Decimal(value.precision(), value.scale());
+ getDecimalWriter(arrowType).setPosition(idx());
+ getDecimalWriter(arrowType).writeDecimal(value);
}
+ </#if>
</#if>
</#list>
</#list>
@@ -205,7 +220,7 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
<#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
<#assign upperName = minor.class?upper_case />
<#assign capName = minor.class?cap_first />
- <#if !minor.typeParams?? >
+ <#if !minor.typeParams?? || minor.class == "Decimal" >
@Override
public ${capName}Writer ${lowerName}(String name) {
data.setType(idx(), MinorType.STRUCT);
@@ -220,6 +235,14 @@ public class UnionWriter extends AbstractFieldWriter implements FieldWriter {
return getListWriter().${lowerName}();
}
</#if>
+ <#if minor.class == "Decimal">
+ @Override
+ public ${capName}Writer ${lowerName}(String name<#list minor.typeParams as typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
+ data.setType(idx(), MinorType.STRUCT);
+ getStructWriter().setPosition(idx());
+ return getStructWriter().${lowerName}(name<#list minor.typeParams as typeParam>, ${typeParam.name}</#list>);
+ }
+ </#if>
</#list></#list>
@Override
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java b/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
index 50ca53f..0dc1bdd 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
@@ -163,6 +163,13 @@ public final class DecimalVector extends BaseFixedWidthVector {
}
/**
+ * Return precision for the decimal value.
+ */
+ public int getPrecision() {
+ return precision;
+ }
+
+ /**
* Return scale for the decimal value.
*/
public int getScale() {
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/complex/impl/PromotableWriter.java b/java/vector/src/main/java/org/apache/arrow/vector/complex/impl/PromotableWriter.java
index f92347d..6e8089c 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/complex/impl/PromotableWriter.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/complex/impl/PromotableWriter.java
@@ -59,7 +59,6 @@ public class PromotableWriter extends AbstractPromotableFieldWriter {
}
private MinorType type;
- private ArrowType arrowType;
private ValueVector vector;
private UnionVector unionVector;
private State state;
@@ -170,14 +169,9 @@ public class PromotableWriter extends AbstractPromotableFieldWriter {
}
private void setWriter(ValueVector v) {
- setWriter(v, null);
- }
-
- private void setWriter(ValueVector v, ArrowType arrowType) {
state = State.SINGLE;
vector = v;
type = v.getMinorType();
- this.arrowType = arrowType;
switch (type) {
case STRUCT:
writer = nullableStructWriterFactory.build((StructVector) vector);
@@ -211,7 +205,11 @@ public class PromotableWriter extends AbstractPromotableFieldWriter {
protected FieldWriter getWriter(MinorType type, ArrowType arrowType) {
if (state == State.UNION) {
- ((UnionWriter) writer).getWriter(type);
+ if (type == MinorType.DECIMAL) {
+ ((UnionWriter) writer).getWriter(type, arrowType);
+ } else {
+ ((UnionWriter) writer).getWriter(type);
+ }
} else if (state == State.UNTYPED) {
if (type == null) {
// ???
@@ -224,11 +222,15 @@ public class PromotableWriter extends AbstractPromotableFieldWriter {
ValueVector v = listVector != null ? listVector.addOrGetVector(fieldType).getVector() :
fixedListVector.addOrGetVector(fieldType).getVector();
v.allocateNew();
- setWriter(v, arrowType);
+ setWriter(v);
writer.setPosition(position);
} else if (type != this.type) {
promoteToUnion();
- ((UnionWriter) writer).getWriter(type);
+ if (type == MinorType.DECIMAL) {
+ ((UnionWriter) writer).getWriter(type, arrowType);
+ } else {
+ ((UnionWriter) writer).getWriter(type);
+ }
}
return writer;
}
@@ -268,32 +270,24 @@ public class PromotableWriter extends AbstractPromotableFieldWriter {
@Override
public void write(DecimalHolder holder) {
- // Infer decimal scale and precision
- if (arrowType == null) {
- arrowType = new ArrowType.Decimal(MAX_DECIMAL_PRECISION, holder.scale);
- }
-
- getWriter(MinorType.DECIMAL, arrowType).write(holder);
+ getWriter(MinorType.DECIMAL, new ArrowType.Decimal(MAX_DECIMAL_PRECISION, holder.scale)).write(holder);
}
@Override
- public void writeDecimal(int start, ArrowBuf buffer) {
- // Cannot infer decimal scale and precision
- if (arrowType == null) {
- throw new IllegalStateException("Cannot infer decimal scale and precision");
- }
-
- getWriter(MinorType.DECIMAL, arrowType).writeDecimal(start, buffer);
+ public void writeDecimal(int start, ArrowBuf buffer, ArrowType arrowType) {
+ getWriter(MinorType.DECIMAL, new ArrowType.Decimal(MAX_DECIMAL_PRECISION,
+ ((ArrowType.Decimal) arrowType).getScale())).writeDecimal(start, buffer, arrowType);
}
@Override
public void writeDecimal(BigDecimal value) {
- // Infer decimal scale and precision
- if (arrowType == null) {
- arrowType = new ArrowType.Decimal(MAX_DECIMAL_PRECISION, value.scale());
- }
+ getWriter(MinorType.DECIMAL, new ArrowType.Decimal(MAX_DECIMAL_PRECISION, value.scale())).writeDecimal(value);
+ }
- getWriter(MinorType.DECIMAL, arrowType).writeDecimal(value);
+ @Override
+ public void writeBigEndianBytesToDecimal(byte[] value, ArrowType arrowType) {
+ getWriter(MinorType.DECIMAL, new ArrowType.Decimal(MAX_DECIMAL_PRECISION,
+ ((ArrowType.Decimal) arrowType).getScale())).writeBigEndianBytesToDecimal(value, arrowType);
}
@Override
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java b/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
index a9f7a17..2703d26 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
@@ -96,6 +96,24 @@ public class DecimalUtility {
}
/**
+ * Check that the decimal scale equals the vectorScale and that the decimal precision is
+ * less than or equal to the vectorPrecision. If not, then an UnsupportedOperationException is
+ * thrown, otherwise returns true.
+ */
+ public static boolean checkPrecisionAndScale(int decimalPrecision, int decimalScale, int vectorPrecision,
+ int vectorScale) {
+ if (decimalScale != vectorScale) {
+ throw new UnsupportedOperationException("BigDecimal scale must equal that in the Arrow vector: " +
+ decimalScale + " != " + vectorScale);
+ }
+ if (decimalPrecision > vectorPrecision) {
+ throw new UnsupportedOperationException("BigDecimal precision can not be greater than that in the Arrow " +
+ "vector: " + decimalPrecision + " > " + vectorPrecision);
+ }
+ return true;
+ }
+
+ /**
* Write the given BigDecimal to the ArrowBuf at the given value index. Will throw an
* UnsupportedOperationException if the decimal size is greater than the Decimal vector byte
* width.
diff --git a/java/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestComplexCopier.java b/java/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestComplexCopier.java
index c5c59c9..5caa440 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestComplexCopier.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/complex/impl/TestComplexCopier.java
@@ -20,16 +20,23 @@ package org.apache.arrow.vector.complex.impl;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.math.BigDecimal;
+
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.vector.compare.VectorEqualsVisitor;
import org.apache.arrow.vector.complex.FixedSizeListVector;
import org.apache.arrow.vector.complex.ListVector;
import org.apache.arrow.vector.complex.MapVector;
+import org.apache.arrow.vector.complex.StructVector;
import org.apache.arrow.vector.complex.reader.FieldReader;
+import org.apache.arrow.vector.complex.writer.BaseWriter.StructWriter;
import org.apache.arrow.vector.complex.writer.FieldWriter;
+import org.apache.arrow.vector.holders.DecimalHolder;
import org.apache.arrow.vector.types.Types;
+import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.FieldType;
+import org.apache.arrow.vector.util.DecimalUtility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -130,8 +137,8 @@ public class TestComplexCopier {
mapWriter.value().integer().writeInt(i);
mapWriter.endEntry();
mapWriter.startEntry();
- mapWriter.key().integer().writeInt(i * 2);
- mapWriter.value().integer().writeInt(i * 2);
+ mapWriter.key().decimal().writeDecimal(BigDecimal.valueOf(i * 2));
+ mapWriter.value().decimal().writeDecimal(BigDecimal.valueOf(i * 2));
mapWriter.endEntry();
mapWriter.endMap();
}
@@ -175,9 +182,8 @@ public class TestComplexCopier {
listWriter.list().endList();
listWriter.list().startList();
- listWriter.list().bigInt().writeBigInt(i * 4);
- listWriter.list().bigInt().writeBigInt(i * 5);
- listWriter.list().bigInt().writeBigInt(i * 6);
+ listWriter.list().decimal().writeDecimal(BigDecimal.valueOf(i * 4));
+ listWriter.list().decimal().writeDecimal(BigDecimal.valueOf(i * 5));
listWriter.list().endList();
listWriter.endList();
}
@@ -199,4 +205,150 @@ public class TestComplexCopier {
}
}
+
+ @Test
+ public void testCopyFixedSizedListOfDecimalsVector() {
+ try (FixedSizeListVector from = FixedSizeListVector.empty("v", 3, allocator);
+ FixedSizeListVector to = FixedSizeListVector.empty("v", 3, allocator)) {
+ from.addOrGetVector(FieldType.nullable(new ArrowType.Decimal(3, 0)));
+ to.addOrGetVector(FieldType.nullable(new ArrowType.Decimal(3, 0)));
+
+ DecimalHolder holder = new DecimalHolder();
+ holder.buffer = allocator.buffer(DecimalUtility.DECIMAL_BYTE_LENGTH);
+
+ // populate from vector
+ UnionFixedSizeListWriter writer = from.getWriter();
+ for (int i = 0; i < COUNT; i++) {
+ writer.startList();
+ writer.decimal().writeDecimal(BigDecimal.valueOf(i));
+
+ DecimalUtility.writeBigDecimalToArrowBuf(new BigDecimal(i * 2), holder.buffer, 0);
+ holder.start = 0;
+ holder.scale = 0;
+ holder.precision = 3;
+ writer.decimal().write(holder);
+
+ DecimalUtility.writeBigDecimalToArrowBuf(new BigDecimal(i * 3), holder.buffer, 0);
+ writer.decimal().writeDecimal(0, holder.buffer, new ArrowType.Decimal(3, 0));
+
+ writer.endList();
+ }
+ from.setValueCount(COUNT);
+ to.setValueCount(COUNT);
+
+ // copy values
+ FieldReader in = from.getReader();
+ FieldWriter out = to.getWriter();
+ for (int i = 0; i < COUNT; i++) {
+ in.setPosition(i);
+ out.setPosition(i);
+ ComplexCopier.copy(in, out);
+ }
+
+ // validate equals
+ assertTrue(VectorEqualsVisitor.vectorEquals(from, to));
+ holder.buffer.close();
+ }
+ }
+
+ @Test
+ public void testCopyUnionListWithDecimal() {
+ try (ListVector from = ListVector.empty("v", allocator);
+ ListVector to = ListVector.empty("v", allocator)) {
+
+ UnionListWriter listWriter = from.getWriter();
+ listWriter.allocate();
+
+ for (int i = 0; i < COUNT; i++) {
+ listWriter.setPosition(i);
+ listWriter.startList();
+
+ listWriter.decimal().writeDecimal(BigDecimal.valueOf(i * 2));
+ listWriter.integer().writeInt(i);
+
+ listWriter.endList();
+ }
+ from.setValueCount(COUNT);
+
+ // copy values
+ FieldReader in = from.getReader();
+ FieldWriter out = to.getWriter();
+ for (int i = 0; i < COUNT; i++) {
+ in.setPosition(i);
+ out.setPosition(i);
+ ComplexCopier.copy(in, out);
+ }
+
+ to.setValueCount(COUNT);
+
+ // validate equals
+ assertTrue(VectorEqualsVisitor.vectorEquals(from, to));
+
+ }
+ }
+
+ @Test
+ public void testCopyStructVector() {
+ try (final StructVector from = StructVector.empty("v", allocator);
+ final StructVector to = StructVector.empty("v", allocator)) {
+
+ from.allocateNewSafe();
+
+ NullableStructWriter structWriter = from.getWriter();
+ for (int i = 0; i < COUNT; i++) {
+ structWriter.setPosition(i);
+ structWriter.start();
+ structWriter.integer("int").writeInt(i);
+ structWriter.decimal("dec", 0, 38).writeDecimal(BigDecimal.valueOf(i * 2));
+ StructWriter innerStructWriter = structWriter.struct("struc");
+ innerStructWriter.start();
+ innerStructWriter.integer("innerint").writeInt(i * 3);
+ innerStructWriter.decimal("innerdec", 0, 38).writeDecimal(BigDecimal.valueOf(i * 4));
+ innerStructWriter.end();
+ structWriter.end();
+ }
+
+ from.setValueCount(COUNT);
+
+ // copy values
+ FieldReader in = from.getReader();
+ FieldWriter out = to.getWriter();
+ for (int i = 0; i < COUNT; i++) {
+ in.setPosition(i);
+ out.setPosition(i);
+ ComplexCopier.copy(in, out);
+ }
+ to.setValueCount(COUNT);
+
+ // validate equals
+ assertTrue(VectorEqualsVisitor.vectorEquals(from, to));
+ }
+ }
+
+ @Test
+ public void testCopyDecimalVectorWrongScale() {
+ try (FixedSizeListVector from = FixedSizeListVector.empty("v", 3, allocator);
+ FixedSizeListVector to = FixedSizeListVector.empty("v", 3, allocator)) {
+ from.addOrGetVector(FieldType.nullable(new ArrowType.Decimal(3, 2)));
+ to.addOrGetVector(FieldType.nullable(new ArrowType.Decimal(3, 1)));
+
+ // populate from vector
+ UnionFixedSizeListWriter writer = from.getWriter();
+ for (int i = 0; i < COUNT; i++) {
+ writer.startList();
+ writer.decimal().writeDecimal(BigDecimal.valueOf(1.23));
+ writer.decimal().writeDecimal(BigDecimal.valueOf(2.45));
+ writer.endList();
+ }
+ from.setValueCount(COUNT);
+ to.setValueCount(COUNT);
+
+ // copy values
+ FieldReader in = from.getReader();
+ FieldWriter out = to.getWriter();
+ UnsupportedOperationException e = assertThrows(UnsupportedOperationException.class,
+ () -> ComplexCopier.copy(in, out));
+ assertTrue(e.getMessage().contains("BigDecimal scale must equal that in the Arrow vector: 2 != 1"));
+ }
+ }
}