Skip to content

Commit 4a93d5d

Browse files
committed
Implemented getting prepared statement metadata
1 parent 07b8b1f commit 4a93d5d

File tree

5 files changed

+55
-67
lines changed

5 files changed

+55
-67
lines changed

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

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.clickhouse.jdbc;
22

3-
import com.clickhouse.client.api.metadata.TableSchema;
4-
import com.clickhouse.data.ClickHouseColumn;
53
import com.clickhouse.client.api.metadata.TableSchema;
64
import com.clickhouse.data.Tuple;
75
import com.clickhouse.jdbc.internal.ExceptionUtils;
@@ -32,7 +30,6 @@
3230
import java.sql.SQLFeatureNotSupportedException;
3331
import java.sql.SQLType;
3432
import java.sql.SQLXML;
35-
import java.sql.Statement;
3633
import java.sql.Time;
3734
import java.sql.Timestamp;
3835
import java.sql.Types;
@@ -49,6 +46,7 @@
4946
import java.util.ArrayList;
5047
import java.util.Calendar;
5148
import java.util.Collection;
49+
import java.util.Collections;
5250
import java.util.List;
5351
import java.util.Map;
5452

@@ -68,12 +66,8 @@ public class PreparedStatementImpl extends StatementImpl implements PreparedStat
6866
String [] valueSegments;
6967
Object [] parameters;
7068
String insertIntoSQL;
71-
72-
ShowStatementType showStatementType;
73-
7469
StatementType statementType;
7570

76-
7771
private final ParameterMetaData parameterMetaData;
7872

7973
private ResultSetMetaData resultSetMetaData = null;
@@ -83,22 +77,19 @@ public PreparedStatementImpl(ConnectionImpl connection, String sql) throws SQLEx
8377
this.originalSql = sql.trim();
8478
//Split the sql string into an array of strings around question mark tokens
8579
this.sqlSegments = splitStatement(originalSql);
86-
Object[] parseResult = parseStatement(originalSql);
87-
this.statementType = (StatementType) parseResult[0];
80+
this.statementType = parseStatementType(originalSql);
8881

8982
switch (statementType) {
9083
case INSERT:
9184
insertIntoSQL = originalSql.substring(0, originalSql.indexOf("VALUES") + 6);
9285
valueSegments = originalSql.substring(originalSql.indexOf("VALUES") + 6).split("\\?");
9386
break;
94-
case SHOW:
95-
showStatementType = (ShowStatementType) parseResult[1];
96-
break;
9787
}
9888

9989
//Create an array of objects to store the parameters
10090
this.parameters = new Object[sqlSegments.length - 1];
10191
this.defaultCalendar = connection.defaultCalendar;
92+
this.parameterMetaData = new ParameterMetaDataImpl(this.parameters.length);
10293
}
10394

