Skip to content

Commit 814581b

Browse files
authored
sql expression/methods was removed incorrectly from values section (#2228)
* Fix bug in insert when we have (?, `parseDateTimeBestEffort`(?, ?), ?, 1) some sql methods and not only ? we have removed that currently we are inserting what was provided by the user only looking on the values part * Remove detection of 'INSET INTO .. SELECT' from detecting as INSERT
1 parent 7ce2cd8 commit 814581b

File tree

3 files changed

+151
-25
lines changed

3 files changed

+151
-25
lines changed

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

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public class PreparedStatementImpl extends StatementImpl implements PreparedStat
5858

5959
String originalSql;
6060
String [] sqlSegments;
61+
String [] valueSegments;
6162
Object [] parameters;
6263
String insertIntoSQL;
6364

@@ -71,6 +72,7 @@ public PreparedStatementImpl(ConnectionImpl connection, String sql) throws SQLEx
7172

7273
if (statementType == StatementType.INSERT) {
7374
insertIntoSQL = originalSql.substring(0, originalSql.indexOf("VALUES") + 6);
75+
valueSegments = originalSql.substring(originalSql.indexOf("VALUES") + 6).split("\\?");
7476
}
7577

7678
//Create an array of objects to store the parameters
@@ -84,41 +86,27 @@ public PreparedStatementImpl(ConnectionImpl connection, String sql) throws SQLEx
8486
this.defaultCalendar = connection.defaultCalendar;
8587
}
8688

