diff --git a/gradle.properties b/gradle.properties index 38783ef845..4f8f71eb12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ kotlin.parallel.tasks.in.project=true # This is version for PgJdbc itself # Note: it should not include "-SNAPSHOT" as it is automatically added by build.gradle.kts # Release version can be generated by using -Prelease or -Prc= arguments -pgjdbc.version=42.3.5-yb-3 +pgjdbc.version=42.3.5-yb-4 # The options below configures the use of local clone (e.g. testing development versions) # You can pass un-comment it, or pass option -PlocalReleasePlugins, or -PlocalReleasePlugins= diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java index 4a9137d24c..a33fb3f635 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java @@ -1361,7 +1361,7 @@ public void refreshRow() throws SQLException { if (i > 1) { selectSQL.append(", "); } - selectSQL.append(pgmd.getBaseColumnName(i)); + Utils.escapeIdentifier(selectSQL, pgmd.getBaseColumnName(i)); } selectSQL.append(" from ").append(onlyTable).append(tableName).append(" where "); @@ -1371,7 +1371,8 @@ public void refreshRow() throws SQLException { for (int i = 0; i < numKeys; i++) { PrimaryKey primaryKey = primaryKeys.get(i); - selectSQL.append(primaryKey.name).append(" = ?"); + Utils.escapeIdentifier(selectSQL, primaryKey.name); + selectSQL.append(" = ?"); if (i < numKeys - 1) { selectSQL.append(" and "); diff --git a/pgjdbc/src/main/java/org/postgresql/util/StreamWrapper.java b/pgjdbc/src/main/java/org/postgresql/util/StreamWrapper.java index ed44553d53..2be532498b 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/StreamWrapper.java +++ b/pgjdbc/src/main/java/org/postgresql/util/StreamWrapper.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; /** * Wrapper around a length-limited InputStream. @@ -51,7 +52,7 @@ public StreamWrapper(InputStream stream) throws PSQLException { if (memoryLength == -1) { final int diskLength; - final File tempFile = File.createTempFile(TEMP_FILE_PREFIX, null); + final File tempFile = Files.createTempFile(TEMP_FILE_PREFIX, ".tmp").toFile(); FileOutputStream diskOutputStream = new FileOutputStream(tempFile); diskOutputStream.write(rawData); try { 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 fbb3136c54..3556e997ca 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java @@ -118,6 +118,7 @@ ReplaceProcessingTest.class, ResultSetMetaDataTest.class, ResultSetTest.class, + ResultSetRefreshTest.class, ReturningParserTest.class, SearchPathLookupTest.class, ServerCursorTest.class, diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetRefreshTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetRefreshTest.java new file mode 100644 index 0000000000..a4a9b61e17 --- /dev/null +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetRefreshTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.test.jdbc2; + +import static org.junit.Assert.assertTrue; + +import org.postgresql.test.TestUtil; + +import org.junit.Test; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class ResultSetRefreshTest extends BaseTest4 { + @Test + public void testWithDataColumnThatRequiresEscaping() throws Exception { + TestUtil.dropTable(con, "refresh_row_bad_ident"); + TestUtil.execute("CREATE TABLE refresh_row_bad_ident (id int PRIMARY KEY, \"1 FROM refresh_row_bad_ident; SELECT 2; SELECT *\" int)", con); + TestUtil.execute("INSERT INTO refresh_row_bad_ident (id) VALUES (1), (2), (3)", con); + + Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + ResultSet rs = stmt.executeQuery("SELECT * FROM refresh_row_bad_ident"); + assertTrue(rs.next()); + try { + rs.refreshRow(); + } catch (SQLException ex) { + throw new RuntimeException("ResultSet.refreshRow() did not handle escaping data column identifiers", ex); + } + rs.close(); + stmt.close(); + } + + @Test + public void testWithKeyColumnThatRequiresEscaping() throws Exception { + TestUtil.dropTable(con, "refresh_row_bad_ident"); + TestUtil.execute("CREATE TABLE refresh_row_bad_ident (\"my key\" int PRIMARY KEY)", con); + TestUtil.execute("INSERT INTO refresh_row_bad_ident VALUES (1), (2), (3)", con); + + Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + ResultSet rs = stmt.executeQuery("SELECT * FROM refresh_row_bad_ident"); + assertTrue(rs.next()); + try { + rs.refreshRow(); + } catch (SQLException ex) { + throw new RuntimeException("ResultSet.refreshRow() did not handle escaping key column identifiers", ex); + } + rs.close(); + stmt.close(); + } +}