From a67829165240a295fb11b7648c6b65d1784d6b75 Mon Sep 17 00:00:00 2001 From: Lexert19 Date: Sun, 29 Mar 2026 00:35:29 +0100 Subject: [PATCH 1/3] Add X-TimeZone header support to REST API (#17344) --- .../protocol/filter/AuthorizationFilter.java | 36 ++++- .../v2/impl/GrafanaApiServiceImpl.java | 10 +- .../protocol/v2/impl/RestApiServiceImpl.java | 9 +- .../iotdb/db/it/IoTDBRestServiceIT.java | 129 ++++++++++++++++++ 4 files changed, 176 insertions(+), 8 deletions(-) diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java index a62a402e3d293..6330e14645b90 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java @@ -39,6 +39,7 @@ import javax.ws.rs.ext.Provider; import java.io.IOException; +import java.time.DateTimeException; import java.time.ZoneId; import java.util.Base64; import java.util.UUID; @@ -88,6 +89,12 @@ public void filter(ContainerRequestContext containerRequestContext) throws IOExc if (user == null) { return; } + + ZoneId zoneId = parseTimeZone(containerRequestContext); + if (zoneId == null) { + return; + } + String sessionid = UUID.randomUUID().toString(); if (SESSION_MANAGER.getCurrSession() == null) { RestClientSession restClientSession = new RestClientSession(sessionid); @@ -97,7 +104,7 @@ public void filter(ContainerRequestContext containerRequestContext) throws IOExc SESSION_MANAGER.getCurrSession(), user.getUserId(), user.getUsername(), - ZoneId.systemDefault(), + zoneId, IoTDBConstant.ClientVersion.V_1_0); } BasicSecurityContext basicSecurityContext = @@ -147,6 +154,33 @@ private User checkLogin( return user; } + /** + * Parses the X-TimeZone header from the request. + * + * @param requestContext the incoming HTTP request + * @return the parsed ZoneId, or {@code null} if the header is invalid (the request is aborted) + */ + private ZoneId parseTimeZone(ContainerRequestContext requestContext) { + String timeZoneHeader = requestContext.getHeaderString("X-TimeZone"); + if (timeZoneHeader == null || timeZoneHeader.isEmpty()) { + return ZoneId.systemDefault(); + } + try { + return ZoneId.of(timeZoneHeader); + } catch (DateTimeException e) { + Response resp = + Response.status(Status.BAD_REQUEST) + .type(MediaType.APPLICATION_JSON) + .entity( + new ExecutionStatus() + .code(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode()) + .message("Invalid time zone: " + timeZoneHeader)) + .build(); + requestContext.abortWith(resp); + return null; + } + } + @Override public void filter( ContainerRequestContext requestContext, ContainerResponseContext responseContext) diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java index 5b120b9c1d7a3..b1f5f3f5238cf 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java @@ -91,8 +91,8 @@ public Response variables(SQL sql, SecurityContext securityContext) { try { RequestValidationHandler.validateSQL(sql); - Statement statement = - StatementGenerator.createStatement(sql.getSql(), ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + Statement statement = StatementGenerator.createStatement(sql.getSql(), zoneId); if (!(statement instanceof ShowStatement) && !(statement instanceof QueryStatement)) { return Response.ok() .entity( @@ -168,7 +168,8 @@ public Response expression(ExpressionRequest expressionRequest, SecurityContext sql += " " + expressionRequest.getControl(); } - Statement statement = StatementGenerator.createStatement(sql, ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + Statement statement = StatementGenerator.createStatement(sql, zoneId); Response response = authorizationHandler.checkAuthority(securityContext, statement); if (response != null) { @@ -232,7 +233,8 @@ public Response node(List requestBody, SecurityContext securityContext) // TODO: necessary to create a PartialPath PartialPath path = new PartialPath(Joiner.on(".").join(requestBody)); String sql = "show child paths " + path; - Statement statement = StatementGenerator.createStatement(sql, ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + Statement statement = StatementGenerator.createStatement(sql, zoneId); Response response = authorizationHandler.checkAuthority(securityContext, statement); if (response != null) { diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java index f6c42533a6231..c09fa0c45f423 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java @@ -270,7 +270,8 @@ public Response executeNonQueryStatement(SQL sql, SecurityContext securityContex boolean finish = false; try { RequestValidationHandler.validateSQL(sql); - statement = StatementGenerator.createStatement(sql.getSql(), ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + statement = StatementGenerator.createStatement(sql.getSql(), zoneId); if (statement == null) { return Response.ok() .entity( @@ -310,9 +311,10 @@ public Response executeNonQueryStatement(SQL sql, SecurityContext securityContex return Response.ok().entity(ExceptionHandler.tryCatchException(e)).build(); } finally { long costTime = System.nanoTime() - startTime; - if (statement != null) + if (statement != null) { CommonUtils.addStatementExecutionLatency( OperationType.EXECUTE_NON_QUERY_PLAN, statement.getType().name(), costTime); + } if (queryId != null) { if (finish) { long executionTime = COORDINATOR.getTotalExecutionTime(queryId); @@ -332,7 +334,8 @@ public Response executeQueryStatement(SQL sql, SecurityContext securityContext) boolean finish = false; try { RequestValidationHandler.validateSQL(sql); - statement = StatementGenerator.createStatement(sql.getSql(), ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + statement = StatementGenerator.createStatement(sql.getSql(), zoneId); if (statement == null) { return Response.ok() diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index 76a246149cd94..09561676582f0 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -26,6 +26,7 @@ import org.apache.iotdb.itbase.category.LocalStandaloneIT; import org.apache.iotdb.itbase.category.RemoteIT; import org.apache.iotdb.itbase.env.BaseEnv; +import org.apache.iotdb.rpc.TSStatusCode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.JsonObject; @@ -52,6 +53,8 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Base64; import java.util.List; @@ -2354,4 +2357,130 @@ public void queryDateAndBlobV2(CloseableHttpClient httpClient) { } } } + + @Test + public void testQueryWithValidTimeZoneHeaderV2() { + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + try { + HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/insertTablet"); + String insertJson = + "{\"timestamps\":[1774713387626],\"measurements\":[\"s3\"],\"data_types\":[\"INT32\"],\"values\":[[11]],\"is_aligned\":false,\"device\":\"root.sg25\"}"; + insertPost.setEntity(new StringEntity(insertJson, Charset.defaultCharset())); + try (CloseableHttpResponse resp = executeWithRetry(insertPost, httpClient)) { + assertEquals(200, resp.getStatusLine().getStatusCode()); + } + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); + httpPost.setHeader("X-TimeZone", "Europe/Warsaw"); + String sql = + "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + CloseableHttpResponse response = httpClient.execute(httpPost); + assertEquals(200, response.getStatusLine().getStatusCode()); + String message = EntityUtils.toString(response.getEntity(), "utf-8"); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + assertTrue(result.has("timestamps")); + assertTrue(result.getAsJsonArray("timestamps").size() > 0); + long expectedTimestamp = + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) + .toInstant() + .toEpochMilli(); + assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); + } catch (IOException e) { + fail(e.getMessage()); + } finally { + try { + httpClient.close(); + } catch (IOException e) { + } + } + } + + @Test + public void testNonQueryWithValidTimeZoneHeaderV2() throws Exception { + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + try { + nonQueryWithTimeZone( + httpClient, + "{\"sql\":\"CREATE TIMESERIES root.sg.d1.s1 WITH DATATYPE=INT32\"}", + "Europe/Warsaw"); + nonQueryWithTimeZone( + httpClient, + "{\"sql\":\"INSERT INTO root.sg.d1(time, s1) VALUES (2026-03-28T00:00:00, 123)\"}", + "Europe/Warsaw"); + + HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); + queryPost.setEntity( + new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg.d1\"}", StandardCharsets.UTF_8)); + try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { + String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + long expected = + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) + .toInstant() + .toEpochMilli(); + assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); + } + } finally { + try { + httpClient.close(); + } catch (IOException e) { + } + } + } + + @Test + public void testQueryWithInvalidTimeZoneHeaderV2() { + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); + httpPost.setHeader("X-TimeZone", "Invalid/Zone"); + String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + CloseableHttpResponse response = executeWithRetry(httpPost, httpClient); + assertEquals(400, response.getStatusLine().getStatusCode()); + String message = EntityUtils.toString(response.getEntity(), "utf-8"); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), result.get("code").getAsInt()); + assertTrue(result.get("message").getAsString().contains("Invalid time zone")); + } catch (IOException e) { + fail(e.getMessage()); + } finally { + try { + httpClient.close(); + } catch (IOException e) { + } + } + } + + private void nonQueryWithTimeZone(CloseableHttpClient httpClient, String json, String timeZone) { + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); + httpPost.setHeader("X-TimeZone", timeZone); + httpPost.setEntity(new StringEntity(json, StandardCharsets.UTF_8)); + try (CloseableHttpResponse response = executeWithRetry(httpPost, httpClient)) { + String message = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + assertEquals(200, result.get("code").getAsInt()); + } catch (IOException e) { + fail(e.getMessage()); + } + } + + private CloseableHttpResponse executeWithRetry(HttpPost httpPost, CloseableHttpClient httpClient) + throws IOException { + CloseableHttpResponse response = null; + for (int i = 0; i < 30; i++) { + try { + response = httpClient.execute(httpPost); + break; + } catch (Exception e) { + if (i == 29) throw e; + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + } + } + return response; + } } From a286e68bbe7694b977f343bab27c398b2a86ea42 Mon Sep 17 00:00:00 2001 From: Lexert19 Date: Fri, 3 Apr 2026 14:05:50 +0200 Subject: [PATCH 2/3] Support Time-Zone header and add examples for REST API --- .../java/org/apache/iotdb/HttpExample.java | 26 +++ .../java/org/apache/iotdb/HttpsExample.java | 27 +++ .../org/apache/iotdb/TableHttpExample.java | 30 ++++ .../org/apache/iotdb/TableHttpsExample.java | 30 ++++ .../protocol/filter/AuthorizationFilter.java | 10 +- .../table/v1/impl/RestApiServiceImpl.java | 4 +- .../v1/impl/GrafanaApiServiceImpl.java | 10 +- .../protocol/v1/impl/RestApiServiceImpl.java | 6 +- .../iotdb/db/it/IoTDBRestServiceIT.java | 162 ++++++++++-------- 9 files changed, 221 insertions(+), 84 deletions(-) diff --git a/example/rest-java-example/src/main/java/org/apache/iotdb/HttpExample.java b/example/rest-java-example/src/main/java/org/apache/iotdb/HttpExample.java index bccc2fd254949..dd9b2bdf831d5 100644 --- a/example/rest-java-example/src/main/java/org/apache/iotdb/HttpExample.java +++ b/example/rest-java-example/src/main/java/org/apache/iotdb/HttpExample.java @@ -53,6 +53,7 @@ public static void main(String[] args) { httpExample.ping(); httpExample.insertTablet(); httpExample.query(); + httpExample.queryWithTimeZone(); } public void ping() { @@ -138,4 +139,29 @@ public void query() { } } } + + public void queryWithTimeZone() { + CloseableHttpClient httpClient = SSLClient.getInstance().getHttpClient(); + CloseableHttpResponse response = null; + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:18080/rest/v1/query"); + String sql = "{\"sql\":\"select * from root.sg25 where time <= 2026-03-28T00:00:00\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + response = httpClient.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String message = EntityUtils.toString(responseEntity, UTF8); + ObjectMapper mapper = new ObjectMapper(); + LOGGER.info("message with time zone = {}", mapper.readValue(message, Map.class)); + } catch (IOException e) { + LOGGER.error("The query with time zone rest api failed", e); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + LOGGER.error("Response close error", e); + } + } + } } diff --git a/example/rest-java-example/src/main/java/org/apache/iotdb/HttpsExample.java b/example/rest-java-example/src/main/java/org/apache/iotdb/HttpsExample.java index a3dbbceafc7fe..2e5c167133bcd 100644 --- a/example/rest-java-example/src/main/java/org/apache/iotdb/HttpsExample.java +++ b/example/rest-java-example/src/main/java/org/apache/iotdb/HttpsExample.java @@ -52,6 +52,7 @@ public static void main(String[] args) { httpsExample.pingHttps(); httpsExample.insertTablet(); httpsExample.query(); + httpsExample.queryWithTimeZone(); } public void pingHttps() { @@ -138,4 +139,30 @@ public void query() { } } } + + public void queryWithTimeZone() { + CloseableHttpClient httpClient = SSLClient.getInstance().getHttpClient(); + CloseableHttpResponse response = null; + try { + HttpPost httpPost = getHttpPost("https://127.0.0.1:18080/rest/v1/query"); + httpPost.addHeader("Time-Zone", "+05:00"); + String sql = "{\"sql\":\"select * from root.sg25 where time <= 2026-03-28T00:00:00\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + response = httpClient.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String message = EntityUtils.toString(responseEntity, UTF8); + ObjectMapper mapper = new ObjectMapper(); + LOGGER.info("message with time zone = {}", mapper.readValue(message, Map.class)); + } catch (IOException e) { + LOGGER.error("Https query with time zone rest api failed", e); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + LOGGER.error("Response close error", e); + } + } + } } diff --git a/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpExample.java b/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpExample.java index b9651245d0206..c51ef67e6ad64 100644 --- a/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpExample.java +++ b/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpExample.java @@ -27,6 +27,8 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.charset.Charset; @@ -34,6 +36,7 @@ import java.util.Base64; public class TableHttpExample { + private static final Logger LOGGER = LoggerFactory.getLogger(TableHttpExample.class); private static final String UTF8 = "utf-8"; @@ -50,6 +53,7 @@ public static void main(String[] args) { httpExample.nonQuery(); httpExample.insertTablet(); httpExample.query(); + httpExample.queryWithTimeZone(); } public void ping() { @@ -220,4 +224,30 @@ public void query() { } } } + + public void queryWithTimeZone() { + CloseableHttpClient httpClient = SSLClient.getInstance().getHttpClient(); + CloseableHttpResponse response = null; + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:18080/rest/table/v1/query"); + httpPost.addHeader("Time-Zone", "+05:00"); + String sql = + "{\"database\":\"test\",\"sql\":\"select * from sg211 where time <= 2026-03-28T00:00:00\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + response = httpClient.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String message = EntityUtils.toString(responseEntity, UTF8); + LOGGER.info("message with time zone = {}", JsonParser.parseString(message).getAsJsonObject()); + } catch (IOException e) { + LOGGER.error("The query with time zone rest api failed", e); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + LOGGER.error("Response close error", e); + } + } + } } diff --git a/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpsExample.java b/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpsExample.java index 200dbf66fdbcb..181db2ae999d9 100644 --- a/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpsExample.java +++ b/example/rest-java-example/src/main/java/org/apache/iotdb/TableHttpsExample.java @@ -27,6 +27,8 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.charset.Charset; @@ -34,6 +36,7 @@ import java.util.Base64; public class TableHttpsExample { + private static final Logger LOGGER = LoggerFactory.getLogger(TableHttpsExample.class); private static final String UTF8 = "utf-8"; @@ -50,6 +53,7 @@ public static void main(String[] args) { httpExample.nonQuery(); httpExample.insertTablet(); httpExample.query(); + httpExample.queryWithTimeZone(); } public void ping() { @@ -220,4 +224,30 @@ public void query() { } } } + + public void queryWithTimeZone() { + CloseableHttpClient httpClient = SSLClient.getInstance().getHttpClient(); + CloseableHttpResponse response = null; + try { + HttpPost httpPost = getHttpPost("https://127.0.0.1:18080/rest/table/v1/query"); + httpPost.addHeader("Time-Zone", "+05:00"); + String sql = + "{\"database\":\"test\",\"sql\":\"select * from sg211 where time <= 2026-03-28T00:00:00\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + response = httpClient.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String message = EntityUtils.toString(responseEntity, UTF8); + LOGGER.info("message with time zone = {}", JsonParser.parseString(message).getAsJsonObject()); + } catch (IOException e) { + LOGGER.error("The query with time zone rest api failed", e); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + LOGGER.error("Response close error", e); + } + } + } } diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java index 6330e14645b90..e274734cb3eda 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java @@ -90,7 +90,7 @@ public void filter(ContainerRequestContext containerRequestContext) throws IOExc return; } - ZoneId zoneId = parseTimeZone(containerRequestContext); + ZoneId zoneId = resolveTimeZone(containerRequestContext); if (zoneId == null) { return; } @@ -155,13 +155,13 @@ private User checkLogin( } /** - * Parses the X-TimeZone header from the request. + * Resolves the Time-Zone header from the request. * * @param requestContext the incoming HTTP request - * @return the parsed ZoneId, or {@code null} if the header is invalid (the request is aborted) + * @return the resolved ZoneId, or {@code null} if the header is invalid (the request is aborted) */ - private ZoneId parseTimeZone(ContainerRequestContext requestContext) { - String timeZoneHeader = requestContext.getHeaderString("X-TimeZone"); + private ZoneId resolveTimeZone(ContainerRequestContext requestContext) { + String timeZoneHeader = requestContext.getHeaderString("Time-Zone"); if (timeZoneHeader == null || timeZoneHeader.isEmpty()) { return ZoneId.systemDefault(); } diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java index b35e9d27f595c..e66cb88a6e144 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java @@ -51,7 +51,6 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; -import java.time.ZoneId; import java.util.List; import java.util.Optional; @@ -287,7 +286,8 @@ private Statement createStatement( } clientSession.setSqlDialect(IClientSession.SqlDialect.TABLE); - return relationSqlParser.createStatement(sql.getSql(), ZoneId.systemDefault(), clientSession); + return relationSqlParser.createStatement( + sql.getSql(), clientSession.getZoneId(), clientSession); } private Response validateStatement(Statement statement, boolean userQuery) { diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java index 0db4cd06c669f..2fa8c755eea45 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java @@ -91,8 +91,8 @@ public Response variables(SQL sql, SecurityContext securityContext) { try { RequestValidationHandler.validateSQL(sql); - Statement statement = - StatementGenerator.createStatement(sql.getSql(), ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + Statement statement = StatementGenerator.createStatement(sql.getSql(), zoneId); if (!(statement instanceof ShowStatement) && !(statement instanceof QueryStatement)) { return Response.ok() .entity( @@ -168,7 +168,8 @@ public Response expression(ExpressionRequest expressionRequest, SecurityContext sql += " " + expressionRequest.getControl(); } - Statement statement = StatementGenerator.createStatement(sql, ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + Statement statement = StatementGenerator.createStatement(sql, zoneId); Response response = authorizationHandler.checkAuthority(securityContext, statement); if (response != null) { @@ -232,7 +233,8 @@ public Response node(List requestBody, SecurityContext securityContext) // TODO: necessary to create a partial path? PartialPath path = new PartialPath(Joiner.on(".").join(requestBody)); String sql = "show child paths " + path; - Statement statement = StatementGenerator.createStatement(sql, ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + Statement statement = StatementGenerator.createStatement(sql, zoneId); Response response = authorizationHandler.checkAuthority(securityContext, statement); if (response != null) { diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java index 329ac47034bdb..df02cc8e5b6f9 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java @@ -87,7 +87,8 @@ public Response executeNonQueryStatement(SQL sql, SecurityContext securityContex Statement statement = null; try { RequestValidationHandler.validateSQL(sql); - statement = StatementGenerator.createStatement(sql.getSql(), ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + statement = StatementGenerator.createStatement(sql.getSql(), zoneId); if (statement == null) { return Response.ok() .entity( @@ -177,7 +178,8 @@ public Response executeQueryStatement(SQL sql, SecurityContext securityContext) Statement statement = null; try { RequestValidationHandler.validateSQL(sql); - statement = StatementGenerator.createStatement(sql.getSql(), ZoneId.systemDefault()); + ZoneId zoneId = SESSION_MANAGER.getCurrSession().getZoneId(); + statement = StatementGenerator.createStatement(sql.getSql(), zoneId); if (statement == null) { return Response.ok() .entity( diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index 09561676582f0..d96d1ec2ddb92 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -477,6 +477,9 @@ public void insertAndQuery() { listUser(httpClient); selectCount(httpClient); selectLast(httpClient); + queryWithValidTimeZoneHeader(httpClient); + nonQueryWithValidTimeZoneHeader(httpClient); + queryWithInvalidTimeZoneHeader(httpClient); queryV2(httpClient); queryGroupByLevelV2(httpClient); @@ -497,6 +500,9 @@ public void insertAndQuery() { listUserV2(httpClient); selectCountV2(httpClient); selectLastV2(httpClient); + queryWithValidTimeZoneHeaderV2(httpClient); + nonQueryWithValidTimeZoneHeaderV2(httpClient); + queryWithInvalidTimeZoneHeaderV2(httpClient); perData(httpClient); List insertTablet_right_json_list = new ArrayList<>(); List insertTablet_error_json_list = new ArrayList<>(); @@ -2358,19 +2364,63 @@ public void queryDateAndBlobV2(CloseableHttpClient httpClient) { } } - @Test - public void testQueryWithValidTimeZoneHeaderV2() { - CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + public void queryWithValidTimeZoneHeader(CloseableHttpClient httpClient) { + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/query"); + httpPost.setHeader("Time-Zone", "+05:00"); + String sql = + "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + CloseableHttpResponse response = httpClient.execute(httpPost); + assertEquals(200, response.getStatusLine().getStatusCode()); + String message = EntityUtils.toString(response.getEntity(), "utf-8"); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + assertTrue(result.has("timestamps")); + assertTrue(result.getAsJsonArray("timestamps").size() > 0); + long expectedTimestamp = + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")).toInstant().toEpochMilli(); + assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); + } catch (IOException e) { + fail(e.getMessage()); + } + } + + public void nonQueryWithValidTimeZoneHeader(CloseableHttpClient httpClient) { try { - HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/insertTablet"); - String insertJson = - "{\"timestamps\":[1774713387626],\"measurements\":[\"s3\"],\"data_types\":[\"INT32\"],\"values\":[[11]],\"is_aligned\":false,\"device\":\"root.sg25\"}"; - insertPost.setEntity(new StringEntity(insertJson, Charset.defaultCharset())); - try (CloseableHttpResponse resp = executeWithRetry(insertPost, httpClient)) { - assertEquals(200, resp.getStatusLine().getStatusCode()); + HttpPost createPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/nonQuery"); + nonQuery( + httpClient, + "{\"sql\":\"CREATE TIMESERIES root.sg_tz.d1.s1 WITH DATATYPE=INT32\"}", + createPost); + + HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/nonQuery"); + insertPost.setHeader("Time-Zone", "+05:00"); + nonQuery( + httpClient, + "{\"sql\":\"INSERT INTO root.sg_tz.d1(time, s1) VALUES (2026-03-28T00:00:00, 123)\"}", + insertPost); + + HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/query"); + queryPost.setEntity( + new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg_tz.d1\"}", StandardCharsets.UTF_8)); + try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { + String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + long expected = + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")) + .toInstant() + .toEpochMilli(); + assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); } + } catch (IOException e) { + fail(e.getMessage()); + } + } + + public void queryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) { + try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); - httpPost.setHeader("X-TimeZone", "Europe/Warsaw"); + httpPost.setHeader("Time-Zone", "+05:00"); String sql = "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); @@ -2381,62 +2431,52 @@ public void testQueryWithValidTimeZoneHeaderV2() { assertTrue(result.has("timestamps")); assertTrue(result.getAsJsonArray("timestamps").size() > 0); long expectedTimestamp = - ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) - .toInstant() - .toEpochMilli(); + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")).toInstant().toEpochMilli(); assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); } catch (IOException e) { fail(e.getMessage()); - } finally { - try { - httpClient.close(); - } catch (IOException e) { - } } } - @Test - public void testNonQueryWithValidTimeZoneHeaderV2() throws Exception { - CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + public void nonQueryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) { try { - nonQueryWithTimeZone( + HttpPost createPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); + nonQuery( httpClient, - "{\"sql\":\"CREATE TIMESERIES root.sg.d1.s1 WITH DATATYPE=INT32\"}", - "Europe/Warsaw"); - nonQueryWithTimeZone( + "{\"sql\":\"CREATE TIMESERIES root.sg_tz.d2.s1 WITH DATATYPE=INT32\"}", + createPost); + + HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); + insertPost.setHeader("Time-Zone", "+05:00"); + nonQuery( httpClient, - "{\"sql\":\"INSERT INTO root.sg.d1(time, s1) VALUES (2026-03-28T00:00:00, 123)\"}", - "Europe/Warsaw"); + "{\"sql\":\"INSERT INTO root.sg_tz.d2(time, s1) VALUES (2026-03-28T00:00:00, 123)\"}", + insertPost); HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); queryPost.setEntity( - new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg.d1\"}", StandardCharsets.UTF_8)); + new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg_tz.d2\"}", StandardCharsets.UTF_8)); try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); long expected = - ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")) .toInstant() .toEpochMilli(); assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); } - } finally { - try { - httpClient.close(); - } catch (IOException e) { - } + } catch (IOException e) { + fail(e.getMessage()); } } - @Test - public void testQueryWithInvalidTimeZoneHeaderV2() { - CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + public void queryWithInvalidTimeZoneHeader(CloseableHttpClient httpClient) { try { - HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); - httpPost.setHeader("X-TimeZone", "Invalid/Zone"); + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/query"); + httpPost.setHeader("Time-Zone", "Invalid/Zone"); String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); - CloseableHttpResponse response = executeWithRetry(httpPost, httpClient); + CloseableHttpResponse response = httpClient.execute(httpPost); assertEquals(400, response.getStatusLine().getStatusCode()); String message = EntityUtils.toString(response.getEntity(), "utf-8"); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); @@ -2444,43 +2484,23 @@ public void testQueryWithInvalidTimeZoneHeaderV2() { assertTrue(result.get("message").getAsString().contains("Invalid time zone")); } catch (IOException e) { fail(e.getMessage()); - } finally { - try { - httpClient.close(); - } catch (IOException e) { - } } } - private void nonQueryWithTimeZone(CloseableHttpClient httpClient, String json, String timeZone) { - HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); - httpPost.setHeader("X-TimeZone", timeZone); - httpPost.setEntity(new StringEntity(json, StandardCharsets.UTF_8)); - try (CloseableHttpResponse response = executeWithRetry(httpPost, httpClient)) { - String message = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + public void queryWithInvalidTimeZoneHeaderV2(CloseableHttpClient httpClient) { + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); + httpPost.setHeader("Time-Zone", "Invalid/Zone"); + String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + CloseableHttpResponse response = httpClient.execute(httpPost); + assertEquals(400, response.getStatusLine().getStatusCode()); + String message = EntityUtils.toString(response.getEntity(), "utf-8"); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); - assertEquals(200, result.get("code").getAsInt()); + assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), result.get("code").getAsInt()); + assertTrue(result.get("message").getAsString().contains("Invalid time zone")); } catch (IOException e) { fail(e.getMessage()); } } - - private CloseableHttpResponse executeWithRetry(HttpPost httpPost, CloseableHttpClient httpClient) - throws IOException { - CloseableHttpResponse response = null; - for (int i = 0; i < 30; i++) { - try { - response = httpClient.execute(httpPost); - break; - } catch (Exception e) { - if (i == 29) throw e; - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - throw new RuntimeException(ex); - } - } - } - return response; - } } From f0c638eb75c89daa195fa31bd81d2835c8e90430 Mon Sep 17 00:00:00 2001 From: Lexert19 Date: Fri, 3 Apr 2026 19:50:20 +0200 Subject: [PATCH 3/3] fix test resource leaks --- .../iotdb/db/it/IoTDBRestServiceIT.java | 106 ++++++++++++++---- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index d96d1ec2ddb92..32a8cb861496e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -2365,13 +2365,14 @@ public void queryDateAndBlobV2(CloseableHttpClient httpClient) { } public void queryWithValidTimeZoneHeader(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/query"); httpPost.setHeader("Time-Zone", "+05:00"); String sql = "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); - CloseableHttpResponse response = httpClient.execute(httpPost); + response = httpClient.execute(httpPost); assertEquals(200, response.getStatusLine().getStatusCode()); String message = EntityUtils.toString(response.getEntity(), "utf-8"); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); @@ -2381,11 +2382,22 @@ public void queryWithValidTimeZoneHeader(CloseableHttpClient httpClient) { ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")).toInstant().toEpochMilli(); assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); } catch (IOException e) { + e.printStackTrace(); fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } } } public void nonQueryWithValidTimeZoneHeader(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; try { HttpPost createPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/nonQuery"); nonQuery( @@ -2403,28 +2415,37 @@ public void nonQueryWithValidTimeZoneHeader(CloseableHttpClient httpClient) { HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/query"); queryPost.setEntity( new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg_tz.d1\"}", StandardCharsets.UTF_8)); - try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { - String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); - JsonObject result = JsonParser.parseString(message).getAsJsonObject(); - long expected = - ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")) - .toInstant() - .toEpochMilli(); - assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); - } + response = httpClient.execute(queryPost); + String message = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + long expected = + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")).toInstant().toEpochMilli(); + assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); + } catch (IOException e) { + e.printStackTrace(); fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } } } public void queryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); httpPost.setHeader("Time-Zone", "+05:00"); String sql = "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); - CloseableHttpResponse response = httpClient.execute(httpPost); + response = httpClient.execute(httpPost); assertEquals(200, response.getStatusLine().getStatusCode()); String message = EntityUtils.toString(response.getEntity(), "utf-8"); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); @@ -2434,11 +2455,22 @@ public void queryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) { ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")).toInstant().toEpochMilli(); assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); } catch (IOException e) { + e.printStackTrace(); fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } } } public void nonQueryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; try { HttpPost createPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); nonQuery( @@ -2456,51 +2488,81 @@ public void nonQueryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) { HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); queryPost.setEntity( new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg_tz.d2\"}", StandardCharsets.UTF_8)); - try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { - String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); - JsonObject result = JsonParser.parseString(message).getAsJsonObject(); - long expected = - ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")) - .toInstant() - .toEpochMilli(); - assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); - } + response = httpClient.execute(queryPost); + String message = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); + long expected = + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("+05:00")).toInstant().toEpochMilli(); + assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); + } catch (IOException e) { + e.printStackTrace(); fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } } } public void queryWithInvalidTimeZoneHeader(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v1/query"); httpPost.setHeader("Time-Zone", "Invalid/Zone"); String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); - CloseableHttpResponse response = httpClient.execute(httpPost); + response = httpClient.execute(httpPost); assertEquals(400, response.getStatusLine().getStatusCode()); String message = EntityUtils.toString(response.getEntity(), "utf-8"); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), result.get("code").getAsInt()); assertTrue(result.get("message").getAsString().contains("Invalid time zone")); } catch (IOException e) { + e.printStackTrace(); fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } } } public void queryWithInvalidTimeZoneHeaderV2(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); httpPost.setHeader("Time-Zone", "Invalid/Zone"); String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); - CloseableHttpResponse response = httpClient.execute(httpPost); + response = httpClient.execute(httpPost); assertEquals(400, response.getStatusLine().getStatusCode()); String message = EntityUtils.toString(response.getEntity(), "utf-8"); JsonObject result = JsonParser.parseString(message).getAsJsonObject(); assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), result.get("code").getAsInt()); assertTrue(result.get("message").getAsString().contains("Invalid time zone")); } catch (IOException e) { + e.printStackTrace(); fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } } } }