diff --git a/CHANGELOG.md b/CHANGELOG.md index b01b05fa..ee031daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ See [Partial writes](https://docs.influxdata.com/influxdb3/core/write-data/http-api/v3-write-lp/#partial-writes) for more. For InfluxDB Clustered version, set `useV2Api=true` for writing. +### Bug Fixes + +1. [#384](https://github.com/InfluxCommunity/influxdb3-java/pull/384): Always set `precision` to `nanosecond` when + writing Points. + ## 1.9.0 [2026-04-23] ### Features diff --git a/src/main/java/com/influxdb/v3/client/config/ClientConfig.java b/src/main/java/com/influxdb/v3/client/config/ClientConfig.java index 11021d6d..8acb1ade 100644 --- a/src/main/java/com/influxdb/v3/client/config/ClientConfig.java +++ b/src/main/java/com/influxdb/v3/client/config/ClientConfig.java @@ -53,7 +53,10 @@ *
  • authScheme - authentication scheme
  • *
  • organization - organization to be used for operations
  • *
  • database - database to be used for InfluxDB operations
  • - *
  • writePrecision - precision to use when writing points to InfluxDB
  • + *
  • writePrecision - precision to use when writing to InfluxDB. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server.
  • *
  • defaultTags - defaultTags added when writing points to InfluxDB
  • *
  • gzipThreshold - threshold when gzip compression is used for writing points to InfluxDB
  • *
  • writeNoSync - skip waiting for WAL persistence on write
  • @@ -547,8 +550,11 @@ public Builder database(@Nullable final String database) { * Sets the default precision to use for the timestamp of points * if no precision is specified in the write API call. * - * @param writePrecision default precision to use for the timestamp of points - * if no precision is specified in the write API call + * @param writePrecision default precision to use for the timestamp + * if no precision is specified in the write API call. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @return this */ @Nonnull diff --git a/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java b/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java index 3dc05155..5880549c 100644 --- a/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java +++ b/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java @@ -304,7 +304,14 @@ private void writeData(@Nonnull final List data, @Nonnull final WriteOpti + "or use default configuration at 'ClientConfig.database'."); } - WritePrecision precision = options.precisionSafe(config); + WritePrecision precision; + + if (isWritePoint(data)) { + // When writing Point(s), the timestamp is always converted to nanoseconds. + precision = WritePrecision.NS; + } else { + precision = options.precisionSafe(config); + } options.validate(config); String path; @@ -472,4 +479,13 @@ private byte[] gzipData(@Nonnull final byte[] data) throws IOException { return out.toByteArray(); } + + private boolean isWritePoint(@Nonnull final List data) { + for (T writeAble : data) { + if (writeAble instanceof Point) { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/influxdb/v3/client/write/WriteOptions.java b/src/main/java/com/influxdb/v3/client/write/WriteOptions.java index 00618ec1..3487709b 100644 --- a/src/main/java/com/influxdb/v3/client/write/WriteOptions.java +++ b/src/main/java/com/influxdb/v3/client/write/WriteOptions.java @@ -40,7 +40,9 @@ *
      *
    • database - specifies the database to be used for InfluxDB operations
    • *
    • organization - specifies the organization to be used for InfluxDB operations
    • - *
    • precision - specifies the precision to use for the timestamp of points
    • + *
    • precision - specifies the precision to use for timestamps in line protocol records. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; for those writes, the client + * always sends {@link WritePrecision#NS} precision to the server.
    • *
    • defaultTags - specifies tags to be added by default to all write operations using points.
    • *
    • tagOrder - specifies preferred tag order for point serialization.
    • *
    • noSync - skip waiting for WAL persistence on write
    • @@ -122,8 +124,11 @@ public static WriteOptions defaultWriteOptions() { * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. */ @@ -138,8 +143,11 @@ public WriteOptions(@Nullable final String database, * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param defaultTags Default tags to be added when writing points. @@ -156,8 +164,11 @@ public WriteOptions(@Nullable final String database, * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -185,8 +196,11 @@ public WriteOptions(@Nullable final Map headers) { * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param defaultTags Default tags to be added when writing points. @@ -207,8 +221,11 @@ public WriteOptions(@Nullable final String database, * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -232,8 +249,11 @@ public WriteOptions(@Nullable final String database, * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -263,8 +283,11 @@ public WriteOptions(@Nullable final String database, * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -305,8 +328,11 @@ public WriteOptions(@Nullable final String database, * * @param database The database to be used for InfluxDB operations. * If it is not specified then use {@link ClientConfig#getDatabase()}. - * @param precision The precision to use for the timestamp of points. + * @param precision The precision to use for the timestamp. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. diff --git a/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java b/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java index 4382b646..b635fceb 100644 --- a/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java +++ b/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java @@ -412,7 +412,10 @@ void writePointWithDefaultWriteOptionsCustomConfig() throws Exception { client.writePoint(point); } - checkWriteCalled("/api/v3/write_lp", "DB", "second", true, "true", null, true); + // When writing Point, precision sent to the server is always nanosecond + var expectedPrecision = "nanosecond"; + + checkWriteCalled("/api/v3/write_lp", "DB", expectedPrecision, true, "true", null, true); } @Test @@ -447,7 +450,47 @@ void writePointsWithDefaultWriteOptionsCustomConfig() throws Exception { client.writePoints(List.of(point)); } - checkWriteCalled("/api/v3/write_lp", "DB", "second", true, "true", null, true); + // When writing Point, precision sent to the server is always nanosecond + var expectedPrecision = "nanosecond"; + + checkWriteCalled("/api/v3/write_lp", "DB", expectedPrecision, true, "true", null, true); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("pointPrecisionIgnoredCases") + void pointWritesIgnoreWriteOptionsPrecision( + @Nonnull final String name, + @Nonnull final WritePrecision configuredPrecision, + final boolean manyPoints) throws Exception { + mockServer.enqueue(createResponse(200)); + ClientConfig cfg = new ClientConfig.Builder() + .host(baseURL) + .token("TOKEN".toCharArray()) + .database("DB") + .build(); + try (InfluxDBClient client = InfluxDBClient.getInstance(cfg)) { + Point point = new Point("mem"); + point.setTag("tag", "one"); + point.setField("value", 1.0); + WriteOptions options = new WriteOptions.Builder() + .precision(configuredPrecision) + .build(); + if (manyPoints) { + client.writePoints(List.of(point), options); + } else { + client.writePoint(point, options); + } + } + checkWriteCalled("/api/v3/write_lp", "DB", "nanosecond", true, null, null, false); + } + + private static Stream pointPrecisionIgnoredCases() { + return Stream.of( + Arguments.of("writePoint precision=S", WritePrecision.S, false), + Arguments.of("writePoint precision=MS", WritePrecision.MS, false), + Arguments.of("writePoints precision=S", WritePrecision.S, true), + Arguments.of("writePoints precision=US", WritePrecision.US, true) + ); } private void checkWriteCalled(final String expectedPath, final String expectedDB, diff --git a/src/test/java/com/influxdb/v3/client/integration/E2ETest.java b/src/test/java/com/influxdb/v3/client/integration/E2ETest.java index dc02f7da..cba42021 100644 --- a/src/test/java/com/influxdb/v3/client/integration/E2ETest.java +++ b/src/test/java/com/influxdb/v3/client/integration/E2ETest.java @@ -595,10 +595,43 @@ public void testMultipleQueries() throws Exception { } } } - - } + @EnabledIfEnvironmentVariable(named = "TESTING_INFLUXDB_URL", matches = ".*") + @EnabledIfEnvironmentVariable(named = "TESTING_INFLUXDB_TOKEN", matches = ".*") + @EnabledIfEnvironmentVariable(named = "TESTING_INFLUXDB_DATABASE", matches = ".*") + @Test + public void testWriteWithDifferentTimeUnit() throws Exception { + try (InfluxDBClient client = InfluxDBClient.getInstance( + System.getenv("TESTING_INFLUXDB_URL"), + System.getenv("TESTING_INFLUXDB_TOKEN").toCharArray(), + System.getenv("TESTING_INFLUXDB_DATABASE"), + null)) { + var writeOptions = new WriteOptions.Builder().precision(WritePrecision.MS).build(); + String measurement = "test_" + UUID.randomUUID(); + List points = List.of( + Point.measurement(measurement) + .setTag("type", "test") + .setFloatField("rads", 3.14) + .setIntegerField("life", 42) + .setTimestamp(Instant.now().toEpochMilli(), WritePrecision.MS), + Point.measurement(measurement) + .setTag("type", "test") + .setFloatField("rads", 3.14) + .setIntegerField("life", 12) + .setTimestamp(Instant.now().plusSeconds(1).getEpochSecond(), WritePrecision.S), + Point.measurement(measurement) + .setTag("type", "test") + .setFloatField("rads", 3.14) + .setIntegerField("life", 432) + .setTimestamp(Instant.now().plusSeconds(2).toEpochMilli() * 1000, WritePrecision.US) + ); + client.writePoints(points, writeOptions); + var results = client.queryPoints(String.format("select * from \"%s\"", measurement)) + .collect(Collectors.toList()); + Assertions.assertThat(results).hasSize(3); + } + } private void assertGetDataSuccess(@Nonnull final InfluxDBClient influxDBClient) { influxDBClient.writePoint(