postgresql-jdbc.git / summary / log / commit / refs
commit edcdccd658cbf3f2bfd677901f7bebac13a6259b
Author: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
Date: Fri Aug 12 16:51:10 2016 +0000
refactor: introduce ResultHandlerBase to factor out common error processing logic
.../java/org/postgresql/core/ResultHandler.java | 12 ++++
.../org/postgresql/core/ResultHandlerBase.java | 78 ++++++++++++++++++++++
.../org/postgresql/core/ResultHandlerDelegate.java | 16 +++++
.../java/org/postgresql/core/SetupQueryRunner.java | 27 +-------
.../org/postgresql/core/v3/QueryExecutorImpl.java | 64 ++++--------------
.../org/postgresql/jdbc/BatchResultHandler.java | 29 ++++----
.../jdbc/CallableBatchResultHandler.java | 8 +++
.../java/org/postgresql/jdbc/PgConnection.java | 38 ++---------
.../main/java/org/postgresql/jdbc/PgResultSet.java | 29 ++------
.../main/java/org/postgresql/jdbc/PgStatement.java | 35 ++++------
10 files changed, 168 insertions(+), 168 deletions(-)
diff --git a/pgjdbc/src/main/java/org/postgresql/core/ResultHandler.java b/pgjdbc/src/main/java/org/postgresql/core/ResultHandler.java
index 34b391fc..b6f29c82 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/ResultHandler.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/ResultHandler.java
@@ -83,4 +83,16 @@ public interface ResultHandler {
* statements are executed successfully and which are not.
*/
void secureProgress();
+
+ /**
+ * Returns the first encountered exception. The rest are chained via {@link SQLException#setNextException(SQLException)}
+ * @return the first encountered exception
+ */
+ SQLException getException();
+
+ /**
+ * Returns the first encountered warning. The rest are chained via {@link SQLException#setNextException(SQLException)}
+ * @return the first encountered warning
+ */
+ SQLWarning getWarning();
}
diff --git a/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerBase.java b/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerBase.java
new file mode 100644
index 00000000..2b87d0d4
--- /dev/null
+++ b/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerBase.java
@@ -0,0 +1,78 @@
+/*-------------------------------------------------------------------------
+*
+* Copyright (c) 2016-2016, PostgreSQL Global Development Group
+*
+*
+*-------------------------------------------------------------------------
+*/
+
+package org.postgresql.core;
+
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.util.List;
+
+/**
+ * Empty implementation of {@link ResultHandler} interface.
+ * {@link SQLException#setNextException(SQLException)} has {@code O(N)} complexity,
+ * so this class tracks the last exception object to speedup {@code setNextException}.
+ */
+public class ResultHandlerBase implements ResultHandler {
+ // Last exception is tracked to avoid O(N) SQLException#setNextException just in case there
+ // will be lots of exceptions (e.g. all batch rows fail with constraint violation or so)
+ private SQLException firstException;
+ private SQLException lastException;
+
+ private SQLWarning firstWarning;
+ private SQLWarning lastWarning;
+
+ @Override
+ public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
+ ResultCursor cursor) {
+ }
+
+ @Override
+ public void handleCommandStatus(String status, int updateCount, long insertOID) {
+ }
+
+ @Override
+ public void secureProgress() {
+ }
+
+ @Override
+ public void handleWarning(SQLWarning warning) {
+ if (firstWarning == null) {
+ firstWarning = lastWarning = warning;
+ return;
+ }
+ lastWarning.setNextException(warning);
+ lastWarning = warning;
+ }
+
+ @Override
+ public void handleError(SQLException error) {
+ if (firstException == null) {
+ firstException = lastException = error;
+ return;
+ }
+ lastException.setNextException(error);
+ lastException = error;
+ }
+
+ @Override
+ public void handleCompletion() throws SQLException {
+ if (firstException != null) {
+ throw firstException;
+ }
+ }
+
+ @Override
+ public SQLException getException() {
+ return firstException;
+ }
+
+ @Override
+ public SQLWarning getWarning() {
+ return firstWarning;
+ }
+}
diff --git a/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerDelegate.java b/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerDelegate.java
index fe74960c..8c4ff03a 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerDelegate.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/ResultHandlerDelegate.java
@@ -59,4 +59,20 @@ public class ResultHandlerDelegate implements ResultHandler {
delegate.secureProgress();
}
}
+
+ @Override
+ public SQLException getException() {
+ if (delegate != null) {
+ return delegate.getException();
+ }
+ return null;
+ }
+
+ @Override
+ public SQLWarning getWarning() {
+ if (delegate != null) {
+ return delegate.getWarning();
+ }
+ return null;
+ }
}
diff --git a/pgjdbc/src/main/java/org/postgresql/core/SetupQueryRunner.java b/pgjdbc/src/main/java/org/postgresql/core/SetupQueryRunner.java
index 3e611d6c..584b04fc 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/SetupQueryRunner.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/SetupQueryRunner.java
@@ -23,13 +23,9 @@ import java.util.List;
*/
public class SetupQueryRunner {
- private static class SimpleResultHandler implements ResultHandler {
- private SQLException error;
+ private static class SimpleResultHandler extends ResultHandlerBase {
private List<byte[][]> tuples;
- SimpleResultHandler() {
- }
-
List<byte[][]> getResults() {
return tuples;
}
@@ -39,31 +35,10 @@ public class SetupQueryRunner {
this.tuples = tuples;
}
- public void handleCommandStatus(String status, int updateCount, long insertOID) {
- }
-
public void handleWarning(SQLWarning warning) {
// We ignore warnings. We assume we know what we're
// doing in the setup queries.
}
-
- public void handleError(SQLException newError) {
- if (error == null) {
- error = newError;
- } else {
- error.setNextException(newError);
- }
- }
-
- public void handleCompletion() throws SQLException {
- if (error != null) {
- throw error;
- }
- }
-
- @Override
- public void secureProgress() {
- }
}
public static byte[][] run(QueryExecutor executor, String queryString,
diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
index 620f0bf5..772e6da6 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
@@ -26,6 +26,7 @@ import org.postgresql.core.QueryExecutor;
import org.postgresql.core.QueryExecutorBase;
import org.postgresql.core.ResultCursor;
import org.postgresql.core.ResultHandler;
+import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.ResultHandlerDelegate;
import org.postgresql.core.SqlCommand;
import org.postgresql.core.SqlCommandType;
@@ -262,9 +263,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
try {
try {
handler = sendQueryPreamble(handler, flags);
- ErrorTrackingResultHandler trackingHandler = new ErrorTrackingResultHandler(handler);
sendQuery(query, (V3ParameterList) parameters, maxRows, fetchSize, flags,
- trackingHandler, null);
+ handler, null);
if ((flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) != 0) {
// Sync message is not required for 'Q' execution as 'Q' ends with ReadyForQuery message
// on its own
@@ -355,24 +355,6 @@ public class QueryExecutorImpl extends QueryExecutorBase {
private static final int MAX_BUFFERED_RECV_BYTES = 64000;
private static final int NODATA_QUERY_RESPONSE_SIZE_BYTES = 250;
- // Helper handler that tracks error status.
- private static class ErrorTrackingResultHandler extends ResultHandlerDelegate {
- private boolean sawError = false;
-
- ErrorTrackingResultHandler(ResultHandler delegateHandler) {
- super(delegateHandler);
- }
-
- public void handleError(SQLException error) {
- sawError = true;
- super.handleError(error);
- }
-
- boolean hasErrors() {
- return sawError;
- }
- }
-
public synchronized void execute(Query[] queries, ParameterList[] parameterLists,
BatchResultHandler batchHandler, int maxRows, int fetchSize, int flags) throws SQLException {
waitOnLock();
@@ -396,7 +378,6 @@ public class QueryExecutorImpl extends QueryExecutorBase {
ResultHandler handler = batchHandler;
try {
handler = sendQueryPreamble(batchHandler, flags);
- ErrorTrackingResultHandler trackingHandler = new ErrorTrackingResultHandler(handler);
estimatedReceiveBufferBytes = 0;
for (int i = 0; i < queries.length; ++i) {
@@ -406,14 +387,14 @@ public class QueryExecutorImpl extends QueryExecutorBase {
parameters = SimpleQuery.NO_PARAMETERS;
}
- sendQuery(query, parameters, maxRows, fetchSize, flags, trackingHandler, batchHandler);
+ sendQuery(query, parameters, maxRows, fetchSize, flags, handler, batchHandler);
- if (trackingHandler.hasErrors()) {
+ if (handler.getException() != null) {
break;
}
}
- if (!trackingHandler.hasErrors()) {
+ if (handler.getException() == null) {
if ((flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) != 0) {
// Sync message is not required for 'Q' execution as 'Q' ends with ReadyForQuery message
// on its own
@@ -508,13 +489,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
logger.debug("Issuing BEGIN before fastpath or copy call.");
}
- ResultHandler handler = new ResultHandlerDelegate(null) {
+ ResultHandler handler = new ResultHandlerBase() {
private boolean sawBegin = false;
- private SQLException sqle = null;
-
- public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
- ResultCursor cursor) {
- }
public void handleCommandStatus(String status, int updateCount, long insertOID) {
if (!sawBegin) {
@@ -537,20 +513,6 @@ public class QueryExecutorImpl extends QueryExecutorBase {
// them errors.
handleError(warning);
}
-
- public void handleError(SQLException error) {
- if (sqle == null) {
- sqle = error;
- } else {
- sqle.setNextException(error);
- }
- }
-
- public void handleCompletion() throws SQLException {
- if (sqle != null) {
- throw sqle;
- }
- }
};
try {
@@ -1204,7 +1166,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
* See the comments above MAX_BUFFERED_RECV_BYTES's declaration for details.
*/
private void flushIfDeadlockRisk(Query query, boolean disallowBatching,
- ErrorTrackingResultHandler trackingHandler,
+ ResultHandler resultHandler,
BatchResultHandler batchHandler,
final int flags) throws IOException {
// Assume all statements need at least this much reply buffer space,
@@ -1240,7 +1202,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
if (disallowBatching || estimatedReceiveBufferBytes >= MAX_BUFFERED_RECV_BYTES) {
logger.debug("Forcing Sync, receive buffer full or batching disallowed");
sendSync();
- processResults(trackingHandler, flags);
+ processResults(resultHandler, flags);
estimatedReceiveBufferBytes = 0;
if (batchHandler != null) {
batchHandler.secureProgress();
@@ -1253,7 +1215,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
* Send a query to the backend.
*/
private void sendQuery(Query query, V3ParameterList parameters, int maxRows, int fetchSize,
- int flags, ErrorTrackingResultHandler trackingHandler,
+ int flags, ResultHandler resultHandler,
BatchResultHandler batchHandler) throws IOException, SQLException {
// Now the query itself.
Query[] subqueries = query.getSubqueries();
@@ -1265,20 +1227,20 @@ public class QueryExecutorImpl extends QueryExecutorBase {
boolean disallowBatching = (flags & QueryExecutor.QUERY_DISALLOW_BATCHING) != 0;
if (subqueries == null) {
- flushIfDeadlockRisk(query, disallowBatching, trackingHandler, batchHandler, flags);
+ flushIfDeadlockRisk(query, disallowBatching, resultHandler, batchHandler, flags);
// If we saw errors, don't send anything more.
- if (!trackingHandler.hasErrors()) {
+ if (resultHandler.getException() == null) {
sendOneQuery((SimpleQuery) query, (SimpleParameterList) parameters, maxRows, fetchSize,
flags);
}
} else {
for (int i = 0; i < subqueries.length; ++i) {
final Query subquery = subqueries[i];
- flushIfDeadlockRisk(subquery, disallowBatching, trackingHandler, batchHandler, flags);
+ flushIfDeadlockRisk(subquery, disallowBatching, resultHandler, batchHandler, flags);
// If we saw errors, don't send anything more.
- if (trackingHandler.hasErrors()) {
+ if (resultHandler.getException() != null) {
break;
}
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/BatchResultHandler.java b/pgjdbc/src/main/java/org/postgresql/jdbc/BatchResultHandler.java
index df31d06d..634e243c 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/BatchResultHandler.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/BatchResultHandler.java
@@ -1,10 +1,18 @@
+/*-------------------------------------------------------------------------
+*
+* Copyright (c) 2016-2016, PostgreSQL Global Development Group
+*
+*
+*-------------------------------------------------------------------------
+*/
+
package org.postgresql.jdbc;
import org.postgresql.core.Field;
import org.postgresql.core.ParameterList;
import org.postgresql.core.Query;
import org.postgresql.core.ResultCursor;
-import org.postgresql.core.ResultHandler;
+import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.v3.BatchedQuery;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
@@ -22,12 +30,8 @@ import java.util.List;
/**
* Internal class, it is not a part of public API.
*/
-public class BatchResultHandler implements ResultHandler {
+public class BatchResultHandler extends ResultHandlerBase {
private PgStatement pgStatement;
- private BatchUpdateException batchException = null;
- // Last exception is tracked to avoid O(N) SQLException#setNextException just in case there
- // will be lots of exceptions (e.g. all batch rows fail with constraint violation or so)
- private SQLException lastException;
private int resultIndex = 0;
private final Query[] queries;
@@ -78,7 +82,7 @@ public class BatchResultHandler implements ResultHandler {
resultIndex--;
// If exception thrown, no need to collect generated keys
// Note: some generated keys might be secured in generatedKeys
- if (updateCount > 0 && (batchException == null || isAutoCommit())) {
+ if (updateCount > 0 && (getException() == null || isAutoCommit())) {
allGeneratedRows.add(latestGeneratedRows);
if (generatedKeys == null) {
generatedKeys = latestGeneratedKeysRs;
@@ -129,7 +133,7 @@ public class BatchResultHandler implements ResultHandler {
}
public void handleError(SQLException newError) {
- if (batchException == null) {
+ if (getException() == null) {
Arrays.fill(updateCounts, committedRows, updateCounts.length, Statement.EXECUTE_FAILED);
if (allGeneratedRows != null) {
allGeneratedRows.clear();
@@ -140,20 +144,19 @@ public class BatchResultHandler implements ResultHandler {
queryString = queries[resultIndex].toString(parameterLists[resultIndex]);
}
- batchException = new BatchUpdateException(
+ super.handleError(new BatchUpdateException(
GT.tr("Batch entry {0} {1} was aborted: {2} Call getNextException to see the cause.",
new Object[]{resultIndex, queryString, newError.getMessage()}),
- newError.getSQLState(), uncompressUpdateCount());
- lastException = batchException;
+ newError.getSQLState(), uncompressUpdateCount()));
}
resultIndex++;
- lastException.setNextException(newError);
- lastException = newError;
+ super.handleError(newError);
}
public void handleCompletion() throws SQLException {
updateGeneratedKeys();
+ SQLException batchException = getException();
if (batchException != null) {
if (isAutoCommit()) {
// Re-create batch exception since rows after exception might indeed succeed.
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/CallableBatchResultHandler.java b/pgjdbc/src/main/java/org/postgresql/jdbc/CallableBatchResultHandler.java
index f8942168..3e49405b 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/CallableBatchResultHandler.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/CallableBatchResultHandler.java
@@ -1,3 +1,11 @@
+/*-------------------------------------------------------------------------
+*
+* Copyright (c) 2016-2016, PostgreSQL Global Development Group
+*
+*
+*-------------------------------------------------------------------------
+*/
+
package org.postgresql.jdbc;
import org.postgresql.core.Field;
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
index 2d7d600a..92854177 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
@@ -17,14 +17,12 @@ import org.postgresql.core.BaseStatement;
import org.postgresql.core.CachedQuery;
import org.postgresql.core.ConnectionFactory;
import org.postgresql.core.Encoding;
-import org.postgresql.core.Field;
import org.postgresql.core.Logger;
import org.postgresql.core.Oid;
import org.postgresql.core.Provider;
import org.postgresql.core.Query;
import org.postgresql.core.QueryExecutor;
-import org.postgresql.core.ResultCursor;
-import org.postgresql.core.ResultHandler;
+import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.ServerVersion;
import org.postgresql.core.SqlCommand;
import org.postgresql.core.TransactionState;
@@ -64,7 +62,6 @@ import java.sql.Types;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -1047,36 +1044,13 @@ public class PgConnection implements BaseConnection {
/**
* Handler for transaction queries
*/
- private class TransactionCommandHandler implements ResultHandler {
- private SQLException error;
-
- public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
- ResultCursor cursor) {
- }
-
- public void handleCommandStatus(String status, int updateCount, long insertOID) {
- }
-
- public void handleWarning(SQLWarning warning) {
- PgConnection.this.addWarning(warning);
- }
-
- public void handleError(SQLException newError) {
- if (error == null) {
- error = newError;
- } else {
- error.setNextException(newError);
- }
- }
-
+ private class TransactionCommandHandler extends ResultHandlerBase {
public void handleCompletion() throws SQLException {
- if (error != null) {
- throw error;
+ SQLWarning warning = getWarning();
+ if (warning != null) {
+ PgConnection.this.addWarning(warning);
}
- }
-
- @Override
- public void secureProgress() {
+ super.handleCompletion();
}
}
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
index 916bac61..fe4fab66 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
@@ -16,7 +16,7 @@ import org.postgresql.core.Field;
import org.postgresql.core.Oid;
import org.postgresql.core.Query;
import org.postgresql.core.ResultCursor;
-import org.postgresql.core.ResultHandler;
+import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.ServerVersion;
import org.postgresql.core.TypeInfo;
import org.postgresql.core.Utils;
@@ -1751,8 +1751,7 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
}
}
- public class CursorResultHandler implements ResultHandler {
- private SQLException error;
+ public class CursorResultHandler extends ResultHandlerBase {
public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
ResultCursor cursor) {
@@ -1765,31 +1764,15 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
PSQLState.PROTOCOL_VIOLATION));
}
- public void handleWarning(SQLWarning warning) {
- PgResultSet.this.addWarning(warning);
- }
-
- public void handleError(SQLException newError) {
- if (error == null) {
- error = newError;
- } else {
- error.setNextException(newError);
- }
- }
-
public void handleCompletion() throws SQLException {
- if (error != null) {
- throw error;
+ SQLWarning warning = getWarning();
+ if (warning != null) {
+ PgResultSet.this.addWarning(warning);
}
- }
-
- @Override
- public void secureProgress() {
+ super.handleCompletion();
}
}
- ;
-
public BaseStatement getPGStatement() {
return statement;
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java
index 2876db7a..54755c64 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java
@@ -18,7 +18,7 @@ import org.postgresql.core.ParameterList;
import org.postgresql.core.Query;
import org.postgresql.core.QueryExecutor;
import org.postgresql.core.ResultCursor;
-import org.postgresql.core.ResultHandler;
+import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.SqlCommand;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
@@ -190,9 +190,9 @@ public class PgStatement implements Statement, BaseStatement {
/**
* ResultHandler implementations for updates, queries, and either-or.
*/
- public class StatementResultHandler implements ResultHandler {
- private SQLException error;
+ public class StatementResultHandler extends ResultHandlerBase {
private ResultWrapper results;
+ private ResultWrapper lastResult;
ResultWrapper getResults() {
return results;
@@ -200,12 +200,13 @@ public class PgStatement implements Statement, BaseStatement {
private void append(ResultWrapper newResult) {
if (results == null) {
- results = newResult;
+ lastResult = results = newResult;
} else {
- results.append(newResult);
+ lastResult.append(newResult);
}
}
+ @Override
public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
ResultCursor cursor) {
try {
@@ -216,30 +217,18 @@ public class PgStatement implements Statement, BaseStatement {
}
}
+ @Override
public void handleCommandStatus(String status, int updateCount, long insertOID) {
append(new ResultWrapper(updateCount, insertOID));
}
- public void handleWarning(SQLWarning warning) {
- PgStatement.this.addWarning(warning);
- }
-
- public void handleError(SQLException newError) {
- if (error == null) {
- error = newError;
- } else {
- error.setNextException(newError);
- }
- }
-
+ @Override
public void handleCompletion() throws SQLException {
- if (error != null) {
- throw error;
+ SQLWarning warning = getWarning();
+ if (warning != null) {
+ PgStatement.this.addWarning(warning);
}
- }
-
- @Override
- public void secureProgress() {
+ super.handleCompletion();
}
}
[parent: 0452e79c42ca]