Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-1812949 add get object and get bytes support for native arrow structured types #1968

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
93e98ea
return toStringResult for getObject and getBytes called on structured…
sfc-gh-mkubik Oct 29, 2024
3ae60f5
fix formatting
sfc-gh-mkubik Oct 29, 2024
a55e26a
remove getBytes implementation from structured types converters
sfc-gh-mkubik Oct 29, 2024
2e86075
remove getBytes, add null check to getObject
sfc-gh-mkubik Oct 29, 2024
c807e36
SNOW-1374896 Returning json string from method getObject when resultF…
sfc-gh-pmotacki Oct 30, 2024
475f18d
Merge branch 'master' into SNOW-1374896-add-get-object-and-bytes-support
sfc-gh-mkubik Nov 14, 2024
4a74df7
address review comments
sfc-gh-mkubik Nov 14, 2024
b30bb71
Merge branch 'master' into SNOW-1374896-add-get-object-and-bytes-support
sfc-gh-mkubik Nov 14, 2024
219d3c5
fix formatting
sfc-gh-mkubik Nov 14, 2024
d1ca630
remove variant from quotable type in ArrowStringRepresentationBuilder…
sfc-gh-mkubik Nov 14, 2024
230e935
add toBytes returning toString.toBytes, make compatibility tests latest
sfc-gh-mkubik Nov 15, 2024
8f58284
fix formatting
sfc-gh-mkubik Nov 18, 2024
9d3d019
ensure UTF-8 is used for both expected and actual value in string com…
sfc-gh-mkubik Nov 18, 2024
b62a4d9
set getBytes charset to UTF-8
sfc-gh-mkubik Nov 18, 2024
9857661
change charset in JSON converter for varchar
sfc-gh-mkubik Nov 18, 2024
e001bbb
use default charset in bytes assert
sfc-gh-mkubik Nov 19, 2024
04a476d
fix formatting
sfc-gh-mkubik Nov 19, 2024
55e7135
ensure UTF-8 in getBytes assert
sfc-gh-mkubik Nov 19, 2024
f911113
remove charset from assert
sfc-gh-mkubik Nov 19, 2024
4681524
remove UTF-8 charset specification from VarCharConverter
sfc-gh-mkubik Nov 19, 2024
2f0032c
add charset to both VarcharConverter and BytesConverter for Varchar type
sfc-gh-mkubik Nov 19, 2024
67e001b
assert charset is utf-8
sfc-gh-mkubik Nov 19, 2024
f851245
add charset specification
sfc-gh-mkubik Nov 20, 2024
ffb99e0
Merge branch 'master' into SNOW-1812949-add-get-object-and-bytes-support
sfc-gh-mkubik Nov 20, 2024
6a06311
add license to struct object wrapper, reuse constructor for SfSqlArra…
sfc-gh-mkubik Nov 22, 2024
496f99c
rename obj to arrayString in getJsonArray
sfc-gh-mkubik Nov 22, 2024
9e97ba7
Merge branch 'master' into SNOW-1812949-add-get-object-and-bytes-support
sfc-gh-mkubik Nov 26, 2024
2b9636d
merge getString getBytes and getObject test into one method to reuse …
sfc-gh-mkubik Nov 26, 2024
b2e1136
fix formatting
sfc-gh-mkubik Nov 26, 2024
5dff05b
split getJsonString in SfSqlArray into getJsonString for writes and g…
sfc-gh-mkubik Nov 26, 2024
afc7e75
Merge branch 'master' into SNOW-1812949-add-get-object-and-bytes-support
sfc-gh-mkubik Nov 26, 2024
22e118e
fix conflicts
sfc-gh-mkubik Nov 27, 2024
52b5c6e
Merge branch 'SNOW-1812949-add-get-object-and-bytes-support' of githu…
sfc-gh-mkubik Nov 27, 2024
fedace4
remove incorrect dependency, fix filename after resolving merge confl…
sfc-gh-mkubik Nov 27, 2024
1d864ee
remove testThrowingGettingObjectIfTypeWasNotIndicatedAndFormatNativeA…
sfc-gh-mkubik Nov 29, 2024
aae2c84
fix formatting
sfc-gh-mkubik Nov 29, 2024
a8ebedb
Merge branch 'master' into SNOW-1812949-add-get-object-and-bytes-support
sfc-gh-mkubik Nov 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions src/main/java/net/snowflake/client/core/SFArrowResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import java.util.stream.Stream;
import net.snowflake.client.core.arrow.ArrayConverter;
import net.snowflake.client.core.arrow.ArrowVectorConverter;
import net.snowflake.client.core.arrow.StructConverter;
import net.snowflake.client.core.arrow.StructObjectWrapper;
import net.snowflake.client.core.arrow.VarCharConverter;
import net.snowflake.client.core.arrow.VectorTypeConverter;
import net.snowflake.client.core.json.Converters;
Expand Down Expand Up @@ -576,12 +576,11 @@ public Object getObject(int columnIndex) throws SFException {
converter.setSessionTimeZone(sessionTimeZone);
Object obj = converter.toObject(index);
boolean isStructuredType = resultSetMetaData.isStructuredTypeColumn(columnIndex);
if (type == Types.STRUCT && isStructuredType) {
if (converter instanceof VarCharConverter) {
return createJsonSqlInput(columnIndex, obj);
} else if (converter instanceof StructConverter) {
return createArrowSqlInput(columnIndex, (Map<String, Object>) obj);
if (type == Types.STRUCT && isStructuredType && converter instanceof VarCharConverter) {
sfc-gh-mkubik marked this conversation as resolved.
Show resolved Hide resolved
if (obj == null) {
return null;
}
return new StructObjectWrapper((String) obj, createJsonSqlInput(columnIndex, obj));
}
return obj;
}
Expand All @@ -605,15 +604,6 @@ private Object createJsonSqlInput(int columnIndex, Object obj) throws SFExceptio
}
}

