Skip to content

Commit f9d0a55

Browse files
committed
implemented Connection#createStruct
1 parent 751ddb1 commit f9d0a55

File tree

5 files changed

+109
-17
lines changed

5 files changed

+109
-17
lines changed

jdbc-v2/src/main/java/com/clickhouse/jdbc/ConnectionImpl.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.clickhouse.client.api.metadata.TableSchema;
77
import com.clickhouse.client.api.query.GenericRecord;
88
import com.clickhouse.client.api.query.QuerySettings;
9+
import com.clickhouse.data.ClickHouseColumn;
910
import com.clickhouse.data.ClickHouseDataType;
1011
import com.clickhouse.jdbc.internal.ExceptionUtils;
1112
import com.clickhouse.jdbc.internal.JdbcConfiguration;
@@ -574,14 +575,15 @@ public Array createArrayOf(String typeName, Object[] elements) throws SQLExcepti
574575

575576
@Override
576577
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
577-
//TODO: Should this be supported?
578-
if (!config.isIgnoreUnsupportedRequests()) {
579-
throw new SQLFeatureNotSupportedException("createStruct not supported", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED);
578+
ClickHouseColumn column = ClickHouseColumn.of("v", typeName);
579+
if (column.getDataType().equals(ClickHouseDataType.Tuple)) {
580+
return new com.clickhouse.jdbc.types.Struct(column, attributes);
581+
} else {
582+
throw new SQLException("Only Tuple datatype is supported for Struct", ExceptionUtils.SQL_STATE_CLIENT_ERROR);
580583
}
581-
582-
return null;
583584
}
584585

