diff --git a/src/main/java/net/snowflake/client/core/SFBaseStatement.java b/src/main/java/net/snowflake/client/core/SFBaseStatement.java index a2c15e27f..62d933b2e 100644 --- a/src/main/java/net/snowflake/client/core/SFBaseStatement.java +++ b/src/main/java/net/snowflake/client/core/SFBaseStatement.java @@ -50,6 +50,10 @@ public void addProperty(String propertyName, Object propertyValue) throws SFExce } } + public Map getStatementParameters() { + return statementParametersMap; + } + /** * Describe a statement. This is invoked when prepareStatement() occurs. SFStatementMetadata * should be returned by this action, which contains metadata such as the schema of the result. diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetSerializableV1.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetSerializableV1.java index 27d24b44d..764acdb9b 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetSerializableV1.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetSerializableV1.java @@ -572,6 +572,7 @@ public static SnowflakeResultSetSerializableV1 create( SessionUtil.getCommonParams(rootNode.path("data").path("parameters")); if (resultSetSerializable.parameters.isEmpty()) { resultSetSerializable.parameters = sfSession.getCommonParameters(); + resultSetSerializable.setStatemementLevelParameters(sfStatement.getStatementParameters()); } // initialize column metadata @@ -887,6 +888,18 @@ private static long initMemoryLimit(Map parameters) { return memoryLimit; } + /** + * If statement parameter values are available, set those values in the resultset list of + * parameters so they overwrite the session-level cached parameter values. + * + * @param stmtParamsMap + */ + private void setStatemementLevelParameters(Map stmtParamsMap) { + for (Map.Entry entry : stmtParamsMap.entrySet()) { + this.parameters.put(entry.getKey(), entry.getValue()); + } + } + /** * Setup all transient fields based on serialized fields and System Runtime. * diff --git a/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java b/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java index a19b211e7..47e02b17b 100644 --- a/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java @@ -1621,6 +1621,63 @@ public void testHTAPOptimizations() throws SQLException { } } + /** + * This tests that statement parameters are still used correctly when the HTAP optimization of + * removing all parameters is enabled. + * + * @throws SQLException + */ + @Test + @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) + public void testHTAPStatementParameterCaching() throws SQLException { + // Set the HTAP test parameter to true + try (Connection con = getSnowflakeAdminConnection()) { + Statement statement = con.createStatement(); + statement.execute( + "alter account " + + TestUtil.systemGetEnv("SNOWFLAKE_TEST_ACCOUNT") + + " set ENABLE_SNOW_654741_FOR_TESTING=true"); + } + Connection con = getConnection(); + Statement statement = con.createStatement(); + // Set up a test table with time, date, and timestamp values + statement.execute("create or replace table timetable (t1 time, t2 timestamp, t3 date)"); + statement.execute( + "insert into timetable values ('13:53:11', '2023-08-17 13:53:33', '2023-08-17')"); + // Set statement- level parameters that will affect the output (set output format params) + statement + .unwrap(SnowflakeStatement.class) + .setParameter("TIME_OUTPUT_FORMAT", "HH12:MI:SS.FF AM"); + statement.unwrap(SnowflakeStatement.class).setParameter("DATE_OUTPUT_FORMAT", "DD-MON-YYYY"); + statement + .unwrap(SnowflakeStatement.class) + .setParameter("TIMESTAMP_OUTPUT_FORMAT", "YYYY-MM-DD\"T\"HH24:MI:SS"); + ResultSet resultSet = statement.executeQuery("select * from timetable"); + resultSet.next(); + // Assert that the values match the format of the specified statement parameter output format + // values + assertEquals("01:53:11.000000000 PM", resultSet.getString(1)); + assertEquals("2023-08-17T13:53:33", resultSet.getString(2)); + assertEquals("17-Aug-2023", resultSet.getString(3)); + // Set a different statement parameter value for DATE_OUTPUT_FORMAT + statement.unwrap(SnowflakeStatement.class).setParameter("DATE_OUTPUT_FORMAT", "MM/DD/YYYY"); + resultSet = statement.executeQuery("select * from timetable"); + resultSet.next(); + // Verify it matches the new statement parameter specified output format + assertEquals("08/17/2023", resultSet.getString(3)); + statement.execute("drop table timetable if exists"); + statement.close(); + con.close(); + // cleanup + try (Connection con2 = getSnowflakeAdminConnection()) { + statement = con2.createStatement(); + statement.execute( + "alter account " + + TestUtil.systemGetEnv("SNOWFLAKE_TEST_ACCOUNT") + + " unset ENABLE_SNOW_654741_FOR_TESTING"); + } + } + @Test @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) public void testS3PutInGS() throws Throwable {