10495
private String compileSql(String [] segments) {
@@ -328,18 +319,19 @@ public ResultSetMetaData getMetaData() throws SQLException {
328319
String sql = JdbcUtils.replaceQuestionMarks(originalSql, JdbcUtils.NULL);
329320
TableSchema tSchema = connection.getClient().getTableSchemaFromQuery(sql);
330321
resultSetMetaData = new ResultSetMetaDataImpl(tSchema.getColumns(),
331-
tSchema.getDatabaseName(), "", tSchema.getTableName(), Collections.emptyMap());
322+
connection.getSchema(), connection.getCatalog(),
323+
tSchema.getTableName(), Collections.emptyMap());
332324
} catch (Exception e) {
333-
// fallback to empty until
325+
LOG.warn("Failed to get schema for statement '{}'", originalSql);
334326
}
335-
} else if (statementType == StatementType.SHOW) {
336-
// predefined (it can be different for different objects)
337-
} else if (statementType == StatementType.DESCRIBE) {
338-
// predefined
339-
} else {
340-
// fallback to empty
341327
}
342-
} else if (resultSetMetaData == null) {
328+
329+
if (resultSetMetaData == null) {
330+
resultSetMetaData = new ResultSetMetaDataImpl(Collections.emptyList(),
331+
connection.getSchema(), connection.getCatalog(),
332+
"", Collections.emptyMap());
333+
}
334+
} else if (currentResultSet != null) {
343335
resultSetMetaData = currentResultSet.getMetaData();
344336
}
345337

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ public ResultSetImpl(StatementImpl parentStatement, QueryResponse response, Clic
3939
this.response = response;
4040
this.reader = reader;
4141
TableSchema tableMetadata = reader.getSchema();
42+
43+
// Result set contains columns from one database (there is a special table engine 'Merge' to do cross DB queries)
4244
this.metaData = new ResultSetMetaDataImpl(tableMetadata
43-
.getColumns(), tableMetadata.getDatabaseName(), "", tableMetadata.getTableName(),
45+
.getColumns(), response.getSettings().getDatabase(), "", tableMetadata.getTableName(),
4446
Collections.emptyMap());
4547
this.closed = false;
4648
this.wasNull = false;

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

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.sql.SQLWarning;
2020
import java.sql.Statement;
2121
import java.util.ArrayList;
22-
import java.util.Arrays;
2322
import java.util.Collections;
2423
import java.util.List;
2524
import java.util.UUID;
@@ -60,31 +59,14 @@ protected enum StatementType {
6059
SELECT, INSERT, DELETE, UPDATE, CREATE, DROP, ALTER, TRUNCATE, USE, SHOW, DESCRIBE, EXPLAIN, SET, KILL, OTHER, INSERT_INTO_SELECT
6160
}
6261

63-
protected enum ShowStatementType {
64-
TABLES, USERS, PROCESSLIST
65-
}
66-
67-
protected static StatementType parseStatementType(String sql) {
68-
return (StatementType) parseStatement(sql)[0];
69-
}
70-
71-
private static final Object[] OTHER_STMT_TYPE_RESULT = new Object[] {StatementType.OTHER};
72-
73-
/**
74-
* Returns non-empty array with at list StatementType on position 0.
75-
* If Show statement - returns rest token from the statement.
76-
*
77-
* @param sql - raw SQL statement
78-
* @return Object[] - parse result
79-
*/
80-
public static Object[] parseStatement(String sql) {
62+
public static StatementType parseStatementType(String sql) {
8163
if (sql == null) {
82-
return OTHER_STMT_TYPE_RESULT;
64+
return StatementType.OTHER;
8365
}
8466

8567
String trimmedSql = sql.trim();
8668
if (trimmedSql.isEmpty()) {
87-
return OTHER_STMT_TYPE_RESULT;
69+
return StatementType.OTHER;
8870
}
8971

9072
trimmedSql = BLOCK_COMMENT.matcher(trimmedSql).replaceAll("").trim(); // remove comments
@@ -138,14 +120,6 @@ public static Object[] parseStatement(String sql) {
138120
break;
139121
case "SHOW":
140122
statementType = StatementType.SHOW;
141-
ShowStatementType showStatementType = null;
142-
for (String token : tokens) {
143-
if (!token.isEmpty()) {
144-
showStatementType = ShowStatementType.valueOf(token.toUpperCase());
145-
break;
146-
}
147-
}
148-
parseResult = new Object[] {statementType, showStatementType};
149123
break;
150124
case "DESCRIBE":
151125
statementType = StatementType.DESCRIBE;
@@ -160,13 +134,13 @@ public static Object[] parseStatement(String sql) {
160134
statementType = StatementType.KILL;
161135
break;
162136
default:
163-
parseResult = OTHER_STMT_TYPE_RESULT;
137+
statementType = StatementType.OTHER;
164138
}
165-
return parseResult == null ? new Object[] {statementType} : parseResult;
139+
return statementType;
166140
}
167141
}
168142

169-
return OTHER_STMT_TYPE_RESULT;
143+
return StatementType.OTHER;
170144
}
171145

172146
protected static String parseTableName(String sql) {
@@ -242,6 +216,7 @@ public ResultSetImpl executeQuery(String sql, QuerySettings settings) throws SQL
242216
mergedSettings.setQueryId(lastQueryId);
243217
}
244218
LOG.debug("Query ID: {}", lastQueryId);
219+
mergedSettings.setDatabase(connection.getSchema());
245220

246221
try {
247222
lastSql = parseJdbcEscapeSyntax(sql);

jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public class ResultSetMetaDataImpl implements java.sql.ResultSetMetaData, JdbcV2
2222

2323
private final Map<ClickHouseDataType, Class<?>> typeClassMap;
2424

25-
public ResultSetMetaDataImpl(List<ClickHouseColumn> columns, String schema, String catalog, String tableName, Map<ClickHouseDataType, Class<?>> typeClassMap) {
25+
public ResultSetMetaDataImpl(List<ClickHouseColumn> columns, String schema, String catalog, String tableName,
26+
Map<ClickHouseDataType, Class<?>> typeClassMap) {
2627
this.columns = columns;
2728
this.schema = schema;
2829
this.catalog = catalog;
@@ -115,7 +116,7 @@ public String getColumnName(int column) throws SQLException {
115116

116117
@Override
117118
public String getSchemaName(int column) throws SQLException {
118-
return "";
119+
return schema;
119120
}
120121

121122
@Override

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

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.TimeZone;
2222

2323
import static org.testng.Assert.*;
24+
import static org.testng.Assert.assertEquals;
2425

2526

2627
public class PreparedStatementTest extends JdbcIntegrationTest {
@@ -322,29 +323,46 @@ void testInsert() throws Exception {
322323
}
323324

324325
@Test(dataProvider = "testGetMetadataDataProvider")
325-
void testGetMetadata(String sql) throws Exception {
326+
void testGetMetadata(String sql, int colCountBeforeExecution, Object[] values,
327+
int colCountAfterExecution) throws Exception {
326328
String tableName = "test_get_metadata";
327-
runQuery("CREATE TABLE " + tableName + " ( a1 String, b2 Float, b3 Float ) Engine=MergeTree ORDER BY ()");
329+
runQuery("CREATE TABLE IF NOT EXISTS " + tableName + " ( a1 String, b2 Float, b3 Float ) Engine=MergeTree ORDER BY ()");
328330

329331
try (Connection conn = getJdbcConnection();
330-
PreparedStatement stmt = conn.prepareStatement(sql)) {
332+
PreparedStatement stmt = conn.prepareStatement(String.format(sql, tableName))) {
331333
ResultSetMetaData metadataRs = stmt.getMetaData();
332334
assertNotNull(metadataRs);
335+
Assert.assertEquals(metadataRs.getColumnCount(), colCountBeforeExecution);
333336

334-
Assert.assertEquals(metadataRs.getColumnCount(), 3);
335-
Assert.assertEquals(metadataRs.getColumnName(1), "a1");
336-
Assert.assertEquals(metadataRs.getColumnType(1), Types.VARCHAR);
337-
Assert.assertEquals(metadataRs.getColumnName(2), "b2");
338-
Assert.assertEquals(metadataRs.getColumnType(2), Types.FLOAT);
339-
Assert.assertEquals(metadataRs.getColumnName(3), "b3");
340-
Assert.assertEquals(metadataRs.getColumnType(3), Types.FLOAT);
337+
for (int i = 1; i <= metadataRs.getColumnCount(); i++) {
338+
System.out.println("label=" + metadataRs.getColumnName(i) + " type=" + metadataRs.getColumnType(i));
339+
assertEquals(metadataRs.getSchemaName(i), stmt.getConnection().getSchema());
340+
}
341+
342+
if (values != null) {
343+
for (int i = 0; i < values.length; i++) {
344+
stmt.setObject(i + 1, values[i]);
345+
}
346+
}
347+
348+
stmt.execute();
349+
metadataRs = stmt.getMetaData();
350+
351+
assertNotNull(metadataRs);
352+
assertEquals(metadataRs.getColumnCount(), colCountAfterExecution);
353+
for (int i = 1; i <= metadataRs.getColumnCount(); i++) {
354+
System.out.println("label=" + metadataRs.getColumnName(i) + " type=" + metadataRs.getColumnType(i));
355+
assertEquals(metadataRs.getSchemaName(i), stmt.getConnection().getSchema());
356+
}
341357
}
342358
}
343359

344360
@DataProvider(name = "testGetMetadataDataProvider")
345361
static Object[][] testGetMetadataDataProvider() {
346362
return new Object[][] {
347-
{"INSERT INTO `%s` VALUES (?, ?, ?)"}
363+
{"INSERT INTO `%s` VALUES (?, ?, ?)", 0, new Object[]{"test", 0.3, 0.4}, 0},
364+
{"SELECT * FROM `%s`", 3, null, 3},
365+
{"SHOW TABLES", 0, null, 1}
348366
};
349367
}
350368

0 commit comments

Comments
 (0)