Permalink
Browse files

fix: use server-prepared statements for batch inserts when prepareThr…

…eshold>0

Use server-prepared statements when more than 1 row is inserted via executeBatch() API.
Previously it could take up to prepareThresolds batch executions.

see #836
  • Loading branch information...
vlsi committed Jun 7, 2017
1 parent 59236b7 commit abc3d9d7f34a001322fbbe53f25d5e77a33a667f
@@ -1550,6 +1550,13 @@ public void setURL(int parameterIndex, java.net.URL x) throws SQLException {
@Override
public int[] executeBatch() throws SQLException {
try {
if (batchParameters.size() > 1 && m_prepareThreshold > 0) {
// Use server-prepared statements when there's more than one statement in a batch
// Technically speaking, it might cause to create a server-prepared statement
// just for 2 executions even for prepareThreshold=5. That however should be
// acceptable since prepareThreshold is a optimization kind of parameter.
this.preparedQuery.increaseExecuteCount(m_prepareThreshold);
}
return super.executeBatch();
} finally {
defaultTimeZone = null;
@@ -6,6 +6,7 @@
package org.postgresql.test.jdbc2;
import org.postgresql.PGProperty;
import org.postgresql.PGStatement;
import org.postgresql.test.TestUtil;
import org.junit.Assert;
@@ -1277,4 +1278,50 @@ public static void assertBatchResult(String message, int[] expected, int[] actua
Arrays.toString(clone),
Arrays.toString(actual));
}
@Test
public void testServerPrepareMultipleRows() throws SQLException {
PreparedStatement ps = null;
try {
ps = con.prepareStatement("INSERT INTO prep(a) VALUES (?)");
// 2 is not enough for insertRewrite=true case since it would get executed as a single multi-insert statement
for (int i = 0; i < 3; i++) {
ps.setInt(1, i);
ps.addBatch();
}
int[] actual = ps.executeBatch();
Assert.assertTrue(
"More than 1 row is inserted via executeBatch, it should lead to multiple server statements, thus the statements should be server-prepared",
((PGStatement) ps).isUseServerPrepare());
assertBatchResult("3 rows inserted via batch", new int[]{1, 1, 1}, actual);
} finally {
TestUtil.closeQuietly(ps);
}
}
@Test
public void testNoServerPrepareOneRow() throws SQLException {
PreparedStatement ps = null;
try {
ps = con.prepareStatement("INSERT INTO prep(a) VALUES (?)");
ps.setInt(1, 1);
ps.addBatch();
int[] actual = ps.executeBatch();
int prepareThreshold = ((PGStatement) ps).getPrepareThreshold();
if (prepareThreshold == 1) {
Assert.assertTrue(
"prepareThreshold=" + prepareThreshold
+ " thus the statement should be server-prepared",
((PGStatement) ps).isUseServerPrepare());
} else {
Assert.assertFalse(
"Just one row inserted via executeBatch, prepareThreshold=" + prepareThreshold
+ " thus the statement should not be server-prepared",
((PGStatement) ps).isUseServerPrepare());
}
assertBatchResult("1 rows inserted via batch", new int[]{1}, actual);
} finally {
TestUtil.closeQuietly(ps);
}
}
}

0 comments on commit abc3d9d

Please sign in to comment.