Skip to content

Commit c3e9a3b

Browse files
authored
Merge pull request #581 from aguibert/db2-sequence-query
Add handling for sequence-based queries used by Hibernate
2 parents fee33d5 + 87fa878 commit c3e9a3b

File tree

5 files changed

+84
-5
lines changed

5 files changed

+84
-5
lines changed

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/DRDAQueryRequest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@ public DRDAQueryRequest(ByteBuf buffer, ConnectionMetaData metadata) {
4848
}
4949

5050
/**
51-
* @return True if the SQL is a query (i.e. SELECT or WITH), false otherwise
52-
* IllegalArgumentException thrown if the passed in SQL value is null
51+
* @return True if the SQL is a query (e.g. SELECT or WITH), false otherwise
52+
* @throws IllegalArgumentException if the passed in SQL value is null
5353
*/
5454
public static boolean isQuery(String sql) {
5555
if (sql != null) {
56-
return sql.trim().toLowerCase().startsWith("select")
57-
|| sql.trim().toLowerCase().startsWith("with");
56+
String trimmedLower = sql.trim().toLowerCase();
57+
return trimmedLower.startsWith("select")
58+
|| trimmedLower.startsWith("with")
59+
|| trimmedLower.startsWith("values");
5860
} else {
5961
throw new IllegalArgumentException("SQLState.NULL_SQL_TEXT");
6062
}

vertx-db2-client/src/test/java/io/vertx/db2client/QueryVariationsTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.vertx.db2client;
22

33
import java.util.Arrays;
4+
import java.util.concurrent.atomic.AtomicInteger;
5+
import java.util.function.Consumer;
46

57
import org.junit.Test;
68
import org.junit.runner.RunWith;
@@ -9,6 +11,7 @@
911
import io.vertx.ext.unit.junit.VertxUnitRunner;
1012
import io.vertx.sqlclient.Row;
1113
import io.vertx.sqlclient.RowIterator;
14+
import io.vertx.sqlclient.RowSet;
1215
import io.vertx.sqlclient.Tuple;
1316

1417
/**
@@ -121,5 +124,68 @@ public void testSectionReuse(TestContext ctx) {
121124
}));
122125
}));
123126
}
127+
128+
/**
129+
* Test that queries starting with the "VALUES" keyword work properly
130+
*/
131+
@Test
132+
public void testSequenceQuery(TestContext ctx) {
133+
connect(ctx.asyncAssertSuccess(con -> {
134+
con.query("values nextval for my_seq")
135+
.execute(ctx.asyncAssertSuccess(rowSet1 -> {
136+
// Initially the sequence should be N (where N >= 1)
137+
int startingSeq = assertSequenceResult(ctx, rowSet1, seqVal -> {
138+
ctx.assertTrue(seqVal >= 1, "Sequence value was not >= 1. Value: " + seqVal);
139+
});
140+
con.query("VALUES nextval for my_seq")
141+
.execute(ctx.asyncAssertSuccess(rowSet2 -> {
142+
// Next the sequence should be N+1
143+
assertSequenceResult(ctx, rowSet2, seqVal -> ctx.assertEquals(startingSeq + 1, seqVal));
144+
con.query("VALUES nextval for my_seq")
145+
.execute(ctx.asyncAssertSuccess(rowSet3 -> {
146+
// Finally, the sequence should be N+2
147+
assertSequenceResult(ctx, rowSet3, seqVal -> ctx.assertEquals(startingSeq + 2, seqVal));
148+
}));
149+
}));
150+
}));
151+
}));
152+
}
153+
154+
/**
155+
* Like testSequenceQuery but with prepared statements
156+
*/
157+
@Test
158+
public void testSequenceQueryPrepared(TestContext ctx) {
159+
connect(ctx.asyncAssertSuccess(con -> {
160+
con.preparedQuery("VALUES nextval for my_seq")
161+
.execute(ctx.asyncAssertSuccess(rowSet1 -> {
162+
// Initially the sequence should be N (where N >= 1)
163+
int startingSeq = assertSequenceResult(ctx, rowSet1, seqVal -> {
164+
ctx.assertTrue(seqVal >= 1, "Sequence value was not >= 1. Value: " + seqVal);
165+
});
166+
con.preparedQuery("values nextval for my_seq")
167+
.execute(ctx.asyncAssertSuccess(rowSet2 -> {
168+
// Next the sequence should be N+1
169+
assertSequenceResult(ctx, rowSet2, seqVal -> ctx.assertEquals(startingSeq + 1, seqVal));
170+
con.preparedQuery("values nextval for my_seq")
171+
.execute(ctx.asyncAssertSuccess(rowSet3 -> {
172+
// Finally, the sequence should be N+2
173+
assertSequenceResult(ctx, rowSet3, seqVal -> ctx.assertEquals(startingSeq + 2, seqVal));
174+
}));
175+
}));
176+
}));
177+
}));
178+
}
179+
180+
private int assertSequenceResult(TestContext ctx, RowSet<Row> rowSet, Consumer<Integer> validation) {
181+
ctx.assertEquals(1, rowSet.size());
182+
RowIterator<Row> rows = rowSet.iterator();
183+
ctx.assertTrue(rows.hasNext());
184+
Row row = rows.next();
185+
ctx.assertNotNull(row);
186+
int seqVal = row.getInteger(0);
187+
validation.accept(seqVal);
188+
return seqVal;
189+
}
124190

125191
}

vertx-db2-client/src/test/java/io/vertx/db2client/junit/DB2Resource.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private void runInitSql(Connection con) throws Exception {
106106
try {
107107
con.createStatement().execute(currentLine);
108108
} catch (SQLSyntaxErrorException e) {
109-
if (sql.startsWith("DROP TABLE ") && e.getErrorCode() == -204) {
109+
if (sql.startsWith("DROP ") && e.getErrorCode() == -204) {
110110
System.out.println(" ignoring syntax exception: " + e.getMessage());
111111
} else {
112112
throw e;
@@ -115,6 +115,9 @@ private void runInitSql(Connection con) throws Exception {
115115
currentLine = "";
116116
}
117117
}
118+
if (!currentLine.isEmpty()) {
119+
throw new IllegalStateException("Dangling SQL on init script. Ensure all statements are terminated with ';' char. SQL: " + currentLine);
120+
}
118121
}
119122

120123
}

vertx-db2-client/src/test/resources/init.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,7 @@ CREATE TABLE collector_test
104104
);
105105
INSERT INTO collector_test VALUES (1, 32767, 2147483647, 9223372036854775807, 123.456, 1.234567, 'HELLO,WORLD');
106106
INSERT INTO collector_test VALUES (2, 32767, 2147483647, 9223372036854775807, 123.456, 1.234567, 'hello,world');
107+
108+
-- Sequence used by QueryVariationsTest
109+
DROP SEQUENCE my_seq;
110+
CREATE SEQUENCE my_seq INCREMENT BY 1 START WITH 1;

vertx-db2-client/src/test/resources/init.zos.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,7 @@ CREATE TABLE ROWTEST(
114114
id ROWID NOT NULL GENERATED ALWAYS,
115115
message varchar(1024)
116116
);
117+
118+
-- Sequence used by QueryVariationsTest
119+
DROP SEQUENCE my_seq;
120+
CREATE SEQUENCE my_seq INCREMENT BY 1 START WITH 1;

0 commit comments

Comments
 (0)