|
74 | 74 | import static org.junit.Assert.assertFalse; |
75 | 75 | import static org.junit.Assert.assertNotNull; |
76 | 76 | import static org.junit.Assert.assertNull; |
| 77 | +import static org.junit.Assert.assertThrows; |
77 | 78 | import static org.junit.Assert.assertTrue; |
78 | 79 | import static org.junit.Assert.fail; |
79 | 80 |
|
@@ -390,6 +391,122 @@ public void testInsertNullIntoTime() { |
390 | 391 | } |
391 | 392 | } |
392 | 393 |
|
| 394 | + @Test |
| 395 | + public void testInsertUnsupportedTimeExpressions() throws SQLException { |
| 396 | + try (Connection connection = EnvFactory.getEnv().getTableConnection(); |
| 397 | + Statement statement = connection.createStatement()) { |
| 398 | + statement.execute("USE test"); |
| 399 | + statement.execute( |
| 400 | + "CREATE TABLE rejected_time_expression (device_id STRING TAG, value INT64 FIELD)"); |
| 401 | + statement.execute( |
| 402 | + "CREATE TABLE rejected_custom_time_expression " |
| 403 | + + "(device_id STRING TAG, event_time TIMESTAMP TIME, value INT64 FIELD)"); |
| 404 | + String[] expressions = {"1735660800000 + 1000", "?", "1.5", "true", "abs(1)"}; |
| 405 | + for (String expression : expressions) { |
| 406 | + for (String columns : new String[] {" (time, device_id, value)", ""}) { |
| 407 | + assertUnsupportedInsertExpression( |
| 408 | + statement, |
| 409 | + "INSERT INTO rejected_time_expression" |
| 410 | + + columns |
| 411 | + + " VALUES (" |
| 412 | + + expression |
| 413 | + + ", 'd1', 1)"); |
| 414 | + } |
| 415 | + } |
| 416 | + for (String sql : |
| 417 | + new String[] { |
| 418 | + "INSERT INTO rejected_time_expression (device_id, value, time) VALUES ('d1', 1, ?)", |
| 419 | + "INSERT INTO rejected_custom_time_expression (device_id, event_time, value) " |
| 420 | + + "VALUES ('d1', ?, 1)", |
| 421 | + "INSERT INTO rejected_custom_time_expression VALUES ('d1', ?, 1)", |
| 422 | + "INSERT INTO rejected_time_expression (time, device_id, value) " |
| 423 | + + "VALUES (1735660800000, 'd1', ?)", |
| 424 | + "INSERT INTO rejected_time_expression (time, device_id, value) " |
| 425 | + + "VALUES (1735660800000, 'valid', 1), (?, 'invalid', 2)", |
| 426 | + "INSERT INTO rejected_time_expression " |
| 427 | + + "VALUES (1735660800000, 'valid', 1), (?, 'invalid', 2)" |
| 428 | + }) { |
| 429 | + assertUnsupportedInsertExpression(statement, sql); |
| 430 | + } |
| 431 | + for (String sql : |
| 432 | + new String[] { |
| 433 | + "INSERT INTO rejected_time_expression (time, device_id, value) VALUES (NULL, 'd1', 1)", |
| 434 | + "INSERT INTO rejected_time_expression VALUES (NULL, 'd1', 1)" |
| 435 | + }) { |
| 436 | + SQLException exception = assertThrows(SQLException.class, () -> statement.execute(sql)); |
| 437 | + assertEquals(sql, TSStatusCode.SEMANTIC_ERROR.getStatusCode(), exception.getErrorCode()); |
| 438 | + assertTrue( |
| 439 | + exception.getMessage(), exception.getMessage().contains("Timestamp cannot be null")); |
| 440 | + } |
| 441 | + for (String table : |
| 442 | + new String[] {"rejected_time_expression", "rejected_custom_time_expression"}) { |
| 443 | + try (ResultSet resultSet = statement.executeQuery("SELECT count(*) FROM " + table)) { |
| 444 | + assertTrue(resultSet.next()); |
| 445 | + assertEquals(0, resultSet.getLong(1)); |
| 446 | + assertFalse(resultSet.next()); |
| 447 | + } |
| 448 | + } |
| 449 | + } |
| 450 | + } |
| 451 | + |
| 452 | + private static void assertUnsupportedInsertExpression(Statement statement, String sql) { |
| 453 | + SQLException exception = assertThrows(SQLException.class, () -> statement.execute(sql)); |
| 454 | + assertEquals(sql, TSStatusCode.SEMANTIC_ERROR.getStatusCode(), exception.getErrorCode()); |
| 455 | + String message = exception.getMessage(); |
| 456 | + assertTrue(message, message.contains("Unsupported expression:")); |
| 457 | + assertFalse(message, message.contains("ClassCastException")); |
| 458 | + assertFalse(message, message.contains("cannot be cast")); |
| 459 | + assertFalse(message, message.contains("org.apache.iotdb")); |
| 460 | + } |
| 461 | + |
| 462 | + @Test |
| 463 | + public void testInsertSupportedTimeValues() throws SQLException { |
| 464 | + try (Connection connection = EnvFactory.getEnv().getTableConnection(); |
| 465 | + Statement statement = connection.createStatement()) { |
| 466 | + statement.execute("USE test"); |
| 467 | + statement.execute( |
| 468 | + "CREATE TABLE supported_time_expression (device_id STRING TAG, value INT64 FIELD)"); |
| 469 | + String[] expressions = { |
| 470 | + "1735660800000", "'2025-01-01T00:00:00+08:00'", "NOW()", "NOW() + 1d", "NOW() - 1d" |
| 471 | + }; |
| 472 | + for (boolean explicitColumns : new boolean[] {true, false}) { |
| 473 | + for (int i = 0; i < expressions.length; i++) { |
| 474 | + String deviceId = "d" + explicitColumns + i; |
| 475 | + long before = System.currentTimeMillis(); |
| 476 | + statement.execute( |
| 477 | + "INSERT INTO supported_time_expression" |
| 478 | + + (explicitColumns ? " (time, device_id, value)" : "") |
| 479 | + + " VALUES (" |
| 480 | + + expressions[i] |
| 481 | + + ", '" |
| 482 | + + deviceId |
| 483 | + + "', " |
| 484 | + + i |
| 485 | + + ")"); |
| 486 | + long after = System.currentTimeMillis(); |
| 487 | + try (ResultSet resultSet = |
| 488 | + statement.executeQuery( |
| 489 | + "SELECT time, value FROM supported_time_expression WHERE device_id = '" |
| 490 | + + deviceId |
| 491 | + + "'")) { |
| 492 | + assertTrue(resultSet.next()); |
| 493 | + long timestamp = resultSet.getLong(1); |
| 494 | + if (i < 2) { |
| 495 | + assertEquals(1735660800000L, timestamp); |
| 496 | + } else { |
| 497 | + long offset = i == 3 ? 86400000L : i == 4 ? -86400000L : 0; |
| 498 | + // Allow clock skew between the test client and cluster nodes. |
| 499 | + assertTrue(timestamp >= before + offset - 10000); |
| 500 | + assertTrue(timestamp <= after + offset + 10000); |
| 501 | + } |
| 502 | + assertEquals(i, resultSet.getLong(2)); |
| 503 | + assertFalse(resultSet.next()); |
| 504 | + } |
| 505 | + } |
| 506 | + } |
| 507 | + } |
| 508 | + } |
| 509 | + |
393 | 510 | @Test |
394 | 511 | public void testInsertNaN() throws SQLException { |
395 | 512 | try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); |
|
0 commit comments