87-
private String compileSql() {
89+
private String compileSql(String []segments) {
8890
StringBuilder sb = new StringBuilder();
89-
for (int i = 0; i < sqlSegments.length; i++) {
90-
sb.append(sqlSegments[i]);
91+
for (int i = 0; i < segments.length; i++) {
92+
sb.append(segments[i]);
9193
if (i < parameters.length) {
9294
sb.append(parameters[i]);
9395
}
9496
}
9597
LOG.trace("Compiled SQL: {}", sb);
9698
return sb.toString();
9799
}
98-
99-
private String valuesSql() {
100-
StringBuilder sb = new StringBuilder("(");
101-
for (int i = 0; i < parameters.length; i++) {
102-
if (i > 0) {
103-
sb.append(", ");
104-
}
105-
sb.append(parameters[i]);
106-
}
107-
sb.append(")");
108-
LOG.trace("Compiled Value SQL: {}", sb);
109-
return sb.toString();
110-
}
111-
112100
@Override
113101
public ResultSet executeQuery() throws SQLException {
114102
checkClosed();
115-
return executeQuery(compileSql());
103+
return executeQuery(compileSql(sqlSegments));
116104
}
117105

118106
@Override
119107
public int executeUpdate() throws SQLException {
120108
checkClosed();
121-
return executeUpdate(compileSql());
109+
return executeUpdate(compileSql(sqlSegments));
122110
}
123111

124112
@Override
@@ -245,17 +233,18 @@ public void setObject(int parameterIndex, Object x) throws SQLException {
245233
@Override
246234
public boolean execute() throws SQLException {
247235
checkClosed();
248-
return execute(compileSql());
236+
return execute(compileSql(sqlSegments));
249237
}
250238

251239
@Override
252240
public void addBatch() throws SQLException {
253241
checkClosed();
254242
if (statementType == StatementType.INSERT) {
255-
addBatch(valuesSql());
243+
addBatch(compileSql(valueSegments));
256244
} else {
257-
addBatch(compileSql());
245+
addBatch(compileSql(sqlSegments));
258246
}
247+
259248
}
260249

261250
@Override

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected void checkClosed() throws SQLException {
5757
}
5858

5959
protected enum StatementType {
60-
SELECT, INSERT, DELETE, UPDATE, CREATE, DROP, ALTER, TRUNCATE, USE, SHOW, DESCRIBE, EXPLAIN, SET, KILL, OTHER
60+
SELECT, INSERT, DELETE, UPDATE, CREATE, DROP, ALTER, TRUNCATE, USE, SHOW, DESCRIBE, EXPLAIN, SET, KILL, OTHER, INSERT_INTO_SELECT
6161
}
6262

6363
protected static StatementType parseStatementType(String sql) {
@@ -84,7 +84,13 @@ protected static StatementType parseStatementType(String sql) {
8484
switch (tokens[0].toUpperCase()) {
8585
case "SELECT": return StatementType.SELECT;
8686
case "WITH": return StatementType.SELECT;
87-
case "INSERT": return StatementType.INSERT;
87+
case "INSERT":
88+
for (String token : tokens) {
89+
if (token.equalsIgnoreCase("SELECT")) {
90+
return StatementType.INSERT_INTO_SELECT;
91+
}
92+
}
93+
return StatementType.INSERT;
8894
case "DELETE": return StatementType.DELETE;
8995
case "UPDATE": return StatementType.UPDATE;
9096
case "CREATE": return StatementType.CREATE;

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

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ void testWithClause() throws Exception {
281281

282282
@Test(groups = { "integration" })
283283
void testInsert() throws Exception {
284-
int ROWS = 100000;
284+
int ROWS = 1000;
285285
String payload = RandomStringUtils.random(1024, true, true);
286286
try (Connection conn = getJdbcConnection()) {
287287
for (int j = 0; j < 10; j++) {
@@ -322,4 +322,135 @@ void testInsert() throws Exception {
322322

323323
}
324324
}
325+
326+
@Test(groups = { "integration" })
327+
void testMetabaseBug01() throws Exception {
328+
try (Connection conn = getJdbcConnection()) {
329+
try (Statement stmt = conn.createStatement()) {
330+
stmt.execute("CREATE TABLE `users` (`id` Int32, `name` Nullable(String), `last_login` Nullable(DateTime64(3, 'GMT0')), `password` Nullable(String)) ENGINE Memory;");
331+
stmt.execute("CREATE TABLE `users_tmp` (`id` Int32, `name` Nullable(String), `last_login` Nullable(DateTime64(3, 'GMT0')), `password` Nullable(String)) ENGINE Memory;");
332+
stmt.execute("CREATE TABLE `users_tmp01` (`id` Int32, `name` Nullable(String), `last_login` Nullable(DateTime64(3, 'GMT0')), `password` Nullable(String)) ENGINE Memory;");
333+
stmt.execute("CREATE TABLE `users_tmp02` (`id` Int32, `name` Nullable(String), `last_login` Nullable(DateTime64(3, 'GMT0')), `password` Nullable(String)) ENGINE Memory;");
334+
}
335+
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO `users` (`name`, `last_login`, `password`, `id`) VALUES (?, `parseDateTimeBestEffort`(?, ?), ?, 1), (?, `parseDateTimeBestEffort`(?, ?), ?, 2), (?, `parseDateTimeBestEffort`(?, ?), ?, 3), (?, `parseDateTimeBestEffort`(?, ?), ?, 4), (?, `parseDateTimeBestEffort`(?, ?), ?, 5), (?, `parseDateTimeBestEffort`(?, ?), ?, 6), (?, `parseDateTimeBestEffort`(?, ?), ?, 7), (?, `parseDateTimeBestEffort`(?, ?), ?, 8), (?, `parseDateTimeBestEffort`(?, ?), ?, 9), (?, `parseDateTimeBestEffort`(?, ?), ?, 10), (?, `parseDateTimeBestEffort`(?, ?), ?, 11), (?, `parseDateTimeBestEffort`(?, ?), ?, 12), (?, `parseDateTimeBestEffort`(?, ?), ?, 13), (?, `parseDateTimeBestEffort`(?, ?), ?, 14), (?, `parseDateTimeBestEffort`(?, ?), ?, 15)")) {
336+
stmt.setObject(1, "Plato Yeshua");
337+
stmt.setObject(2, "2014-04-01 08:30:00.000");
338+
stmt.setObject(3, "UTC");
339+
stmt.setObject(4, "4be68cda-6fd5-4ba7-944e-2b475600bda5");
340+
stmt.setObject(5, "Felipinho Asklepios");
341+
stmt.setObject(6, "2014-12-05 15:15:00.000");
342+
stmt.setObject(7, "UTC");
343+
stmt.setObject(8, "5bb19ad9-f3f8-421f-9750-7d398e38428d");
344+
stmt.setObject(9, "Kaneonuskatew Eiran");
345+
stmt.setObject(10, "2014-11-06 16:15:00.000");
346+
stmt.setObject(11, "UTC");
347+
stmt.setObject(12, "a329ccfe-b99c-42eb-9c93-cb9adc3eb1ab");
348+
stmt.setObject(13, "Simcha Yan");
349+
stmt.setObject(14, "2014-01-01 08:30:00.000");
350+
stmt.setObject(15, "UTC");
351+
stmt.setObject(16, "a61f97c6-4484-4a63-b37e-b5e58bfa2ecb");
352+
stmt.setObject(17, "Quentin Sören");
353+
stmt.setObject(18, "2014-10-03 17:30:00.000");
354+
stmt.setObject(19, "UTC");
355+
stmt.setObject(20, "10a0fea8-9bb4-48fe-a336-4d9cbbd78aa0");
356+
stmt.setObject(21, "Shad Ferdynand");
357+
stmt.setObject(22, "2014-08-02 12:30:00.000");
358+
stmt.setObject(23, "UTC");
359+
stmt.setObject(24, "d35c9d78-f9cf-4f52-b1cc-cb9078eebdcb");
360+
stmt.setObject(25, "Conchúr Tihomir");
361+
stmt.setObject(26, "2014-08-02 09:30:00.000");
362+
stmt.setObject(27, "UTC");
363+
stmt.setObject(28, "900335ad-e03b-4259-abc7-76aac21cedca");
364+
stmt.setObject(29, "Szymon Theutrich");
365+
stmt.setObject(30, "2014-02-01 10:15:00.000");
366+
stmt.setObject(31, "UTC");
367+
stmt.setObject(32, "d6c47a54-9d88-4c4a-8054-ace76764ed0d");
368+
stmt.setObject(33, "Nils Gotam");
369+
stmt.setObject(34, "2014-04-03 09:30:00.000");
370+
stmt.setObject(35, "UTC");
371+
stmt.setObject(36, "b085040c-7aa4-4e96-8c8f-420b2c99c920");
372+
stmt.setObject(37, "Frans Hevel");
373+
stmt.setObject(38, "2014-07-03 19:30:00.000");
374+
stmt.setObject(39, "UTC");
375+
stmt.setObject(40, "b7a43e91-9fb9-4fe9-ab6f-ea51ab0f94e4");
376+
stmt.setObject(41, "Spiros Teofil");
377+
stmt.setObject(42, "2014-11-01 07:00:00.000");
378+
stmt.setObject(43, "UTC");
379+
stmt.setObject(44, "62b9602c-27b8-44ea-adbd-2748f26537af");
380+
stmt.setObject(45, "Kfir Caj");
381+
stmt.setObject(46, "2014-07-03 01:30:00.000");
382+
stmt.setObject(47, "UTC");
383+
stmt.setObject(48, "dfe21df3-f364-479d-a5e7-04bc5d85ad2b");
384+
stmt.setObject(49, "Dwight Gresham");
385+
stmt.setObject(50, "2014-08-01 10:30:00.000");
386+
stmt.setObject(51, "UTC");
387+
stmt.setObject(52, "75a1ebf1-cae7-4a50-8743-32d97500f2cf");
388+
stmt.setObject(53, "Broen Olujimi");
389+
stmt.setObject(54, "2014-10-03 13:45:00.000");
390+
stmt.setObject(55, "UTC");
391+
stmt.setObject(56, "f9b65c74-9f91-4cfd-9248-94a53af82866");
392+
stmt.setObject(57, "Rüstem Hebel");
393+
stmt.setObject(58, "2014-08-01 12:45:00.000");
394+
stmt.setObject(59, "UTC");
395+
stmt.setObject(60, "02ad6b15-54b0-4491-bf0f-d781b0a2c4f5");
396+
stmt.addBatch();
397+
stmt.executeBatch();
398+
}
399+
try (Statement stmt01 = conn.createStatement()) {
400+
try (ResultSet rs = stmt01.executeQuery("SELECT count(*) FROM `users`")) {
401+
assertTrue(rs.next());
402+
assertEquals(rs.getInt(1), 15);
403+
}
404+
}
405+
406+
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO `users_tmp` SELECT * FROM `users` WHERE id = ?")) {
407+
stmt.setInt(1, 1);
408+
stmt.addBatch();
409+
stmt.setInt(1, 2);
410+
stmt.addBatch();
411+
stmt.setInt(1, 3);
412+
stmt.addBatch();
413+
stmt.executeBatch();
414+
}
415+
416+
try (Statement stmt01 = conn.createStatement()) {
417+
try (ResultSet rs = stmt01.executeQuery("SELECT count(*) FROM `users_tmp`")) {
418+
assertTrue(rs.next());
419+
assertEquals(rs.getInt(1), 3);
420+
}
421+
}
422+
423+
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO `users_tmp01` SELECT * FROM `users` WHERE id = ?")) {
424+
stmt.setInt(1, 1);
425+
stmt.addBatch();
426+
stmt.executeBatch();
427+
}
428+
429+
try (Statement stmt01 = conn.createStatement()) {
430+
try (ResultSet rs = stmt01.executeQuery("SELECT count(*) FROM `users_tmp01`")) {
431+
assertTrue(rs.next());
432+
assertEquals(rs.getInt(1), 1);
433+
}
434+
}
435+
436+
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO `users_tmp02` (`name`, `last_login`, `password`, `id`) VALUES (?, `parseDateTimeBestEffort`(?, ?), ?, ?)")) {
437+
for (int i=0; i < 10; i++) {
438+
stmt.setObject(1, "Plato Yeshua");
439+
stmt.setObject(2, "2014-04-01 08:30:00.000");
440+
stmt.setObject(3, "UTC");
441+
stmt.setObject(4, "4be68cda-6fd5-4ba7-944e-2b475600bda5");
442+
stmt.setObject(5, i);
443+
stmt.addBatch();
444+
}
445+
stmt.executeBatch();
446+
}
447+
448+
try (Statement stmt01 = conn.createStatement()) {
449+
try (ResultSet rs = stmt01.executeQuery("SELECT count(*) FROM `users_tmp02`")) {
450+
assertTrue(rs.next());
451+
assertEquals(rs.getInt(1), 10);
452+
}
453+
}
454+
}
455+
}
325456
}

0 commit comments

Comments
 (0)