private Object createArrowSqlInput(int columnIndex, Map<String, Object> input)
throws SFException {
if (input == null) {
return null;
}
return new ArrowSqlInput(
input, session, converters, resultSetMetaData.getColumnFields(columnIndex));
}

@Override
public Array getArray(int columnIndex) throws SFException {
ArrowVectorConverter converter = currentChunkIterator.getCurrentConverter(columnIndex - 1);
Expand All @@ -625,16 +615,19 @@ public Array getArray(int columnIndex) throws SFException {
}
if (converter instanceof VarCharConverter) {
return getJsonArray((String) obj, columnIndex);
} else if (converter instanceof ArrayConverter) {
return getArrowArray((List<Object>) obj, columnIndex);
} else if (converter instanceof VectorTypeConverter) {
return getArrowArray((List<Object>) obj, columnIndex);
} else if (converter instanceof ArrayConverter || converter instanceof VectorTypeConverter) {
StructObjectWrapper structObjectWrapper = (StructObjectWrapper) obj;
return getArrowArray(
structObjectWrapper.getJsonString(),
(List<Object>) structObjectWrapper.getObject(),
columnIndex);
} else {
throw new SFException(queryId, ErrorCode.INVALID_STRUCT_DATA);
}
}

private SfSqlArray getArrowArray(List<Object> elements, int columnIndex) throws SFException {
private SfSqlArray getArrowArray(String text, List<Object> elements, int columnIndex)
throws SFException {
try {
List<FieldMetadata> fieldMetadataList = resultSetMetaData.getColumnFields(columnIndex);
if (fieldMetadataList.size() != 1) {
Expand All @@ -651,62 +644,74 @@ private SfSqlArray getArrowArray(List<Object> elements, int columnIndex) throws
switch (columnType) {
case Types.INTEGER:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.integerConverter(columnType))
.toArray(Integer[]::new));
case Types.SMALLINT:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.smallIntConverter(columnType))
.toArray(Short[]::new));
case Types.TINYINT:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.tinyIntConverter(columnType))
.toArray(Byte[]::new));
case Types.BIGINT:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.bigIntConverter(columnType)).toArray(Long[]::new));
case Types.DECIMAL:
case Types.NUMERIC:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.bigDecimalConverter(columnType))
.toArray(BigDecimal[]::new));
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGNVARCHAR:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.varcharConverter(columnType, columnSubType, scale))
.toArray(String[]::new));
case Types.BINARY:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.bytesConverter(columnType, scale))
.toArray(Byte[][]::new));
case Types.FLOAT:
case Types.REAL:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.floatConverter(columnType)).toArray(Float[]::new));
case Types.DOUBLE:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.doubleConverter(columnType))
.toArray(Double[]::new));
case Types.DATE:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.dateFromIntConverter(sessionTimeZone))
.toArray(Date[]::new));
case Types.TIME:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.timeFromIntConverter(scale)).toArray(Time[]::new));
case Types.TIMESTAMP:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(
elements,
Expand All @@ -715,13 +720,16 @@ private SfSqlArray getArrowArray(List<Object> elements, int columnIndex) throws
.toArray(Timestamp[]::new));
case Types.BOOLEAN:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, converters.booleanConverter(columnType))
.toArray(Boolean[]::new));
case Types.STRUCT:
return new SfSqlArray(columnSubType, mapAndConvert(elements, e -> e).toArray(Map[]::new));
return new SfSqlArray(
text, columnSubType, mapAndConvert(elements, e -> e).toArray(Map[]::new));
case Types.ARRAY:
return new SfSqlArray(
text,
columnSubType,
mapAndConvert(elements, e -> ((List) e).stream().toArray(Map[]::new))
.toArray(Map[][]::new));
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/net/snowflake/client/core/SFBaseResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -294,67 +294,79 @@ protected SfSqlArray getJsonArray(String obj, int columnIndex) throws SFExceptio
switch (columnType) {
case Types.INTEGER:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().integerConverter(columnType))
.toArray(Integer[]::new));
case Types.SMALLINT:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().smallIntConverter(columnType))
.toArray(Short[]::new));
case Types.TINYINT:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().tinyIntConverter(columnType))
.toArray(Byte[]::new));
case Types.BIGINT:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().bigIntConverter(columnType))
.toArray(Long[]::new));
case Types.DECIMAL:
case Types.NUMERIC:
return new SfSqlArray(
obj,
columnSubType,
convertToFixedArray(
getStream(nodeElements, getConverters().bigDecimalConverter(columnType))));
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGNVARCHAR:
return new SfSqlArray(
obj,
columnSubType,
getStream(
nodeElements,
getConverters().varcharConverter(columnType, columnSubType, scale))
.toArray(String[]::new));
case Types.BINARY:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().bytesConverter(columnType, scale))
.toArray(Byte[][]::new));
case Types.FLOAT:
case Types.REAL:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().floatConverter(columnType))
.toArray(Float[]::new));
case Types.DOUBLE:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().doubleConverter(columnType))
.toArray(Double[]::new));
case Types.DATE:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().dateStringConverter(session))
.toArray(Date[]::new));
case Types.TIME:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().timeFromStringConverter(session))
.toArray(Time[]::new));
case Types.TIMESTAMP:
return new SfSqlArray(
obj,
columnSubType,
getStream(
nodeElements,
Expand All @@ -364,16 +376,19 @@ protected SfSqlArray getJsonArray(String obj, int columnIndex) throws SFExceptio
.toArray(Timestamp[]::new));
case Types.BOOLEAN:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().booleanConverter(columnType))
.toArray(Boolean[]::new));
case Types.STRUCT:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().structConverter(OBJECT_MAPPER))
.toArray(Map[]::new));
case Types.ARRAY:
return new SfSqlArray(
obj,
columnSubType,
getStream(nodeElements, getConverters().arrayConverter(OBJECT_MAPPER))
.toArray(Map[][]::new));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.sql.Types;
import java.util.List;
import java.util.TimeZone;
import net.snowflake.client.core.arrow.StructObjectWrapper;
import net.snowflake.client.core.json.Converters;
import net.snowflake.client.jdbc.ErrorCode;
import net.snowflake.client.jdbc.FieldMetadata;
Expand Down Expand Up @@ -87,7 +88,7 @@ public Object getObject(int columnIndex) throws SFException {

case Types.STRUCT:
if (resultSetMetaData.isStructuredTypeColumn(columnIndex)) {
return getSqlInput((String) obj, columnIndex);
return new StructObjectWrapper((String) obj, getSqlInput((String) obj, columnIndex));
} else {
throw new SFException(ErrorCode.FEATURE_UNSUPPORTED, "data type: " + type);
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/net/snowflake/client/core/SfSqlArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@
@SnowflakeJdbcInternalApi
public class SfSqlArray implements Array {

private String text;
private int baseType;
private Object elements;

public SfSqlArray(String text, int baseType, Object elements) {
sfc-gh-mkubik marked this conversation as resolved.
Show resolved Hide resolved
this.text = text;
this.baseType = baseType;
this.elements = elements;
}

public SfSqlArray(int baseType, Object elements) {
this.baseType = baseType;
this.elements = elements;
Expand Down Expand Up @@ -82,6 +89,13 @@ public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map)
public void free() throws SQLException {}

public String getJsonString() throws SQLException {
if (text == null) {
text = buildJsonStringFromElements(elements);
}
return text;
}

private static String buildJsonStringFromElements(Object elements) throws SQLException {
try {
return SnowflakeUtil.mapJson(elements);
sfc-gh-mkubik marked this conversation as resolved.
Show resolved Hide resolved
} catch (JsonProcessingException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ public ArrayConverter(ListVector valueVector, int vectorIndex, DataConversionCon

@Override
public Object toObject(int index) throws SFException {
return vector.getObject(index);
return isNull(index) ? null : new StructObjectWrapper(toString(index), vector.getObject(index));
}

@Override
public byte[] toBytes(int index) throws SFException {
return isNull(index) ? null : toString(index).getBytes();
}

@Override
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/net/snowflake/client/core/arrow/MapConverter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.snowflake.client.core.arrow;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.snowflake.client.core.DataConversionContext;
import net.snowflake.client.core.SFException;
Expand Down Expand Up @@ -28,11 +30,23 @@ public MapConverter(MapVector valueVector, int columnIndex, DataConversionContex

@Override
public Object toObject(int index) throws SFException {
if (isNull(index)) {
return null;
}

List<JsonStringHashMap<String, Object>> entriesList =
(List<JsonStringHashMap<String, Object>>) vector.getObject(index);
return entriesList.stream()
.collect(
Collectors.toMap(entry -> entry.get("key").toString(), entry -> entry.get("value")));
Map<String, Object> map =
entriesList.stream()
.collect(
Collectors.toMap(
entry -> entry.get("key").toString(), entry -> entry.get("value")));
return new StructObjectWrapper(toString(index), map);
}

@Override
public byte[] toBytes(int index) throws SFException {
return isNull(index) ? null : toString(index).getBytes(StandardCharsets.UTF_8);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ public StructConverter(StructVector vector, int columnIndex, DataConversionConte

@Override
public Object toObject(int index) throws SFException {
return structVector.getObject(index);
return isNull(index)
? null
: new StructObjectWrapper(toString(index), structVector.getObject(index));
}

@Override
public byte[] toBytes(int index) throws SFException {
return isNull(index) ? null : toString(index).getBytes();
}

@Override
Expand All @@ -32,9 +39,13 @@ public String toString(int index) throws SFException {
SnowflakeType logicalType =
ArrowVectorConverterUtil.getSnowflakeTypeFromFieldMetadata(fieldVector.getField());
try {
ArrowVectorConverter converter =
ArrowVectorConverterUtil.initConverter(fieldVector, context, columnIndex);
builder.appendKeyValue(childName, converter.toString(index), logicalType);
if (fieldVector.isNull(index)) {
builder.appendKeyValue(childName, null, logicalType);
} else {
ArrowVectorConverter converter =
ArrowVectorConverterUtil.initConverter(fieldVector, context, columnIndex);
builder.appendKeyValue(childName, converter.toString(index), logicalType);
}
} catch (SnowflakeSQLException e) {
return structVector.getObject(index).toString();
}
Expand Down
Loading
Loading