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

Adding Array Support including Unit Tests #81

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
118 changes: 118 additions & 0 deletions src/main/java/org/opensearch/jdbc/ArrayImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.jdbc;

import java.sql.JDBCType;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.ResultSet;
import java.sql.Struct;
import java.sql.Array;
import java.util.Arrays;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;


/**
* This class implements the {@link java.sql.Struct} interface.
* <p>
* {@code StructImpl} provides a simple implementation of a struct data type.
* </p>
*/
public class ArrayImpl implements Array {
private ArrayList<Object> arrayData;
private JDBCType baseTypeName;

public ArrayImpl(ArrayList<Object> arrayData, JDBCType baseTypeName) {
this.arrayData = arrayData;
this.baseTypeName = baseTypeName;
}

@Override
public String getBaseTypeName() throws SQLException {
return this.baseTypeName.toString();
}

@Override
public int getBaseType() throws SQLException {
throw new SQLFeatureNotSupportedException("getBaseType() is not supported");
}

@Override
public Object getArray() throws SQLException {
return arrayData.toArray();
}

@Override
public Object getArray(Map<String, Class<?>> map) throws SQLException {
throw new SQLFeatureNotSupportedException("getArray(map) is not supported");
}

@Override
public Object getArray(long index, int count) throws SQLException {
if (index < 1 || index > arrayData.size() || index + count - 1 > arrayData.size() || count <= 0) {
throw new SQLException("Invalid index or count");
}
int fromIndex = (int) index - 1;
int toIndex = fromIndex + count;
return arrayData.subList(fromIndex, toIndex).toArray();
}

@Override
public Object getArray(long index, int count, Map<String, Class<?>> map) throws SQLException {
throw new SQLFeatureNotSupportedException("getArray(index, count, map) is not supported");
}

@Override
public ResultSet getResultSet() throws SQLException {
throw new SQLFeatureNotSupportedException("getResultSet() is not supported");
}

@Override
public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
throw new SQLFeatureNotSupportedException("getResultSet(map) is not supported");
}

@Override
public ResultSet getResultSet(long index, int count) throws SQLException {
throw new SQLFeatureNotSupportedException("getResultSet(index, count) is not supported");
}

@Override
public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map) throws SQLException {
throw new SQLFeatureNotSupportedException("getResultSet(index, count, map) is not supported");
}

@Override
public void free() throws SQLException {
arrayData = null;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof Array)) {
return false;
}
if (obj == this) {
return true;
}
Array other = (Array) obj;
try {
Object[] myArray = (Object[]) this.getArray();
Object[] otherArray = (Object[]) this.getArray();

if (!(this.getBaseTypeName().equals(other.getBaseTypeName())) || myArray.length != otherArray.length) {
return false;
}
return Arrays.equals(myArray, otherArray);
}
catch (SQLException e) {
return false;
}
}
}
27 changes: 24 additions & 3 deletions src/main/java/org/opensearch/jdbc/ResultSetImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.JDBCType;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -579,10 +580,24 @@ protected <T> T getObjectX(int columnIndex, Class<T> javaClass) throws SQLExcept

protected <T> T getObjectX(int columnIndex, Class<T> javaClass, Map<String, Object> conversionParams) throws SQLException {
final Object value = getColumn(columnIndex);
final TypeConverter tc = TypeConverters.getInstance(getColumnMetaData(columnIndex).getOpenSearchType().getJdbcType());
// Change made to identify if value is of type array since it isn't an official supported field type

JDBCType trueJdbcType = getColumnMetaData(columnIndex).getOpenSearchType().getJdbcType();

if (javaClass == Array.class) {
trueJdbcType = JDBCType.ARRAY;
if (conversionParams == null) {
conversionParams = new HashMap<String, Object>();
}
conversionParams.put("baseType", getColumnMetaData(columnIndex).getOpenSearchType().getJdbcType());
}

final TypeConverter tc = TypeConverters.getInstance(trueJdbcType);

if (null == tc) {
throw new SQLException("Conversion from " + getColumnMetaData(columnIndex).getOpenSearchType() + " not supported.");
}

return tc.convert(value, javaClass, conversionParams);
}

