This is an automated email from the git hooks/post-receive script. ebourg-guest pushed a commit to annotated tag REL9_3_1102 in repository libpostgresql-jdbc-java.
commit e3b821fc20eed5658fdb771f2797adde8256d6f7 Author: Jeremy Whiting <[email protected]> Date: Wed Jan 22 19:06:31 2014 +0000 Added feature to disable column name sanitiser with a new property. Added test cases for existing default behaviour along with tests for behaviour when sanitiser is disabled. Can be configured via Driver or DataSource configuration property. --- org/postgresql/Driver.java.in | 4 +- org/postgresql/core/BaseConnection.java | 5 + org/postgresql/ds/common/BaseDataSource.java | 24 +++- org/postgresql/jdbc2/AbstractJdbc2Connection.java | 13 ++ org/postgresql/jdbc2/AbstractJdbc2ResultSet.java | 19 ++- org/postgresql/test/TestUtil.java | 24 ++++ .../test/jdbc2/ColumnSanitiserDisabledTest.java | 133 +++++++++++++++++++++ .../test/jdbc2/ColumnSanitiserEnabledTest.java | 126 +++++++++++++++++++ org/postgresql/test/jdbc2/Jdbc2TestSuite.java | 2 + .../optional/CaseOptimiserDataSourceTest.java | 116 ++++++++++++++++++ .../test/jdbc2/optional/OptionalTestSuite.java | 1 + 11 files changed, 462 insertions(+), 5 deletions(-) diff --git a/org/postgresql/Driver.java.in b/org/postgresql/Driver.java.in index 7a16026..25a16e2 100644 --- a/org/postgresql/Driver.java.in +++ b/org/postgresql/Driver.java.in @@ -478,7 +478,9 @@ public class Driver implements java.sql.Driver { "kerberosServerName", Boolean.FALSE, "The Kerberos service name to use when authenticating with GSSAPI. This is equivalent to libpq's PGKRBSRVNAME environment variable." }, { "jaasApplicationName", Boolean.FALSE, - "Specifies the name of the JAAS system or application login configuration." } + "Specifies the name of the JAAS system or application login configuration." }, + { "disableColumnSanitiser", Boolean.FALSE, + "Enable optimization that disables column name sanitiser." } }; /** diff --git a/org/postgresql/core/BaseConnection.java b/org/postgresql/core/BaseConnection.java index 6373d53..fb27867 100644 --- a/org/postgresql/core/BaseConnection.java +++ b/org/postgresql/core/BaseConnection.java @@ -154,4 +154,9 @@ public interface BaseConnection extends PGConnection, Connection * @return True for binary transfer, false for text transfer. */ public boolean binaryTransferSend(int oid); + + /** + * Return whether to disable column name sanitization. + */ + public boolean isColumnSanitiserDisabled(); } diff --git a/org/postgresql/ds/common/BaseDataSource.java b/org/postgresql/ds/common/BaseDataSource.java index 514620c..3ab97dc 100644 --- a/org/postgresql/ds/common/BaseDataSource.java +++ b/org/postgresql/ds/common/BaseDataSource.java @@ -65,7 +65,8 @@ public abstract class BaseDataSource implements Referenceable private int protocolVersion = 0; private String applicationName; private String stringType=null; - private boolean logLevelSet = false; + private boolean logLevelSet = false; + private boolean disableColumnSanitiser = false; /** * Gets a connection to the PostgreSQL database. The database is identified by the @@ -499,6 +500,22 @@ public abstract class BaseDataSource implements Referenceable { this.stringType = stringType; } + + /** + * Returns the state of column sanitiser optimisation. + * @return boolean is optimisation enabled + */ + public boolean isColumnSanitiserDisabled() { + return disableColumnSanitiser; + } + + /** + * Set the state of column sanitiser optimisation. + * @param boolean new optimisation state + */ + public void setDisableColumnSanitiser(boolean disableColumnSanitiser) { + this.disableColumnSanitiser = disableColumnSanitiser; + } /** * Generates a DriverManager URL from the other properties supplied. @@ -555,6 +572,7 @@ public abstract class BaseDataSource implements Referenceable if (binaryTransferDisable != null) { sb.append("&binaryTransferDisable=").append(binaryTransferDisable); } + sb.append("&disableColumnSanitiser=").append(disableColumnSanitiser); return sb.toString(); } @@ -583,6 +601,7 @@ public abstract class BaseDataSource implements Referenceable applicationName = p.getProperty("ApplicationName"); stringType = p.getProperty("stringtype"); binaryTransfer = Boolean.parseBoolean(p.getProperty("binaryTransfer")); + disableColumnSanitiser = Boolean.parseBoolean(p.getProperty("disableColumnSanitiser")); } /** @@ -653,6 +672,7 @@ public abstract class BaseDataSource implements Referenceable { ref.add(new StringRefAddr("ApplicationName", applicationName)); } + ref.add(new StringRefAddr("disableColumnSanitiser", Boolean.toString(disableColumnSanitiser))); return ref; } @@ -682,6 +702,7 @@ public abstract class BaseDataSource implements Referenceable out.writeObject(binaryTransferEnable); out.writeObject(binaryTransferDisable); out.writeBoolean(logLevelSet); + out.writeBoolean(disableColumnSanitiser); } protected void readBaseObject(ObjectInputStream in) throws IOException, ClassNotFoundException @@ -709,6 +730,7 @@ public abstract class BaseDataSource implements Referenceable binaryTransferEnable = (String)in.readObject(); binaryTransferDisable = (String)in.readObject(); logLevelSet = in.readBoolean(); + disableColumnSanitiser = in.readBoolean(); } public void initializeFrom(BaseDataSource source) throws IOException, ClassNotFoundException { diff --git a/org/postgresql/jdbc2/AbstractJdbc2Connection.java b/org/postgresql/jdbc2/AbstractJdbc2Connection.java index 48a5260..c84de44 100644 --- a/org/postgresql/jdbc2/AbstractJdbc2Connection.java +++ b/org/postgresql/jdbc2/AbstractJdbc2Connection.java @@ -58,6 +58,8 @@ public abstract class AbstractJdbc2Connection implements BaseConnection private final Query rollbackQuery; private TypeInfo _typeCache; + + private boolean disableColumnSanitiser = false; // Default statement prepare threshold. protected int prepareThreshold; @@ -260,6 +262,8 @@ public abstract class AbstractJdbc2Connection implements BaseConnection openStackTrace = new Throwable("Connection was created at this point:"); enableDriverManagerLogging(); } + this.disableColumnSanitiser = Boolean.valueOf(info.getProperty("" + + "disableColumnSanitiser", Boolean.FALSE.toString())); } private Set<Integer> getOidSet(String oidList) throws PSQLException { @@ -1246,4 +1250,13 @@ public abstract class AbstractJdbc2Connection implements BaseConnection { return protoConnection.getBackendPID(); } + + public boolean isColumnSanitiserDisabled() { + return this.disableColumnSanitiser; + } + + public void setDisableColumnSanitiser(boolean disableColumnSanitiser) + { + this.disableColumnSanitiser = disableColumnSanitiser; + } } diff --git a/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java b/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java index edbfdb1..5c2c26f 100644 --- a/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java +++ b/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java @@ -25,6 +25,7 @@ import java.util.StringTokenizer; import java.util.TimeZone; import java.util.Calendar; import java.util.Locale; + import org.postgresql.core.*; import org.postgresql.largeobject.*; import org.postgresql.util.ByteConverter; @@ -2731,15 +2732,20 @@ public abstract class AbstractJdbc2ResultSet implements BaseResultSet, org.postg private int findColumnIndex(String columnName) { - if (columnNameIndexMap == null) + if (columnNameIndexMap == null) { columnNameIndexMap = new HashMap(fields.length * 2); // The JDBC spec says when you have duplicate columns names, // the first one should be returned. So load the map in // reverse order so the first ones will overwrite later ones. + boolean isSanitiserDisabled = connection.isColumnSanitiserDisabled(); for (int i = fields.length - 1; i >= 0; i--) { - columnNameIndexMap.put(fields[i].getColumnLabel().toLowerCase(Locale.US), new Integer(i + 1)); + if (isSanitiserDisabled){ + columnNameIndexMap.put(fields[i].getColumnLabel(), new Integer(i + 1)); + } else { + columnNameIndexMap.put(fields[i].getColumnLabel().toLowerCase(Locale.US), new Integer(i + 1)); + } } } @@ -2748,6 +2754,13 @@ public abstract class AbstractJdbc2ResultSet implements BaseResultSet, org.postg { return index.intValue(); } + + index = (Integer)columnNameIndexMap.get(columnName.toUpperCase(Locale.US)); + if (index != null) + { + columnNameIndexMap.put(columnName, index); + return index.intValue(); + } index = (Integer)columnNameIndexMap.get(columnName.toLowerCase(Locale.US)); if (index != null) @@ -2755,7 +2768,7 @@ public abstract class AbstractJdbc2ResultSet implements BaseResultSet, org.postg columnNameIndexMap.put(columnName, index); return index.intValue(); } - + return 0; } diff --git a/org/postgresql/test/TestUtil.java b/org/postgresql/test/TestUtil.java index 4c42aee..ab91549 100644 --- a/org/postgresql/test/TestUtil.java +++ b/org/postgresql/test/TestUtil.java @@ -531,4 +531,28 @@ public class TestUtil System.out.println(); } } + + /* + * Find the column for the given label. Only SQLExceptions + * for system or set-up problems are thrown. + * The PSQLState.UNDEFINED_COLUMN type exception is + * consumed to allow cleanup. Relying on the caller + * to detect if the column lookup was successful. + */ + public static int findColumn(PreparedStatement query, String label) throws SQLException + { + int returnValue = 0; + ResultSet rs = query.executeQuery(); + if (rs.next()) + { + try + { + returnValue = rs.findColumn(label); + } + catch (SQLException sqle) + {} //consume exception to allow cleanup of resource. + } + rs.close(); + return returnValue; + } } diff --git a/org/postgresql/test/jdbc2/ColumnSanitiserDisabledTest.java b/org/postgresql/test/jdbc2/ColumnSanitiserDisabledTest.java new file mode 100644 index 0000000..d3d9199 --- /dev/null +++ b/org/postgresql/test/jdbc2/ColumnSanitiserDisabledTest.java @@ -0,0 +1,133 @@ +/*------------------------------------------------------------------------- + * + * Copyright (c) 2004-2014, PostgreSQL Global Development Group + * + * + *------------------------------------------------------------------------- + */ +package org.postgresql.test.jdbc2; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.postgresql.core.BaseConnection; +import org.postgresql.test.TestUtil; + +/* + * This test suite will check the behaviour of the findColumnIndex + * method. This is testing the behaviour when sanitiser is disabled. + */ +public class ColumnSanitiserDisabledTest extends TestCase +{ + private Connection conn; + + public ColumnSanitiserDisabledTest(String name) + { + super(name); + } + + protected void setUp() throws Exception + { + Properties props = new Properties(); + props.setProperty("disableColumnSanitiser", Boolean.TRUE.toString()); + conn = TestUtil.openDB(props); + assertTrue(conn instanceof BaseConnection); + BaseConnection bc = (BaseConnection)conn; + assertTrue( + "Expected state [TRUE] of base connection configuration failed test." + , bc.isColumnSanitiserDisabled()); + /* Quoted columns will be stored with case preserved. Driver will + * receive column names as defined in db server. */ + TestUtil.createTable(conn, "allmixedup", + "id int primary key, \"DESCRIPTION\" varchar(40), \"fOo\" varchar(3)"); + Statement data = conn.createStatement(); + data.execute(TestUtil.insertSQL("allmixedup", + "1,'mixed case test', 'bar'")); + data.close(); + } + + protected void tearDown() throws Exception + { + TestUtil.dropTable(conn, "allmixedup"); + TestUtil.closeDB(conn); + System.setProperty("disableColumnSanitiser", "false"); + } + + /* + * Test cases checking different combinations of columns origination from + * database against application supplied column names. + */ + + public void testTableColumnLowerNowFindFindLowerCaseColumn() + throws SQLException + { + findColumn("id", true); + } + + public void testTableColumnLowerNowFindFindUpperCaseColumn() + throws SQLException + { + findColumn("ID", true); + } + + public void testTableColumnLowerNowFindFindMixedCaseColumn() + throws SQLException + { + findColumn("Id", false); + } + + public void testTableColumnUpperNowFindFindLowerCaseColumn() + throws SQLException + { + findColumn("description", true); + } + + public void testTableColumnUpperNowFindFindUpperCaseColumn() + throws SQLException + { + findColumn("DESCRIPTION", true); + } + + public void testTableColumnUpperNowFindFindMixedCaseColumn() + throws SQLException + { + findColumn("Description", false); + } + + public void testTableColumnMixedNowFindLowerCaseColumn() + throws SQLException + { + findColumn("foo", false); + } + + public void testTableColumnMixedNowFindFindUpperCaseColumn() + throws SQLException + { + findColumn("FOO", false); + } + + public void testTableColumnMixedNowFindFindMixedCaseColumn() + throws SQLException + { + findColumn("fOo", true); + } + + private void findColumn(String label, boolean failOnNotFound) + throws SQLException + { + PreparedStatement query = conn + .prepareStatement("select * from allmixedup"); + if (0 == TestUtil.findColumn(query, label) && failOnNotFound) + { + fail(String + .format("Expected to find the column with the label [%1$s].", + label)); + } + query.close(); + } +} diff --git a/org/postgresql/test/jdbc2/ColumnSanitiserEnabledTest.java b/org/postgresql/test/jdbc2/ColumnSanitiserEnabledTest.java new file mode 100644 index 0000000..3dd356b --- /dev/null +++ b/org/postgresql/test/jdbc2/ColumnSanitiserEnabledTest.java @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------- + * + * Copyright (c) 2004-2014, PostgreSQL Global Development Group + * + * + *------------------------------------------------------------------------- + */ +package org.postgresql.test.jdbc2; + +import org.postgresql.core.BaseConnection; +import org.postgresql.test.TestUtil; + +import junit.framework.TestCase; + +import java.sql.*; +import java.util.Properties; + +/* + * This test suite will check the behaviour of the findColumnIndex + * method. The tests will check the behaviour of the method when + * the sanitiser is enabled. Default behaviour of the driver. + */ +public class ColumnSanitiserEnabledTest extends TestCase +{ + private Connection conn; + + public ColumnSanitiserEnabledTest(String name) + { + super(name); + } + + protected void setUp() throws Exception + { + Properties props = new Properties(); + props.setProperty("disableColumnSanitiser", Boolean.FALSE.toString()); + conn = TestUtil.openDB(props); + assertTrue(conn instanceof BaseConnection); + BaseConnection bc = (BaseConnection)conn; + assertFalse("Expected state [FALSE] of base connection configuration failed test.", bc.isColumnSanitiserDisabled()); + TestUtil.createTable( conn,"allmixedup", + "id int primary key, \"DESCRIPTION\" varchar(40), \"fOo\" varchar(3)"); + Statement data = conn.createStatement(); + data.execute(TestUtil.insertSQL("allmixedup", + "1,'mixed case test', 'bar'")); + data.close(); + } + + protected void tearDown() throws Exception + { + TestUtil.dropTable(conn, "allmixedup"); + TestUtil.closeDB(conn); + } + + /* + * Test cases checking different combinations of columns origination from + * database against application supplied column names. + */ + + public void testTableColumnLowerNowFindFindLowerCaseColumn() + throws SQLException + { + findColumn("id", true); + } + + public void testTableColumnLowerNowFindFindUpperCaseColumn() + throws SQLException + { + findColumn("ID", true); + } + + public void testTableColumnLowerNowFindFindMixedCaseColumn() + throws SQLException + { + findColumn("Id", true); + } + + public void testTableColumnUpperNowFindFindLowerCaseColumn() + throws SQLException + { + findColumn("description", true); + } + + public void testTableColumnUpperNowFindFindUpperCaseColumn() + throws SQLException + { + findColumn("DESCRIPTION", true); + } + + public void testTableColumnUpperNowFindFindMixedCaseColumn() + throws SQLException + { + findColumn("Description", true); + } + + public void testTableColumnMixedNowFindLowerCaseColumn() + throws SQLException + { + findColumn("foo", true); + } + + public void testTableColumnMixedNowFindFindUpperCaseColumn() + throws SQLException + { + findColumn("FOO", true); + } + + public void testTableColumnMixedNowFindFindMixedCaseColumn() + throws SQLException + { + findColumn("fOo", true); + } + + private void findColumn(String label, boolean failOnNotFound) + throws SQLException + { + PreparedStatement query = conn + .prepareStatement("select * from allmixedup"); + if (0 == TestUtil.findColumn(query, label) && failOnNotFound) + { + fail(String + .format("Expected to find the column with the label [%1$s].", + label)); + } + query.close(); + } +} diff --git a/org/postgresql/test/jdbc2/Jdbc2TestSuite.java b/org/postgresql/test/jdbc2/Jdbc2TestSuite.java index 699aaab..732e498 100644 --- a/org/postgresql/test/jdbc2/Jdbc2TestSuite.java +++ b/org/postgresql/test/jdbc2/Jdbc2TestSuite.java @@ -42,6 +42,8 @@ public class Jdbc2TestSuite extends TestSuite suite.addTestSuite(DatabaseMetaDataPropertiesTest.class); suite.addTestSuite(SearchPathLookupTest.class); suite.addTestSuite(EncodingTest.class); + suite.addTestSuite(ColumnSanitiserDisabledTest.class); + suite.addTestSuite(ColumnSanitiserEnabledTest.class); // Connectivity/Protocols diff --git a/org/postgresql/test/jdbc2/optional/CaseOptimiserDataSourceTest.java b/org/postgresql/test/jdbc2/optional/CaseOptimiserDataSourceTest.java new file mode 100644 index 0000000..7413854 --- /dev/null +++ b/org/postgresql/test/jdbc2/optional/CaseOptimiserDataSourceTest.java @@ -0,0 +1,116 @@ +/*------------------------------------------------------------------------- + * + * Copyright (c) 2004-2014, PostgreSQL Global Development Group + * + * + *------------------------------------------------------------------------- + */ +package org.postgresql.test.jdbc2.optional; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.TestCase; + +import org.postgresql.core.BaseConnection; +import org.postgresql.ds.common.BaseDataSource; +import org.postgresql.jdbc2.optional.SimpleDataSource; +import org.postgresql.test.TestUtil; +/* + * DataSource test to ensure the BaseConnection is configured with column + * sanitiser disabled. + */ +public class CaseOptimiserDataSourceTest extends TestCase +{ + private BaseDataSource bds; + protected Connection conn; + + protected void initializeDataSource() + { + if (bds == null) + { + bds = new SimpleDataSource(); + setupDataSource(bds); + bds.setColumnSanitiserDisabled(true); + } + } + + public void setUp() throws SQLException + { + Connection conn = getDataSourceConnection(); + assertTrue(conn instanceof BaseConnection); + BaseConnection bc = (BaseConnection)conn; + assertTrue( + "Expected state [TRUE] of base connection configuration failed test." + , bc.isColumnSanitiserDisabled()); + Statement insert = conn.createStatement(); + TestUtil.createTable( conn, "allmixedup", + "id int primary key, \"DESCRIPTION\" varchar(40), \"fOo\" varchar(3)"); + insert.execute(TestUtil.insertSQL("allmixedup", + "1,'mixed case test', 'bar'")); + insert.close(); + conn.close(); + } + + @Override + public void tearDown() throws SQLException + { + Connection conn = getDataSourceConnection(); + Statement drop = conn.createStatement(); + drop.execute("drop table allmixedup"); + drop.close(); + conn.close(); + bds.setColumnSanitiserDisabled(false); + } + + /* + * Test to ensure a datasource can be configured with the column sanitiser + * optimisation. This test checks for a side effect of the sanitiser being + * disabled. The column is not expected to be found. + */ + public void testDataSourceDisabledSanitiserPropertySucceeds() + throws SQLException + { + String label = "FOO"; + PreparedStatement query = getDataSourceConnection().prepareStatement( + "select * from allmixedup"); + if (0 < TestUtil.findColumn(query, label)) + { + fail(String.format( + "Did not expect to find the column with the label [%1$s].", + label)); + } + query.close(); + } + + /** + * Gets a connection from the current BaseDataSource + */ + protected Connection getDataSourceConnection() throws SQLException + { + if (bds == null) + { + initializeDataSource(); + } + return bds.getConnection(); + } + + public static void setupDataSource(BaseDataSource bds) + { + bds.setServerName(TestUtil.getServer()); + bds.setPortNumber(TestUtil.getPort()); + bds.setDatabaseName(TestUtil.getDatabase()); + bds.setUser(TestUtil.getUser()); + bds.setPassword(TestUtil.getPassword()); + bds.setPrepareThreshold(TestUtil.getPrepareThreshold()); + bds.setLogLevel(TestUtil.getLogLevel()); + bds.setProtocolVersion(TestUtil.getProtocolVersion()); + } + + public CaseOptimiserDataSourceTest(String name) + { + super(name); + } +} diff --git a/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java b/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java index f4a7cc3..88e6af9 100644 --- a/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java +++ b/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java @@ -29,6 +29,7 @@ public class OptionalTestSuite extends TestSuite suite.addTestSuite(SimpleDataSourceTest.class); suite.addTestSuite(ConnectionPoolTest.class); suite.addTestSuite(PoolingDataSourceTest.class); + suite.addTestSuite(CaseOptimiserDataSourceTest.class); return suite; } } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/libpostgresql-jdbc-java.git _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

