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

StructuredType part 1. #1557

Closed
Closed
160 changes: 160 additions & 0 deletions src/main/java/net/snowflake/client/core/JsonSqlInput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package net.snowflake.client.core;

import com.fasterxml.jackson.databind.JsonNode;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's not use wildcard imports

import java.util.Iterator;

public class JsonSqlInput implements SQLInput {

// TODO extractedType maybe getObject should return raw input then it won't be needed
public JsonNode getInput() {
return input;
}

private final JsonNode input;
private final Iterator<JsonNode> elements;

public JsonSqlInput(JsonNode input) {
this.input = input;
elements = input.elements();
}

@Override
public String readString() throws SQLException {
return elements.next().textValue();
}

@Override
public boolean readBoolean() throws SQLException {
return elements.next().booleanValue();
}

@Override
public byte readByte() throws SQLException {
return 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to add some todo comments for default values?

}

@Override
public short readShort() throws SQLException {
return 0;
}

@Override
public int readInt() throws SQLException {
return 0;
}

@Override
public long readLong() throws SQLException {
return 0;
}

@Override
public float readFloat() throws SQLException {
return 0;
}

@Override
public double readDouble() throws SQLException {
return 0;
}

@Override
public BigDecimal readBigDecimal() throws SQLException {
return null;
}

@Override
public byte[] readBytes() throws SQLException {
return new byte[0];
}

@Override
public Date readDate() throws SQLException {
return null;
}

@Override
public Time readTime() throws SQLException {
return null;
}

@Override
public Timestamp readTimestamp() throws SQLException {
return null;
}

@Override
public Reader readCharacterStream() throws SQLException {
return null;
}

@Override
public InputStream readAsciiStream() throws SQLException {
return null;
}

@Override
public InputStream readBinaryStream() throws SQLException {
return null;
}

@Override
public Object readObject() throws SQLException {
return null;
}

@Override
public Ref readRef() throws SQLException {
return null;
}

@Override
public Blob readBlob() throws SQLException {
return null;
}

@Override
public Clob readClob() throws SQLException {
return null;
}

@Override
public Array readArray() throws SQLException {
return null;
}

@Override
public boolean wasNull() throws SQLException {
return false;
}

@Override
public URL readURL() throws SQLException {
return null;
}

@Override
public NClob readNClob() throws SQLException {
return null;
}

@Override
public String readNString() throws SQLException {
return null;
}

@Override
public SQLXML readSQLXML() throws SQLException {
return null;
}

@Override
public RowId readRowId() throws SQLException {
return null;
}
}
43 changes: 29 additions & 14 deletions src/main/java/net/snowflake/client/core/SFArrowResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,9 @@
*/
package net.snowflake.client.core;

import static net.snowflake.client.core.StmtUtil.eventHandler;
import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetProperty;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.TimeZone;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.snowflake.client.core.arrow.ArrowVectorConverter;
import net.snowflake.client.jdbc.*;
import net.snowflake.client.jdbc.ArrowResultChunk.ArrowChunkIterator;
Expand All @@ -29,9 +20,20 @@
import net.snowflake.common.core.SqlState;
import org.apache.arrow.memory.RootAllocator;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.*;
import java.util.TimeZone;

import static net.snowflake.client.core.StmtUtil.eventHandler;
import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetProperty;