586+
585587
@Override
586588
public void setSchema(String schema) throws SQLException {
587589
ensureOpen();

jdbc-v2/src/main/java/com/clickhouse/jdbc/PreparedStatementImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ private static String encodeObject(Object x, Long length) throws SQLException {
783783
return "fromUnixTimestamp64Nano(" + (((Instant) x).getEpochSecond() * 1_000_000_000L + ((Instant) x).getNano()) + ")";
784784
} else if (x instanceof InetAddress) {
785785
return "'" + ((InetAddress) x).getHostAddress() + "'";
786-
} else if (x instanceof Array) {
786+
} else if (x instanceof java.sql.Array) {
787787
StringBuilder listString = new StringBuilder();
788788
listString.append("[");
789789
int i = 0;

jdbc-v2/src/main/java/com/clickhouse/jdbc/types/Array.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ public class Array implements java.sql.Array {
1414
private static final Logger log = LoggerFactory.getLogger(Array.class);
1515
Object[] array;
1616
int type; //java.sql.Types
17-
String typeName;
17+
String elementTypeName;
1818

19-
public Array(List<Object> list, String itemTypeName, int itemType) throws SQLException {
19+
public Array(List<Object> list, String elementTypeName, int itemType) throws SQLException {
2020
if (list == null) {
2121
throw ExceptionUtils.toSqlState(new IllegalArgumentException("List cannot be null"));
2222
}
2323

2424
this.array = list.toArray();
2525
this.type = itemType;
26-
this.typeName = itemTypeName;
26+
this.elementTypeName = elementTypeName;
2727
}
2828

2929
@Override
3030
public String getBaseTypeName() throws SQLException {
31-
return typeName;
31+
return elementTypeName;
3232
}
3333

3434
@Override
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.clickhouse.jdbc.types;
2+
3+
import com.clickhouse.data.ClickHouseColumn;
4+
5+
import java.sql.SQLException;
6+
import java.util.Map;
7+
8+
public class Struct implements java.sql.Struct {
9+
10+
private final Object[] attributes;
11+
12+
private final ClickHouseColumn column;
13+
14+
public Struct(ClickHouseColumn column, Object[] attributes) {
15+
this.column = column;
16+
this.attributes = attributes;
17+
}
18+
19+
@Override
20+
public String getSQLTypeName() throws SQLException {
21+
return column.getOriginalTypeName();
22+
}
23+
24+
@Override
25+
public Object[] getAttributes() throws SQLException {
26+
return attributes;
27+
}
28+
29+
@Override
30+
public Object[] getAttributes(Map<String, Class<?>> map) throws SQLException {
31+
return attributes;
32+
}
33+
34+
public ClickHouseColumn getColumn() {
35+
return column;
36+
}
37+
}

jdbc-v2/src/test/java/com/clickhouse/jdbc/ConnectionTest.java

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import java.sql.SQLException;
2525
import java.sql.SQLFeatureNotSupportedException;
2626
import java.sql.Statement;
27+
import java.sql.Struct;
28+
import java.sql.Timestamp;
29+
import java.time.LocalDateTime;
30+
import java.time.ZoneId;
2731
import java.util.Arrays;
2832
import java.util.Base64;
2933
import java.util.Properties;
@@ -363,16 +367,65 @@ public static Object[][] setAndGetClientInfoTestDataProvider() {
363367

364368
@Test(groups = { "integration" })
365369
public void createArrayOfTest() throws SQLException {
366-
Connection localConnection = this.getJdbcConnection();
367-
Array array = localConnection.createArrayOf("Int8", new Object[] { 1, 2, 3 });
368-
Assert.assertNotNull(array);
369-
Assert.assertEquals(array.getArray(), new Object[] { 1, 2, 3 });
370+
try (Connection conn = new ConnectionImpl(getEndpointString(), null)) {
371+
final String arrayType = "Array(Array(String))";
372+
final String tableName = "array_create_test";
373+
try (Statement stmt = conn.createStatement()) {
374+
stmt.executeUpdate("CREATE TABLE " +tableName + " (v1 " + arrayType + ") ENGINE MergeTree ORDER BY ()");
375+
376+
377+
String[][] srcArray = new String[][] {
378+
new String[] {"v1"},
379+
new String[] {"v1", "v2"},
380+
new String[] {"v1", "v2", "v3"},
381+
};
382+
Array arrayValue = conn.createArrayOf(arrayType, srcArray );
383+
try (PreparedStatement pStmt = conn.prepareStatement("INSERT INTO " + tableName + " (v1) VALUES (?)")) {
384+
pStmt.setArray(1, arrayValue);
385+
pStmt.executeUpdate();
386+
pStmt.setObject(1, arrayValue);
387+
pStmt.executeUpdate();
388+
}
389+
390+
try (ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName)) {
391+
Assert.assertTrue(rs.next());
392+
Array array1 = rs.getArray(1);
393+
rs.next();
394+
Array array2 = rs.getArray(1);
395+
Assert.assertEquals(array1, array2);
396+
}
397+
}
398+
}
370399
}
371400

372401
@Test(groups = { "integration" })
373-
public void createStructTest() throws SQLException {
374-
Connection localConnection = this.getJdbcConnection();
375-
assertThrows(SQLFeatureNotSupportedException.class, () -> localConnection.createStruct("type-name", new Object[] { 1, 2, 3 }));
402+
public void testCreateStruct() throws SQLException {
403+
try (Connection conn = this.getJdbcConnection()) {
404+
final String tableName = "test_struct_tuple";
405+
final String tupleType = "Tuple(Int8, String, DateTime64)";
406+
try (Statement stmt = conn.createStatement()) {
407+
stmt.executeUpdate("CREATE TABLE " + tableName +" (v1 " + tupleType + ") ENGINE MergeTree ORDER BY ()");
408+
409+
final java.sql.Timestamp timePart = Timestamp.valueOf(LocalDateTime.now(ZoneId.of("America/Los_Angeles")));
410+
timePart.setNanos(333000000);
411+
412+
Struct tupleValue = conn.createStruct(tupleType, new Object[] {120, "test tuple value", timePart});
413+
414+
try (PreparedStatement pStmt = conn.prepareStatement("INSERT INTO " +tableName + " VALUES (?)")) {
415+
pStmt.setObject(1, tupleValue);
416+
pStmt.executeUpdate();
417+
}
418+
419+
420+
try (ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName)) {
421+
Assert.assertTrue(rs.next());
422+
Struct structValue = (Struct) rs.getObject(1);
423+
Assert.assertEquals(structValue.getAttributes()[0], 120);
424+
Assert.assertEquals(structValue.getAttributes()[1], "test tuple value");
425+
Assert.assertEquals(structValue.getAttributes()[2], timePart);
426+
}
427+
}
428+
}
376429
}
377430

378431
@Test(groups = { "integration" })

0 commit comments

Comments
 (0)