Skip to content

Commit

Permalink
NIFI-13529: Update the Calcite Connection properties to indicate that…
Browse files Browse the repository at this point in the history
… timezone is UTC timezone. We do this because we already take care to ensure that timestamps, etc. are normalized to UTC timezone before passing them in. We do not want the Avatica ResultSet then treating Timestamp objects as local timestamps. We want them treated as UTC timestamps.
  • Loading branch information
markap14 committed Jul 9, 2024
1 parent 5193436 commit 02bdd79
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ private CalciteConnection createConnection(final Properties properties) throws S
calciteProperties = properties;
}

// If not explicitly set, default timezone to UTC. We ensure that when we provide timestamps, we convert them to UTC. We don't want
// Calcite trying to convert them again.
calciteProperties.putIfAbsent("timeZone", "UTC");

final Connection sqlConnection = DriverManager.getConnection("jdbc:calcite:", calciteProperties);
final CalciteConnection connection = sqlConnection.unwrap(CalciteConnection.class);
connection.getRootSchema().setCacheEnabled(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -85,6 +87,25 @@ public void testAddFunction() throws SQLException, NoSuchMethodException, IOExce
}
}

@Test
public void testWithTimestamp() throws SQLException, IOException {
final String query = "SELECT * FROM CANNED_DATA";

try (final CalciteDatabase database = createNameTimestampDatabase();
final PreparedStatement stmt = database.getConnection().prepareStatement(query);
final ResultSet resultSet = stmt.executeQuery()) {

assertTrue(resultSet.next());

// We should get the same result whether we call getTimestamp() or getObject(). We should also get back the same original Long value.
final Timestamp timestamp = resultSet.getTimestamp(2);
assertEquals(timestamp, resultSet.getObject(2));
assertEquals(1704056400000L, timestamp.getTime());

assertFalse(resultSet.next());
}
}

public static class ToUpperCase {
public String invoke(final String value) {
return value.toUpperCase();
Expand Down Expand Up @@ -113,6 +134,25 @@ private CalciteDatabase createNameNumberDatabase() throws SQLException {
return database;
}

private CalciteDatabase createNameTimestampDatabase() throws SQLException {
final CalciteDatabase database = new CalciteDatabase();

final NiFiTableSchema tableSchema = new NiFiTableSchema(List.of(
new ColumnSchema("name", String.class, false),
new ColumnSchema("dob", Timestamp.class, false)
));

final List<Object[]> rows = new ArrayList<>();
rows.add(new Object[] {"Mark", new Timestamp(1704056400000L)});

final ListDataSource arrayListDataSource = new ListDataSource(tableSchema, rows);

final NiFiTable table = new NiFiTable("CANNED_DATA", arrayListDataSource, mock(ComponentLog.class));
database.addTable(table);

return database;
}


private static class ListDataSource implements ResettableDataSource {
private final NiFiTableSchema schema;
Expand Down

0 comments on commit 02bdd79

Please sign in to comment.