Repository: pgjdbc/pgjdbc
Pull request #1435 (2019-03-12 04:52:49)

Expose parameter status messages (GUC_REPORT) to the user
Add a new `Map PGConnection.getParameterStatuses()` method that tracks the
latest values of all `GUC_REPORT` parameters reported by the server in
`ParameterStatus` protocol messages from the server. The map is read-only. A
convenience `PGConnection.getParameterStatus(String)` wrapper is also provided.

This provides a PgJDBC equivalent to the `PQparameterStatus(...)` `libpq` API
function.

Extensions may define custom GUCs that are set as `GUC_REPORT` when they
`DefineCustomStringVariable(...)` etc. This feature will properly handle such
GUCs, allowing applications to generate parameter status change messages in
their extensions and have them available to the JDBC driver without needing
round trips.

No assumptions are made about which server GUCs are `GUC_REPORT` or their
names, so it'll work (with possible test case tweaks) on current and future
server versions.

Github issue pgjdbc/pgjdbc#1428

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing](https://github.com/pgjdbc/pgjdbc/blob/master/CONTRIBUTING.md) document?
* [x] Have you checked to ensure there aren't other open [Pull Requests](../../pulls) for the same update/change?

### New Feature Submissions:

1. [x] Does your submission pass tests?
2. [x] Does mvn checkstyle:check pass ?

### Changes to Existing Features:

* [ ] Does this break existing behaviour? **no**
* [x] Have you added an explanation of what your changes do and why you'd like us to include them?
* [x] Have you written new tests for your core changes, as applicable?
* [x] Have you successfully run tests with your changes locally?

AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.160 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23000854) (commit https://github.com/pgjdbc/pgjdbc/commit/479265df93 by @ringerc)
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.161 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23001833) (commit https://github.com/pgjdbc/pgjdbc/commit/9be0206670 by @ringerc)
davecramer: @ringerc I'll try to look at this ASAP, off the top though, we need remove the tests for 8.3
sehrope: Haven't tried building it but skimmed through the code and so far looks good. Found one commented out method that should be removed (separate comment for that; guessing its from older version of putting this together).

Why are the session_authorization and is_superuser GUCs blacklisted? It's the user's app so if they want to reference those things, why not? It's not like they can't run `SHOW is_superuser` and get it themselves right?
sehrope: Overall looks good. Builds locally and new tests pass. Only things I found were those small cosmetic ones.

Also, I don't have a particular opinion on exposing those two GUCs. I'm just not sure why they're being handled separately.
ringerc: I'll fix the issue with the commented-out code. Whoops.

As for special casing of `is_superuser` and `session_authorization` that's because of the comments in `guc.c`:

`        /* Not for general use --- used by SET SESSION AUTHORIZATION */`

However, I checked `src/interfaces/libpq` and its `PQparameterStatus` doesn't do anything like that. So I'll remove that logic.
ringerc: They're also documented in the libpq manual so I'll follow that lead.
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.163 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23032899) (commit https://github.com/pgjdbc/pgjdbc/commit/7a59a5702b by @ringerc)
ringerc: Failing on [8.2](https://travis-ci.org/pgjdbc/pgjdbc/jobs/505603743), [8.3](https://travis-ci.org/pgjdbc/pgjdbc/jobs/505603742), and [8.4](https://travis-ci.org/pgjdbc/pgjdbc/jobs/505603741) with

```
transactionalParametersCommit(org.postgresql.test.jdbc2.ParameterStatusTest)  Time elapsed: 0.018 sec  <<< FAILURE!
java.lang.AssertionError: expected:<Driver Tests> but was:<null>
	at org.junit.Assert.fail(Assert.java:88)
	at org.junit.Assert.failNotEquals(Assert.java:834)
	at org.junit.Assert.assertEquals(Assert.java:118)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at org.postgresql.test.jdbc2.ParameterStatusTest.transactionalParametersCommon(ParameterStatusTest.java:89)
	at org.postgresql.test.jdbc2.ParameterStatusTest.transactionalParametersCommit(ParameterStatusTest.java:124)
transactionalParametersRollback(org.postgresql.test.jdbc2.ParameterStatusTest)  Time elapsed: 0.014 sec  <<< FAILURE!
java.lang.AssertionError: expected:<Driver Tests> but was:<null>
	at org.junit.Assert.fail(Assert.java:88)
	at org.junit.Assert.failNotEquals(Assert.java:834)
	at org.junit.Assert.assertEquals(Assert.java:118)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at org.postgresql.test.jdbc2.ParameterStatusTest.transactionalParametersCommon(ParameterStatusTest.java:89)
	at org.postgresql.test.jdbc2.ParameterStatusTest.transactionalParametersRollback(ParameterStatusTest.java:109)
reportUpdatedParameters(org.postgresql.test.jdbc2.ParameterStatusTest)  Time elapsed: 0.021 sec  <<< ERROR!
org.postgresql.util.PSQLException: ERROR: unrecognized configuration parameter "application_name"
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2470)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2213)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:309)
	at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
	at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
	at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:311)
	at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:297)
	at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:274)
	at org.postgresql.jdbc.PgStatement.executeUpdate(PgStatement.java:246)
	at org.postgresql.test.jdbc2.ParameterStatusTest.reportUpdatedParameters(ParameterStatusTest.java:73)
expectedInitialParameters(org.postgresql.test.jdbc2.ParameterStatusTest)  Time elapsed: 0.017 sec  <<< FAILURE!
java.lang.AssertionError: expected:<Driver Tests> but was:<null>
	at org.junit.Assert.fail(Assert.java:88)
	at org.junit.Assert.failNotEquals(Assert.java:834)
	at org.junit.Assert.assertEquals(Assert.java:118)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at org.postgresql.test.jdbc2.ParameterStatusTest.expectedInitialParameters(ParameterStatusTest.java:49)
transactionalParametersAutocommit(org.postgresql.test.jdbc2.ParameterStatusTest)  Time elapsed: 0.019 sec  <<< FAILURE!
java.lang.AssertionError: expected:<Driver Tests> but was:<null>
	at org.junit.Assert.fail(Assert.java:88)
	at org.junit.Assert.failNotEquals(Assert.java:834)
	at org.junit.Assert.assertEquals(Assert.java:118)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at org.postgresql.test.jdbc2.ParameterStatusTest.transactionalParametersAutocommit(ParameterStatusTest.java:141)
```
ringerc: `application_name` was added in 9.0, so that's why.

I'll make that test conditional on version. I'm tempted to just skip the whole test on ancient postgres, but we might as well test the initial parameters and just skip the `application_name` and transactional boundary stuff.

WIP
ringerc: Modified to apply appropriate server version filters. I hadn't realised PgJDBC tested as far back as 8.2; that's impressive actually. Building.
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.164 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23062306) (commit https://github.com/pgjdbc/pgjdbc/commit/f3b61dbee1 by @ringerc)
AppVeyorBot: :x: [Build pgjdbc 1.0.165 failed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23062986) (commit https://github.com/pgjdbc/pgjdbc/commit/3908c5650c by @ringerc)
ringerc: I've seen [this connection timeout test failure](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23062986/job/02s0ocyd93c46373) in my local test runs too, it's an unrelated spurious failure:

```
testShortQueryTimeout(org.postgresql.test.jdbc2.StatementTest)  Time elapsed: 0.219 sec  <<< ERROR!
org.postgresql.util.PSQLException: ERROR: canceling statement due to user request
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2470)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2213)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:309)
	at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
	at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
	at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:311)
	at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:297)
	at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:274)
	at org.postgresql.jdbc.PgStatement.executeQuery(PgStatement.java:225)
	at org.postgresql.test.jdbc2.StatementTest.testShortQueryTimeout(StatementTest.java:737)
```

that I suspect is a test bug due to host timing/scheduling/load. The test probably needs a couple of retries.
ringerc: Seen [this failure](https://travis-ci.org/pgjdbc/pgjdbc/jobs/506126498#L5977) twice too

```
Failed tests: 
  DatabaseMetaDataTest.testCrossReference:242 expected:<ww_m_[]fkey> but was:<ww_m_[n_]fkey>
```
AppVeyorBot: :x: [Build pgjdbc 1.0.166 failed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23067800) (commit https://github.com/pgjdbc/pgjdbc/commit/4ac3d32674 by @ringerc)
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.167 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23068476) (commit https://github.com/pgjdbc/pgjdbc/commit/cf945dcc06 by @ringerc)
vlsi: In general it looks good. I don't really think we should expose `Map`, should we?
Are there use cases for that?
sehrope: Without the `Map` there's no way to get all the parameter names (and values) as they're not necessarily known to the client. The server could set the value for a custom parameter (ex: for a fork) that the client does not know of and a user program may want to show that in a debug context.
codecov-io: # [Codecov](https://codecov.io/gh/pgjdbc/pgjdbc/pull/1435?src=pr&el=h1) Report
> Merging [#1435](https://codecov.io/gh/pgjdbc/pgjdbc/pull/1435?src=pr&el=desc) into [master](https://codecov.io/gh/pgjdbc/pgjdbc/commit/0c5cf475d35fb73d921eac922089cf4406e48c9d?src=pr&el=desc) will **increase** coverage by `0.02%`.
> The diff coverage is `72.72%`.



```diff
@@             Coverage Diff              @@
##             master    #1435      +/-   ##
============================================
+ Coverage     68.74%   68.76%   +0.02%     
- Complexity     3902     3909       +7     
============================================
  Files           179      179              
  Lines         16414    16425      +11     
  Branches       2672     2673       +1     
============================================
+ Hits          11284    11295      +11     
  Misses         3882     3882              
  Partials       1248     1248
```

vlsi: > Without the Map there's no way to get all the parameter names 

That's true.
My initial thought was client did know which parameters are needed.
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.170 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23092727) (commit https://github.com/pgjdbc/pgjdbc/commit/e297180bda by @ringerc)
ringerc: Tests pass (with the follow-up commits that fix test problems), and issues raised have been resolved.
ringerc: @davecramer and @vlsi I think this is good to go now
ringerc: Rebased.

BTW @sehrope forgot to retain author metadata etc in 42d6bfa when picking out of this PR - I don't overly mind, but please keep it in mind in future.
AppVeyorBot: :white_check_mark: [Build pgjdbc 1.0.184 completed](https://ci.appveyor.com/project/davecramer/pgjdbc/builds/23387648) (commit https://github.com/pgjdbc/pgjdbc/commit/79b9f6d301 by @ringerc)
sehrope: @ringerc I think it was a timing issue as I had ran into it myself trying out some [encoding related changes](https://travis-ci.org/sehrope/pgjdbc/jobs/505997845#L7274-L7279). I saw your note regarding the test failures and then a few hours later, when I pushed a separate PR for the FK name changes, I guess you had also pushed one to this branch. I chalk up the names being similar to great minds thinking alike :smile:.
ringerc: @sehrope Ha, that's hilarious. No worries.
ringerc: @vlsi and @davecramer I think this is merge-ready. May I have your approval to merge?

Patch:
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..25df7a72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 
 ## [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)
diff --git a/README.md b/README.md
index 4676cd0a..0ed5dfbc 100644
--- a/README.md
+++ b/README.md
@@ -24,30 +24,30 @@ 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.6-blue.svg)][mvn-jre8]
 ```xml
 <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
-    <version>42.2.5</version>
+    <version>42.2.6</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.6.jre7-blue.svg)][mvn-jre7]
 ```xml
 <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
-    <version>42.2.5.jre7</version>
+    <version>42.2.6.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.6.jre6-blue.svg)][mvn-jre6]
 ```xml
 <dependency>
     <groupId>org.postgresql</groupId>
     <artifactId>postgresql</artifactId>
-    <version>42.2.5.jre6</version>
+    <version>42.2.6.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"
@@ -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/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/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/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/pgjdbc/pom.xml b/pgjdbc/pom.xml
index 8a859c38..fc2ff119 100644
--- a/pgjdbc/pom.xml
+++ b/pgjdbc/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.postgresql</groupId>
     <artifactId>pgjdbc-core-parent</artifactId>
-    <version>1.1.5</version>
+    <version>1.1.6</version>
     <relativePath />
   </parent>
 
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/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..1f77f15b 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;
@@ -389,4 +396,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/QueryExecutorImpl.java b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
index f43bb78b..a787283a 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java
@@ -2619,6 +2619,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/jdbc/PgConnection.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
index d1271743..42bfe0a2 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
@@ -1724,4 +1724,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/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"),


Test patch:
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/Jdbc2TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java
index 3f372393..803f5162 100644
--- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java
@@ -122,7 +122,8 @@ import org.junit.runners.Suite;
         CopyLargeFileTest.class,
         ServerErrorTest.class,
         UpsertTest.class,
-        OuterJoinSyntaxTest.class
+        OuterJoinSyntaxTest.class,
+        ParameterStatusTest.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..54515876
--- /dev/null
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ParameterStatusTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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());
+
+  @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/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();