Repository: pgjdbc/pgjdbc
Pull request #1457 (2019-04-03 21:33:50)

attempt at fixing DataSources broken by connection failover urls (#1039)
meant as a starting point to discuss and test solution(s) to #1039. (see discussion there)
will work on checkstyle and stuff when I know this is the way to go.

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing](https://github.com/pgjdbc/pgjdbc/blob/master/CONTRIBUTING.md) document?
* [y] Have you checked to ensure there aren't other open [Pull Requests](../../pulls) for the same update/change?

<!-- You can erase any parts of this template not applicable to your Pull Request. -->

### New Feature Submissions:

1. [y] Does your submission pass tests?
2. [x] Does mvn checkstyle:check pass ?

### Changes to Existing Features:

* [n] Does this break existing behaviour? If so please explain.
* [y] Have you added an explanation of what your changes do and why you'd like us to include them?
* [y] Have you written new tests for your core changes, as applicable?
* [y] Have you successfully run tests with your changes locally?


AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.197 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23581591) (commit https://github.com/pgjdbc/pgjdbc/commit/932e30254f by @teicher)
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.220 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23784766) (commit https://github.com/pgjdbc/pgjdbc/commit/b651144d31 by @teicher)

Patch:
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 3a9228c3..4efe774b 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -9,6 +9,7 @@
 
 1. [ ] Does your submission pass tests?
 2. [ ] Does mvn checkstyle:check pass ?
+3. [ ] Have you added your new test classes to an existing test suite?
 
 ### Changes to Existing Features:
 
diff --git a/.travis.yml b/.travis.yml
index b2a842e8..26404e1b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,6 +39,7 @@ before_script:
   - if [[ $TRAVIS_BRANCH == release/* ]]; then echo "MAVEN_OPTS='-Xmx1g'" > ~/.mavenrc; else echo "MAVEN_OPTS='-Xmx1g -Dgpg.skip=true'" > ~/.mavenrc; fi
   - test "x$PG_VERSION" == 'x' || test "x$NO_HSTORE" == 'xY' || psql test -c 'CREATE EXTENSION hstore;' -U postgres
   - test "x$PG_VERSION" == 'x' || test "x$CREATE_PLPGSQL" == 'x' || createlang -U postgres plpgsql test
+  - test "x$PG_VERSION" == 'x' || test "x$PLPGSQL_EXTENSION" == 'x' || psql test -c 'CREATE EXTENSION IF NOT EXISTS plpgsql;' -U postgres
 
 env:
   global:
@@ -102,6 +103,36 @@ matrix:
       - PG_VERSION=10
       - JDK=12
       - TZ=America/New_York # flips between −05:00 and −04:00
+    - jdk: openjdk-ea
+      sudo: required
+      addons:
+        postgresql: "11"
+      env:
+        - PG_VERSION=11
+        - XA=true
+        - COVERAGE=Y
+        - NO_HSTORE=Y
+        - PLPGSQL_EXTENSION=Y
+    - jdk: oraclejdk9
+      sudo: required
+      addons:
+        postgresql: "11"
+      env:
+        - PG_VERSION=11
+        - XA=true
+        - COVERAGE=Y
+        - NO_HSTORE=Y
+        - PLPGSQL_EXTENSION=Y
+    - jdk: oraclejdk8
+      sudo: required
+      addons:
+        postgresql: "11"
+      env:
+        - PG_VERSION=11
+        - XA=true
+        - COVERAGE=Y
+        - NO_HSTORE=Y
+        - PLPGSQL_EXTENSION=Y
     - jdk: oraclejdk11
       sudo: required
       addons:
@@ -188,24 +219,6 @@ matrix:
         - COVERAGE=Y
         - NO_HSTORE=Y
         - CREATE_PLPGSQL=Y
-    - jdk: oraclejdk8
-      sudo: required
-      dist: precise
-      env:
-        - PG_VERSION=8.3
-        - XA=true
-        - COVERAGE=Y
-        - NO_HSTORE=Y
-        - CREATE_PLPGSQL=Y
-    - jdk: oraclejdk8
-      sudo: required
-      dist: precise
-      env:
-        - PG_VERSION=8.2
-        - XA=true
-        - COVERAGE=Y
-        - NO_HSTORE=Y
-        - CREATE_PLPGSQL=Y
     - jdk: oraclejdk8
       addons:
         postgresql: "9.6"
diff --git a/.travis/travis_build.sh b/.travis/travis_build.sh
index 0ccc6878..00ef433e 100755
--- a/.travis/travis_build.sh
+++ b/.travis/travis_build.sh
@@ -8,6 +8,10 @@ then
   python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);'
   export PROJECT_VERSION=$(mvn -B -N org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -v '\[')
   export PARENT_VERSION=$(mvn -B -N org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.parent.version | grep -v '\[')
+  export CHECK_PARENT_VERSION=$(mvn help:evaluate -Dexpression=project.parent.version -q -DforceStdout -f pgjdbc/pom.xml)
+  # just make sure that pom.xml has the same value as pgjdbc/pom.xml
+  test "$PARENT_VERSION" = "$CHECK_PARENT_VERSION"
+
   exec ./packaging/rpm_ci
 fi
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77acdb89..c0adbf47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,8 +10,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 
 ### Fixed
 
+## [42.2.8] (2019-09-13)
+### Changed
+
+### Added
+
+### Fixed
+
+* fix: Revert inet default Java type to PGObject and handle values with net masks [PR 1568](https://github.com/pgjdbc/pgjdbc/pull/1568) 
+
+## [42.2.7] (2019-09-03)
+### Changed
+
+
+### Added
+- Expose parameter status messages (GUC_REPORT) to the user [PR 1435](https://github.com/pgjdbc/pgjdbc/pull/1435)
+- Add automatic module name to manifest for jdk9+ [PR 1538](https://github.com/pgjdbc/pgjdbc/pull/1538)
+- Log ignoring rollback when no transaction in progress [PR 1549](https://github.com/pgjdbc/pgjdbc/pull/1549)
+- Map inet type to InetAddress [PR 1527](https://github.com/pgjdbc/pgjdbc/pull/1527) [issue 1134](https://github.com/pgjdbc/pgjdbc/issues/1134)
+
+### Fixed
+- fix [issue 1547](https://github.com/pgjdbc/pgjdbc/issues/1547) As long as peek returns some bytes do not reset the timeout, this allows us to continue checking until any async notifies are consumed [PR 1548](https://github.com/pgjdbc/pgjdbc/pull/1548)
+- fix: [issue 1466](https://github.com/pgjdbc/pgjdbc/issues/1466) In logical decoding the if the backend was requesting a reply we… [PR 1467](https://github.com/pgjdbc/pgjdbc/pull/1467) 
+- fix: [issue 1534](https://github.com/pgjdbc/pgjdbc/issues/1534) Proleptic java.time support [PR 1539](https://github.com/pgjdbc/pgjdbc/pull/1539)
+- fix Ensure isValid() will not last more than timeout seconds [PR 1557](https://github.com/pgjdbc/pgjdbc/pull/1557)
 ## [42.2.6] (2019-06-19)
 ### Known issues
+- Waffle has [dropped support](https://github.com/Waffle/waffle/releases/tag/waffle-1.9.0) for 1.6, 1.7 as such the new waffle 1.9.x is only available in jre8
 - Microseconds in timestamps might be truncated when transferred in binary mode
 - 24:00 time handling is not consistent [issue 1385](https://github.com/pgjdbc/pgjdbc/issues/1385)
 - Unexpected packet type during stream replication [issue 1466](https://github.com/pgjdbc/pgjdbc/issues/1466)
@@ -219,4 +244,6 @@ thrown to caller to be dealt with so no need to log at this verbosity by pgjdbc
 [42.2.4]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.3...REL42.2.4
 [42.2.5]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.4...REL42.2.5
 [42.2.6]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.5...REL42.2.6
-[Unreleased]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.6...HEAD
+[42.2.7]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.6...REL42.2.7
+[42.2.8]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.7...REL42.2.8
+[Unreleased]: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.8...HEAD
diff --git a/README.md b/README.md
index 4676cd0a..bfe9c89d 100644
--- a/README.md
+++ b/README.md
@@ -24,36 +24,36 @@ Most people do not need to compile PgJDBC. You can download the precompiled driv
 ### Maven Central
 You can search on The Central Repository with GroupId and ArtifactId [![Maven Search](https://img.shields.io/badge/org.postgresql-postgresql-yellow.svg)][mvn-search] for:
 
-[![Java 8](https://img.shields.io/badge/Java_8-42.2.5-blue.svg)][mvn-jre8]
+[![Java 8](https://img.shields.io/badge/Java_8-42.2.7-blue.svg)][mvn-jre8]
 ```xml
 <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
-    <version>42.2.5</version>
+    <version>42.2.7</version>
 </dependency>
 ```
 
-[![Java 7](https://img.shields.io/badge/Java_7-42.2.5.jre7-blue.svg)][mvn-jre7]
+[![Java 7](https://img.shields.io/badge/Java_7-42.2.7.jre7-blue.svg)][mvn-jre7]
 ```xml
 <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
-    <version>42.2.5.jre7</version>
+    <version>42.2.7.jre7</version>
 </dependency>
 ```
 
-[![Java 6](https://img.shields.io/badge/Java_6-42.2.5.jre6-blue.svg)][mvn-jre6]
+[![Java 6](https://img.shields.io/badge/Java_6-42.2.7.jre6-blue.svg)][mvn-jre6]
 ```xml
 <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
-    <version>42.2.5.jre6</version>
+    <version>42.2.7.jre6</version>
 </dependency>
 ```
 [mvn-search]: http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.postgresql%22%20AND%20a%3A%22postgresql%22 "Search on Maven Central"
-[mvn-jre6]: http://search.maven.org/#artifactdetails|org.postgresql|postgresql|42.2.5.jre6|bundle
-[mvn-jre7]: http://search.maven.org/#artifactdetails|org.postgresql|postgresql|42.2.5.jre7|bundle
-[mvn-jre8]: http://search.maven.org/#artifactdetails|org.postgresql|postgresql|42.2.5|bundle
+[mvn-jre6]: http://search.maven.org/#artifactdetails|org.postgresql|postgresql|42.2.7.jre6|bundle
+[mvn-jre7]: http://search.maven.org/#artifactdetails|org.postgresql|postgresql|42.2.7.jre7|bundle
+[mvn-jre8]: http://search.maven.org/#artifactdetails|org.postgresql|postgresql|42.2.7|bundle
 
 #### Development snapshots
 Snapshot builds (builds from `master` branch) are also deployed to Maven Central, so you can test current development version (test some bugfix) using:
@@ -61,9 +61,9 @@ Snapshot builds (builds from `master` branch) are also deployed to Maven Central
 <dependency>
   <groupId>org.postgresql</groupId>
   <artifactId>postgresql</artifactId>
-  <version>42.2.6-SNAPSHOT</version> <!-- Java 8 -->
-  <version>42.2.6.jre7-SNAPSHOT</version> <!-- Java 7 -->
-  <version>42.2.6.jre6-SNAPSHOT</version> <!-- Java 6 -->
+  <version>42.2.8-SNAPSHOT</version> <!-- Java 8 -->
+  <version>42.2.8.jre7-SNAPSHOT</version> <!-- Java 7 -->
+  <version>42.2.8.jre6-SNAPSHOT</version> <!-- Java 6 -->
 </dependency>
 ```
 
@@ -141,7 +141,7 @@ In addition to the standard connection parameters the driver supports a number o
 | readOnly                      | Boolean | true    | Puts this connection in read-only mode |
 | disableColumnSanitiser        | Boolean | false   | Enable optimization that disables column name sanitiser |
 | assumeMinServerVersion        | String  | null    | Assume the server is at least that version |
-| currentSchema                 | String  | null    | Specify the schema to be set in the search-path |
+| currentSchema                 | String  | null    | Specify the schema (or several schema separated by commas) to be set in the search-path |
 | targetServerType              | String  | any     | Specifies what kind of server to connect, possible values: any, master, slave (deprecated), secondary, preferSlave (deprecated), preferSecondary |
 | hostRecheckSeconds            | Integer | 10      | Specifies period (seconds) after which the host status is checked again in case it has changed |
 | loadBalanceHosts              | Boolean | false   | If disabled hosts are connected in the given order. If enabled hosts are chosen randomly from the set of suitable candidates |
diff --git a/codecov.yml b/codecov.yml
index 72deba08..c4067ade 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,6 +1,6 @@
 codecov:
   notify:
-    after_n_builds: 10
+    after_n_builds: 11
     require_ci_to_pass: false
 comment:
   layout: header, changes, diff
diff --git a/contributors.json b/contributors.json
index d286662a..bbe3dcd6 100644
--- a/contributors.json
+++ b/contributors.json
@@ -1,5 +1,6 @@
 {
    "Adam Brusselback" : "https://github.com/Tostino",
+   "Adrien" : "https://github.com/arobert-delfingen",
    "AlBundy33" : "https://github.com/AlBundy33",
    "AlexElin" : "https://github.com/AlexElin",
    "Alexander Kjäll" : "https://github.com/alexanderkjall",
@@ -21,6 +22,7 @@
    "Eric McCormack" : "https://github.com/ericmack",
    "Florin Asăvoaie" : "https://github.com/FlorinAsavoaie",
    "George Kankava" : "https://github.com/georgekankava",
+   "Hajar Razip" : "https://github.com/mshajarrazip",
    "Hari Babu Kommi" : "https://github.com/kommiharibabu",
    "Harry Chan" : "https://github.com/hc-codersatlas",
    "Hugh Cole-Baker" : "https://github.com/sigmaris",
@@ -51,11 +53,13 @@
    "Marios Trivyzas" : "https://github.com/matriv",
    "Mark Nguyen" : "https://github.com/Mrk-Nguyen",
    "Mathias Fußenegger" : "https://github.com/mfussenegger",
+   "Matteo Melli" : "https://github.com/teoincontatto",
    "Michael Glaesemann" : "https://github.com/grzm",
    "MichaelZg" : "https://github.com/michaelzg",
    "Michele Mancioppi" : "https://github.com/michele-mancioppi",
    "Minglei Tu" : "https://github.com/tminglei",
    "Mykola Nikishov" : "https://github.com/manandbytes",
+   "Myo Wai Thant" : "https://github.com/myowaithant9",
    "Nikolai Ivanov" : "https://github.com/nicktorwald",
    "Pavel Raiskup" : "https://github.com/praiskup",
    "Pawel" : "https://github.com/veselov",
@@ -72,15 +76,18 @@
    "Selene Feigl" : "https://github.com/sfeigl",
    "Sidi Mohamed EL AATIFI" : "https://github.com/elaatifi",
    "Simon Stelling" : "https://github.com/stellingsimon",
+   "Steinar Bang" : "https://github.com/steinarb",
    "Stephen Nelson" : "https://github.com/lordnelson",
    "Steve Ungerer" : "https://github.com/scubasau",
    "Sualeh Fatehi" : "https://github.com/sualeh",
    "Tanya Gordeeva" : "https://github.com/tmgordeeva",
    "Thach Hoang" : "https://github.com/thachhoang",
+   "Tim Ward" : "https://github.com/timothyjward",
    "Trygve Laugstøl" : "https://github.com/trygvis",
    "Tyson Andre" : "https://github.com/TysonAndre",
    "Vladimir Gordiychuk" : "https://github.com/Gordiychuk",
    "Vladimir Sitnikov" : "https://github.com/vlsi",
+   "Vsevolod Kaimashnikov" : "https://github.com/vsevolodk",
    "Zemian Deng" : "https://github.com/zemian",
    "aryabukhin" : "https://github.com/aryabukhin",
    "bazzargh" : "https://github.com/bazzargh",
diff --git a/docs/_posts/2019-06-19-42.2.6-release.md b/docs/_posts/2019-06-19-42.2.6-release.md
index e3d1b38d..8ec9fb54 100644
--- a/docs/_posts/2019-06-19-42.2.6-release.md
+++ b/docs/_posts/2019-06-19-42.2.6-release.md
@@ -7,6 +7,13 @@ version: 42.2.6
 ---
 **Notable changes**
 
+### Known issues
+- Waffle has [dropped support](https://github.com/Waffle/waffle/releases/tag/waffle-1.9.0) for 1.6, 1.7 as such the new waffle 1.9.x is only available in jre8
+- Microseconds in timestamps might be truncated when transferred in binary mode
+- 24:00 time handling is not consistent [issue 1385](https://github.com/pgjdbc/pgjdbc/issues/1385)
+- Unexpected packet type during stream replication [issue 1466](https://github.com/pgjdbc/pgjdbc/issues/1466)
+- Driver goes missing after OSGi bundle restart [issue 1476](https://github.com/pgjdbc/pgjdbc/issues/1476)
+
 ### Changed
 - Change IS_GENERATED to IS_GENERATEDCOLUMN as per spec [PR 1485](https://github.com/pgjdbc/pgjdbc/pull/1485)
 - Fix missing metadata columns, and misspelled columns in PgDatabaseMetaData#getTables [PR 1323](https://github.com/pgjdbc/pgjdbc/pull/1323)
@@ -29,12 +36,6 @@ version: 42.2.6
 - Fix execution with big decimal in simple query mode. [PR 1463](https://github.com/pgjdbc/pgjdbc/pull/1463)
 - Fix rounding for timestamps truncated to dates before 1970 [PR 1502](https://github.com/pgjdbc/pgjdbc/pull/1502)
 
-### Known issues
-- Microseconds in timestamps might be truncated when transferred in binary mode
-- 24:00 time handling is not consistent [issue 1385](https://github.com/pgjdbc/pgjdbc/issues/1385)
-- Unexpected packet type during stream replication [issue 1466](https://github.com/pgjdbc/pgjdbc/issues/1466)
-- Driver goes missing after OSGi bundle restart [issue 1476](https://github.com/pgjdbc/pgjdbc/issues/1476)
-
 
 <!--more-->
 
diff --git a/docs/_posts/2019-09-10-42.2.7-release.md b/docs/_posts/2019-09-10-42.2.7-release.md
new file mode 100644
index 00000000..769adb36
--- /dev/null
+++ b/docs/_posts/2019-09-10-42.2.7-release.md
@@ -0,0 +1,103 @@
+---
+title: PostgreSQL JDBC Driver 42.2.7 Released
+date: 2019-09-10 13:50:37 +0000
+categories:
+  - new_release
+version: 42.2.7
+---
+**Notable changes**
+
+### Changed
+
+### Added
+- Expose parameter status messages (GUC_REPORT) to the user [PR 1435](https://github.com/pgjdbc/pgjdbc/pull/1435)
+- Add automatic module name to manifest for jdk9+ [PR 1538](https://github.com/pgjdbc/pgjdbc/pull/1538)
+- Log ignoring rollback when no transaction in progress [PR 1549](https://github.com/pgjdbc/pgjdbc/pull/1549)
+- Map inet type to InetAddress [PR 1527](https://github.com/pgjdbc/pgjdbc/pull/1527) [issue 1134](https://github.com/pgjdbc/pgjdbc/issues/1134)
+
+### Fixed
+- fix [issue 1547](https://github.com/pgjdbc/pgjdbc/issues/1547) As long as peek returns some bytes do not reset the timeout, this allows us to continue checking until any async notifies are consumed [PR 1548](https://github.com/pgjdbc/pgjdbc/pull/1548)
+- fix: [issue 1466](https://github.com/pgjdbc/pgjdbc/issues/1466) In logical decoding the if the backend was requesting a reply we… [PR 1467](https://github.com/pgjdbc/pgjdbc/pull/1467)
+- fix: [issue 1534](https://github.com/pgjdbc/pgjdbc/issues/1534) Proleptic java.time support [PR 1539](https://github.com/pgjdbc/pgjdbc/pull/1539)
+- fix Ensure isValid() will not last more than timeout seconds [PR 1557](https://github.com/pgjdbc/pgjdbc/pull/1557)
+
+<!--more-->
+
+**Commits by author**
+
+Adrien (1):
+
+* Ensure isValid() will not last more than timeout seconds [PR 1557](https://github.com/pgjdbc/pgjdbc/pull/1557) [b2eaefe](https://github.com/pgjdbc/pgjdbc/commit/b2eaefef1787b8ab0b8fcb266d10be4945a4fe25)
+
+Craig Ringer (2):
+
+* Expose parameter status messages (GUC_REPORT) to the user [PR 1435](https://github.com/pgjdbc/pgjdbc/pull/1435) [ce8333a](https://github.com/pgjdbc/pgjdbc/commit/ce8333a56ba74022adeb545b68e7d2bee32d966f)
+* Make ConnectTimeout test accept NoRouteToHostException [PR 1526](https://github.com/pgjdbc/pgjdbc/pull/1526) [08d8129](https://github.com/pgjdbc/pgjdbc/commit/08d81291c69d02d8973d6b39dac82bdaad91f2ee)
+
+Dave Cramer (8):
+
+* note that waffle 1.9.x is only supported in jre8 version Update README to point to new maven coordinates [58804e9](https://github.com/pgjdbc/pgjdbc/commit/58804e9af41368fc9e956a7dd6cf799cb1d72420)
+* add automatic module name to manifest for jdk9+ [PR 1538](https://github.com/pgjdbc/pgjdbc/pull/1538) [0600990](https://github.com/pgjdbc/pgjdbc/commit/0600990007669119b73ee2adb064184a4c62343f)
+* fix issue 1547, as long as peek returns some bytes do not reset the timeout, this allows us to continue checking until any async notifies are consumed [PR 1548](https://github.com/pgjdbc/pgjdbc/pull/1548) [36a75cb](https://github.com/pgjdbc/pgjdbc/commit/36a75cbaab4bda1b55f48aa9064258051cd89b10)
+* fix: In logical decoding the if the backend was requesting a reply we… [PR 1467](https://github.com/pgjdbc/pgjdbc/pull/1467) [f89e62c](https://github.com/pgjdbc/pgjdbc/commit/f89e62cdce4895f163dc95353cd31614347624b6)
+* Log ignoring rollback when no transaction in progress [PR 1549](https://github.com/pgjdbc/pgjdbc/pull/1549) [bda74d7](https://github.com/pgjdbc/pgjdbc/commit/bda74d7eaa341c02427af4065d8321c8e45bfd83)
+* fix assertion message [PR 1553](https://github.com/pgjdbc/pgjdbc/pull/1553) [ba82948](https://github.com/pgjdbc/pgjdbc/commit/ba8294841a2e589e15dfcb79dbd31a83ec615208)
+* remove failing tests for PostgreSQL version 8.3 add in tests for 11 [89464a5](https://github.com/pgjdbc/pgjdbc/commit/89464a54777b9272893ab24bc5e28a24623e41bb)
+* Fix travis parsing issue [634ac7d](https://github.com/pgjdbc/pgjdbc/commit/634ac7d8fee23eb5231ce91c616a64d120f8d8ee)
+
+Hajar Razip (2):
+
+* docs: add note on behavior of ResultSet.getString() [PR 1286](https://github.com/pgjdbc/pgjdbc/pull/1286) (#1528) [c30556c](https://github.com/pgjdbc/pgjdbc/commit/c30556c6c059f25d4ed43608d1b2a2f02a168389)
+* docs: update resultset.md in head to reflect 94 [PR 1528](https://github.com/pgjdbc/pgjdbc/pull/1528) (#1536) [fc8efc9](https://github.com/pgjdbc/pgjdbc/commit/fc8efc9a98e86059701e8674017947c0b702cab1)
+
+Matteo Melli (1):
+
+* Updated scram to version 2.0 [PR 1532](https://github.com/pgjdbc/pgjdbc/pull/1532) [fcbbc3e](https://github.com/pgjdbc/pgjdbc/commit/fcbbc3e6408cc1bcf459b740c683f3db40a5050c)
+
+Myo Wai Thant (1):
+
+* Issue 1134 Map inet type to InetAddress [PR 1527](https://github.com/pgjdbc/pgjdbc/pull/1527) [1d0c477](https://github.com/pgjdbc/pgjdbc/commit/1d0c477abbe23f23681a924ee0d216a5f7188079)
+
+Pavel Raiskup (2):
+
+* fix parent version in pgjdbc/pom.xml as well [3db55da](https://github.com/pgjdbc/pgjdbc/commit/3db55daf2dccdd49555fd73b70be5c15609cccfa)
+* rpm: remove karaf plugin [8495127](https://github.com/pgjdbc/pgjdbc/commit/8495127fe0450f94923251f67ab8e2208319437f)
+
+Philippe Marschall (1):
+
+* fix: proleptic java.time support [PR 1539](https://github.com/pgjdbc/pgjdbc/pull/1539) [60fa6d3](https://github.com/pgjdbc/pgjdbc/commit/60fa6d374a392d00475be0c128804c43b2852a35)
+
+Sehrope Sarkuni (2):
+
+* docs: Add note to GitHub PR templates about test suites [PR 1531](https://github.com/pgjdbc/pgjdbc/pull/1531) [51f3d0b](https://github.com/pgjdbc/pgjdbc/commit/51f3d0b75078e5c8687c7eae20ff37b28e65abec)
+* Sort test suites and enable missed tests [PR 1530](https://github.com/pgjdbc/pgjdbc/pull/1530) [aa8778d](https://github.com/pgjdbc/pgjdbc/commit/aa8778d91bd166e2f351343855d6e0b0b71b1e62)
+
+Steinar Bang (1):
+
+* Add an apache karaf feature for the PostgreSQL JDBC driver to fix [PR 1552](https://github.com/pgjdbc/pgjdbc/pull/1552) (#1554) [e2f6e9f](https://github.com/pgjdbc/pgjdbc/commit/e2f6e9fc54a60f4b310bab9d83d74dbdc8941f32)
+
+Tim Ward (1):
+
+* Check that JDBC Connections that are closed by the server do not report as valid [PR 1533](https://github.com/pgjdbc/pgjdbc/pull/1533) [56399ef](https://github.com/pgjdbc/pgjdbc/commit/56399efddd25281ccefd90c56e9db084c550d195)
+
+Vsevolod Kaimashnikov (1):
+
+* Add more info about currentSchema property. [PR 1481](https://github.com/pgjdbc/pgjdbc/pull/1481) [d96ed59](https://github.com/pgjdbc/pgjdbc/commit/d96ed59eba6a2279da337684e696b198ec60685c)
+
+<a name="contributors_{{ page.version }}"></a>
+### Contributors to this release
+
+We thank the following people for their contributions to this release.
+
+[Adrien](https://github.com/arobert-delfingen)  
+[Craig Ringer](https://github.com/ringerc)  
+[Dave Cramer](davec@postgresintl.com)  
+[Hajar Razip](https://github.com/mshajarrazip)  
+[Matteo Melli](https://github.com/teoincontatto)  
+[Myo Wai Thant](https://github.com/myowaithant9)  
+[Pavel Raiskup](https://github.com/praiskup)  
+[Philippe Marschall](https://github.com/marschall)  
+[Sehrope Sarkuni](https://github.com/sehrope)  
+[Steinar Bang](https://github.com/steinarb)  
+[Tim Ward](https://github.com/timothyjward)  
+[Vsevolod Kaimashnikov](https://github.com/vsevolodk)  
diff --git a/docs/_posts/2019-09-13-42.2.8-release.md b/docs/_posts/2019-09-13-42.2.8-release.md
new file mode 100644
index 00000000..5351f212
--- /dev/null
+++ b/docs/_posts/2019-09-13-42.2.8-release.md
@@ -0,0 +1,31 @@
+---
+title: PostgreSQL JDBC Driver 42.2.8 Released
+date: 2019-09-13 13:23:26 +0000
+categories:
+  - new_release
+version: 42.2.8
+---
+**Notable changes**
+
+### Changed
+
+### Added
+
+### Fixed
+
+
+<!--more-->
+
+**Commits by author**
+
+Sehrope Sarkuni (1):
+
+* fix: Revert inet default Java type to PGObject and handle values with net masks [PR 1568](https://github.com/pgjdbc/pgjdbc/pull/1568) [3df32f9](https://github.com/pgjdbc/pgjdbc/commit/3df32f9bf9da38cc5f0fbb212a3034e4634dd3c7)
+
+<a name="contributors_{{ page.version }}"></a>
+### Contributors to this release
+
+We thank the following people for their contributions to this release.
+
+[Dave Cramer](davec@postgresintl.com)  
+[Sehrope Sarkuni](https://github.com/sehrope)  
diff --git a/docs/documentation/94/resultset.md b/docs/documentation/94/resultset.md
index 58c5f5a4..02204858 100644
--- a/docs/documentation/94/resultset.md
+++ b/docs/documentation/94/resultset.md
@@ -16,4 +16,14 @@ The following must be considered when using the `ResultSet` interface:
 * You must close a `ResultSet` by calling `close()` once you have finished using
 	it.
 * Once you make another query with the `Statement` used to create a `ResultSet`,
-	the currently open `ResultSet` instance is closed automatically.
\ No newline at end of file
+	the currently open `ResultSet` instance is closed automatically.
+* When PreparedStatement API is used, `ResultSet` switches to binary mode after 
+	five query executions (this default is set by the `prepareThreshold` 
+	connection property, see [Server Prepared Statements](server-prepare.md)). 
+	This may cause unexpected behavior when some methods are called. For example, 
+	results on method calls such as `getString()` on non-string data types, 	
+	while logically　equivalent, may be formatted differently after execution exceeds 
+	the set `prepareThreshold` when conversion to object method switches to one 
+	matching the return mode. 
+	
+	
\ No newline at end of file
diff --git a/docs/documentation/head/connect.md b/docs/documentation/head/connect.md
index c455aca4..20d817c6 100644
--- a/docs/documentation/head/connect.md
+++ b/docs/documentation/head/connect.md
@@ -411,7 +411,7 @@ Connection conn = DriverManager.getConnection(url);
 
 * **currentSchema** = String
 
-	Specify the schema to be set in the search-path. 
+	Specify the schema (or several schema separated by commas) to be set in the search-path. 
 	This schema will be used to resolve unqualified object names used in statements over this connection.
 
 * **targetServerType** = String
diff --git a/docs/documentation/head/ext.md b/docs/documentation/head/ext.md
index ea7cee9b..2a46d469 100644
--- a/docs/documentation/head/ext.md
+++ b/docs/documentation/head/ext.md
@@ -16,6 +16,7 @@ next: geometric.html
 * [Large Objects](largeobjects.html)
 * [Listen / Notify](listennotify.html)
 * [Server Prepared Statements](server-prepare.html)
+* [Parameter Status Messages](parameterstatus.html)
 * [Physical and Logical replication API](replication.html)
 * [Arrays](arrays.html)
 
diff --git a/docs/documentation/head/parameterstatus.md b/docs/documentation/head/parameterstatus.md
new file mode 100644
index 00000000..f83fda21
--- /dev/null
+++ b/docs/documentation/head/parameterstatus.md
@@ -0,0 +1,63 @@
+---
+layout: default_docs
+title: Physical and Logical replication API
+header: Chapter 9. PostgreSQL™ Extensions to the JDBC API
+resource: media
+previoustitle: Parameter Status Messages
+previous: server-prepare.html
+nexttitle: Physical and Logical replication API
+next: replication.html
+---
+
+# Parameter Status Messages
+
+PostgreSQL supports server parameters, also called server variables or,
+internally, Grand Unified Configuration (GUC) variables. These variables are
+manipulated by the `SET` command, `postgresql.conf`, `ALTER SYSTEM SET`, `ALTER
+USER SET`, `ALTER DATABASE SET`, the `set_config(...)` SQL-callable function,
+etc. See [the PostgreSQL manual](https://www.postgresql.org/docs/current/config-setting.html).
+
+For a subset of these variables the server will *automatically report changes
+to the value to the client driver and application*. These variables are known
+internally as `GUC_REPORT` variables after the name of the flag that enables
+the functionality.
+
+The server keeps track of all the variable scopes and reports when a variable
+reverts to a prior value, so the client doesn't have to guess what the current
+value is and whether some server-side function could've changed it.  Whenever
+the value changes, no matter why or how it changes, the server reports the new
+effective value in a *Parameter Status* protocol message to the client.  PgJDBC
+uses many of these reports internally.
+
+As of PgJDBC 42.2.6, it also exposes the parameter status information to user
+applications via the PGConnection extensions interface.
+
+## Methods
+
+Two methods on `org.postgresql.PGConnection` provide the client interface to
+reported parameters. Parameter names are case-insensitive and case-preserving.
+
+* `Map PGConnection.getParameterStatuses()` - return a map of all reported
+  parameters and their values.
+
+* `String PGConnection.getParameterStatus()` - shorthand to retrieve one
+  value by name, or null if no value has been reported.
+
+See the `PGConnection` JavaDoc for details.
+
+## Example
+
+If you're working directly with a `java.sql.Connection` you can
+
+    import org.postgresql.PGConnection;
+
+    void my_function(Connection conn) {
+
+        System.out.println("My application name is " +
+            ((PGConnection)conn).getParameterStatus("application_name"));
+
+    }
+
+## Other client drivers
+
+The `libpq` equivalent is the `PQparameterStatus(...)` API function.
diff --git a/docs/documentation/head/replication.md b/docs/documentation/head/replication.md
index 5d821fb2..223851df 100644
--- a/docs/documentation/head/replication.md
+++ b/docs/documentation/head/replication.md
@@ -3,8 +3,8 @@ layout: default_docs
 title: Physical and Logical replication API
 header: Chapter 9. PostgreSQL™ Extensions to the JDBC API
 resource: media
-previoustitle: Server Prepared Statements
-previous: server-prepare.html
+previoustitle: Parameter Status Messages
+previous: parameterstatus.html
 nexttitle: Arrays
 next: arrays.html
 ---
diff --git a/docs/documentation/head/resultset.md b/docs/documentation/head/resultset.md
index 58c5f5a4..2be54d19 100644
--- a/docs/documentation/head/resultset.md
+++ b/docs/documentation/head/resultset.md
@@ -16,4 +16,12 @@ The following must be considered when using the `ResultSet` interface:
 * You must close a `ResultSet` by calling `close()` once you have finished using
 	it.
 * Once you make another query with the `Statement` used to create a `ResultSet`,
-	the currently open `ResultSet` instance is closed automatically.
\ No newline at end of file
+	the currently open `ResultSet` instance is closed automatically.
+* When PreparedStatement API is used, `ResultSet` switches to binary mode after 
+	five query executions (this default is set by the `prepareThreshold` 
+	connection property, see [Server Prepared Statements](server-prepare.md)). 
+	This may cause unexpected behavior when some methods are called. For example, 
+	results on method calls such as `getString()` on non-string data types, 	
+	while logically　equivalent, may be formatted differently after execution exceeds 
+	the set `prepareThreshold` when conversion to object method switches to one 
+	matching the return mode. 
\ No newline at end of file
diff --git a/docs/documentation/head/server-prepare.md b/docs/documentation/head/server-prepare.md
index 76f1504e..c9a55953 100644
--- a/docs/documentation/head/server-prepare.md
+++ b/docs/documentation/head/server-prepare.md
@@ -5,8 +5,8 @@ header: Chapter 9. PostgreSQL™ Extensions to the JDBC API
 resource: media
 previoustitle: Listen / Notify
 previous: listennotify.html
-nexttitle: Physical and Logical replication API
-next: replication.html
+nexttitle: Parameter Status Messages
+next: parameterstatus.html
 ---
 
 ### Motivation
diff --git a/packaging/rpm/postgresql-jdbc.spec.tpl b/packaging/rpm/postgresql-jdbc.spec.tpl
index e0256ff4..45f81791 100644
--- a/packaging/rpm/postgresql-jdbc.spec.tpl
+++ b/packaging/rpm/postgresql-jdbc.spec.tpl
@@ -61,7 +61,6 @@ BuildArch:	noarch
 BuildRequires:	java-devel >= 1.8
 BuildRequires:	maven-local
 BuildRequires:	java-comment-preprocessor
-BuildRequires:	properties-maven-plugin
 BuildRequires:	maven-enforcer-plugin
 BuildRequires:	maven-plugin-bundle
 BuildRequires:	maven-plugin-build-helper
@@ -107,6 +106,9 @@ find -name "*.jar" -or -name "*.class" | xargs rm -f
 %pom_xpath_inject pom:parent "<relativePath>pgjdbc-parent-poms/pgjdbc-versions</relativePath>"
 %pom_xpath_set pom:relativePath ../pgjdbc-parent-poms/pgjdbc-core-parent pgjdbc
 %pom_xpath_remove "pom:plugin[pom:artifactId = 'maven-shade-plugin']" pgjdbc
+%pom_remove_plugin :karaf-maven-plugin pgjdbc
+%pom_remove_plugin :properties-maven-plugin pgjdbc-parent-poms/pgjdbc-core-parent
+%pom_remove_plugin :properties-maven-plugin pgjdbc-parent-poms/pgjdbc-versions
 
 # compat symlink: requested by dtardon (libreoffice), reverts part of
 # 0af97ce32de877 commit.
diff --git a/pgjdbc/pom.xml b/pgjdbc/pom.xml
index 8a859c38..128f39e4 100644
--- a/pgjdbc/pom.xml
+++ b/pgjdbc/pom.xml
@@ -3,14 +3,14 @@
   <parent>
     <groupId>org.postgresql</groupId>
     <artifactId>pgjdbc-core-parent</artifactId>
-    <version>1.1.5</version>
+    <version>1.1.6</version>
     <relativePath />
   </parent>
 
   <artifactId>postgresql</artifactId>
   <packaging>bundle</packaging>
   <name>PostgreSQL JDBC Driver - JDBC 4.2</name>
-  <version>42.2.7-SNAPSHOT</version>
+  <version>42.2.9-SNAPSHOT</version>
   <description>Java JDBC 4.2 (JRE 8+) driver for PostgreSQL database</description>
   <url>https://github.com/pgjdbc/pgjdbc</url>
 
@@ -40,7 +40,7 @@
     <dependency>
       <groupId>com.ongres.scram</groupId>
       <artifactId>client</artifactId>
-      <version>1.0.0-beta.2</version>
+      <version>2.1</version>
     </dependency>
   </dependencies>
 
@@ -240,6 +240,17 @@
           <outputEncoding>UTF-8</outputEncoding>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestEntries>
+              <Automatic-Module-Name>org.postgresql.jdbc</Automatic-Module-Name>
+            </manifestEntries>
+          </archive>
+        </configuration>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-shade-plugin</artifactId>
@@ -290,6 +301,27 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.karaf.tooling</groupId>
+        <artifactId>karaf-maven-plugin</artifactId>
+        <version>4.2.5</version>
+        <extensions>true</extensions>
+        <configuration>
+          <startLevel>80</startLevel>
+          <includeTransitiveDependency>false</includeTransitiveDependency>
+          <aggregateFeatures>false</aggregateFeatures>
+          <includeProjectArtifact>true</includeProjectArtifact>
+        </configuration>
+        <executions>
+          <execution>
+            <id>generate-features-file</id>
+            <phase>package</phase>
+            <goals>
+              <goal>features-generate-descriptor</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
 
     <pluginManagement>
@@ -297,7 +329,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-checkstyle-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.0</version>
           <dependencies>
             <dependency>
               <groupId>com.puppycrawl.tools</groupId>
diff --git a/pgjdbc/src/main/feature/feature.xml b/pgjdbc/src/main/feature/feature.xml
new file mode 100644
index 00000000..1beb662e
--- /dev/null
+++ b/pgjdbc/src/main/feature/feature.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+  <feature name="postgresql" description="PostgreSQL JDBC driver karaf feature" version="${project.version}">
+    <feature>transaction-api</feature>
+  </feature>
+</features>
diff --git a/pgjdbc/src/main/java/org/postgresql/PGConnection.java b/pgjdbc/src/main/java/org/postgresql/PGConnection.java
index ba2a04e9..fd764563 100644
--- a/pgjdbc/src/main/java/org/postgresql/PGConnection.java
+++ b/pgjdbc/src/main/java/org/postgresql/PGConnection.java
@@ -17,6 +17,8 @@ import java.sql.Array;
 import java.sql.SQLException;
 import java.sql.Statement;
 
+import java.util.Map;
+
 /**
  * This interface defines the public PostgreSQL extensions to java.sql.Connection. All Connections
  * returned by the PostgreSQL driver implement PGConnection.
@@ -236,4 +238,76 @@ public interface PGConnection {
    * @return replication API for the current connection
    */
   PGReplicationConnection getReplicationAPI();
+
+  /**
+   * <p>Returns the current values of all parameters reported by the server.</p>
+   *
+   * <p>PostgreSQL reports values for a subset of parameters (GUCs) to the client
+   * at connect-time, then sends update messages whenever the values change
+   * during a session. PgJDBC records the latest values and exposes it to client
+   * applications via <code>getParameterStatuses()</code>.</p>
+   *
+   * <p>PgJDBC exposes individual accessors for some of these parameters as
+   * listed below. They are more backwarrds-compatible and should be preferred
+   * where possible.</p>
+   *
+   * <p>Not all parameters are reported, only those marked
+   * <code>GUC_REPORT</code> in the source code. The <code>pg_settings</code>
+   * view does not expose information about which parameters are reportable.
+   * PgJDBC's map will only contain the parameters the server reports values
+   * for, so you cannot use this method as a substitute for running a
+   * <code>SHOW paramname;</code> or <code>SELECT
+   * current_setting('paramname');</code> query for arbitrary parameters.</p>
+   *
+   * <p>Parameter names are <i>case-insensitive</i> and <i>case-preserving</i>
+   * in this map, like in PostgreSQL itself. So <code>DateStyle</code> and
+   * <code>datestyle</code> are the same key.</p>
+   *
+   * <p>
+   *  As of PostgreSQL 11 the reportable parameter list, and related PgJDBC
+   *  interfaces or accesors, are:
+   * </p>
+   *
+   * <ul>
+   *  <li>
+   *    <code>application_name</code> -
+   *    {@link java.sql.Connection#getClientInfo()},
+   *    {@link java.sql.Connection#setClientInfo(java.util.Properties)}
+   *    and <code>ApplicationName</code> connection property.
+   *  </li>
+   *  <li>
+   *    <code>client_encoding</code> - PgJDBC always sets this to <code>UTF8</code>.
+   *    See <code>allowEncodingChanges</code> connection property.
+   *  </li>
+   *  <li><code>DateStyle</code> - PgJDBC requires this to always be set to <code>ISO</code></li>
+   *  <li><code>standard_conforming_strings</code> - indirectly via {@link #escapeLiteral(String)}</li>
+   *  <li>
+   *    <code>TimeZone</code> - set from JDK timezone see {@link java.util.TimeZone#getDefault()}
+   *    and {@link java.util.TimeZone#setDefault(TimeZone)}
+   *  </li>
+   *  <li><code>integer_datetimes</code></li>
+   *  <li><code>IntervalStyle</code></li>
+   *  <li><code>server_encoding</code></li>
+   *  <li><code>server_version</code></li>
+   *  <li><code>is_superuser</code> </li>
+   *  <li><code>session_authorization</code></li>
+   * </ul>
+   *
+   * <p>Note that some PgJDBC operations will change server parameters
+   * automatically.</p>
+   *
+   * @return unmodifiable map of case-insensitive parameter names to parameter values
+   * @since 42.2.6
+   */
+  Map<String,String> getParameterStatuses();
+
+  /**
+   * Shorthand for getParameterStatuses().get(...) .
+   *
+   * @param parameterName case-insensitive parameter name
+   * @return parameter value if defined, or null if no parameter known
+   * @see #getParameterStatuses
+   * @since 42.2.6
+   */
+  String getParameterStatus(String parameterName);
 }
diff --git a/pgjdbc/src/main/java/org/postgresql/PGProperty.java b/pgjdbc/src/main/java/org/postgresql/PGProperty.java
index 37d2f950..b342b44c 100644
--- a/pgjdbc/src/main/java/org/postgresql/PGProperty.java
+++ b/pgjdbc/src/main/java/org/postgresql/PGProperty.java
@@ -367,10 +367,10 @@ public enum PGProperty {
   ALLOW_ENCODING_CHANGES("allowEncodingChanges", "false", "Allow for changes in client_encoding"),
 
   /**
-   * Specify the schema to be set in the search-path. This schema will be used to resolve
+   * Specify the schema (or several schema separated by commas) to be set in the search-path. This schema will be used to resolve
    * unqualified object names used in statements over this connection.
    */
-  CURRENT_SCHEMA("currentSchema", null, "Specify the schema to be set in the search-path"),
+  CURRENT_SCHEMA("currentSchema", null, "Specify the schema (or several schema separated by commas) to be set in the search-path"),
 
   TARGET_SERVER_TYPE("targetServerType", "any", "Specifies what kind of server to connect", false,
       "any", "master", "slave", "secondary",  "preferSlave", "preferSecondary"),
diff --git a/pgjdbc/src/main/java/org/postgresql/core/PGStream.java b/pgjdbc/src/main/java/org/postgresql/core/PGStream.java
index 7ed6fc3e..d8bcb3a6 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/PGStream.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/PGStream.java
@@ -115,25 +115,39 @@ public class PGStream implements Closeable, Flushable {
    * @throws IOException if something wrong happens
    */
   public boolean hasMessagePending() throws IOException {
+
+    boolean available = false;
+
+    // In certain cases, available returns 0, yet there are bytes
     if (pgInput.available() > 0) {
       return true;
     }
-    // In certain cases, available returns 0, yet there are bytes
-    long now = System.currentTimeMillis();
+    long now = System.nanoTime() / 1000000;
+
     if (now < nextStreamAvailableCheckTime && minStreamAvailableCheckDelay != 0) {
       // Do not use ".peek" too often
       return false;
     }
-    nextStreamAvailableCheckTime = now + minStreamAvailableCheckDelay;
+
     int soTimeout = getNetworkTimeout();
     setNetworkTimeout(1);
     try {
-      return pgInput.peek() != -1;
+      available = (pgInput.peek() != -1);
     } catch (SocketTimeoutException e) {
       return false;
     } finally {
       setNetworkTimeout(soTimeout);
     }
+
+    /*
+    If none available then set the next check time
+    In the event that there more async bytes available we will continue to get them all
+    see issue 1547 https://github.com/pgjdbc/pgjdbc/issues/1547
+     */
+    if (!available) {
+      nextStreamAvailableCheckTime = now + minStreamAvailableCheckDelay;
+    }
+    return available;
   }
 
   public void setMinStreamAvailableCheckDelay(int delay) {
diff --git a/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java b/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java
index d6db7292..8d95e8d2 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java
@@ -18,6 +18,7 @@ import java.io.IOException;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
 
@@ -452,4 +453,9 @@ public interface QueryExecutor extends TypeTransferModeRegistry {
   void setNetworkTimeout(int milliseconds) throws IOException;
 
   int getNetworkTimeout() throws IOException;
+
+  // Expose parameter status to PGConnection
+  Map<String,String> getParameterStatuses();
+
+  String getParameterStatus(String parameterName);
 }
diff --git a/pgjdbc/src/main/java/org/postgresql/core/QueryExecutorBase.java b/pgjdbc/src/main/java/org/postgresql/core/QueryExecutorBase.java
index 8fe0bbb8..fbe5c498 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/QueryExecutorBase.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/QueryExecutorBase.java
@@ -19,7 +19,10 @@ import java.io.IOException;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
 import java.util.Properties;
+import java.util.TreeMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -52,6 +55,10 @@ public abstract class QueryExecutorBase implements QueryExecutor {
   private final LruCache<Object, CachedQuery> statementCache;
   private final CachedQueryCreateAction cachedQueryCreateAction;
 
+  // For getParameterStatuses(), GUC_REPORT tracking
+  private final TreeMap<String,String> parameterStatuses
+      = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER);
+
   protected QueryExecutorBase(PGStream pgStream, String user,
       String database, int cancelSignalTimeout, Properties info) throws SQLException {
     this.pgStream = pgStream;
@@ -344,6 +351,10 @@ public abstract class QueryExecutorBase implements QueryExecutor {
   }
 
   protected boolean willHealViaReparse(SQLException e) {
+    if (e == null || e.getSQLState() == null) {
+      return false;
+    }
+
     // "prepared statement \"S_2\" does not exist"
     if (PSQLState.INVALID_SQL_STATEMENT_NAME.getState().equals(e.getSQLState())) {
       return true;
@@ -389,4 +400,42 @@ public abstract class QueryExecutorBase implements QueryExecutor {
   protected boolean hasNotifications() {
     return notifications.size() > 0;
   }
+
+  @Override
+  public final Map<String,String> getParameterStatuses() {
+    return Collections.unmodifiableMap(parameterStatuses);
+  }
+
+  @Override
+  public final String getParameterStatus(String parameterName) {
+    return parameterStatuses.get(parameterName);
+  }
+
+  /**
+   * Update the parameter status map in response to a new ParameterStatus
+   * wire protocol message.
+   *
+   * <p>The server sends ParameterStatus messages when GUC_REPORT settings are
+   * initially assigned and whenever they change.</p>
+   *
+   * <p>A future version may invoke a client-defined listener class at this point,
+   * so this should be the only access path.</p>
+   *
+   * <p>Keys are case-insensitive and case-preserving.</p>
+   *
+   * <p>The server doesn't provide a way to report deletion of a reportable
+   * parameter so we don't expose one here.</p>
+   *
+   * @param parameterName case-insensitive case-preserving name of parameter to create or update
+   * @param parameterStatus new value of parameter
+   * @see org.postgresql.PGConnection#getParameterStatuses
+   * @see org.postgresql.PGConnection#getParameterStatus
+   */
+  protected void onParameterStatus(String parameterName, String parameterStatus) {
+    if (parameterName == null || parameterName.equals("")) {
+      throw new IllegalStateException("attempt to set GUC_REPORT parameter with null or empty-string name");
+    }
+
+    parameterStatuses.put(parameterName, parameterStatus);
+  }
 }
diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java b/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java
index 78cdcc4d..e342cb25 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java
@@ -495,9 +495,9 @@ public class ConnectionFactoryImpl extends ConnectionFactory {
     /* SSPI negotiation state, if used */
     ISSPIClient sspiClient = null;
 
-    //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
+    //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.1"
     /* SCRAM authentication state, if used */
-    org.postgresql.jre8.sasl.ScramAuthenticator scramAuthenticator = null;
+    org.postgresql.jre7.sasl.ScramAuthenticator scramAuthenticator = null;
     //#endif
 
     try {
@@ -661,8 +661,8 @@ public class ConnectionFactoryImpl extends ConnectionFactory {
               case AUTH_REQ_SASL:
                 LOGGER.log(Level.FINEST, " <=BE AuthenticationSASL");
 
-                //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
-                scramAuthenticator = new org.postgresql.jre8.sasl.ScramAuthenticator(user, password, pgStream);
+                //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.1"
+                scramAuthenticator = new org.postgresql.jre7.sasl.ScramAuthenticator(user, password, pgStream);
                 scramAuthenticator.processServerMechanismsAndInit();
                 scramAuthenticator.sendScramClientFirstMessage();
                 // This works as follows:
@@ -674,12 +674,12 @@ public class ConnectionFactoryImpl extends ConnectionFactory {
                           "SCRAM authentication is not supported by this driver. You need JDK >= 8 and pgjdbc >= 42.2.0 (not \".jre\" versions)",
                           areq), PSQLState.CONNECTION_REJECTED);
                   //#endif
-                  //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
+                  //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.1"
                 }
                 break;
                 //#endif
 
-              //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
+              //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.1"
               case AUTH_REQ_SASL_CONTINUE:
                 scramAuthenticator.processServerFirstMessage(msgLen - 4 - 4);
                 break;
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 f43bb78b..6c5cc1e6 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
@@ -62,6 +62,7 @@ import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -1023,7 +1024,6 @@ public class QueryExecutorImpl extends QueryExecutorBase {
       pgStream.sendInteger4(siz + 4);
       pgStream.send(data, off, siz);
 
-      processCopyResults(op, false); // collect any pending notifications without blocking
     } catch (IOException ioe) {
       throw new PSQLException(GT.tr("Database connection failed when writing to copy"),
           PSQLState.CONNECTION_FAILURE, ioe);
@@ -1038,7 +1038,6 @@ public class QueryExecutorImpl extends QueryExecutorBase {
 
     try {
       pgStream.flush();
-      processCopyResults(op, false); // collect any pending notifications without blocking
     } catch (IOException ioe) {
       throw new PSQLException(GT.tr("Database connection failed when writing to copy"),
           PSQLState.CONNECTION_FAILURE, ioe);
@@ -1067,6 +1066,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
     }
   }
 
+  AtomicBoolean processingCopyResults = new AtomicBoolean(false);
+
   /**
    * Handles copy sub protocol responses from server. Unlocks at end of sub protocol, so operations
    * on pgStream or QueryExecutor are not allowed in a method after calling this!
@@ -1080,205 +1081,226 @@ public class QueryExecutorImpl extends QueryExecutorBase {
   CopyOperationImpl processCopyResults(CopyOperationImpl op, boolean block)
       throws SQLException, IOException {
 
-    boolean endReceiving = false;
-    SQLException error = null;
-    SQLException errors = null;
-    int len;
-
-    while (!endReceiving && (block || pgStream.hasMessagePending())) {
-
-      // There is a bug in the server's implementation of the copy
-      // protocol. It returns command complete immediately upon
-      // receiving the EOF marker in the binary protocol,
-      // potentially before we've issued CopyDone. When we are not
-      // blocking, we don't think we are done, so we hold off on
-      // processing command complete and any subsequent messages
-      // until we actually are done with the copy.
-      //
-      if (!block) {
-        int c = pgStream.peekChar();
-        if (c == 'C') {
-          // CommandComplete
-          LOGGER.log(Level.FINEST, " <=BE CommandStatus, Ignored until CopyDone");
-          break;
+    /*
+    *  This is a hack as we should not end up here, but sometimes do with large copy operations.
+     */
+    if ( processingCopyResults.compareAndSet(false,true) == false ) {
+      LOGGER.log(Level.INFO, "Ignoring request to process copy results, already processing");
+      return null;
+    }
+
+    // put this all in a try, finally block and reset the processingCopyResults in the finally clause
+    try {
+      boolean endReceiving = false;
+      SQLException error = null;
+      SQLException errors = null;
+      int len;
+
+      while (!endReceiving && (block || pgStream.hasMessagePending())) {
+
+        // There is a bug in the server's implementation of the copy
+        // protocol. It returns command complete immediately upon
+        // receiving the EOF marker in the binary protocol,
+        // potentially before we've issued CopyDone. When we are not
+        // blocking, we don't think we are done, so we hold off on
+        // processing command complete and any subsequent messages
+        // until we actually are done with the copy.
+        //
+        if (!block) {
+          int c = pgStream.peekChar();
+          if (c == 'C') {
+            // CommandComplete
+            LOGGER.log(Level.FINEST, " <=BE CommandStatus, Ignored until CopyDone");
+            break;
+          }
         }
-      }
 
-      int c = pgStream.receiveChar();
-      switch (c) {
+        int c = pgStream.receiveChar();
+        switch (c) {
 
-        case 'A': // Asynchronous Notify
+          case 'A': // Asynchronous Notify
 
-          LOGGER.log(Level.FINEST, " <=BE Asynchronous Notification while copying");
+            LOGGER.log(Level.FINEST, " <=BE Asynchronous Notification while copying");
 
-          receiveAsyncNotify();
-          break;
+            receiveAsyncNotify();
+            break;
 
-        case 'N': // Notice Response
+          case 'N': // Notice Response
 
-          LOGGER.log(Level.FINEST, " <=BE Notification while copying");
+            LOGGER.log(Level.FINEST, " <=BE Notification while copying");
 
-          addWarning(receiveNoticeResponse());
-          break;
+            addWarning(receiveNoticeResponse());
+            break;
 
-        case 'C': // Command Complete
+          case 'C': // Command Complete
 
-          String status = receiveCommandStatus();
+            String status = receiveCommandStatus();
 
-          try {
-            if (op == null) {
-              throw new PSQLException(GT
+            try {
+              if (op == null) {
+                throw new PSQLException(GT
                   .tr("Received CommandComplete ''{0}'' without an active copy operation", status),
                   PSQLState.OBJECT_NOT_IN_STATE);
+              }
+              op.handleCommandStatus(status);
+            } catch (SQLException se) {
+              error = se;
             }
-            op.handleCommandStatus(status);
-          } catch (SQLException se) {
-            error = se;
-          }
 
-          block = true;
-          break;
+            block = true;
+            break;
 
-        case 'E': // ErrorMessage (expected response to CopyFail)
+          case 'E': // ErrorMessage (expected response to CopyFail)
 
-          error = receiveErrorResponse();
-          // We've received the error and we now expect to receive
-          // Ready for query, but we must block because it might still be
-          // on the wire and not here yet.
-          block = true;
-          break;
+            error = receiveErrorResponse();
+            // We've received the error and we now expect to receive
+            // Ready for query, but we must block because it might still be
+            // on the wire and not here yet.
+            block = true;
+            break;
 
-        case 'G': // CopyInResponse
+          case 'G': // CopyInResponse
 
-          LOGGER.log(Level.FINEST, " <=BE CopyInResponse");
+            LOGGER.log(Level.FINEST, " <=BE CopyInResponse");
 
-          if (op != null) {
-            error = new PSQLException(GT.tr("Got CopyInResponse from server during an active {0}",
+            if (op != null) {
+              error = new PSQLException(GT.tr("Got CopyInResponse from server during an active {0}",
                 op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
-          }
+            }
 
-          op = new CopyInImpl();
-          initCopy(op);
-          endReceiving = true;
-          break;
+            op = new CopyInImpl();
+            initCopy(op);
+            endReceiving = true;
+            break;
 
-        case 'H': // CopyOutResponse
+          case 'H': // CopyOutResponse
 
-          LOGGER.log(Level.FINEST, " <=BE CopyOutResponse");
+            LOGGER.log(Level.FINEST, " <=BE CopyOutResponse");
 
-          if (op != null) {
-            error = new PSQLException(GT.tr("Got CopyOutResponse from server during an active {0}",
-                op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
-          }
+            if (op != null) {
+              error =
+                new PSQLException(GT.tr("Got CopyOutResponse from server during an active {0}",
+                  op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
+            }
 
-          op = new CopyOutImpl();
-          initCopy(op);
-          endReceiving = true;
-          break;
+            op = new CopyOutImpl();
+            initCopy(op);
+            endReceiving = true;
+            break;
 
-        case 'W': // CopyBothResponse
+          case 'W': // CopyBothResponse
 
-          LOGGER.log(Level.FINEST, " <=BE CopyBothResponse");
+            LOGGER.log(Level.FINEST, " <=BE CopyBothResponse");
 
-          if (op != null) {
-            error = new PSQLException(GT.tr("Got CopyBothResponse from server during an active {0}",
-                    op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
-          }
+            if (op != null) {
+              error =
+                new PSQLException(GT.tr("Got CopyBothResponse from server during an active {0}",
+                  op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
+            }
 
-          op = new CopyDualImpl();
-          initCopy(op);
-          endReceiving = true;
-          break;
+            op = new CopyDualImpl();
+            initCopy(op);
+            endReceiving = true;
+            break;
 
-        case 'd': // CopyData
+          case 'd': // CopyData
 
-          LOGGER.log(Level.FINEST, " <=BE CopyData");
+            LOGGER.log(Level.FINEST, " <=BE CopyData");
 
-          len = pgStream.receiveInteger4() - 4;
-          byte[] buf = pgStream.receive(len);
-          if (op == null) {
-            error = new PSQLException(GT.tr("Got CopyData without an active copy operation"),
+            len = pgStream.receiveInteger4() - 4;
+
+            assert len > 0 : "Copy Data length must be greater than 4";
+
+            byte[] buf = pgStream.receive(len);
+            if (op == null) {
+              error = new PSQLException(GT.tr("Got CopyData without an active copy operation"),
                 PSQLState.OBJECT_NOT_IN_STATE);
-          } else if (!(op instanceof CopyOut)) {
-            error = new PSQLException(
+            } else if (!(op instanceof CopyOut)) {
+              error = new PSQLException(
                 GT.tr("Unexpected copydata from server for {0}", op.getClass().getName()),
                 PSQLState.COMMUNICATION_ERROR);
-          } else {
-            op.handleCopydata(buf);
-          }
-          endReceiving = true;
-          break;
+            } else {
+              op.handleCopydata(buf);
+            }
+            endReceiving = true;
+            break;
 
-        case 'c': // CopyDone (expected after all copydata received)
+          case 'c': // CopyDone (expected after all copydata received)
 
-          LOGGER.log(Level.FINEST, " <=BE CopyDone");
+            LOGGER.log(Level.FINEST, " <=BE CopyDone");
 
-          len = pgStream.receiveInteger4() - 4;
-          if (len > 0) {
-            pgStream.receive(len); // not in specification; should never appear
-          }
+            len = pgStream.receiveInteger4() - 4;
+            if (len > 0) {
+              pgStream.receive(len); // not in specification; should never appear
+            }
 
-          if (!(op instanceof CopyOut)) {
-            error = new PSQLException("Got CopyDone while not copying from server",
+            if (!(op instanceof CopyOut)) {
+              error = new PSQLException("Got CopyDone while not copying from server",
                 PSQLState.OBJECT_NOT_IN_STATE);
-          }
+            }
 
-          // keep receiving since we expect a CommandComplete
-          block = true;
-          break;
-        case 'S': // Parameter Status
-          try {
-            receiveParameterStatus();
-          } catch (SQLException e) {
-            error = e;
-            endReceiving = true;
-          }
-          break;
+            // keep receiving since we expect a CommandComplete
+            block = true;
+            break;
+          case 'S': // Parameter Status
+            try {
+              receiveParameterStatus();
+            } catch (SQLException e) {
+              error = e;
+              endReceiving = true;
+            }
+            break;
 
-        case 'Z': // ReadyForQuery: After FE:CopyDone => BE:CommandComplete
+          case 'Z': // ReadyForQuery: After FE:CopyDone => BE:CommandComplete
 
-          receiveRFQ();
-          if (hasLock(op)) {
-            unlock(op);
-          }
-          op = null;
-          endReceiving = true;
-          break;
+            receiveRFQ();
+            if (hasLock(op)) {
+              unlock(op);
+            }
+            op = null;
+            endReceiving = true;
+            break;
 
-        // If the user sends a non-copy query, we've got to handle some additional things.
-        //
-        case 'T': // Row Description (response to Describe)
-          LOGGER.log(Level.FINEST, " <=BE RowDescription (during copy ignored)");
+          // If the user sends a non-copy query, we've got to handle some additional things.
+          //
+          case 'T': // Row Description (response to Describe)
+            LOGGER.log(Level.FINEST, " <=BE RowDescription (during copy ignored)");
 
-          skipMessage();
-          break;
+            skipMessage();
+            break;
 
-        case 'D': // DataRow
-          LOGGER.log(Level.FINEST, " <=BE DataRow (during copy ignored)");
+          case 'D': // DataRow
+            LOGGER.log(Level.FINEST, " <=BE DataRow (during copy ignored)");
 
-          skipMessage();
-          break;
+            skipMessage();
+            break;
 
-        default:
-          throw new IOException(
+          default:
+            throw new IOException(
               GT.tr("Unexpected packet type during copy: {0}", Integer.toString(c)));
-      }
+        }
 
-      // Collect errors into a neat chain for completeness
-      if (error != null) {
-        if (errors != null) {
-          error.setNextException(errors);
+        // Collect errors into a neat chain for completeness
+        if (error != null) {
+          if (errors != null) {
+            error.setNextException(errors);
+          }
+          errors = error;
+          error = null;
         }
-        errors = error;
-        error = null;
       }
-    }
 
-    if (errors != null) {
-      throw errors;
-    }
+      if (errors != null) {
+        throw errors;
+      }
+      return op;
 
-    return op;
+    } finally {
+      /*
+      reset here in the finally block to make sure it really is cleared
+       */
+      processingCopyResults.set(false);
+    }
   }
 
   /*
@@ -2370,6 +2392,9 @@ public class QueryExecutorImpl extends QueryExecutorBase {
    */
   private void skipMessage() throws IOException {
     int len = pgStream.receiveInteger4();
+
+    assert len >= 4 : "Length from skip message must be at least 4 ";
+
     // skip len-4 (length includes the 4 bytes for message length itself
     pgStream.skip(len - 4);
   }
@@ -2440,7 +2465,9 @@ public class QueryExecutorImpl extends QueryExecutorBase {
   }
 
   private void receiveAsyncNotify() throws IOException {
-    pgStream.receiveInteger4(); // MESSAGE SIZE
+    int len = pgStream.receiveInteger4(); // MESSAGE SIZE
+    assert len > 4 : "Length for AsyncNotify must be at least 4";
+
     int pid = pgStream.receiveInteger4();
     String msg = pgStream.receiveString();
     String param = pgStream.receiveString();
@@ -2458,6 +2485,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
     // check at the bottom to see if we need to throw an exception
 
     int elen = pgStream.receiveInteger4();
+    assert elen > 4 : "Error response length must be greater than 4";
+
     EncodingPredictor.DecodeResult totalMessage = pgStream.receiveErrorString(elen - 4);
     ServerErrorMessage errorMsg = new ServerErrorMessage(totalMessage);
 
@@ -2476,6 +2505,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
 
   private SQLWarning receiveNoticeResponse() throws IOException {
     int nlen = pgStream.receiveInteger4();
+    assert nlen > 4 : "Notice Response length must be greater than 4";
+
     ServerErrorMessage warnMsg = new ServerErrorMessage(pgStream.receiveString(nlen - 4));
 
     if (LOGGER.isLoggable(Level.FINEST)) {
@@ -2619,6 +2650,11 @@ public class QueryExecutorImpl extends QueryExecutorBase {
       LOGGER.log(Level.FINEST, " <=BE ParameterStatus({0} = {1})", new Object[]{name, value});
     }
 
+    /* Update client-visible parameter status map for getParameterStatuses() */
+    if (name != null && !name.equals("")) {
+      onParameterStatus(name, value);
+    }
+
     if (name.equals("client_encoding")) {
       if (allowEncodingChanges) {
         if (!value.equalsIgnoreCase("UTF8") && !value.equalsIgnoreCase("UTF-8")) {
diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/replication/V3PGReplicationStream.java b/pgjdbc/src/main/java/org/postgresql/core/v3/replication/V3PGReplicationStream.java
index 11b4defb..66fd2f5e 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/v3/replication/V3PGReplicationStream.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/v3/replication/V3PGReplicationStream.java
@@ -25,6 +25,8 @@ public class V3PGReplicationStream implements PGReplicationStream {
 
   private static final Logger LOGGER = Logger.getLogger(V3PGReplicationStream.class.getName());
   public static final long POSTGRES_EPOCH_2000_01_01 = 946684800000L;
+  private static final long NANOS_PER_MILLISECOND = 1000000L;
+
   private final CopyDual copyDual;
   private final long updateInterval;
   private final ReplicationType replicationType;
@@ -55,8 +57,8 @@ public class V3PGReplicationStream implements PGReplicationStream {
       ReplicationType replicationType
   ) {
     this.copyDual = copyDual;
-    this.updateInterval = updateIntervalMs;
-    this.lastStatusUpdate = System.currentTimeMillis() - updateIntervalMs;
+    this.updateInterval = updateIntervalMs * NANOS_PER_MILLISECOND;
+    this.lastStatusUpdate = System.nanoTime() - (updateIntervalMs * NANOS_PER_MILLISECOND);
     this.lastReceiveLSN = startLSN;
     this.replicationType = replicationType;
   }
@@ -117,12 +119,13 @@ public class V3PGReplicationStream implements PGReplicationStream {
   private ByteBuffer readInternal(boolean block) throws SQLException {
     boolean updateStatusRequired = false;
     while (copyDual.isActive()) {
+
+      ByteBuffer buffer = receiveNextData(block);
+
       if (updateStatusRequired || isTimeUpdate()) {
         timeUpdateStatus();
       }
 
-      ByteBuffer buffer = receiveNextData(block);
-
       if (buffer == null) {
         return null;
       }
@@ -173,7 +176,7 @@ public class V3PGReplicationStream implements PGReplicationStream {
     if ( updateInterval == 0 ) {
       return false;
     }
-    long diff = System.currentTimeMillis() - lastStatusUpdate;
+    long diff = System.nanoTime() - lastStatusUpdate;
     return diff >= updateInterval;
   }
 
@@ -189,14 +192,14 @@ public class V3PGReplicationStream implements PGReplicationStream {
     copyDual.writeToCopy(reply, 0, reply.length);
     copyDual.flushCopy();
 
-    lastStatusUpdate = System.currentTimeMillis();
+    lastStatusUpdate = System.nanoTime();
   }
 
   private byte[] prepareUpdateStatus(LogSequenceNumber received, LogSequenceNumber flushed,
       LogSequenceNumber applied, boolean replyRequired) {
     ByteBuffer byteBuffer = ByteBuffer.allocate(1 + 8 + 8 + 8 + 8 + 1);
 
-    long now = System.currentTimeMillis();
+    long now = System.nanoTime() / NANOS_PER_MILLISECOND;
     long systemClock = TimeUnit.MICROSECONDS.convert((now - POSTGRES_EPOCH_2000_01_01),
         TimeUnit.MICROSECONDS);
 
diff --git a/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java b/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java
index ab64f022..64e9f04b 100644
--- a/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java
+++ b/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java
@@ -23,6 +23,7 @@ import java.io.PrintWriter;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.util.Arrays;
 import java.util.Properties;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -39,16 +40,16 @@ import javax.sql.CommonDataSource;
  *
  * @author Aaron Mulder (ammulder@chariotsolutions.com)
  */
-public abstract class BaseDataSource implements CommonDataSource, Referenceable {
 
+public abstract class BaseDataSource implements CommonDataSource, Referenceable {
   private static final Logger LOGGER = Logger.getLogger(BaseDataSource.class.getName());
 
   // Standard properties, defined in the JDBC 2.0 Optional Package spec
-  private String serverName = "localhost";
+  private String[] serverNames = new String[] {"localhost"};
   private String databaseName = "";
   private String user;
   private String password;
-  private int portNumber = 0;
+  private int[] portNumbers = new int[] {0};
 
   // Map for all other properties
   private Properties properties = new Properties();
@@ -129,9 +130,20 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
    * Gets the name of the host the PostgreSQL database is running on.
    *
    * @return name of the host the PostgreSQL database is running on
+   * @deprecated use {@link #getServerNames()}
    */
+  @Deprecated
   public String getServerName() {
-    return serverName;
+    return serverNames[0];
+  }
+
+  /**
+   * Gets the name of the host(s) the PostgreSQL database is running on.
+   *
+   * @return name of the host(s) the PostgreSQL database is running on
+   */
+  public String[] getServerNames() {
+    return serverNames;
   }
 
   /**
@@ -139,12 +151,30 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
    * only affect future calls to getConnection. The default value is <tt>localhost</tt>.
    *
    * @param serverName name of the host the PostgreSQL database is running on
+   * @deprecated use {@link #setServerNames(String[])}
    */
+  @Deprecated
   public void setServerName(String serverName) {
-    if (serverName == null || serverName.equals("")) {
-      this.serverName = "localhost";
+    this.setServerNames(new String[] { serverName });
+  }
+
+  /**
+   * Sets the name of the host(s) the PostgreSQL database is running on. If this is changed, it will
+   * only affect future calls to getConnection. The default value is <tt>localhost</tt>.
+   *
+   * @param serverNames name of the host(s) the PostgreSQL database is running on
+   */
+  public void setServerNames(String[] serverNames) {
+    if (serverNames == null || serverNames.length == 0) {
+      this.serverNames = new String[] {"localhost"};
     } else {
-      this.serverName = serverName;
+      serverNames = Arrays.copyOf(serverNames, serverNames.length);
+      for (int i = 0; i < serverNames.length; i++) {
+        if (serverNames[i] == null || serverNames[i].equals("")) {
+          serverNames[i] = "localhost";
+        }
+      }
+      this.serverNames = serverNames;
     }
   }
 
@@ -221,20 +251,50 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
    * Gets the port which the PostgreSQL server is listening on for TCP/IP connections.
    *
    * @return The port, or 0 if the default port will be used.
+   * @deprecated use {@link #getPortNumbers()}
    */
+  @Deprecated
   public int getPortNumber() {
-    return portNumber;
+    if (portNumbers == null || portNumbers.length == 0) {
+      return 0;
+    }
+    return portNumbers[0];
+  }
+
+  /**
+   * Gets the port(s) which the PostgreSQL server is listening on for TCP/IP connections.
+   *
+   * @return The port(s), or 0 if the default port will be used.
+   */
+  public int[] getPortNumbers() {
+    return portNumbers;
   }
 
   /**
-   * Gets the port which the PostgreSQL server is listening on for TCP/IP connections. Be sure the
+   * Sets the port which the PostgreSQL server is listening on for TCP/IP connections. Be sure the
    * -i flag is passed to postmaster when PostgreSQL is started. If this is not set, or set to 0,
    * the default port will be used.
    *
    * @param portNumber port which the PostgreSQL server is listening on for TCP/IP
+   * @deprecated use {@link #setPortNumbers(int[])}
    */
+  @Deprecated
   public void setPortNumber(int portNumber) {
-    this.portNumber = portNumber;
+    setPortNumbers(new int[] { portNumber });
+  }
+
+  /**
+   * Sets the port(s) which the PostgreSQL server is listening on for TCP/IP connections. Be sure the
+   * -i flag is passed to postmaster when PostgreSQL is started. If this is not set, or set to 0,
+   * the default port will be used.
+   *
+   * @param portNumbers port(s) which the PostgreSQL server is listening on for TCP/IP
+   */
+  public void setPortNumbers(int[] portNumbers) {
+    if (portNumbers == null || portNumbers.length == 0) {
+      portNumbers = new int[] { 0 };
+    }
+    this.portNumbers = Arrays.copyOf(portNumbers, portNumbers.length);
   }
 
   /**
@@ -1085,9 +1145,14 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
   public String getUrl() {
     StringBuilder url = new StringBuilder(100);
     url.append("jdbc:postgresql://");
-    url.append(serverName);
-    if (portNumber != 0) {
-      url.append(":").append(portNumber);
+    for (int i = 0; i < serverNames.length; i++) {
+      if (i > 0) {
+        url.append(",");
+      }
+      url.append(serverNames[i]);
+      if (portNumbers != null && portNumbers.length >= i && portNumbers[i] != 0) {
+        url.append(":").append(portNumbers[i]);
+      }
     }
     url.append("/").append(URLCoder.encode(databaseName));
 
@@ -1179,23 +1244,28 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
     }
     switch (property) {
       case PG_HOST:
-        serverName = value;
+        setServerNames(value.split(","));
         break;
       case PG_PORT:
-        try {
-          portNumber = Integer.parseInt(value);
-        } catch (NumberFormatException e) {
-          portNumber = 0;
+        String[] ps = value.split(",");
+        int[] ports = new int[ps.length];
+        for (int i = 0 ; i < ps.length; i++) {
+          try {
+            ports[i] = Integer.parseInt(ps[i]);
+          } catch (NumberFormatException e) {
+            ports[i] = 0;
+          }
         }
+        setPortNumbers(ports);
         break;
       case PG_DBNAME:
-        databaseName = value;
+        setDatabaseName(value);
         break;
       case USER:
-        user = value;
+        setUser(value);
         break;
       case PASSWORD:
-        password = value;
+        setPassword(value);
         break;
       default:
         properties.setProperty(property.getName(), value);
@@ -1213,10 +1283,25 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
 
   public Reference getReference() throws NamingException {
     Reference ref = createReference();
-    ref.add(new StringRefAddr("serverName", serverName));
-    if (portNumber != 0) {
-      ref.add(new StringRefAddr("portNumber", Integer.toString(portNumber)));
+    StringBuilder serverString = new StringBuilder();
+    for (int i = 0; i < serverNames.length; i++) {
+      if (i > 0) {
+        serverString.append(",");
+      }
+      String serverName = serverNames[i];
+      serverString.append(serverName);
+    }
+    ref.add(new StringRefAddr("serverName", serverString.toString()));
+
+    StringBuilder portString = new StringBuilder();
+    for (int i = 0; i < portNumbers.length; i++) {
+      if (i > 0) {
+        portString.append(",");
+      }
+      int p = portNumbers[i];
+      portString.append(Integer.toString(p));
     }
+    ref.add(new StringRefAddr("portNumber", portString.toString()));
     ref.add(new StringRefAddr("databaseName", databaseName));
     if (user != null) {
       ref.add(new StringRefAddr("user", user));
@@ -1236,11 +1321,22 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
 
   public void setFromReference(Reference ref) {
     databaseName = getReferenceProperty(ref, "databaseName");
-    String port = getReferenceProperty(ref, "portNumber");
-    if (port != null) {
-      portNumber = Integer.parseInt(port);
+    String portNumberString = getReferenceProperty(ref, "portNumber");
+    if (portNumberString != null) {
+      String[] ps = portNumberString.split(",");
+      int[] ports = new int[ps.length];
+      for (int i = 0; i < ps.length; i++) {
+        try {
+          ports[i] = Integer.parseInt(ps[i]);
+        } catch (NumberFormatException e) {
+          ports[i] = 0;
+        }
+      }
+      setPortNumbers(ports);
+    } else {
+      setPortNumbers(null);
     }
-    serverName = getReferenceProperty(ref, "serverName");
+    setServerNames(getReferenceProperty(ref, "serverName").split(","));
 
     for (PGProperty property : PGProperty.values()) {
       setProperty(property, getReferenceProperty(ref, property.getName()));
@@ -1256,21 +1352,21 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
   }
 
   protected void writeBaseObject(ObjectOutputStream out) throws IOException {
-    out.writeObject(serverName);
+    out.writeObject(serverNames);
     out.writeObject(databaseName);
     out.writeObject(user);
     out.writeObject(password);
-    out.writeInt(portNumber);
+    out.writeObject(portNumbers);
 
     out.writeObject(properties);
   }
 
   protected void readBaseObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
-    serverName = (String) in.readObject();
+    serverNames = (String[]) in.readObject();
     databaseName = (String) in.readObject();
     user = (String) in.readObject();
     password = (String) in.readObject();
-    portNumber = in.readInt();
+    portNumbers = (int[]) in.readObject();
 
     properties = (Properties) in.readObject();
   }
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
index d1271743..d9f4debc 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
@@ -795,6 +795,9 @@ public class PgConnection implements BaseConnection {
 
     if (queryExecutor.getTransactionState() != TransactionState.IDLE) {
       executeTransactionCommand(rollbackQuery);
+    } else {
+      // just log for debugging
+      LOGGER.log(Level.FINE, "Rollback requested but no transaction in progress");
     }
   }
 
@@ -1365,18 +1368,24 @@ public class PgConnection implements BaseConnection {
       return false;
     }
     try {
-      if (replicationConnection) {
-        Statement statement = createStatement();
-        statement.execute("IDENTIFY_SYSTEM");
-        statement.close();
-      } else {
-        if (checkConnectionQuery == null) {
-          checkConnectionQuery = prepareStatement("");
+      int savedNetworkTimeOut = getNetworkTimeout();
+      try {
+        setNetworkTimeout(null, timeout * 1000);
+        if (replicationConnection) {
+          Statement statement = createStatement();
+          statement.execute("IDENTIFY_SYSTEM");
+          statement.close();
+        } else {
+          if (checkConnectionQuery == null) {
+            checkConnectionQuery = prepareStatement("");
+          }
+          checkConnectionQuery.setQueryTimeout(timeout);
+          checkConnectionQuery.executeUpdate();
         }
-        checkConnectionQuery.setQueryTimeout(timeout);
-        checkConnectionQuery.executeUpdate();
+        return true;
+      } finally {
+        setNetworkTimeout(null, savedNetworkTimeOut);
       }
-      return true;
     } catch (SQLException e) {
       if (PSQLState.IN_FAILED_SQL_TRANSACTION.getState().equals(e.getSQLState())) {
         // "current transaction aborted", assume the connection is up and running
@@ -1724,4 +1733,15 @@ public class PgConnection implements BaseConnection {
     }
     return ps;
   }
+
+  @Override
+  public final Map<String,String> getParameterStatuses() {
+    return queryExecutor.getParameterStatuses();
+  }
+
+  @Override
+  public final String getParameterStatus(String parameterName) {
+    return queryExecutor.getParameterStatus(parameterName);
+  }
+
 }
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
index 403acc97..107e9e64 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
@@ -59,7 +59,6 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
 //#endif
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -601,6 +600,44 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
   }
 
   //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
+  private OffsetDateTime getOffsetDateTime(int i) throws SQLException {
+    checkResultSet(i);
+    if (wasNullFlag) {
+      return null;
+    }
+
+    int col = i - 1;
+    int oid = fields[col].getOID();
+
+    if (isBinary(i)) {
+      if (oid == Oid.TIMESTAMPTZ || oid == Oid.TIMESTAMP) {
+        return connection.getTimestampUtils().toOffsetDateTimeBin(thisRow[col]);
+      } else if (oid == Oid.TIMETZ) {
+        // JDBC spec says timetz must be supported
+        Time time = getTime(i);
+        return connection.getTimestampUtils().toOffsetDateTime(time);
+      } else {
+        throw new PSQLException(
+            GT.tr("Cannot convert the column of type {0} to requested type {1}.",
+                Oid.toString(oid), "timestamptz"),
+            PSQLState.DATA_TYPE_MISMATCH);
+      }
+    }
+
+    // If this is actually a timestamptz, the server-provided timezone will override
+    // the one we pass in, which is the desired behaviour. Otherwise, we'll
+    // interpret the timezone-less value in the provided timezone.
+    String string = getString(i);
+    if (oid == Oid.TIMETZ) {
+      // JDBC spec says timetz must be supported
+      // If server sends us a TIMETZ, we ensure java counterpart has date of 1970-01-01
+      Calendar cal = getDefaultCalendar();
+      Time time = connection.getTimestampUtils().toTime(cal, string);
+      return connection.getTimestampUtils().toOffsetDateTime(time);
+    }
+    return connection.getTimestampUtils().toOffsetDateTime(string);
+  }
+
   private LocalDateTime getLocalDateTime(int i) throws SQLException {
     checkResultSet(i);
     if (wasNullFlag) {
@@ -616,8 +653,7 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
               PSQLState.DATA_TYPE_MISMATCH);
     }
     if (isBinary(i)) {
-      TimeZone timeZone = getDefaultCalendar().getTimeZone();
-      return connection.getTimestampUtils().toLocalDateTimeBin(timeZone, thisRow[col]);
+      return connection.getTimestampUtils().toLocalDateTimeBin(thisRow[col]);
     }
 
     String string = getString(i);
@@ -3306,14 +3342,15 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
     } else if (type == UUID.class) {
       return type.cast(getObject(columnIndex));
     } else if (type == InetAddress.class) {
-      Object addressString = getObject(columnIndex);
-      if (addressString == null) {
+      String inetText = getString(columnIndex);
+      if (inetText == null) {
         return null;
       }
+      int slash = inetText.indexOf("/");
       try {
-        return type.cast(InetAddress.getByName(((PGobject) addressString).getValue()));
-      } catch (UnknownHostException e) {
-        throw new SQLException("could not create inet address from string '" + addressString + "'");
+        return type.cast(InetAddress.getByName(slash < 0 ? inetText : inetText.substring(0, slash)));
+      } catch (UnknownHostException ex) {
+        throw new PSQLException(GT.tr("Invalid Inet data."), PSQLState.INVALID_PARAMETER_VALUE, ex);
       }
       // JSR-310 support
       //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
@@ -3357,19 +3394,7 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
       }
     } else if (type == OffsetDateTime.class) {
       if (sqlType == Types.TIMESTAMP_WITH_TIMEZONE || sqlType == Types.TIMESTAMP) {
-        Timestamp timestampValue = getTimestamp(columnIndex);
-        if (wasNull()) {
-          return null;
-        }
-        long time = timestampValue.getTime();
-        if (time == PGStatement.DATE_POSITIVE_INFINITY) {
-          return type.cast(OffsetDateTime.MAX);
-        }
-        if (time == PGStatement.DATE_NEGATIVE_INFINITY) {
-          return type.cast(OffsetDateTime.MIN);
-        }
-        // Postgres stores everything in UTC and does not keep original time zone
-        OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(timestampValue.toInstant(), ZoneOffset.UTC);
+        OffsetDateTime offsetDateTime = getOffsetDateTime(columnIndex);
         return type.cast(offsetDateTime);
       } else {
         throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/TimestampUtils.java b/pgjdbc/src/main/java/org/postgresql/jdbc/TimestampUtils.java
index 4dd76e00..59341329 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/TimestampUtils.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/TimestampUtils.java
@@ -21,6 +21,7 @@ import java.sql.Time;
 import java.sql.Timestamp;
 //#if mvn.project.property.postgresql.jdbc.spec >= "JDBC4.2"
 import java.time.Duration;
+import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -56,6 +57,10 @@ public class TimestampUtils {
   private static final LocalTime MAX_TIME = LocalTime.MAX.minus(Duration.ofMillis(500));
   private static final OffsetDateTime MAX_OFFSET_DATETIME = OffsetDateTime.MAX.minus(Duration.ofMillis(500));
   private static final LocalDateTime MAX_LOCAL_DATETIME = LocalDateTime.MAX.minus(Duration.ofMillis(500));
+  // low value for dates is   4713 BC
+  private static final LocalDate MIN_LOCAL_DATE = LocalDate.of(4713, 1, 1).with(ChronoField.ERA, IsoEra.BCE.getValue());
+  private static final LocalDateTime MIN_LOCAL_DATETIME = MIN_LOCAL_DATE.atStartOfDay();
+  private static final OffsetDateTime MIN_OFFSET_DATETIME = MIN_LOCAL_DATETIME.atOffset(ZoneOffset.UTC);
   //#endif
 
   private static final Field DEFAULT_TIME_ZONE_FIELD;
@@ -469,6 +474,83 @@ public class TimestampUtils {
       return result;
     }
   }
+
+  /**
+   * Parse a string and return a LocalDateTime representing its value.
+   *
+   * @param s The ISO formated date string to parse.
+   * @return null if s is null or a LocalDateTime of the parsed string s.
+   * @throws SQLException if there is a problem parsing s.
+   */
+  public OffsetDateTime toOffsetDateTime(String s) throws SQLException {
+    if (s == null) {
+      return null;
+    }
+
+    int slen = s.length();
+
+    // convert postgres's infinity values to internal infinity magic value
+    if (slen == 8 && s.equals("infinity")) {
+      return OffsetDateTime.MAX;
+    }
+
+    if (slen == 9 && s.equals("-infinity")) {
+      return OffsetDateTime.MIN;
+    }
+
+    ParsedTimestamp ts = parseBackendTimestamp(s);
+
+    Calendar tz = ts.tz;
+    int offsetSeconds;
+    if (tz == null) {
+      offsetSeconds = 0;
+    } else {
+      offsetSeconds = tz.get(Calendar.ZONE_OFFSET) / 1000;
+    }
+    ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(offsetSeconds);
+    // Postgres is always UTC
+    OffsetDateTime result = OffsetDateTime.of(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.nanos, zoneOffset)
+        .withOffsetSameInstant(ZoneOffset.UTC);
+    if (ts.era == GregorianCalendar.BC) {
+      return result.with(ChronoField.ERA, IsoEra.BCE.getValue());
+    } else {
+      return result;
+    }
+  }
+
+  /**
+   * Returns the offset date time object matching the given bytes with Oid#TIMETZ.
+   *
+   * @param t the time value
+   * @return the matching offset date time
+   */
+  public OffsetDateTime toOffsetDateTime(Time t) {
+    // hardcode utc because the backend does not provide us the timezone
+    // hardoce UNIX epoch, JDBC requires OffsetDateTime but doesn't describe what date should be used
+    return t.toLocalTime().atDate(LocalDate.of(1970, 1, 1)).atOffset(ZoneOffset.UTC);
+  }
+
+  /**
+   * Returns the offset date time object matching the given bytes with Oid#TIMESTAMPTZ.
+   *
+   * @param bytes The binary encoded local date time value.
+   * @return The parsed local date time object.
+   * @throws PSQLException If binary format could not be parsed.
+   */
+  public OffsetDateTime toOffsetDateTimeBin(byte[] bytes) throws PSQLException {
+    ParsedBinaryTimestamp parsedTimestamp = this.toProlepticParsedTimestampBin(bytes);
+    if (parsedTimestamp.infinity == Infinity.POSITIVE) {
+      return OffsetDateTime.MAX;
+    } else if (parsedTimestamp.infinity == Infinity.NEGATIVE) {
+      return OffsetDateTime.MIN;
+    }
+
+    // hardcode utc because the backend does not provide us the timezone
+    // Postgres is always UTC
+    Instant instant = Instant.ofEpochSecond(parsedTimestamp.millis / 1000L, parsedTimestamp.nanos);
+    return OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
+  }
+
   //#endif
 
   public synchronized Time toTime(Calendar cal, String s) throws SQLException {
@@ -758,7 +840,7 @@ public class TimestampUtils {
   public synchronized String toString(LocalDate localDate) {
     if (LocalDate.MAX.equals(localDate)) {
       return "infinity";
-    } else if (LocalDate.MIN.equals(localDate)) {
+    } else if (localDate.isBefore(MIN_LOCAL_DATE)) {
       return "-infinity";
     }
 
@@ -792,7 +874,7 @@ public class TimestampUtils {
   public synchronized String toString(OffsetDateTime offsetDateTime) {
     if (offsetDateTime.isAfter(MAX_OFFSET_DATETIME)) {
       return "infinity";
-    } else if (OffsetDateTime.MIN.equals(offsetDateTime)) {
+    } else if (offsetDateTime.isBefore(MIN_OFFSET_DATETIME)) {
       return "-infinity";
     }
 
@@ -824,7 +906,7 @@ public class TimestampUtils {
   public synchronized String toString(LocalDateTime localDateTime) {
     if (localDateTime.isAfter(MAX_LOCAL_DATETIME)) {
       return "infinity";
-    } else if (LocalDateTime.MIN.equals(localDateTime)) {
+    } else if (localDateTime.isBefore(MIN_LOCAL_DATETIME)) {
       return "-infinity";
     }
 
@@ -1056,8 +1138,8 @@ public class TimestampUtils {
     return ts;
   }
 
-  private ParsedBinaryTimestamp toParsedTimestampBin(TimeZone tz, byte[] bytes, boolean timestamptz)
-          throws PSQLException {
+  private ParsedBinaryTimestamp toParsedTimestampBinPlain(byte[] bytes)
+      throws PSQLException {
 
     if (bytes.length != 8) {
       throw new PSQLException(GT.tr("Unsupported binary encoding of {0}.", "timestamp"),
@@ -1106,6 +1188,24 @@ public class TimestampUtils {
     }
     nanos *= 1000;
 
+    long millis = secs * 1000L;
+
+    ParsedBinaryTimestamp ts = new ParsedBinaryTimestamp();
+    ts.millis = millis;
+    ts.nanos = nanos;
+    return ts;
+  }
+
+  private ParsedBinaryTimestamp toParsedTimestampBin(TimeZone tz, byte[] bytes, boolean timestamptz)
+      throws PSQLException {
+
+    ParsedBinaryTimestamp ts = toParsedTimestampBinPlain(bytes);
+    if (ts.infinity != null) {
+      return ts;
+    }
+
+    long secs = ts.millis / 1000L;
+
     secs = toJavaSecs(secs);
     long millis = secs * 1000L;
     if (!timestamptz) {
@@ -1114,9 +1214,25 @@ public class TimestampUtils {
       millis = guessTimestamp(millis, tz);
     }
 
-    ParsedBinaryTimestamp ts = new ParsedBinaryTimestamp();
     ts.millis = millis;
-    ts.nanos = nanos;
+    return ts;
+  }
+
+  private ParsedBinaryTimestamp toProlepticParsedTimestampBin(byte[] bytes)
+      throws PSQLException {
+
+    ParsedBinaryTimestamp ts = toParsedTimestampBinPlain(bytes);
+    if (ts.infinity != null) {
+      return ts;
+    }
+
+    long secs = ts.millis / 1000L;
+
+    // postgres epoc to java epoc
+    secs += 946684800L;
+    long millis = secs * 1000L;
+
+    ts.millis = millis;
     return ts;
   }
 
@@ -1124,21 +1240,22 @@ public class TimestampUtils {
   /**
    * Returns the local date time object matching the given bytes with {@link Oid#TIMESTAMP} or
    * {@link Oid#TIMESTAMPTZ}.
-   *
-   * @param tz time zone to use
    * @param bytes The binary encoded local date time value.
+   *
    * @return The parsed local date time object.
    * @throws PSQLException If binary format could not be parsed.
    */
-  public LocalDateTime toLocalDateTimeBin(TimeZone tz, byte[] bytes) throws PSQLException {
+  public LocalDateTime toLocalDateTimeBin(byte[] bytes) throws PSQLException {
 
-    ParsedBinaryTimestamp parsedTimestamp = this.toParsedTimestampBin(tz, bytes, true);
+    ParsedBinaryTimestamp parsedTimestamp = this.toProlepticParsedTimestampBin(bytes);
     if (parsedTimestamp.infinity == Infinity.POSITIVE) {
       return LocalDateTime.MAX;
     } else if (parsedTimestamp.infinity == Infinity.NEGATIVE) {
       return LocalDateTime.MIN;
     }
 
+    // hardcode utc because the backend does not provide us the timezone
+    // Postgres is always UTC
     return LocalDateTime.ofEpochSecond(parsedTimestamp.millis / 1000L, parsedTimestamp.nanos, ZoneOffset.UTC);
   }
   //#endif
@@ -1426,4 +1543,5 @@ public class TimestampUtils {
   private static long floorMod(long x, long y) {
     return x - floorDiv(x, y) * y;
   }
+
 }
diff --git a/pgjdbc/src/main/java/org/postgresql/jre8/sasl/ScramAuthenticator.java b/pgjdbc/src/main/java/org/postgresql/jre7/sasl/ScramAuthenticator.java
similarity index 85%
rename from pgjdbc/src/main/java/org/postgresql/jre8/sasl/ScramAuthenticator.java
rename to pgjdbc/src/main/java/org/postgresql/jre7/sasl/ScramAuthenticator.java
index 3abe193d..2d973872 100644
--- a/pgjdbc/src/main/java/org/postgresql/jre8/sasl/ScramAuthenticator.java
+++ b/pgjdbc/src/main/java/org/postgresql/jre7/sasl/ScramAuthenticator.java
@@ -3,7 +3,7 @@
  * See the LICENSE file in the project root for more information.
  */
 
-package org.postgresql.jre8.sasl;
+package org.postgresql.jre7.sasl;
 
 import org.postgresql.core.PGStream;
 import org.postgresql.util.GT;
@@ -36,7 +36,6 @@ public class ScramAuthenticator {
   private ScramSession.ServerFirstProcessor serverFirstProcessor;
   private ScramSession.ClientFinalProcessor clientFinalProcessor;
 
-  @FunctionalInterface
   private interface BodySender {
     void sendBody(PGStream pgStream) throws IOException;
   }
@@ -44,7 +43,7 @@ public class ScramAuthenticator {
   private void sendAuthenticationMessage(int bodyLength, BodySender bodySender)
       throws IOException {
     pgStream.sendChar('p');
-    pgStream.sendInteger4(Integer.BYTES + bodyLength);
+    pgStream.sendInteger4(Integer.SIZE / Byte.SIZE + bodyLength);
     bodySender.sendBody(pgStream);
     pgStream.flush();
   }
@@ -94,15 +93,18 @@ public class ScramAuthenticator {
     LOGGER.log(Level.FINEST, " FE=> SASLInitialResponse( {0} )", clientFirstMessage);
 
     String scramMechanismName = scramClient.getScramMechanism().getName();
-    byte[] scramMechanismNameBytes = scramMechanismName.getBytes(StandardCharsets.UTF_8);
-    byte[] clientFirstMessageBytes = clientFirstMessage.getBytes(StandardCharsets.UTF_8);
+    final byte[] scramMechanismNameBytes = scramMechanismName.getBytes(StandardCharsets.UTF_8);
+    final byte[] clientFirstMessageBytes = clientFirstMessage.getBytes(StandardCharsets.UTF_8);
     sendAuthenticationMessage(
         (scramMechanismNameBytes.length + 1) + 4 + clientFirstMessageBytes.length,
-        s -> {
-          s.send(scramMechanismNameBytes);
-          s.sendChar(0); // List terminated in '\0'
-          s.sendInteger4(clientFirstMessageBytes.length);
-          s.send(clientFirstMessageBytes);
+        new BodySender() {
+          @Override
+          public void sendBody(PGStream pgStream) throws IOException {
+            pgStream.send(scramMechanismNameBytes);
+            pgStream.sendChar(0); // List terminated in '\0'
+            pgStream.sendInteger4(clientFirstMessageBytes.length);
+            pgStream.send(clientFirstMessageBytes);
+          }
         }
     );
   }
@@ -132,10 +134,15 @@ public class ScramAuthenticator {
     String clientFinalMessage = clientFinalProcessor.clientFinalMessage();
     LOGGER.log(Level.FINEST, " FE=> SASLResponse( {0} )", clientFinalMessage);
 
-    byte[] clientFinalMessageBytes = clientFinalMessage.getBytes(StandardCharsets.UTF_8);
+    final byte[] clientFinalMessageBytes = clientFinalMessage.getBytes(StandardCharsets.UTF_8);
     sendAuthenticationMessage(
         clientFinalMessageBytes.length,
-        s -> s.send(clientFinalMessageBytes)
+        new BodySender() {
+          @Override
+          public void sendBody(PGStream pgStream) throws IOException {
+            pgStream.send(clientFinalMessageBytes);
+          }
+        }
     );
   }
 
diff --git a/pgjdbc/src/main/java/org/postgresql/util/PSQLState.java b/pgjdbc/src/main/java/org/postgresql/util/PSQLState.java
index 12892ad9..ca4de8ba 100644
--- a/pgjdbc/src/main/java/org/postgresql/util/PSQLState.java
+++ b/pgjdbc/src/main/java/org/postgresql/util/PSQLState.java
@@ -83,6 +83,7 @@ public enum PSQLState {
   INVALID_NAME("42602"),
   DATATYPE_MISMATCH("42804"),
   CANNOT_COERCE("42846"),
+  UNDEFINED_TABLE("42P01"),
 
   OUT_OF_MEMORY("53200"),
   OBJECT_NOT_IN_STATE("55000"),
diff --git a/pom.xml b/pom.xml
index dd9550f6..f50ae2c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
   <artifactId>pgjdbc-aggregate</artifactId>
   <packaging>pom</packaging>
   <name>PostgreSQL JDBC Driver aggregate</name>
-  <version>42.2.7-SNAPSHOT</version>
+  <version>42.2.9-SNAPSHOT</version>
   <description>PgJDBC aggregate project</description>
   <url>https://github.com/pgjdbc/pgjdbc</url>
 


Test patch:
diff --git a/pgjdbc/src/test/java/org/postgresql/replication/ReplicationTestSuite.java b/pgjdbc/src/test/java/org/postgresql/replication/ReplicationTestSuite.java
index 27bbb0a1..ab213ce2 100644
--- a/pgjdbc/src/test/java/org/postgresql/replication/ReplicationTestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/replication/ReplicationTestSuite.java
@@ -22,12 +22,13 @@ import java.sql.Statement;
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
     CopyBothResponseTest.class,
+    LogicalReplicationStatusTest.class,
     LogicalReplicationTest.class,
     LogSequenceNumberTest.class,
     PhysicalReplicationTest.class,
-    LogicalReplicationStatusTest.class,
     ReplicationConnectionTest.class,
-    ReplicationSlotTest.class})
+    ReplicationSlotTest.class,
+})
 public class ReplicationTestSuite {
 
   @BeforeClass
diff --git a/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java b/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java
index d396b314..211d01eb 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java
@@ -915,4 +915,16 @@ public class TestUtil {
       throw new TimeoutException("Wait stop replication slot " + timeInWait + " timeout occurs");
     }
   }
+
+  public static void execute(String sql, Connection connection) throws SQLException {
+    Statement stmt = connection.createStatement();
+    try {
+      stmt.execute(sql);
+    } finally {
+      try {
+        stmt.close();
+      } catch (SQLException e) {
+      }
+    }
+  }
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ConnectTimeoutTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ConnectTimeoutTest.java
index eafaf333..5b967391 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ConnectTimeoutTest.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ConnectTimeoutTest.java
@@ -10,9 +10,11 @@ import static org.junit.Assert.fail;
 
 import org.postgresql.test.TestUtil;
 
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.net.NoRouteToHostException;
 import java.net.SocketTimeoutException;
 import java.sql.DriverManager;
 import java.sql.SQLException;
@@ -41,11 +43,27 @@ public class ConnectTimeoutTest {
     try {
       DriverManager.getConnection(UNREACHABLE_URL, props);
     } catch (SQLException e) {
-      assertTrue("Unexpected " + e.toString(),
-          e.getCause() instanceof SocketTimeoutException);
       final long interval = System.currentTimeMillis() - startTime;
       final long connectTimeoutMillis = CONNECT_TIMEOUT * 1000;
       final long maxDeviation = connectTimeoutMillis / 10;
+
+      /*
+       * If the platform fast-fails the unroutable address connection then this
+       * test may not time out, instead throwing
+       * java.net.NoRouteToHostException. The test has failed in that the connection
+       * attempt did not time out.
+       *
+       * We treat this as a skipped test, as the test didn't really "succeed"
+       * in testing the original behaviour, but it didn't fail either.
+       */
+      Assume.assumeTrue("Host fast-failed connection to unreachable address "
+                        + UNREACHABLE_HOST + " after " + interval + " ms, "
+                        + " before timeout should have triggered.",
+                        e.getCause() instanceof NoRouteToHostException
+                        && interval < connectTimeoutMillis );
+
+      assertTrue("Unexpected " + e.toString() + " with cause " + e.getCause(),
+          e.getCause() instanceof SocketTimeoutException);
       // check that it was not a default system timeout, an approximate value is used
       assertTrue(Math.abs(interval - connectTimeoutMillis) < maxDeviation);
       return;
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java
index 3f372393..01d9fbf9 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java
@@ -32,97 +32,80 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-        ANTTest.class,
-        JavaVersionTest.class,
-
-        DriverTest.class,
-        ConnectionTest.class,
-        DateStyleTest.class,
-        DatabaseMetaDataTest.class,
-        DatabaseMetaDataPropertiesTest.class,
-        SearchPathLookupTest.class,
-        EncodingTest.class,
-        ExpressionPropertiesTest.class,
-        ColumnSanitiserDisabledTest.class,
-        ColumnSanitiserEnabledTest.class,
-        LruCacheTest.class,
-        HostSpecTest.class,
-        ReaderInputStreamTest.class,
-        ServerVersionParseTest.class,
-        ServerVersionTest.class,
-
-        OptionsPropertyTest.class,
-
-        TypeCacheDLLStressTest.class,
-
-        ResultSetTest.class,
-        ResultSetMetaDataTest.class,
-        StringTypeUnspecifiedArrayTest.class,
-        ArrayTest.class,
-        PrimitiveArraySupportTest.class,
-        RefCursorTest.class,
-
-        DateTest.class,
-        TimeTest.class,
-        TimestampTest.class,
-        TimezoneTest.class,
-        PGTimeTest.class,
-        PGTimestampTest.class,
-        TimezoneCachingTest.class,
-        ParserTest.class,
-        ReturningParserTest.class,
-        CommandCompleteParserTest.class,
-        CommandCompleteParserNegativeTest.class,
-        ReplaceProcessingTest.class,
-
-        OidToStringTest.class,
-        OidValueOfTest.class,
-
-        PreparedStatementTest.class,
-        StatementTest.class,
-        QuotationTest.class,
-
-        ServerPreparedStmtTest.class,
-
-        BatchExecuteTest.class,
-        BatchFailureTest.class,
-
-        BatchedInsertReWriteEnabledTest.class,
-        NativeQueryBindLengthTest.class,
-        DeepBatchedInsertStatementTest.class,
-        JBuilderTest.class,
-        MiscTest.class,
-        NotifyTest.class,
-        DatabaseEncodingTest.class,
-        ClientEncodingTest.class,
-
-        BlobTest.class,
-        BlobTransactionTest.class,
-
-        UpdateableResultTest.class,
-
-        CallableStmtTest.class,
-        CursorFetchTest.class,
-        ConcurrentStatementFetch.class,
-        ServerCursorTest.class,
-
-        IntervalTest.class,
-        GeometricTest.class,
-
-        LoginTimeoutTest.class,
-        TestACL.class,
-
-        ConnectTimeoutTest.class,
-
-        PGPropertyTest.class,
-
-        V3ParameterListTests.class,
-
-        CopyTest.class,
-        CopyLargeFileTest.class,
-        ServerErrorTest.class,
-        UpsertTest.class,
-        OuterJoinSyntaxTest.class
+    ANTTest.class,
+    ArrayTest.class,
+    BatchedInsertReWriteEnabledTest.class,
+    BatchExecuteTest.class,
+    BatchFailureTest.class,
+    BlobTest.class,
+    BlobTransactionTest.class,
+    CallableStmtTest.class,
+    ClientEncodingTest.class,
+    ColumnSanitiserDisabledTest.class,
+    ColumnSanitiserEnabledTest.class,
+    CommandCompleteParserNegativeTest.class,
+    CommandCompleteParserTest.class,
+    ConcurrentStatementFetch.class,
+    ConnectionTest.class,
+    ConnectTimeoutTest.class,
+    CopyLargeFileTest.class,
+    CopyTest.class,
+    CursorFetchTest.class,
+    DatabaseEncodingTest.class,
+    DatabaseMetaDataPropertiesTest.class,
+    DatabaseMetaDataTest.class,
+    DateStyleTest.class,
+    DateTest.class,
+    DeepBatchedInsertStatementTest.class,
+    DriverTest.class,
+    EncodingTest.class,
+    ExpressionPropertiesTest.class,
+    GeometricTest.class,
+    GetXXXTest.class,
+    HostSpecTest.class,
+    IntervalTest.class,
+    JavaVersionTest.class,
+    JBuilderTest.class,
+    LoginTimeoutTest.class,
+    LruCacheTest.class,
+    MiscTest.class,
+    NativeQueryBindLengthTest.class,
+    NotifyTest.class,
+    OidToStringTest.class,
+    OidValueOfTest.class,
+    OptionsPropertyTest.class,
+    OuterJoinSyntaxTest.class,
+    ParameterStatusTest.class,
+    ParserTest.class,
+    PGPropertyTest.class,
+    PGTimestampTest.class,
+    PGTimeTest.class,
+    PreparedStatementTest.class,
+    PrimitiveArraySupportTest.class,
+    QuotationTest.class,
+    ReaderInputStreamTest.class,
+    RefCursorTest.class,
+    ReplaceProcessingTest.class,
+    ResultSetMetaDataTest.class,
+    ResultSetTest.class,
+    ReturningParserTest.class,
+    SearchPathLookupTest.class,
+    ServerCursorTest.class,
+    ServerErrorTest.class,
+    ServerPreparedStmtTest.class,
+    ServerVersionParseTest.class,
+    ServerVersionTest.class,
+    StatementTest.class,
+    StringTypeUnspecifiedArrayTest.class,
+    TestACL.class,
+    TimestampTest.class,
+    TimeTest.class,
+    TimezoneCachingTest.class,
+    TimezoneTest.class,
+    TypeCacheDLLStressTest.class,
+    UpdateableResultTest.class,
+    UpsertTest.class,
+    V3ParameterListTests.class,
 })
 public class Jdbc2TestSuite {
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ParameterStatusTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ParameterStatusTest.java
new file mode 100644
index 00000000..9951a306
--- /dev/null
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ParameterStatusTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.jdbc2;
+
+import org.postgresql.PGConnection;
+import org.postgresql.core.ServerVersion;
+import org.postgresql.test.TestUtil;
+
+import org.hamcrest.core.StringStartsWith;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.sql.Statement;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.logging.Logger;
+
+/**
+ * Test JDBC extension API for server reported parameter status messages.
+ *
+ * <p>This test covers client interface for server ParameterStatus messages
+ * (GUC_REPORT) parameters via PGConnection.getParameterStatuses() and
+ * PGConnection.getParameterStatus().</p>
+ */
+public class ParameterStatusTest extends BaseTest4 {
+
+  private final TimeZone tzPlus0800 = TimeZone.getTimeZone("GMT+8:00");
+  private final Logger logger = Logger.getLogger(ParameterStatusTest.class.getName());
+
+  @Override
+  public void tearDown() {
+    TimeZone.setDefault(null);
+  }
+
+  @Test
+  public void expectedInitialParameters() throws Exception {
+    TimeZone.setDefault(tzPlus0800);
+    con = TestUtil.openDB();
+
+    Map<String,String> params = ((PGConnection)con).getParameterStatuses();
+
+    // PgJDBC forces the following parameters
+    Assert.assertEquals("UTF8", params.get("client_encoding"));
+    Assert.assertNotNull(params.get("DateStyle"));
+    Assert.assertThat(params.get("DateStyle"), StringStartsWith.startsWith("ISO"));
+
+    // PgJDBC sets TimeZone via Java's TimeZone.getDefault()
+    // Pg reports POSIX timezones which are negated, so:
+    Assert.assertEquals("GMT-08:00", params.get("TimeZone"));
+
+    // Must be reported. All these exist in 8.2 or above, and we don't bother
+    // with test coverage older than that.
+    Assert.assertNotNull(params.get("integer_datetimes"));
+    Assert.assertNotNull(params.get("is_superuser"));
+    Assert.assertNotNull(params.get("server_encoding"));
+    Assert.assertNotNull(params.get("server_version"));
+    Assert.assertNotNull(params.get("session_authorization"));
+    Assert.assertNotNull(params.get("standard_conforming_strings"));
+
+    if (TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_4)) {
+      Assert.assertNotNull(params.get("IntervalStyle"));
+    } else {
+      Assert.assertNull(params.get("IntervalStyle"));
+    }
+
+    // TestUtil forces "ApplicationName=Driver Tests"
+    // if application_name is supported (9.0 or newer)
+    if (TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0)) {
+      Assert.assertEquals("Driver Tests", params.get("application_name"));
+    } else {
+      Assert.assertNull(params.get("application_name"));
+    }
+
+    // Not reported
+    Assert.assertNull(params.get("nonexistent"));
+    Assert.assertNull(params.get("enable_hashjoin"));
+
+    TestUtil.closeDB(con);
+  }
+
+  @Test
+  public void reportUpdatedParameters() throws Exception {
+    con = TestUtil.openDB();
+
+    if (!TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0)) {
+      /* This test uses application_name which was added in 9.0 */
+      return;
+    }
+
+    con.setAutoCommit(false);
+    Statement stmt = con.createStatement();
+
+    stmt.executeUpdate("SET application_name = 'pgjdbc_ParameterStatusTest2';");
+    stmt.close();
+
+    // Parameter status should be reported before the ReadyForQuery so we will
+    // have already processed it
+    Assert.assertEquals("pgjdbc_ParameterStatusTest2", ((PGConnection)con).getParameterStatus("application_name"));
+
+    TestUtil.closeDB(con);
+  }
+
+  // Run a txn-level SET then a txn-level SET LOCAL so we can make sure we keep
+  // track of the right GUC value at each point.
+  private void transactionalParametersCommon() throws Exception {
+    Statement stmt = con.createStatement();
+
+    // Initial value assigned by TestUtil
+    Assert.assertEquals("Driver Tests", ((PGConnection)con).getParameterStatus("application_name"));
+
+    // PgJDBC begins an explicit txn here due to autocommit=off so the effect
+    // should be lost on rollback but retained on commit per the docs.
+    stmt.executeUpdate("SET application_name = 'pgjdbc_ParameterStatusTestTxn';");
+    Assert.assertEquals("pgjdbc_ParameterStatusTestTxn", ((PGConnection)con).getParameterStatus("application_name"));
+
+    // SET LOCAL is always txn scoped so the effect here will always be
+    // unwound on txn end.
+    stmt.executeUpdate("SET LOCAL application_name = 'pgjdbc_ParameterStatusTestLocal';");
+    Assert.assertEquals("pgjdbc_ParameterStatusTestLocal", ((PGConnection)con).getParameterStatus("application_name"));
+
+    stmt.close();
+  }
+
+  @Test
+  public void transactionalParametersRollback() throws Exception {
+    con = TestUtil.openDB();
+
+    if (!TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0)) {
+      /* This test uses application_name which was added in 9.0 */
+      return;
+    }
+
+    con.setAutoCommit(false);
+
+    transactionalParametersCommon();
+
+    // SET unwinds on ROLLBACK
+    con.rollback();
+
+    Assert.assertEquals("Driver Tests", ((PGConnection)con).getParameterStatus("application_name"));
+
+    TestUtil.closeDB(con);
+  }
+
+  @Test
+  public void transactionalParametersCommit() throws Exception {
+    con = TestUtil.openDB();
+
+    if (!TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0)) {
+      /* This test uses application_name which was added in 9.0 */
+      return;
+    }
+
+    con.setAutoCommit(false);
+
+    transactionalParametersCommon();
+
+    // SET is retained on commit but SET LOCAL is unwound
+    con.commit();
+
+    Assert.assertEquals("pgjdbc_ParameterStatusTestTxn", ((PGConnection)con).getParameterStatus("application_name"));
+
+    TestUtil.closeDB(con);
+  }
+
+  @Test
+  public void transactionalParametersAutocommit() throws Exception {
+    con = TestUtil.openDB();
+
+    if (!TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0)) {
+      /* This test uses application_name which was added in 9.0 */
+      return;
+    }
+
+    con.setAutoCommit(true);
+    Statement stmt = con.createStatement();
+
+    // A SET LOCAL in autocommit should have no visible effect as we report the reset value too
+    Assert.assertEquals("Driver Tests", ((PGConnection)con).getParameterStatus("application_name"));
+    stmt.executeUpdate("SET LOCAL application_name = 'pgjdbc_ParameterStatusTestLocal';");
+    Assert.assertEquals("Driver Tests", ((PGConnection)con).getParameterStatus("application_name"));
+
+    stmt.close();
+    TestUtil.closeDB(con);
+  }
+
+  @Test(expected = UnsupportedOperationException.class)
+  public void parameterMapReadOnly() throws Exception {
+    try {
+      con = TestUtil.openDB();
+      Map params = ((PGConnection)con).getParameterStatuses();
+      params.put("DateStyle", "invalid");
+      Assert.fail("Attempt to write to exposed parameters map must throw");
+    } finally {
+      TestUtil.closeDB(con);
+    }
+  }
+
+  @Test
+  public void parameterMapIsView() throws Exception {
+    con = TestUtil.openDB();
+
+    if (!TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_0)) {
+      /* This test uses application_name which was added in 9.0 */
+      return;
+    }
+
+    Map params = ((PGConnection)con).getParameterStatuses();
+
+    Statement stmt = con.createStatement();
+
+    Assert.assertEquals("Driver Tests", params.get("application_name"));
+    stmt.executeUpdate("SET application_name = 'pgjdbc_paramstatus_view';");
+    Assert.assertEquals("pgjdbc_paramstatus_view", params.get("application_name"));
+
+    stmt.close();
+    TestUtil.closeDB(con);
+  }
+
+}
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/StatementTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/StatementTest.java
index ef684402..7c3cf6e5 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/StatementTest.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/StatementTest.java
@@ -729,11 +729,21 @@ public class StatementTest {
     Statement stmt2 = con.createStatement();
     while (System.currentTimeMillis() < deadLine) {
       try {
-        stmt.execute("select 1");
+        // This usually won't time out but scheduler jitter, server load
+        // etc can cause a timeout.
+        stmt.executeQuery("select 1;");
       } catch (SQLException e) {
-        // ignore "statement cancelled"
+        // Expect "57014 query_canceled" (en-msg is "canceling statement due to statement timeout")
+        // but anything else is fatal. We can't differentiate other causes of statement cancel like
+        // "canceling statement due to user request" without error message matching though, and we
+        // don't want to do that.
+        Assert.assertEquals(
+            "Query is expected to be cancelled via st.close(), got " + e.getMessage(),
+            PSQLState.QUERY_CANCELED.getState(),
+            e.getSQLState());
       }
-      stmt2.executeQuery("select 1");
+      // Must never time out.
+      stmt2.executeQuery("select 1;");
     }
   }
 
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/BaseDataSourceFailoverUrlsTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/BaseDataSourceFailoverUrlsTest.java
new file mode 100644
index 00000000..4b0acd65
--- /dev/null
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/BaseDataSourceFailoverUrlsTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2004, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.jdbc2.optional;
+
+import static org.junit.Assert.assertEquals;
+
+import org.postgresql.ds.common.BaseDataSource;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import javax.naming.NamingException;
+
+/**
+* tests that failover urls survive the parse/rebuild roundtrip with and without specific ports
+*/
+public class BaseDataSourceFailoverUrlsTest {
+
+  private static final String DEFAULT_PORT = "5432";
+
+  @Test
+  public void testFullDefault() throws ClassNotFoundException, NamingException, IOException {
+    roundTripFromUrl("jdbc:postgresql://server/database", "jdbc:postgresql://server:" + DEFAULT_PORT + "/database");
+  }
+
+  @Test
+  public void testTwoNoPorts() throws ClassNotFoundException, NamingException, IOException {
+    roundTripFromUrl("jdbc:postgresql://server1,server2/database", "jdbc:postgresql://server1:" + DEFAULT_PORT + ",server2:" + DEFAULT_PORT + "/database");
+  }
+
+  @Test
+  public void testTwoWithPorts() throws ClassNotFoundException, NamingException, IOException {
+    roundTripFromUrl("jdbc:postgresql://server1:1234,server2:2345/database", "jdbc:postgresql://server1:1234,server2:2345/database");
+  }
+
+  @Test
+  public void testTwoFirstPort() throws ClassNotFoundException, NamingException, IOException {
+    roundTripFromUrl("jdbc:postgresql://server1,server2:2345/database", "jdbc:postgresql://server1:" + DEFAULT_PORT + ",server2:2345/database");
+  }
+
+  @Test
+  public void testTwoLastPort() throws ClassNotFoundException, NamingException, IOException {
+    roundTripFromUrl("jdbc:postgresql://server1:2345,server2/database", "jdbc:postgresql://server1:2345,server2:" + DEFAULT_PORT + "/database");
+  }
+
+  @Test
+  public void testNullPorts() {
+    BaseDataSource bds = newDS();
+    bds.setDatabaseName("database");
+    bds.setPortNumbers(null);
+    assertUrlWithoutParamsEquals("jdbc:postgresql://localhost/database", bds.getURL());
+    assertEquals(0, bds.getPortNumber());
+    assertEquals(0, bds.getPortNumbers()[0]);
+  }
+
+  @Test
+  public void testEmptyPorts() {
+    BaseDataSource bds = newDS();
+    bds.setDatabaseName("database");
+    bds.setPortNumbers(new int[0]);
+    assertUrlWithoutParamsEquals("jdbc:postgresql://localhost/database", bds.getURL());
+    assertEquals(0, bds.getPortNumber());
+    assertEquals(0, bds.getPortNumbers()[0]);
+  }
+
+  private BaseDataSource newDS() {
+    return new BaseDataSource() {
+      @Override
+      public String getDescription() {
+        return "BaseDataSourceFailoverUrlsTest-DS";
+      }
+    };
+  }
+
+  private void roundTripFromUrl(String in, String expected) throws NamingException, ClassNotFoundException, IOException {
+    BaseDataSource bds = newDS();
+
+    bds.setUrl(in);
+    assertUrlWithoutParamsEquals(expected, bds.getURL());
+
+    bds.setFromReference(bds.getReference());
+    assertUrlWithoutParamsEquals(expected, bds.getURL());
+
+    bds.initializeFrom(bds);
+    assertUrlWithoutParamsEquals(expected, bds.getURL());
+  }
+
+  private static String jdbcUrlStripParams(String in) {
+    return in.replaceAll("\\?.*$", "");
+  }
+
+  private static void assertUrlWithoutParamsEquals(String expected, String url) {
+    assertEquals(expected, jdbcUrlStripParams(url));
+  }
+}
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java
index 00c5d1a0..5a43fff4 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java
@@ -20,7 +20,8 @@ import org.junit.runners.Suite;
         SimpleDataSourceWithSetURLTest.class,
         ConnectionPoolTest.class,
         PoolingDataSourceTest.class,
-        CaseOptimiserDataSourceTest.class})
+        CaseOptimiserDataSourceTest.class,
+        BaseDataSourceFailoverUrlsTest.class})
 public class OptionalTestSuite {
 
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc3/CompositeTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc3/CompositeTest.java
index 32468489..3e5a120a 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc3/CompositeTest.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc3/CompositeTest.java
@@ -9,11 +9,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import org.postgresql.PGConnection;
+import org.postgresql.core.ServerVersion;
+import org.postgresql.jdbc.PreferQueryMode;
 import org.postgresql.test.TestUtil;
 import org.postgresql.util.PGobject;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.sql.Array;
@@ -26,6 +31,16 @@ public class CompositeTest {
 
   private Connection conn;
 
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    Connection conn = TestUtil.openDB();
+    try {
+      Assume.assumeTrue("uuid requires PostgreSQL 8.3+", TestUtil.haveMinimumServerVersion(conn, ServerVersion.v8_3));
+    } finally {
+      conn.close();
+    }
+  }
+
   @Before
   public void setUp() throws Exception {
     conn = TestUtil.openDB();
@@ -74,6 +89,7 @@ public class CompositeTest {
 
   @Test
   public void testSimpleArgumentSelect() throws SQLException {
+    Assume.assumeTrue("Skip if running in simple query mode", conn.unwrap(PGConnection.class).getPreferQueryMode() != PreferQueryMode.SIMPLE);
     PreparedStatement pstmt = conn.prepareStatement("SELECT ?");
     PGobject pgo = new PGobject();
     pgo.setType("simplecompositetest");
@@ -87,6 +103,7 @@ public class CompositeTest {
 
   @Test
   public void testComplexArgumentSelect() throws SQLException {
+    Assume.assumeTrue("Skip if running in simple query mode", conn.unwrap(PGConnection.class).getPreferQueryMode() != PreferQueryMode.SIMPLE);
     PreparedStatement pstmt = conn.prepareStatement("SELECT ?");
     PGobject pgo = new PGobject();
     pgo.setType("\"Composites\".\"ComplexCompositeTest\"");
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc3/Jdbc3TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc3/Jdbc3TestSuite.java
index a90abf63..5e41f7bd 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc3/Jdbc3TestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc3/Jdbc3TestSuite.java
@@ -13,18 +13,20 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    Jdbc3CallableStatementTest.class,
-    GeneratedKeysTest.class,
     CompositeQueryParseTest.class,
-    SqlCommandParseTest.class,
+    CompositeTest.class,
+    DatabaseMetaDataTest.class,
+    GeneratedKeysTest.class,
+    Jdbc3BlobTest.class,
+    Jdbc3CallableStatementTest.class,
     Jdbc3SavepointTest.class,
-    TypesTest.class,
-    ResultSetTest.class,
     ParameterMetaDataTest.class,
-    Jdbc3BlobTest.class,
-    DatabaseMetaDataTest.class,
+    ResultSetTest.class,
     SendRecvBufferSizeTest.class,
-    StringTypeParameterTest.class})
+    SqlCommandParseTest.class,
+    StringTypeParameterTest.class,
+    TypesTest.class,
+})
 public class Jdbc3TestSuite {
 
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/IsValidTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/IsValidTest.java
index 8de8f43d..0a4a6441 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/IsValidTest.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/IsValidTest.java
@@ -10,6 +10,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import org.postgresql.core.BaseConnection;
+import org.postgresql.core.ServerVersion;
 import org.postgresql.core.TransactionState;
 import org.postgresql.test.TestUtil;
 import org.postgresql.test.jdbc2.BaseTest4;
@@ -17,7 +18,9 @@ import org.postgresql.test.jdbc2.BaseTest4;
 import org.junit.Test;
 
 import java.sql.Connection;
+import java.sql.ResultSet;
 import java.sql.Statement;
+import java.util.Properties;
 
 public class IsValidTest extends BaseTest4 {
 
@@ -67,4 +70,37 @@ public class IsValidTest extends BaseTest4 {
     }
   }
 
+  @Test
+  public void testIsValidRemoteClose() throws Exception {
+
+    assumeMinimumServerVersion("Unable to use pg_terminate_backend before version 8.4", ServerVersion.v8_4);
+
+    Properties props = new Properties();
+    updateProperties(props);
+    Connection con2 = TestUtil.openPrivilegedDB();
+
+    try {
+
+      assertTrue("First connection should be valid", con.isValid(0));
+
+      String pid;
+      Statement s = con.createStatement();
+
+      try {
+        s.execute("select pg_backend_pid()");
+        ResultSet rs = s.getResultSet();
+        rs.next();
+        pid = rs.getString(1);
+      } finally {
+        TestUtil.closeQuietly(s);
+      }
+
+      TestUtil.execute("select pg_terminate_backend(" + pid + ")", con2);
+
+      assertFalse("The first connection should now be invalid", con.isValid(0));
+
+    } finally {
+      TestUtil.closeQuietly(con2);
+    }
+  }
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/Jdbc4TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/Jdbc4TestSuite.java
index 405d977f..29292445 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/Jdbc4TestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/Jdbc4TestSuite.java
@@ -13,18 +13,20 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-        DatabaseMetaDataTest.class,
-        ArrayTest.class,
-        WrapperTest.class,
-        BinaryTest.class,
-        IsValidTest.class,
-        ClientInfoTest.class,
-        PGCopyInputStreamTest.class,
-        BlobTest.class,
-        BinaryStreamTest.class,
-        CharacterStreamTest.class,
-        UUIDTest.class,
-        XmlTest.class
+    ArrayTest.class,
+    BinaryStreamTest.class,
+    BinaryTest.class,
+    BlobTest.class,
+    CharacterStreamTest.class,
+    ClientInfoTest.class,
+    DatabaseMetaDataTest.class,
+    IsValidTest.class,
+    JsonbTest.class,
+    LogTest.class,
+    PGCopyInputStreamTest.class,
+    UUIDTest.class,
+    WrapperTest.class,
+    XmlTest.class,
 })
 public class Jdbc4TestSuite {
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/GetObjectTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/GetObjectTest.java
index a452bece..bcdc541e 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/GetObjectTest.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/GetObjectTest.java
@@ -22,6 +22,7 @@ import org.postgresql.geometric.PGpolygon;
 import org.postgresql.test.TestUtil;
 import org.postgresql.util.PGInterval;
 import org.postgresql.util.PGmoney;
+import org.postgresql.util.PGobject;
 
 import org.junit.After;
 import org.junit.Before;
@@ -938,42 +939,48 @@ public class GetObjectTest {
     }
   }
 
-  /**
-   * Test the behavior getObject for inet columns.
-   */
-  @Test
-  public void testGetInet4Address() throws SQLException, UnknownHostException {
+  private void testInet(String inet, InetAddress expectedAddr, String expectedText) throws SQLException, UnknownHostException {
+    PGobject expectedObj = new PGobject();
+    expectedObj.setType("inet");
+    expectedObj.setValue(expectedText);
     Statement stmt = conn.createStatement();
-    String expected = "192.168.100.128";
-    stmt.executeUpdate(TestUtil.insertSQL("table1","inet_column","'" + expected + "'"));
-
-    ResultSet rs = stmt.executeQuery(TestUtil.selectSQL("table1", "inet_column"));
+    ResultSet rs = stmt.executeQuery("SELECT '" + inet + "'::inet AS inet_column");
     try {
       assertTrue(rs.next());
-      assertEquals(InetAddress.getByName(expected), rs.getObject("inet_column", InetAddress.class));
-      assertEquals(InetAddress.getByName(expected), rs.getObject(1, InetAddress.class));
+      assertEquals("The string value of the inet should match when fetched via getString(...)", expectedText, rs.getString(1));
+      assertEquals("The string value of the inet should match when fetched via getString(...)", expectedText, rs.getString("inet_column"));
+      assertEquals("The object value of the inet should match when fetched via getObject(...)", expectedObj, rs.getObject(1));
+      assertEquals("The object value of the inet should match when fetched via getObject(...)", expectedObj, rs.getObject("inet_column"));
+      assertEquals("The InetAddress value should match when fetched via getObject(..., InetAddress.class)", expectedAddr, rs.getObject("inet_column", InetAddress.class));
+      assertEquals("The InetAddress value should match when fetched via getObject(..., InetAddress.class)", expectedAddr, rs.getObject(1, InetAddress.class));
     } finally {
       rs.close();
+      stmt.close();
     }
   }
 
   /**
-   * Test the behavior getObject for inet columns.
+   * Test the behavior getObject for ipv4 inet columns.
    */
   @Test
-  public void testGetInet6Address() throws SQLException, UnknownHostException {
-    Statement stmt = conn.createStatement();
-    String expected = "2001:4f8:3:ba:2e0:81ff:fe22:d1f1";
-    stmt.executeUpdate(TestUtil.insertSQL("table1","inet_column","'" + expected + "'"));
+  public void testGetInet4Address() throws SQLException, UnknownHostException {
+    String inet = "192.168.100.128";
+    InetAddress addr = InetAddress.getByName(inet);
+    testInet(inet, addr, inet);
+    testInet(inet + "/16", addr, inet + "/16");
+    testInet(inet + "/32", addr, inet);
+  }
 
-    ResultSet rs = stmt.executeQuery(TestUtil.selectSQL("table1", "inet_column"));
-    try {
-      assertTrue(rs.next());
-      assertEquals(InetAddress.getByName(expected), rs.getObject("inet_column", InetAddress.class));
-      assertEquals(InetAddress.getByName(expected), rs.getObject(1, InetAddress.class));
-    } finally {
-      rs.close();
-    }
+  /**
+   * Test the behavior getObject for ipv6 inet columns.
+   */
+  @Test
+  public void testGetInet6Address() throws SQLException, UnknownHostException {
+    String inet = "2001:4f8:3:ba:2e0:81ff:fe22:d1f1";
+    InetAddress addr = InetAddress.getByName(inet);
+    testInet(inet, addr, inet);
+    testInet(inet + "/16", addr, inet + "/16");
+    testInet(inet + "/128", addr, inet);
   }
 
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/Jdbc41TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/Jdbc41TestSuite.java
index 046696a0..f9ceeed9 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/Jdbc41TestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/Jdbc41TestSuite.java
@@ -13,13 +13,13 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-        SchemaTest.class,
-        AbortTest.class,
-        CloseOnCompletionTest.class,
-        SharedTimerClassLoaderLeakTest.class,
-        NetworkTimeoutTest.class,
-        GetObjectTest.class}
-    )
+    AbortTest.class,
+    CloseOnCompletionTest.class,
+    GetObjectTest.class,
+    NetworkTimeoutTest.class,
+    SchemaTest.class,
+    SharedTimerClassLoaderLeakTest.class,
+})
 public class Jdbc41TestSuite {
 
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/SchemaTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/SchemaTest.java
index 34ca983e..f843ab56 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/SchemaTest.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/jdbc41/SchemaTest.java
@@ -5,10 +5,16 @@
 
 package org.postgresql.test.jdbc4.jdbc41;
 
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
+import org.postgresql.PGProperty;
 import org.postgresql.test.TestUtil;
+import org.postgresql.util.PSQLException;
+import org.postgresql.util.PSQLState;
 
 import org.junit.After;
 import org.junit.Before;
@@ -217,6 +223,90 @@ public class SchemaTest {
     ps.close();
   }
 
+  @Test
+  public void testCurrentSchemaPropertyVisibilityTableDuringFunctionCreation() throws SQLException {
+    Properties properties = new Properties();
+    properties.setProperty(PGProperty.CURRENT_SCHEMA.getName(), "public,schema1,schema2");
+    Connection connection = TestUtil.openDB(properties);
+
+    TestUtil.execute("create table schema1.check_table (test_col text)", connection);
+    TestUtil.execute("insert into schema1.check_table (test_col) values ('test_value')", connection);
+    TestUtil.execute("create or replace function schema2.check_fun () returns text as $$"
+        + " select test_col from check_table"
+        + "$$ language sql immutable", connection);
+    connection.close();
+  }
+
+  @Test
+  public void testCurrentSchemaPropertyNotVisibilityTableDuringFunctionCreation() throws SQLException {
+    Properties properties = new Properties();
+    properties.setProperty(PGProperty.CURRENT_SCHEMA.getName(), "public,schema2");
+
+    try (Connection connection = TestUtil.openDB(properties)) {
+      TestUtil.execute("create table schema1.check_table (test_col text)", connection);
+      TestUtil.execute("insert into schema1.check_table (test_col) values ('test_value')", connection);
+      TestUtil.execute("create or replace function schema2.check_fun (txt text) returns text as $$"
+          + " select test_col from check_table"
+          + "$$ language sql immutable", connection);
+    } catch (PSQLException e) {
+      String sqlState = e.getSQLState();
+      String message = e.getMessage();
+      assertThat("Test creates function in schema 'schema2' and this function try use table \"check_table\" "
+            + "from schema 'schema1'. We expect here sql error code - "
+            + PSQLState.UNDEFINED_TABLE + ", because search_path does not contains schema 'schema1' and "
+            + "postgres does not see table \"check_table\"",
+            sqlState,
+            equalTo(PSQLState.UNDEFINED_TABLE.getState())
+      );
+      assertThat(
+          "Test creates function in schema 'schema2' and this function try use table \"check_table\" "
+              + "from schema 'schema1'. We expect here that sql error message will be contains \"check_table\", "
+              + "because search_path does not contains schema 'schema1' and postgres does not see "
+              + "table \"check_table\"",
+            message,
+            containsString("\"check_table\"")
+      );
+    }
+  }
+
+  @Test
+  public void testCurrentSchemaPropertyVisibilityFunction() throws SQLException {
+    testCurrentSchemaPropertyVisibilityTableDuringFunctionCreation();
+    Properties properties = new Properties();
+    properties.setProperty(PGProperty.CURRENT_SCHEMA.getName(), "public,schema1,schema2");
+    Connection connection = TestUtil.openDB(properties);
+
+    TestUtil.execute("select check_fun()", connection);
+    connection.close();
+  }
+
+  @Test
+  public void testCurrentSchemaPropertyNotVisibilityTableInsideFunction() throws SQLException {
+    testCurrentSchemaPropertyVisibilityTableDuringFunctionCreation();
+    Properties properties = new Properties();
+    properties.setProperty(PGProperty.CURRENT_SCHEMA.getName(), "public,schema2");
+
+    try (Connection connection = TestUtil.openDB(properties)) {
+      TestUtil.execute("select check_fun()", connection);
+    } catch (PSQLException e) {
+      String sqlState = e.getSQLState();
+      String message = e.getMessage();
+      assertThat("Test call function in schema 'schema2' and this function uses table \"check_table\" "
+            + "from schema 'schema1'. We expect here sql error code - " + PSQLState.UNDEFINED_TABLE + ", "
+            + "because search_path does not contains schema 'schema1' and postgres does not see table \"check_table\".",
+            sqlState,
+            equalTo(PSQLState.UNDEFINED_TABLE.getState())
+      );
+      assertThat(
+          "Test call function in schema 'schema2' and this function uses table \"check_table\" "
+              + "from schema 'schema1'. We expect here that sql error message will be contains \"check_table\", because "
+              + " search_path does not contains schema 'schema1' and postgres does not see table \"check_table\"",
+          message,
+          containsString("\"check_table\"")
+      );
+    }
+  }
+
   private void assertColType(PreparedStatement ps, String message, int expected) throws SQLException {
     ResultSet rs = ps.executeQuery();
     ResultSetMetaData md = rs.getMetaData();
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310InfinityTests.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310InfinityTests.java
index f4cc3656..04b81c84 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310InfinityTests.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310InfinityTests.java
@@ -30,11 +30,11 @@ import java.util.Collection;
 public class GetObject310InfinityTests extends BaseTest4 {
   private final String expression;
   private final String pgType;
-  private final Class klass;
+  private final Class<?> klass;
   private final Object expectedValue;
 
   public GetObject310InfinityTests(BinaryMode binaryMode, String expression,
-      String pgType, Class klass, Object expectedValue) {
+      String pgType, Class<?> klass, Object expectedValue) {
     setBinaryMode(binaryMode);
     this.expression = expression;
     this.pgType = pgType;
@@ -56,7 +56,7 @@ public class GetObject310InfinityTests extends BaseTest4 {
       for (String expression : Arrays.asList("-infinity", "infinity")) {
         for (String pgType : Arrays.asList("date", "timestamp",
             "timestamp with time zone")) {
-          for (Class klass : Arrays.asList(LocalDate.class, LocalDateTime.class,
+          for (Class<?> klass : Arrays.asList(LocalDate.class, LocalDateTime.class,
               OffsetDateTime.class)) {
             if (klass.equals(LocalDate.class) && !pgType.equals("date")) {
               continue;
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java
index e3b048bf..b5dc6be6 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java
@@ -6,10 +6,12 @@
 package org.postgresql.test.jdbc42;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
+import org.postgresql.core.ServerVersion;
 import org.postgresql.test.TestUtil;
 import org.postgresql.test.jdbc2.BaseTest4;
 import org.postgresql.util.PSQLException;
@@ -19,20 +21,28 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.OffsetDateTime;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
+import java.time.chrono.IsoEra;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Temporal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.TimeZone;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @RunWith(Parameterized.class)
 public class GetObject310Test extends BaseTest4 {
@@ -191,6 +201,9 @@ public class GetObject310Test extends BaseTest4 {
             // This is a pre-1970 date, so check if it is rounded properly
             "1950-07-20T02:00:00",
 
+            // Ensure the calendar is proleptic
+            "1582-09-30T00:00:00", "1582-10-16T00:00:00",
+
             // On 2000-10-29 03:00:00 Moscow went to regular time, thus local time became 02:00:00
             "2000-10-29T01:59:59", "2000-10-29T02:00:00", "2000-10-29T02:00:01", "2000-10-29T02:59:59",
             "2000-10-29T03:00:00", "2000-10-29T03:00:01", "2000-10-29T03:59:59", "2000-10-29T04:00:00",
@@ -262,4 +275,101 @@ public class GetObject310Test extends BaseTest4 {
     }
   }
 
+  @Test
+  public void testBcTimestamp() throws SQLException {
+
+    Statement stmt = con.createStatement();
+    ResultSet rs = stmt.executeQuery("SELECT '1582-09-30 12:34:56 BC'::timestamp");
+    try {
+      assertTrue(rs.next());
+      LocalDateTime expected = LocalDateTime.of(1582, 9, 30, 12, 34, 56)
+          .with(ChronoField.ERA, IsoEra.BCE.getValue());
+      LocalDateTime actual = rs.getObject(1, LocalDateTime.class);
+      assertEquals(expected, actual);
+      assertFalse(rs.next());
+    } finally {
+      rs.close();
+      stmt.close();
+    }
+  }
+
+  @Test
+  public void testBcTimestamptz() throws SQLException {
+
+    Statement stmt = con.createStatement();
+    ResultSet rs = stmt.executeQuery("SELECT '1582-09-30 12:34:56Z BC'::timestamp");
+    try {
+      assertTrue(rs.next());
+      OffsetDateTime expected = OffsetDateTime.of(1582, 9, 30, 12, 34, 56, 0, UTC)
+          .with(ChronoField.ERA, IsoEra.BCE.getValue());
+      OffsetDateTime actual = rs.getObject(1, OffsetDateTime.class);
+      assertEquals(expected, actual);
+      assertFalse(rs.next());
+    } finally {
+      rs.close();
+      stmt.close();
+    }
+  }
+
+  @Test
+  public void testProlepticCalendarTimestamp() throws SQLException {
+    // date time ranges and CTEs are both new with 8.4
+    assumeMinimumServerVersion(ServerVersion.v8_4);
+    LocalDateTime start = LocalDate.of(1582, 9, 30).atStartOfDay();
+    LocalDateTime end = LocalDate.of(1582, 10, 16).atStartOfDay();
+    long numberOfDays = Duration.between(start, end).toDays() + 1L;
+    List<LocalDateTime> range = Stream.iterate(start, new LocalDateTimePlusOneDay())
+        .limit(numberOfDays)
+        .collect(Collectors.toList());
+
+    runProlepticTests(LocalDateTime.class, "'1582-09-30 00:00'::timestamp, '1582-10-16 00:00'::timestamp", range);
+  }
+
+  @Test
+  public void testProlepticCalendarTimestamptz() throws SQLException {
+    // date time ranges and CTEs are both new with 8.4
+    assumeMinimumServerVersion(ServerVersion.v8_4);
+    OffsetDateTime start = LocalDate.of(1582, 9, 30).atStartOfDay().atOffset(UTC);
+    OffsetDateTime end = LocalDate.of(1582, 10, 16).atStartOfDay().atOffset(UTC);
+    long numberOfDays = Duration.between(start, end).toDays() + 1L;
+    List<OffsetDateTime> range = Stream.iterate(start, new OffsetDateTimePlusOneDay())
+        .limit(numberOfDays)
+        .collect(Collectors.toList());
+
+    runProlepticTests(OffsetDateTime.class, "'1582-09-30 00:00:00 Z'::timestamptz, '1582-10-16 00:00:00 Z'::timestamptz", range);
+  }
+
+  private <T extends Temporal> void runProlepticTests(Class<T> clazz, String selectRange, List<T> range) throws SQLException {
+    List<T> temporals = new ArrayList<>(range.size());
+
+    PreparedStatement stmt = con.prepareStatement("SELECT * FROM generate_series(" + selectRange + ", '1 day');");
+    ResultSet rs = stmt.executeQuery();
+    try {
+      while (rs.next()) {
+        T temporal = rs.getObject(1, clazz);
+        temporals.add(temporal);
+      }
+      assertEquals(range, temporals);
+    } finally {
+      rs.close();
+      stmt.close();
+    }
+  }
+
+  private static class LocalDateTimePlusOneDay implements UnaryOperator<LocalDateTime> {
+
+    @Override
+    public LocalDateTime apply(LocalDateTime x) {
+      return x.plusDays(1);
+    }
+  }
+
+  private static class OffsetDateTimePlusOneDay implements UnaryOperator<OffsetDateTime> {
+
+    @Override
+    public OffsetDateTime apply(OffsetDateTime x) {
+      return x.plusDays(1);
+    }
+  }
+
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/Jdbc42TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/Jdbc42TestSuite.java
index d4e32c59..6b92e46f 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/Jdbc42TestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/Jdbc42TestSuite.java
@@ -11,13 +11,14 @@ import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
 @SuiteClasses({
-    SimpleJdbc42Test.class,
     CustomizeDefaultFetchSizeTest.class,
+    GetObject310InfinityTests.class,
     GetObject310Test.class,
-    PreparedStatementTest.class,
     Jdbc42CallableStatementTest.class,
-    GetObject310InfinityTests.class,
-    SetObject310Test.class})
+    PreparedStatementTest.class,
+    SetObject310Test.class,
+    SimpleJdbc42Test.class,
+})
 public class Jdbc42TestSuite {
 
 }
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310InfinityTests.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310InfinityTests.java
new file mode 100644
index 00000000..86457aa2
--- /dev/null
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310InfinityTests.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.jdbc42;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.postgresql.core.ServerVersion;
+import org.postgresql.test.TestUtil;
+import org.postgresql.test.jdbc2.BaseTest4;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class SetObject310InfinityTests extends BaseTest4 {
+
+  public SetObject310InfinityTests(BinaryMode binaryMode) {
+    setBinaryMode(binaryMode);
+  }
+
+  @Parameterized.Parameters(name = "binary = {0}")
+  public static Iterable<Object[]> data() {
+    Collection<Object[]> ids = new ArrayList<>(2);
+    for (BaseTest4.BinaryMode binaryMode : BaseTest4.BinaryMode.values()) {
+      ids.add(new Object[]{binaryMode});
+    }
+    return ids;
+  }
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    Assume.assumeTrue("PostgreSQL 8.3 does not support 'infinity' for 'date'",
+        TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_4));
+    super.setUp();
+    TestUtil.createTable(con, "table1", "timestamp_without_time_zone_column timestamp without time zone,"
+            + "timestamp_with_time_zone_column timestamp with time zone,"
+            + "date_column date"
+    );
+  }
+
+  @After
+  public void tearDown() throws SQLException {
+    TestUtil.dropTable(con, "table1");
+    super.tearDown();
+  }
+
+  @Test
+  public void testTimestamptz() throws SQLException {
+    runTestforType(OffsetDateTime.MAX, OffsetDateTime.MIN, "timestamp_without_time_zone_column", null);
+  }
+
+  @Test
+  public void testTimestamp() throws SQLException {
+    runTestforType(LocalDateTime.MAX, LocalDateTime.MIN, "timestamp_without_time_zone_column", null);
+  }
+
+  @Test
+  public void testDate() throws SQLException {
+    runTestforType(LocalDate.MAX, LocalDate.MIN, "date_column", null);
+  }
+
+  private void runTestforType(Object max, Object min, String columnName, Integer type) throws SQLException {
+    insert(max, columnName, type);
+    String readback = readString(columnName);
+    assertEquals("infinity", readback);
+    delete();
+
+    insert(min, columnName, type);
+    readback = readString(columnName);
+    assertEquals("-infinity", readback);
+    delete();
+  }
+
+  private void insert(Object data, String columnName, Integer type) throws SQLException {
+    PreparedStatement ps = con.prepareStatement(TestUtil.insertSQL("table1", columnName, "?"));
+    try {
+      if (type != null) {
+        ps.setObject(1, data, type);
+      } else {
+        ps.setObject(1, data);
+      }
+      assertEquals(1, ps.executeUpdate());
+    } finally {
+      ps.close();
+    }
+  }
+
+  private String readString(String columnName) throws SQLException {
+    Statement st = con.createStatement();
+    try {
+      ResultSet rs = st.executeQuery(TestUtil.selectSQL("table1", columnName));
+      try {
+        assertNotNull(rs);
+        assertTrue(rs.next());
+        return rs.getString(1);
+      } finally {
+        rs.close();
+      }
+    } finally {
+      st.close();
+    }
+  }
+
+  private void delete() throws SQLException {
+    Statement st = con.createStatement();
+    try {
+      st.execute("DELETE FROM table1");
+    } finally {
+      st.close();
+    }
+  }
+
+}
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java
index 203132ce..0b87e4e0 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java
@@ -260,6 +260,9 @@ public class SetObject310Test extends BaseTest4 {
             // This is a pre-1970 date, so check if it is rounded properly
             "1950-07-20T02:00:00",
 
+            // Ensure the calendar is proleptic
+            "1582-09-30T00:00:00", "1582-10-16T00:00:00",
+
             // On 2000-10-29 03:00:00 Moscow went to regular time, thus local time became 02:00:00
             "2000-10-29T01:59:59", "2000-10-29T02:00:00", "2000-10-29T02:00:01", "2000-10-29T02:59:59",
             "2000-10-29T03:00:00", "2000-10-29T03:00:01", "2000-10-29T03:59:59", "2000-10-29T04:00:00",
@@ -311,7 +314,7 @@ public class SetObject310Test extends BaseTest4 {
               "OffsetDateTime=" + data + " (with ZoneId=" + dataZone + "), with TimeZone.default="
                   + storeZone + ", setObject(int, Object)", data.toInstant(),
               noTypeRes.toInstant());
-          String withType = rs.getString(1);
+          String withType = rs.getString(2);
           OffsetDateTime withTypeRes = OffsetDateTime.parse(withType.replace(' ', 'T') + ":00");
           assertEquals(
               "OffsetDateTime=" + data + " (with ZoneId=" + dataZone + "), with TimeZone.default="
diff --git a/pgjdbc/src/test/java/org/postgresql/test/ssl/SslTestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/ssl/SslTestSuite.java
index cf48916f..2dece06e 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/ssl/SslTestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/ssl/SslTestSuite.java
@@ -10,9 +10,9 @@ import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    LibPQFactoryHostNameTest.class,
     CommonNameVerifierTest.class,
-    SslTest.class
+    LibPQFactoryHostNameTest.class,
+    SslTest.class,
 })
 public class SslTestSuite {
 }