/** Arrow result set implementation */
public class SFArrowResultSet extends SFBaseResultSet implements DataConversionContext {
static final SFLogger logger = SFLoggerFactory.getLogger(SFArrowResultSet.class);
private static final SFLogger logger = SFLoggerFactory.getLogger(SFArrowResultSet.class);
private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.getObjectMapper();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private static final field for logger has different convention than OBJECT_MAPPER - we should keep and use one of them


/** iterator over current arrow result chunk */
private ArrowChunkIterator currentChunkIterator;
Expand Down Expand Up @@ -477,7 +479,20 @@ public Object getObject(int columnIndex) throws SFException {
converter.setTreatNTZAsUTC(treatNTZAsUTC);
converter.setUseSessionTimezone(useSessionTimezone);
converter.setSessionTimeZone(timeZone);
return converter.toObject(index);
Object obj = converter.toObject(index);
return handleObjectType(columnIndex, obj);
}

private Object handleObjectType(int columnIndex, Object obj) throws SFException {
if (resultSetMetaData.getColumnType(columnIndex) == Types.STRUCT) {
try {
JsonNode jsonNode = OBJECT_MAPPER.readTree((String) obj);
return new JsonSqlInput(jsonNode);
} catch (JsonProcessingException e) {
throw new SFException(e, ErrorCode.INVALID_STRUCT_DATA);
}
}
return obj;
}

@Override
Expand Down
52 changes: 48 additions & 4 deletions src/main/java/net/snowflake/client/core/SFJsonResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@

package net.snowflake.client.core;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;

import com.fasterxml.jackson.databind.node.ArrayNode;
import net.snowflake.client.core.arrow.ArrowResultUtil;
import net.snowflake.client.jdbc.*;
import net.snowflake.client.log.ArgSupplier;
Expand All @@ -23,9 +28,19 @@
import net.snowflake.common.core.SFTimestamp;
import org.apache.arrow.vector.Float8Vector;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.TimeZone;

/** Abstract class used to represent snowflake result set in json format */
public abstract class SFJsonResultSet extends SFBaseResultSet {
private static final SFLogger logger = SFLoggerFactory.getLogger(SFJsonResultSet.class);
private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.getObjectMapper();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which convension for static final fields should we use?


TimeZone sessionTimeZone;

Expand Down Expand Up @@ -86,11 +101,40 @@ public Object getObject(int columnIndex) throws SFException {
case Types.BOOLEAN:
return getBoolean(columnIndex);

case Types.STRUCT:
return getSqlInput((String) obj);

case Types.ARRAY:
return getArrayOfSqlInput((String) obj);

default:
throw new SFException(ErrorCode.FEATURE_UNSUPPORTED, "data type: " + type);
}
}

private Object getArrayOfSqlInput(String input) throws SFException {
try {
List<JsonSqlInput> result = new ArrayList<>();
ArrayNode arrayNode = (ArrayNode) OBJECT_MAPPER.readTree(input);
Iterator nodeElements = arrayNode.elements();
while (nodeElements.hasNext()) {
result.add(new JsonSqlInput((JsonNode) nodeElements.next()));
}
return result;
} catch (JsonProcessingException e) {
throw new SFException(e, ErrorCode.INVALID_STRUCT_DATA);
}
}

private Object getSqlInput(String input) throws SFException {
try {
JsonNode jsonNode = OBJECT_MAPPER.readTree(input);
return new JsonSqlInput(jsonNode);
} catch (JsonProcessingException e) {
throw new SFException(e, ErrorCode.INVALID_STRUCT_DATA);
}
}

/**
* Sometimes large BIGINTS overflow the java Long type. In these cases, return a BigDecimal type
* instead.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.snowflake.client.core.structs;

import java.sql.SQLData;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

public class SnowflakeObjectTypeFactories {
private static final Map<Class<?>, Supplier<SQLData>> factories = new ConcurrentHashMap<>();

public static void register(Class<?> type, Supplier<SQLData> factory) {
Objects.requireNonNull((Object) type, "type cannot be null");
Objects.requireNonNull((Object) factory, "factory cannot be null");
factories.put(type, factory);
}

public static void unregister(Class<?> type) {
Objects.requireNonNull((Object) type, "type cannot be null");
factories.remove(type);
}

public static Optional<Supplier<SQLData>> get(Class<?> type) {
Objects.requireNonNull((Object) type, "type cannot be null");
return Optional.ofNullable(factories.get(type));
}
}
3 changes: 2 additions & 1 deletion src/main/java/net/snowflake/client/jdbc/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ public enum ErrorCode {
INVALID_CONNECT_STRING(200059, SqlState.CONNECTION_EXCEPTION),
INVALID_OKTA_USERNAME(200060, SqlState.CONNECTION_EXCEPTION),
GCP_SERVICE_ERROR(200061, SqlState.SYSTEM_ERROR),
AUTHENTICATOR_REQUEST_TIMEOUT(200062, SqlState.CONNECTION_EXCEPTION);
AUTHENTICATOR_REQUEST_TIMEOUT(200062, SqlState.CONNECTION_EXCEPTION),
INVALID_STRUCT_DATA(200063, SqlState.DATA_EXCEPTION);

public static final String errorMessageResource = "net.snowflake.client.jdbc.jdbc_error_messages";

Expand Down
Loading
Loading