Expand Down Expand Up @@ -1007,7 +1022,10 @@ public Clob getClob(int columnIndex) throws SQLException {

@Override
public Array getArray(int columnIndex) throws SQLException {
throw new SQLFeatureNotSupportedException("Array is not supported");
log.debug(() -> logEntry("getArray (%s, %s)", columnIndex, Array.class));
Array value = getObjectX(columnIndex, Array.class);
log.debug(() -> logExit("getArray", value));
return value;
}

@Override
Expand Down Expand Up @@ -1050,7 +1068,10 @@ public Clob getClob(String columnLabel) throws SQLException {

@Override
public Array getArray(String columnLabel) throws SQLException {
throw new SQLFeatureNotSupportedException("Array is not supported");
log.debug(() -> logEntry("getArray (%s, %s)", columnLabel, Array.class));
Array value = getObjectX(getColumnIndex(columnLabel), Array.class);
log.debug(() -> logExit("getArray", value));
return value;
}

@Override
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/org/opensearch/jdbc/types/ArrayType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
package org.opensearch.jdbc.types;

import java.sql.Array;
import java.sql.JDBCType;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Collections;


import org.opensearch.jdbc.ArrayImpl;

public class ArrayType implements TypeHelper<Array> {

public static final ArrayType INSTANCE = new ArrayType();

private ArrayType() {

}

@Override
public String getTypeName() {
return "Array";
}

@Override
public Array fromValue(Object value, Map<String, Object> conversionParams) {
if (value == null || !(value instanceof ArrayList)) {
return null;
}

JDBCType baseType = conversionParams != null ? (JDBCType) conversionParams.get("baseType") : JDBCType.OTHER;

return new ArrayImpl((ArrayList) value, baseType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package org.opensearch.jdbc.types;

import java.sql.Array;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Struct;
Expand Down Expand Up @@ -38,6 +39,7 @@ public abstract class BaseTypeConverter implements TypeConverter {

typeHandlerMap.put(Struct.class, StructType.INSTANCE);

typeHandlerMap.put(Array.class, ArrayType.INSTANCE);
}

@Override
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/opensearch/jdbc/types/OpenSearchType.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

package org.opensearch.jdbc.types;

import java.sql.Array;
import java.sql.Date;
import java.sql.JDBCType;
import java.sql.Struct;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.HashMap;
Expand Down Expand Up @@ -61,15 +63,17 @@ public enum OpenSearchType {
STRING(JDBCType.VARCHAR, String.class, Integer.MAX_VALUE, 0, false),
IP(JDBCType.VARCHAR, String.class, 15, 0, false),
NESTED(JDBCType.STRUCT, null, 0, 0, false),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe nested should be mapped to array

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you explain why? I may not be following.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nested is mapped to ARRAY in sql plugin, curious why it is different here?
OpenSearchDataType.java#L39

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The sql plugin behavior always returns only the first element, doesn't actually treat it as an Array...
Screenshot 2023-06-02 at 2 07 35 PM

Copy link
Collaborator

Choose a reason for hiding this comment

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

A bug of workbench?

OBJECT(JDBCType.STRUCT, null, 0, 0, false),
OBJECT(JDBCType.STRUCT, Struct.class, 0, 0, false),
DATE(JDBCType.DATE, Date.class, 10, 10, false),
TIME(JDBCType.TIME, Time.class, 8, 8, false),
DATETIME(JDBCType.TIMESTAMP, Timestamp.class, 29, 29, false),
TIMESTAMP(JDBCType.TIMESTAMP, Timestamp.class, 29, 29, false),
BINARY(JDBCType.VARBINARY, String.class, Integer.MAX_VALUE, 0, false),
NULL(JDBCType.NULL, null, 0, 0, false),
UNDEFINED(JDBCType.NULL, null, 0, 0, false),
UNSUPPORTED(JDBCType.OTHER, null, 0, 0, false);
UNSUPPORTED(JDBCType.OTHER, null, 0, 0, false),
ARRAY(JDBCType.ARRAY, Array.class, 0, 0, false);


private static final Map<JDBCType, OpenSearchType> jdbcTypeToOpenSearchTypeMap;

Expand All @@ -91,6 +95,7 @@ public enum OpenSearchType {
jdbcTypeToOpenSearchTypeMap.put(JDBCType.DATE, DATE);
jdbcTypeToOpenSearchTypeMap.put(JDBCType.VARBINARY, BINARY);
jdbcTypeToOpenSearchTypeMap.put(JDBCType.STRUCT, OBJECT);
jdbcTypeToOpenSearchTypeMap.put(JDBCType.ARRAY, ARRAY);
}

/**
Expand Down
23 changes: 22 additions & 1 deletion src/main/java/org/opensearch/jdbc/types/TypeConverters.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package org.opensearch.jdbc.types;

import java.sql.Array;
import java.sql.Date;
import java.sql.JDBCType;
import java.sql.SQLException;
Expand Down Expand Up @@ -58,8 +59,9 @@ public class TypeConverters {

tcMap.put(JDBCType.NULL, new NullTypeConverter());

// Adding Struct Support
tcMap.put(JDBCType.STRUCT, new StructTypeConverter());

tcMap.put(JDBCType.ARRAY, new ArrayTypeConverter());
}

public static TypeConverter getInstance(JDBCType jdbcType) {
Expand All @@ -85,6 +87,25 @@ public Set<Class> getSupportedJavaClasses() {
}
}

public static class ArrayTypeConverter extends BaseTypeConverter {

private static final Set<Class> supportedJavaClasses = Collections.singleton(Array.class);

ArrayTypeConverter() {

}

@Override
public Class getDefaultJavaClass() {
return Array.class;
}

@Override
public Set<Class> getSupportedJavaClasses() {
return supportedJavaClasses;
}
}

public static class TimestampTypeConverter extends BaseTypeConverter {

private static final Set<Class> supportedJavaClasses = Collections.unmodifiableSet(
Expand Down
Loading