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]