-
Notifications
You must be signed in to change notification settings - Fork 171
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
StructuredType part 1. #1557
Changes from all commits
c220deb
9008acb
12a735e
930a875
db59154
240ac15
f9fada6
1888ade
750cee2
a2717e7
779430a
1b01f3b
6281099
6d34b18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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.*; | ||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
@@ -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 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. which convension for static final fields should we use? |
||
|
||
TimeZone sessionTimeZone; | ||
|
||
|
@@ -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. | ||
|
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)); | ||
} | ||
} |
There was a problem hiding this comment.
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