Skip to content
Snippets Groups Projects
Commit ad51f2e5 authored by Christoph Berg's avatar Christoph Berg :satellite:
Browse files

New upstream version 42.2.20

parent 2352dfcf
Branches
Tags upstream/42.2.20
No related merge requests found
......@@ -10,7 +10,7 @@
<artifactId>postgresql</artifactId>
<packaging>jar</packaging>
<name>PostgreSQL JDBC Driver - JDBC 4.2</name>
<version>42.2.19</version>
<version>42.2.20</version>
<description>Java JDBC 4.2 (JRE 8+) driver for PostgreSQL database</description>
<url>https://github.com/pgjdbc/pgjdbc</url>
......
......@@ -10,8 +10,6 @@ import org.postgresql.jdbc.FieldMetadata;
// import org.checkerframework.checker.nullness.qual.Nullable;
// import org.checkerframework.dataflow.qual.Pure;
/*
*/
public class Field {
// The V3 protocol defines two constants for the format of data
public static final int TEXT_FORMAT = 0;
......@@ -20,7 +18,7 @@ public class Field {
private final int length; // Internal Length of this field
private final int oid; // OID of the type
private final int mod; // type modifier of this field
private final String columnLabel; // Column label
private String columnLabel; // Column label
private int format = TEXT_FORMAT; // In the V3 protocol each field has a format
// 0 = text, 1 = binary
......@@ -172,4 +170,8 @@ public class Field {
public boolean isTypeInitialized() {
return pgType != NOT_YET_LOADED;
}
public void upperCaseLabel() {
columnLabel = columnLabel.toUpperCase();
}
}
......@@ -1427,7 +1427,6 @@ public class PgConnection implements BaseConnection {
if (checkConnectionQuery == null) {
checkConnectionQuery = prepareStatement("");
}
checkConnectionQuery.setQueryTimeout(timeout);
checkConnectionQuery.executeUpdate();
}
return true;
......
......@@ -1300,6 +1300,7 @@ public class PgDatabaseMetaData implements DatabaseMetaData {
+ " WHEN 'r' THEN 'TABLE' "
+ " WHEN 'p' THEN 'PARTITIONED TABLE' "
+ " WHEN 'i' THEN 'INDEX' "
+ " WHEN 'P' then 'PARTITIONED INDEX' "
+ " WHEN 'S' THEN 'SEQUENCE' "
+ " WHEN 'v' THEN 'VIEW' "
+ " WHEN 'c' THEN 'TYPE' "
......@@ -1344,7 +1345,7 @@ public class PgDatabaseMetaData implements DatabaseMetaData {
}
String sql = select + orderby;
return createMetaDataStatement().executeQuery(sql);
return ((PgResultSet)createMetaDataStatement().executeQuery(sql)).upperCaseFieldLabels();
}
private static final Map<String, Map<String, String>> tableTypeClauses;
......@@ -1370,6 +1371,10 @@ public class PgDatabaseMetaData implements DatabaseMetaData {
"c.relkind = 'i' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'");
ht.put("NOSCHEMAS", "c.relkind = 'i' AND c.relname !~ '^pg_'");
ht = new HashMap<String, String>();
tableTypeClauses.put("PARTITIONED INDEX", ht);
ht.put("SCHEMAS", "c.relkind = 'I' AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'");
ht.put("NOSCHEMAS", "c.relkind = 'I' AND c.relname !~ '^pg_'");
ht = new HashMap<String, String>();
tableTypeClauses.put("SEQUENCE", ht);
ht.put("SCHEMAS", "c.relkind = 'S'");
ht.put("NOSCHEMAS", "c.relkind = 'S'");
......@@ -2233,7 +2238,19 @@ public class PgDatabaseMetaData implements DatabaseMetaData {
sql +=
" WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey[pos.n] AND con.confrelid = pkc.oid "
+ " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey[pos.n] AND con.conrelid = fkc.oid "
+ " AND con.contype = 'f' AND pkic.relkind = 'i' ";
+ " AND con.contype = 'f' ";
/*
In version 11 we added Partitioned indexes indicated by relkind = 'I'
I could have done this using lower(relkind) = 'i' but chose to be explicit
for clarity
*/
if (!connection.haveMinimumServerVersion(ServerVersion.v11)) {
sql += "AND pkic.relkind = 'i' ";
} else {
sql += "AND (pkic.relkind = 'i' OR pkic.relkind = 'I')";
}
if (!connection.haveMinimumServerVersion(ServerVersion.v9_0)) {
sql += " AND con.oid = dep.objid AND pkic.oid = dep.refobjid AND dep.classid = 'pg_constraint'::regclass::oid AND dep.refclassid = 'pg_class'::regclass::oid ";
} else {
......
......@@ -3911,4 +3911,20 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
}
return sharedCalendar;
}
/**
* This is here to be used by metadata functions
* to make all column labels upper case.
* Because postgres folds columns to lower case in queries it will be easier
* to change the fields after the fact rather than try to coerce all the columns
* to upper case in the queries as this would require surrounding all columns with " and
* escaping them making them even harder to read than they are now.
* @return PgResultSet
*/
protected PgResultSet upperCaseFieldLabels() {
for (Field field: fields ) {
field.upperCaseLabel();
}
return this;
}
}
......@@ -16,13 +16,13 @@ public final class DriverInfo {
// Driver name
public static final String DRIVER_NAME = "PostgreSQL JDBC Driver";
public static final String DRIVER_SHORT_NAME = "PgJDBC";
public static final String DRIVER_VERSION = "42.2.19";
public static final String DRIVER_VERSION = "42.2.20";
public static final String DRIVER_FULL_NAME = DRIVER_NAME + " " + DRIVER_VERSION;
// Driver version
public static final int MAJOR_VERSION = 42;
public static final int MINOR_VERSION = 2;
public static final int PATCH_VERSION = 19;
public static final int PATCH_VERSION = 20;
// JDBC specification
public static final String JDBC_VERSION = "4.2";
......
......@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Implementation-Title: PostgreSQL JDBC Driver
Bundle-License: BSD-2-Clause
Automatic-Module-Name: org.postgresql.jdbc
Implementation-Version: 42.2.19
Implementation-Version: 42.2.20
Specification-Vendor: Oracle Corporation
Specification-Title: JDBC
Implementation-Vendor-Id: org.postgresql
......
/*
* Copyright (c) 2020, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.jdbc;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import org.postgresql.test.TestUtil;
import org.postgresql.test.util.rules.annotation.HaveMinimalServerVersion;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@HaveMinimalServerVersion("9.4")
public class ConnectionValidTest {
@Rule
public Timeout timeout = new Timeout(30, TimeUnit.SECONDS);
private static final int LOCAL_SHADOW_PORT = 9009;
private Connection connection;
private ConnectionBreaker connectionBreaker;
@Before
public void setUp() throws Exception {
final Properties shadowProperties = new Properties();
shadowProperties.setProperty(TestUtil.SERVER_HOST_PORT_PROP,
String.format("%s:%s", "localhost", LOCAL_SHADOW_PORT));
connectionBreaker = new ConnectionBreaker(LOCAL_SHADOW_PORT,
TestUtil.getServer(),
TestUtil.getPort());
connectionBreaker.acceptAsyncConnection();
connection = TestUtil.openDB(shadowProperties);
}
@After
public void tearDown() throws Exception {
connectionBreaker.close();
connection.close();
}
/**
* Tests if a connection is valid within 5 seconds.
* @throws Exception if a database exception occurs.
*/
@Test
public void testIsValid() throws Exception {
connectionBreaker.breakConnection();
boolean result = connection.isValid(5);
assertThat("Is connection valid?",
result,
equalTo(false)
);
}
private static final class ConnectionBreaker {
private final ExecutorService workers;
private final ServerSocket internalServer;
private final Socket pgSocket;
private boolean breakConnection;
/**
* Constructor of the forwarder for the PostgreSQL server.
*
* @param serverPort The forwarder server port.
* @param pgServer The PostgreSQL server address.
* @param pgPort The PostgreSQL server port.
* @throws Exception if anything goes wrong binding the server.
*/
ConnectionBreaker(final int serverPort, final String pgServer,
final int pgPort) throws Exception {
workers = Executors.newCachedThreadPool();
internalServer = new ServerSocket(serverPort);
pgSocket = new Socket(pgServer, pgPort);
breakConnection = false;
}
/**
* Starts to accept a asynchronous connection.
*
* @throws Exception if something goes wrong with the sockets.
*/
public void acceptAsyncConnection() throws Exception {
final InputStream pgServerInputStream = pgSocket.getInputStream();
final OutputStream pgServerOutputStream = pgSocket.getOutputStream();
// Future socket;
final Future<Socket> futureConnection = workers.submit(internalServer::accept);
// Forward reads;
workers.submit(() -> {
while (!breakConnection) {
final Socket conn = futureConnection.get();
int read = pgServerInputStream.read();
conn.getOutputStream().write(read);
}
return null;
});
// Forwards writes;
workers.submit(() -> {
while (!breakConnection) {
final Socket conn = futureConnection.get();
int read = conn.getInputStream().read();
pgServerOutputStream.write(read);
}
return null;
});
}
/**
* Breaks the forwarding.
*/
public void breakConnection() {
this.breakConnection = true;
}
/**
* Closes the sockets.
*/
public void close() throws Exception {
this.workers.shutdown();
this.workers.awaitTermination(5, TimeUnit.SECONDS);
this.internalServer.close();
this.pgSocket.close();
}
}
}
......@@ -810,7 +810,7 @@ public class DatabaseMetaDataTest {
@Test
public void testTableTypes() throws SQLException {
final List<String> expectedTableTypes = new ArrayList<String>(Arrays.asList("FOREIGN TABLE", "INDEX",
final List<String> expectedTableTypes = new ArrayList<String>(Arrays.asList("FOREIGN TABLE", "INDEX", "PARTITIONED INDEX",
"MATERIALIZED VIEW", "PARTITIONED TABLE", "SEQUENCE", "SYSTEM INDEX", "SYSTEM TABLE", "SYSTEM TOAST INDEX",
"SYSTEM TOAST TABLE", "SYSTEM VIEW", "TABLE", "TEMPORARY INDEX", "TEMPORARY SEQUENCE", "TEMPORARY TABLE",
"TEMPORARY VIEW", "TYPE", "VIEW"));
......@@ -829,7 +829,7 @@ public class DatabaseMetaDataTest {
rs.close();
Collections.sort(expectedTableTypes);
Collections.sort(foundTableTypes);
Assert.assertEquals("The table types received from DatabaseMetaData should match the 17 expected types",
Assert.assertEquals("The table types received from DatabaseMetaData should match the 18 expected types",
true, foundTableTypes.equals(expectedTableTypes));
}
......@@ -1336,11 +1336,15 @@ public class DatabaseMetaDataTest {
try {
stmt = con.createStatement();
stmt.execute(
"CREATE TABLE measurement (logdate date not null,peaktemp int,unitsales int ) PARTITION BY RANGE (logdate);");
"CREATE TABLE measurement (logdate date not null primary key,peaktemp int,unitsales int ) PARTITION BY RANGE (logdate);");
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getTables("", "", "measurement", new String[]{"PARTITIONED TABLE"});
assertTrue(rs.next());
assertEquals("measurement", rs.getString("table_name"));
rs.close();
rs = dbmd.getPrimaryKeys("", "", "measurement");
assertTrue(rs.next());
assertEquals("measurement_pkey", rs.getString(6));
} finally {
if (stmt != null) {
......@@ -1560,4 +1564,16 @@ public class DatabaseMetaDataTest {
stmt.close();
}
@Test
public void testUpperCaseMetaDataLabels() throws SQLException {
ResultSet rs = con.getMetaData().getTables(null, null, null, null);
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals("TABLE_CAT", rsmd.getColumnName(1));
assertEquals("TABLE_SCHEM", rsmd.getColumnName(2));
assertEquals("TABLE_NAME", rsmd.getColumnName(3));
assertEquals("TABLE_TYPE", rsmd.getColumnName(4));
assertEquals("REMARKS", rsmd.getColumnName(5));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment