diff --git a/src/main/java/org/moditect/jfranalytics/JfrSchema.java b/src/main/java/org/moditect/jfranalytics/JfrSchema.java index 4fd6298..50661e0 100644 --- a/src/main/java/org/moditect/jfranalytics/JfrSchema.java +++ b/src/main/java/org/moditect/jfranalytics/JfrSchema.java @@ -19,6 +19,7 @@ import java.lang.System.Logger.Level; import java.nio.file.Path; import java.sql.Timestamp; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -108,6 +109,9 @@ private static RelDataType getRelDataType(EventType eventType, ValueDescriptor f case "int": type = typeFactory.createJavaType(int.class); break; + case "boolean": + type = typeFactory.createJavaType(boolean.class); + break; case "long": if ("jdk.jfr.Timestamp".equals(field.getContentType())) { type = typeFactory.createJavaType(Timestamp.class); @@ -178,7 +182,12 @@ else if (recordedClassLoader.getName() != null) { // 3. further special cases else if (field.getAnnotation(Timespan.class) != null) { - return event -> event.getDuration(field.getName()).toNanos(); + return event -> { + Duration duration = event.getDuration(field.getName()); + // Long.MIN_VALUE is used as a sentinel value for absent values e.g. for jdk.GCConfiguration.pauseTarget + // TODO: handle nanos value overflow + return duration.getSeconds() == Long.MIN_VALUE ? Long.MIN_VALUE : duration.toNanos(); + }; } // 4. default pass-through diff --git a/src/test/java/org/moditect/jfranalytics/JfrSchemaFactoryTest.java b/src/test/java/org/moditect/jfranalytics/JfrSchemaFactoryTest.java index 6f3e3eb..26fa470 100644 --- a/src/test/java/org/moditect/jfranalytics/JfrSchemaFactoryTest.java +++ b/src/test/java/org/moditect/jfranalytics/JfrSchemaFactoryTest.java @@ -200,6 +200,33 @@ public void canRunSimpleSelectFromClassLoad() throws Exception { } } + @Test + public void canRunSimpleSelectFromGcConfiguration() throws Exception { + try (Connection connection = getConnection("gc-configuration.jfr")) { + PreparedStatement statement = connection.prepareStatement(""" + SELECT * + FROM "jfr"."jdk.GCConfiguration" + """); + + try (ResultSet rs = statement.executeQuery()) { + assertThat(rs.next()).isTrue(); + + assertThat(rs.getTimestamp(1)).isEqualTo(Timestamp.from(ZonedDateTime.parse("2021-12-28T16:13:32.114000000+01:00").toInstant())); + assertThat(rs.getString(2)).isEqualTo("G1New"); + assertThat(rs.getString(3)).isEqualTo("G1Old"); + assertThat(rs.getInt(4)).isEqualTo(10); + assertThat(rs.getInt(5)).isEqualTo(3); + assertThat(rs.getBoolean(6)).isTrue(); + assertThat(rs.getBoolean(7)).isFalse(); + assertThat(rs.getBoolean(8)).isFalse(); + assertThat(rs.getLong(9)).isEqualTo(Long.MIN_VALUE); + assertThat(rs.getInt(10)).isEqualTo(12); + + assertThat(rs.next()).isFalse(); + } + } + } + @Test public void canUseGetClassNameFunction() throws Exception { try (Connection connection = getConnection("class-loading.jfr")) { diff --git a/src/test/resources/gc-configuration.jfr b/src/test/resources/gc-configuration.jfr new file mode 100644 index 0000000..8edf568 Binary files /dev/null and b/src/test/resources/gc-configuration.jfr differ