diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiIDsWithAttributesTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiIDsWithAttributesTableIT.java index 4457055bd3ee..bdbe468bb1ba 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiIDsWithAttributesTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiIDsWithAttributesTableIT.java @@ -395,12 +395,12 @@ public void subQueryTest1() { String[] expectedHeader = new String[] {"time", "level", "device", "add_num"}; String[] retArray = new String[] { - "1970-01-01T00:00:00.100Z,l5,d1,9.0,", - "1971-01-01T00:00:01.000Z,l4,d1,6.0,", - "1971-01-01T00:00:10.000Z,l5,d1,8.0,", - "1971-04-26T18:01:40.000Z,l4,d1,14.0,", - "1971-08-20T11:33:20.000Z,l5,d1,16.0,", - "1970-01-01T00:00:00.080Z,l4,d2,10.0,", + "1970-01-01T00:00:00.100Z,l5,d1,9,", + "1971-01-01T00:00:01.000Z,l4,d1,6,", + "1971-01-01T00:00:10.000Z,l5,d1,8,", + "1971-04-26T18:01:40.000Z,l4,d1,14,", + "1971-08-20T11:33:20.000Z,l5,d1,16,", + "1970-01-01T00:00:00.080Z,l4,d2,10,", }; expectedHeader = new String[] {"time", "level", "device", "add_num"}; diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBNestedQueryTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBNestedQueryTableIT.java index 48077696c5b1..48fbd7096aeb 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBNestedQueryTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBNestedQueryTableIT.java @@ -151,7 +151,7 @@ public void testRawDataQueryWithConstants() { for (int i = 1; i <= ITERATION_TIMES; i++) { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); - Assert.assertEquals(i + 1.0D, rs.getDouble(2), 0.01); + Assert.assertEquals(i + 1, rs.getInt(2), 0.01); } Assert.assertFalse(rs.next()); } @@ -161,7 +161,7 @@ public void testRawDataQueryWithConstants() { for (int i = 1; i <= ITERATION_TIMES; i++) { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); - Assert.assertEquals(i + 1.0D, rs.getDouble(2), 0.01); + Assert.assertEquals(i + 1, rs.getInt(2), 0.01); } Assert.assertFalse(rs.next()); } @@ -182,8 +182,8 @@ public void testDuplicatedRawDataQueryWithConstants() { for (int i = 1; i <= ITERATION_TIMES; i++) { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); - Assert.assertEquals(i + 1.0D, rs.getDouble(2), 0.01); - Assert.assertEquals(i + 1.0D, rs.getDouble(3), 0.01); + Assert.assertEquals(i + 1, rs.getInt(2), 0.01); + Assert.assertEquals(i + 1, rs.getInt(3), 0.01); } Assert.assertFalse(rs.next()); } @@ -206,10 +206,10 @@ public void testCommutativeLaws() { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); Assert.assertEquals(i, rs.getInt(2)); - Assert.assertEquals(i + 1.0D, rs.getDouble(3), 0.01); - Assert.assertEquals(i + 1.0D, rs.getDouble(4), 0.01); - Assert.assertEquals(i * 2.0D, rs.getDouble(5), 0.01); - Assert.assertEquals(i * 2.0D, rs.getDouble(6), 0.01); + Assert.assertEquals(i + 1, rs.getInt(3), 0.01); + Assert.assertEquals(i + 1, rs.getInt(4), 0.01); + Assert.assertEquals(i * 2, rs.getInt(5), 0.01); + Assert.assertEquals(i * 2, rs.getInt(6), 0.01); } Assert.assertFalse(rs.next()); } @@ -232,12 +232,12 @@ public void testAssociativeLaws() { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); Assert.assertEquals(i, rs.getInt(2)); - Assert.assertEquals(i + 3.0D, rs.getDouble(3), 0.01); - Assert.assertEquals(i + 3.0D, rs.getDouble(4), 0.01); - Assert.assertEquals(i + 3.0D, rs.getDouble(5), 0.01); - Assert.assertEquals(i * 6.0D, rs.getDouble(6), 0.01); - Assert.assertEquals(i * 6.0D, rs.getDouble(7), 0.01); - Assert.assertEquals(i * 6.0D, rs.getDouble(8), 0.01); + Assert.assertEquals(i + 3, rs.getInt(3), 0.01); + Assert.assertEquals(i + 3, rs.getInt(4), 0.01); + Assert.assertEquals(i + 3, rs.getInt(5), 0.01); + Assert.assertEquals(i * 6, rs.getInt(6), 0.01); + Assert.assertEquals(i * 6, rs.getInt(7), 0.01); + Assert.assertEquals(i * 6, rs.getInt(8), 0.01); } Assert.assertFalse(rs.next()); } @@ -260,10 +260,10 @@ public void testDistributiveLaw() { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); Assert.assertEquals(i, rs.getInt(2)); - Assert.assertEquals(2 * i + 2.0D, rs.getDouble(3), 0.01); - Assert.assertEquals(2 * i + 2.0D, rs.getDouble(4), 0.01); - Assert.assertEquals(i / 2.0D + 0.5D, rs.getDouble(5), 0.01); - Assert.assertEquals(i / 2.0D + 0.5D, rs.getDouble(6), 0.01); + Assert.assertEquals(2 * i + 2, rs.getInt(3), 0.01); + Assert.assertEquals(2 * i + 2, rs.getInt(4), 0.01); + Assert.assertEquals((i + 1) / 2, rs.getInt(5), 0.01); + Assert.assertEquals(i / 2 + 1 / 2, rs.getInt(6), 0.01); } Assert.assertFalse(rs.next()); } @@ -289,9 +289,9 @@ public void testOrderOfArithmeticOperations() { for (int i = 1; i <= ITERATION_TIMES; i++) { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); - Assert.assertEquals(2 * i + 2.0D, rs.getDouble(2), 0.01); - Assert.assertEquals(2 * i + 3.0D, rs.getDouble(3), 0.01); - Assert.assertEquals(3 * i + 3.0D, rs.getDouble(4), 0.01); + Assert.assertEquals(2 * i + 2, rs.getInt(2), 0.01); + Assert.assertEquals(2 * i + 3, rs.getInt(3), 0.01); + Assert.assertEquals(3 * i + 3, rs.getInt(4), 0.01); } Assert.assertFalse(rs.next()); } @@ -302,9 +302,9 @@ public void testOrderOfArithmeticOperations() { for (int i = 1; i <= ITERATION_TIMES; i++) { Assert.assertTrue(rs.next()); Assert.assertEquals(i, rs.getLong(1)); - Assert.assertEquals(2.0D - i / 2.0D, rs.getDouble(2), 0.01); - Assert.assertEquals(1.5 - i / 2.0D, rs.getDouble(3), 0.01); - Assert.assertEquals((1.0D / 3.0D) * (1.0D - i), rs.getDouble(4), 0.01); + Assert.assertEquals(2 - i / 2, rs.getInt(2), 0.01); + Assert.assertEquals((1 - i) / 2 + 1, rs.getInt(3), 0.01); + Assert.assertEquals((1 - i) / (2 + 1), rs.getInt(4), 0.01); } Assert.assertFalse(rs.next()); } diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/alignbydevice/IoTDBAlignByDeviceTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/alignbydevice/IoTDBAlignByDeviceTableIT.java index 3d52c616d72c..0ba23f288f5d 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/alignbydevice/IoTDBAlignByDeviceTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/alignbydevice/IoTDBAlignByDeviceTableIT.java @@ -314,14 +314,14 @@ public void duplicateProjectionsTest() { String[] expectedHeader = new String[] {"Time", "device_id", "_col2", "_col3", "alias"}; String[] retArray = new String[] { - "1970-01-01T00:00:00.001Z,d0,1102.0,1102.0,1102.0,", - "1970-01-01T00:00:00.002Z,d0,40001.0,40001.0,40001.0,", - "1970-01-01T00:00:00.050Z,d0,50001.0,50001.0,50001.0,", - "1970-01-01T00:00:00.100Z,d0,200.0,200.0,200.0,", - "1970-01-01T00:00:00.101Z,d0,200.0,200.0,200.0,", - "1970-01-01T00:00:00.103Z,d0,200.0,200.0,200.0,", - "1970-01-01T00:00:00.105Z,d0,200.0,200.0,200.0,", - "1970-01-01T00:00:01.000Z,d0,55556.0,55556.0,55556.0,", + "1970-01-01T00:00:00.001Z,d0,1102,1102,1102,", + "1970-01-01T00:00:00.002Z,d0,40001,40001,40001,", + "1970-01-01T00:00:00.050Z,d0,50001,50001,50001,", + "1970-01-01T00:00:00.100Z,d0,200,200,200,", + "1970-01-01T00:00:00.101Z,d0,200,200,200,", + "1970-01-01T00:00:00.103Z,d0,200,200,200,", + "1970-01-01T00:00:00.105Z,d0,200,200,200,", + "1970-01-01T00:00:01.000Z,d0,55556,55556,55556,", }; tableResultSetEqualTest( "select Time, device_id, s1+1, s1+1, s1+1 as alias from vehicle where (((\"time\" > 10) AND (\"s1\" > 190)) OR (\"s2\" > 190.0) OR ((\"time\" < 4) AND (\"s1\" > 100))) order by device_id, time", diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/aligned/IoTDBPredicatePushDownTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/aligned/IoTDBPredicatePushDownTableIT.java index 33baa557d435..438f82d69526 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/aligned/IoTDBPredicatePushDownTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/aligned/IoTDBPredicatePushDownTableIT.java @@ -31,7 +31,7 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import static org.apache.iotdb.relational.it.query.old.aligned.TableUtils.tableResultSetEqualTest; +import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest; @RunWith(IoTDBTestRunner.class) @Category({TableLocalStandaloneIT.class, TableClusterIT.class}) @@ -62,16 +62,16 @@ public void testAlignedRawDataAlignByTime1() { String[] expectedHeader1 = new String[] {"Time", "s2", "s3"}; String[] retArray1 = new String[] { - "10,10,10,", - "11,11,11,", - "12,12,12,", - "14,14,14,", - "15,15,15,", - "16,16,16,", - "17,17,17,", - "18,18,18,", - "19,19,19,", - "20,20,20," + "1970-01-01T00:00:00.010Z,10,10,", + "1970-01-01T00:00:00.011Z,11,11,", + "1970-01-01T00:00:00.012Z,12,12,", + "1970-01-01T00:00:00.014Z,14,14,", + "1970-01-01T00:00:00.015Z,15,15,", + "1970-01-01T00:00:00.016Z,16,16,", + "1970-01-01T00:00:00.017Z,17,17,", + "1970-01-01T00:00:00.018Z,18,18,", + "1970-01-01T00:00:00.019Z,19,19,", + "1970-01-01T00:00:00.020Z,20,20," }; tableResultSetEqualTest( "select Time,s2, s3 from table0 where device='d1' and s2 - 1 >= 9 and s2 < 30", @@ -82,8 +82,16 @@ public void testAlignedRawDataAlignByTime1() { String[] expectedHeader2 = new String[] {"Time", "s3"}; String[] retArray2 = new String[] { - "10,10,", "11,11,", "12,12,", "14,14,", "15,15,", "16,16,", "17,17,", "18,18,", "19,19,", - "20,20," + "1970-01-01T00:00:00.010Z,10,", + "1970-01-01T00:00:00.011Z,11,", + "1970-01-01T00:00:00.012Z,12,", + "1970-01-01T00:00:00.014Z,14,", + "1970-01-01T00:00:00.015Z,15,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20," }; tableResultSetEqualTest( "select Time,s3 from table0 where device='d1' and s2 - 1 >= 9 and s2 < 30", @@ -94,8 +102,16 @@ public void testAlignedRawDataAlignByTime1() { String[] expectedHeader3 = new String[] {"Time", "s2"}; String[] retArray3 = new String[] { - "10,10,", "11,11,", "12,12,", "14,14,", "15,15,", "16,16,", "17,17,", "18,18,", "19,19,", - "20,20," + "1970-01-01T00:00:00.010Z,10,", + "1970-01-01T00:00:00.011Z,11,", + "1970-01-01T00:00:00.012Z,12,", + "1970-01-01T00:00:00.014Z,14,", + "1970-01-01T00:00:00.015Z,15,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20," }; tableResultSetEqualTest( "select Time,s2 from table0 where device='d1' and s2 - 1 >= 9 and s2 < 30", @@ -104,7 +120,8 @@ public void testAlignedRawDataAlignByTime1() { database); String[] expectedHeader4 = new String[] {"Time", "s2"}; - String[] retArray4 = new String[] {"14,14,", "15,15,"}; + String[] retArray4 = + new String[] {"1970-01-01T00:00:00.014Z,14,", "1970-01-01T00:00:00.015Z,15,"}; tableResultSetEqualTest( "select Time,s2 from table0 where device='d1' and s2 - 1 >= 9 and s2 < 30 offset 3 limit 2", expectedHeader4, @@ -118,23 +135,23 @@ public void testAlignedRawDataAlignByTime2() { String[] expectedHeader1 = new String[] {"Time", "s2", "_col2"}; String[] retArray1 = new String[] { - "3,null,30001.0,", - "13,130000,130001.0,", - "16,16,17.0,", - "17,17,18.0,", - "18,18,19.0,", - "19,19,20.0,", - "20,20,21.0,", - "21,null,22.0,", - "22,null,23.0,", - "23,null,230001.0,", - "24,null,25.0,", - "25,null,26.0,", - "26,null,27.0,", - "27,null,28.0,", - "28,null,29.0,", - "29,null,30.0,", - "30,null,31.0,", + "1970-01-01T00:00:00.003Z,null,30001,", + "1970-01-01T00:00:00.013Z,130000,130001,", + "1970-01-01T00:00:00.016Z,16,17,", + "1970-01-01T00:00:00.017Z,17,18,", + "1970-01-01T00:00:00.018Z,18,19,", + "1970-01-01T00:00:00.019Z,19,20,", + "1970-01-01T00:00:00.020Z,20,21,", + "1970-01-01T00:00:00.021Z,null,22,", + "1970-01-01T00:00:00.022Z,null,23,", + "1970-01-01T00:00:00.023Z,null,230001,", + "1970-01-01T00:00:00.024Z,null,25,", + "1970-01-01T00:00:00.025Z,null,26,", + "1970-01-01T00:00:00.026Z,null,27,", + "1970-01-01T00:00:00.027Z,null,28,", + "1970-01-01T00:00:00.028Z,null,29,", + "1970-01-01T00:00:00.029Z,null,30,", + "1970-01-01T00:00:00.030Z,null,31,", }; tableResultSetEqualTest( "select Time,s2, s3 + 1 from table0 where device='d1' and s3 + 1 > 16", @@ -145,23 +162,23 @@ public void testAlignedRawDataAlignByTime2() { String[] expectedHeader2 = new String[] {"Time", "s2"}; String[] retArray2 = new String[] { - "3,null,", - "13,130000,", - "16,16,", - "17,17,", - "18,18,", - "19,19,", - "20,20,", - "21,null,", - "22,null,", - "23,null,", - "24,null,", - "25,null,", - "26,null,", - "27,null,", - "28,null,", - "29,null,", - "30,null,", + "1970-01-01T00:00:00.003Z,null,", + "1970-01-01T00:00:00.013Z,130000,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20,", + "1970-01-01T00:00:00.021Z,null,", + "1970-01-01T00:00:00.022Z,null,", + "1970-01-01T00:00:00.023Z,null,", + "1970-01-01T00:00:00.024Z,null,", + "1970-01-01T00:00:00.025Z,null,", + "1970-01-01T00:00:00.026Z,null,", + "1970-01-01T00:00:00.027Z,null,", + "1970-01-01T00:00:00.028Z,null,", + "1970-01-01T00:00:00.029Z,null,", + "1970-01-01T00:00:00.030Z,null,", }; tableResultSetEqualTest( "select Time,s2 from table0 where device='d1' and s3 + 1 > 16", @@ -172,23 +189,23 @@ public void testAlignedRawDataAlignByTime2() { String[] expectedHeader3 = new String[] {"Time", "s3"}; String[] retArray3 = new String[] { - "3,30000,", - "13,130000,", - "16,16,", - "17,17,", - "18,18,", - "19,19,", - "20,20,", - "21,21,", - "22,22,", - "23,230000,", - "24,24,", - "25,25,", - "26,26,", - "27,27,", - "28,28,", - "29,29,", - "30,30,", + "1970-01-01T00:00:00.003Z,30000,", + "1970-01-01T00:00:00.013Z,130000,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20,", + "1970-01-01T00:00:00.021Z,21,", + "1970-01-01T00:00:00.022Z,22,", + "1970-01-01T00:00:00.023Z,230000,", + "1970-01-01T00:00:00.024Z,24,", + "1970-01-01T00:00:00.025Z,25,", + "1970-01-01T00:00:00.026Z,26,", + "1970-01-01T00:00:00.027Z,27,", + "1970-01-01T00:00:00.028Z,28,", + "1970-01-01T00:00:00.029Z,29,", + "1970-01-01T00:00:00.030Z,30,", }; tableResultSetEqualTest( "select Time,s3 from table0 where device='d1' and s3 + 1 > 16", @@ -197,7 +214,12 @@ public void testAlignedRawDataAlignByTime2() { database); String[] expectedHeader4 = new String[] {"Time", "s3"}; - String[] retArray4 = new String[] {"3,30000,", "13,130000,", "16,16,"}; + String[] retArray4 = + new String[] { + "1970-01-01T00:00:00.003Z,30000,", + "1970-01-01T00:00:00.013Z,130000,", + "1970-01-01T00:00:00.016Z,16," + }; tableResultSetEqualTest( "select Time,s3 from table0 where device='d1' and s3 + 1 > 16 limit 3", expectedHeader4, @@ -210,17 +232,17 @@ public void testNonAlignedRawDataAlignByTime1() { String[] expectedHeader1 = new String[] {"Time", "s2", "s3"}; String[] retArray1 = new String[] { - "10,10,10,", - "11,11,11,", - "12,12,12,", - "13,13,13,", - "14,14,14,", - "15,15,15,", - "16,16,16,", - "17,17,17,", - "18,18,18,", - "19,19,19,", - "20,20,20," + "1970-01-01T00:00:00.010Z,10,10,", + "1970-01-01T00:00:00.011Z,11,11,", + "1970-01-01T00:00:00.012Z,12,12,", + "1970-01-01T00:00:00.013Z,13,13,", + "1970-01-01T00:00:00.014Z,14,14,", + "1970-01-01T00:00:00.015Z,15,15,", + "1970-01-01T00:00:00.016Z,16,16,", + "1970-01-01T00:00:00.017Z,17,17,", + "1970-01-01T00:00:00.018Z,18,18,", + "1970-01-01T00:00:00.019Z,19,19,", + "1970-01-01T00:00:00.020Z,20,20," }; tableResultSetEqualTest( "select Time,s2, s3 from table0 where device='d2' and s2 - 1 >= 9 and s2 < 30", @@ -231,8 +253,17 @@ public void testNonAlignedRawDataAlignByTime1() { String[] expectedHeader2 = new String[] {"Time", "s3"}; String[] retArray2 = new String[] { - "10,10,", "11,11,", "12,12,", "13,13,", "14,14,", "15,15,", "16,16,", "17,17,", "18,18,", - "19,19,", "20,20," + "1970-01-01T00:00:00.010Z,10,", + "1970-01-01T00:00:00.011Z,11,", + "1970-01-01T00:00:00.012Z,12,", + "1970-01-01T00:00:00.013Z,13,", + "1970-01-01T00:00:00.014Z,14,", + "1970-01-01T00:00:00.015Z,15,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20," }; tableResultSetEqualTest( "select Time,s3 from table0 where device='d2' and s2 - 1 >= 9 and s2 < 30", @@ -243,8 +274,17 @@ public void testNonAlignedRawDataAlignByTime1() { String[] expectedHeader3 = new String[] {"Time", "s2"}; String[] retArray3 = new String[] { - "10,10,", "11,11,", "12,12,", "13,13,", "14,14,", "15,15,", "16,16,", "17,17,", "18,18,", - "19,19,", "20,20," + "1970-01-01T00:00:00.010Z,10,", + "1970-01-01T00:00:00.011Z,11,", + "1970-01-01T00:00:00.012Z,12,", + "1970-01-01T00:00:00.013Z,13,", + "1970-01-01T00:00:00.014Z,14,", + "1970-01-01T00:00:00.015Z,15,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20," }; tableResultSetEqualTest( "select Time,s2 from table0 where device='d2' and s2 - 1 >= 9 and s2 < 30", @@ -253,7 +293,12 @@ public void testNonAlignedRawDataAlignByTime1() { database); String[] expectedHeader4 = new String[] {"Time", "s2"}; - String[] retArray4 = new String[] {"12,12,", "13,13,", "14,14,"}; + String[] retArray4 = + new String[] { + "1970-01-01T00:00:00.012Z,12,", + "1970-01-01T00:00:00.013Z,13,", + "1970-01-01T00:00:00.014Z,14," + }; tableResultSetEqualTest( "select Time,s2 from table0 where device='d2' and s2 - 1 >= 9 and s2 < 30 offset 2 limit 3", expectedHeader4, @@ -266,21 +311,21 @@ public void testNonAlignedRawDataAlignByTime2() { String[] expectedHeader1 = new String[] {"Time", "s2", "s3"}; String[] retArray1 = new String[] { - "16,16,16,", - "17,17,17,", - "18,18,18,", - "19,19,19,", - "20,20,20,", - "21,null,21,", - "22,null,22,", - "23,null,23,", - "24,null,24,", - "25,null,25,", - "26,null,26,", - "27,null,27,", - "28,null,28,", - "29,null,29,", - "30,null,30,", + "1970-01-01T00:00:00.016Z,16,16,", + "1970-01-01T00:00:00.017Z,17,17,", + "1970-01-01T00:00:00.018Z,18,18,", + "1970-01-01T00:00:00.019Z,19,19,", + "1970-01-01T00:00:00.020Z,20,20,", + "1970-01-01T00:00:00.021Z,null,21,", + "1970-01-01T00:00:00.022Z,null,22,", + "1970-01-01T00:00:00.023Z,null,23,", + "1970-01-01T00:00:00.024Z,null,24,", + "1970-01-01T00:00:00.025Z,null,25,", + "1970-01-01T00:00:00.026Z,null,26,", + "1970-01-01T00:00:00.027Z,null,27,", + "1970-01-01T00:00:00.028Z,null,28,", + "1970-01-01T00:00:00.029Z,null,29,", + "1970-01-01T00:00:00.030Z,null,30,", }; tableResultSetEqualTest( "select Time,s2, s3 from table0 where device='d2' and s3 + 1 > 16", @@ -291,21 +336,21 @@ public void testNonAlignedRawDataAlignByTime2() { String[] expectedHeader2 = new String[] {"Time", "s2"}; String[] retArray2 = new String[] { - "16,16,", - "17,17,", - "18,18,", - "19,19,", - "20,20,", - "21,null,", - "22,null,", - "23,null,", - "24,null,", - "25,null,", - "26,null,", - "27,null,", - "28,null,", - "29,null,", - "30,null,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20,", + "1970-01-01T00:00:00.021Z,null,", + "1970-01-01T00:00:00.022Z,null,", + "1970-01-01T00:00:00.023Z,null,", + "1970-01-01T00:00:00.024Z,null,", + "1970-01-01T00:00:00.025Z,null,", + "1970-01-01T00:00:00.026Z,null,", + "1970-01-01T00:00:00.027Z,null,", + "1970-01-01T00:00:00.028Z,null,", + "1970-01-01T00:00:00.029Z,null,", + "1970-01-01T00:00:00.030Z,null,", }; tableResultSetEqualTest( "select Time,s2 from table0 where device='d2' and s3 + 1 > 16", @@ -316,8 +361,21 @@ public void testNonAlignedRawDataAlignByTime2() { String[] expectedHeader3 = new String[] {"Time", "s3"}; String[] retArray3 = new String[] { - "16,16,", "17,17,", "18,18,", "19,19,", "20,20,", "21,21,", "22,22,", "23,23,", "24,24,", - "25,25,", "26,26,", "27,27,", "28,28,", "29,29,", "30,30,", + "1970-01-01T00:00:00.016Z,16,", + "1970-01-01T00:00:00.017Z,17,", + "1970-01-01T00:00:00.018Z,18,", + "1970-01-01T00:00:00.019Z,19,", + "1970-01-01T00:00:00.020Z,20,", + "1970-01-01T00:00:00.021Z,21,", + "1970-01-01T00:00:00.022Z,22,", + "1970-01-01T00:00:00.023Z,23,", + "1970-01-01T00:00:00.024Z,24,", + "1970-01-01T00:00:00.025Z,25,", + "1970-01-01T00:00:00.026Z,26,", + "1970-01-01T00:00:00.027Z,27,", + "1970-01-01T00:00:00.028Z,28,", + "1970-01-01T00:00:00.029Z,29,", + "1970-01-01T00:00:00.030Z,30,", }; tableResultSetEqualTest( "select Time,s3 from table0 where device='d2' and s3 + 1 > 16", @@ -328,7 +386,11 @@ public void testNonAlignedRawDataAlignByTime2() { String[] expectedHeader4 = new String[] {"Time", "s3"}; String[] retArray4 = new String[] { - "26,26,", "27,27,", "28,28,", "29,29,", "30,30,", + "1970-01-01T00:00:00.026Z,26,", + "1970-01-01T00:00:00.027Z,27,", + "1970-01-01T00:00:00.028Z,28,", + "1970-01-01T00:00:00.029Z,29,", + "1970-01-01T00:00:00.030Z,30,", }; tableResultSetEqualTest( "select Time,s3 from table0 where device='d2' and s3 + 1 > 16 offset 10", @@ -539,27 +601,27 @@ public void testRawDataAlignByDevice1() { String[] expectedHeader = new String[] {"Time", "Device", "s2", "s3"}; String[] retArray = new String[] { - "10,d2,10,10,", - "11,d2,11,11,", - "12,d2,12,12,", - "13,d2,13,13,", - "14,d2,14,14,", - "15,d2,15,15,", - "16,d2,16,16,", - "17,d2,17,17,", - "18,d2,18,18,", - "19,d2,19,19,", - "20,d2,20,20,", - "10,d1,10,10,", - "11,d1,11,11,", - "12,d1,12,12,", - "14,d1,14,14,", - "15,d1,15,15,", - "16,d1,16,16,", - "17,d1,17,17,", - "18,d1,18,18,", - "19,d1,19,19,", - "20,d1,20,20," + "1970-01-01T00:00:00.010Z,d2,10,10,", + "1970-01-01T00:00:00.011Z,d2,11,11,", + "1970-01-01T00:00:00.012Z,d2,12,12,", + "1970-01-01T00:00:00.013Z,d2,13,13,", + "1970-01-01T00:00:00.014Z,d2,14,14,", + "1970-01-01T00:00:00.015Z,d2,15,15,", + "1970-01-01T00:00:00.016Z,d2,16,16,", + "1970-01-01T00:00:00.017Z,d2,17,17,", + "1970-01-01T00:00:00.018Z,d2,18,18,", + "1970-01-01T00:00:00.019Z,d2,19,19,", + "1970-01-01T00:00:00.020Z,d2,20,20,", + "1970-01-01T00:00:00.010Z,d1,10,10,", + "1970-01-01T00:00:00.011Z,d1,11,11,", + "1970-01-01T00:00:00.012Z,d1,12,12,", + "1970-01-01T00:00:00.014Z,d1,14,14,", + "1970-01-01T00:00:00.015Z,d1,15,15,", + "1970-01-01T00:00:00.016Z,d1,16,16,", + "1970-01-01T00:00:00.017Z,d1,17,17,", + "1970-01-01T00:00:00.018Z,d1,18,18,", + "1970-01-01T00:00:00.019Z,d1,19,19,", + "1970-01-01T00:00:00.020Z,d1,20,20,", }; tableResultSetEqualTest( "select Time, Device,s2, s3 from table0 where s2 - 1 >= 9 and s2 < 30 order by device desc", @@ -573,38 +635,38 @@ public void testRawDataAlignByDevice2() { String[] expectedHeader = new String[] {"Time", "Device", "s2", "_col3"}; String[] retArray = new String[] { - "3,d1,null,30001.0,", - "13,d1,130000,130001.0,", - "16,d1,16,17.0,", - "17,d1,17,18.0,", - "18,d1,18,19.0,", - "19,d1,19,20.0,", - "20,d1,20,21.0,", - "21,d1,null,22.0,", - "22,d1,null,23.0,", - "23,d1,null,230001.0,", - "24,d1,null,25.0,", - "25,d1,null,26.0,", - "26,d1,null,27.0,", - "27,d1,null,28.0,", - "28,d1,null,29.0,", - "29,d1,null,30.0,", - "30,d1,null,31.0,", - "16,d2,16,17.0,", - "17,d2,17,18.0,", - "18,d2,18,19.0,", - "19,d2,19,20.0,", - "20,d2,20,21.0,", - "21,d2,null,22.0,", - "22,d2,null,23.0,", - "23,d2,null,24.0,", - "24,d2,null,25.0,", - "25,d2,null,26.0,", - "26,d2,null,27.0,", - "27,d2,null,28.0,", - "28,d2,null,29.0,", - "29,d2,null,30.0,", - "30,d2,null,31.0,", + "1970-01-01T00:00:00.003Z,d1,null,30001,", + "1970-01-01T00:00:00.013Z,d1,130000,130001,", + "1970-01-01T00:00:00.016Z,d1,16,17,", + "1970-01-01T00:00:00.017Z,d1,17,18,", + "1970-01-01T00:00:00.018Z,d1,18,19,", + "1970-01-01T00:00:00.019Z,d1,19,20,", + "1970-01-01T00:00:00.020Z,d1,20,21,", + "1970-01-01T00:00:00.021Z,d1,null,22,", + "1970-01-01T00:00:00.022Z,d1,null,23,", + "1970-01-01T00:00:00.023Z,d1,null,230001,", + "1970-01-01T00:00:00.024Z,d1,null,25,", + "1970-01-01T00:00:00.025Z,d1,null,26,", + "1970-01-01T00:00:00.026Z,d1,null,27,", + "1970-01-01T00:00:00.027Z,d1,null,28,", + "1970-01-01T00:00:00.028Z,d1,null,29,", + "1970-01-01T00:00:00.029Z,d1,null,30,", + "1970-01-01T00:00:00.030Z,d1,null,31,", + "1970-01-01T00:00:00.016Z,d2,16,17,", + "1970-01-01T00:00:00.017Z,d2,17,18,", + "1970-01-01T00:00:00.018Z,d2,18,19,", + "1970-01-01T00:00:00.019Z,d2,19,20,", + "1970-01-01T00:00:00.020Z,d2,20,21,", + "1970-01-01T00:00:00.021Z,d2,null,22,", + "1970-01-01T00:00:00.022Z,d2,null,23,", + "1970-01-01T00:00:00.023Z,d2,null,24,", + "1970-01-01T00:00:00.024Z,d2,null,25,", + "1970-01-01T00:00:00.025Z,d2,null,26,", + "1970-01-01T00:00:00.026Z,d2,null,27,", + "1970-01-01T00:00:00.027Z,d2,null,28,", + "1970-01-01T00:00:00.028Z,d2,null,29,", + "1970-01-01T00:00:00.029Z,d2,null,30,", + "1970-01-01T00:00:00.030Z,d2,null,31,", }; tableResultSetEqualTest( "select Time,Device,s2, s3 + 1 from table0 where s3 + 1 > 16 order by device", diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/orderBy/IoTDBOrderByTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/orderBy/IoTDBOrderByTableIT.java index 91ff9309c826..d3cc7b19f36f 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/orderBy/IoTDBOrderByTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/orderBy/IoTDBOrderByTableIT.java @@ -277,7 +277,7 @@ public void orderByTest15() { while (resultSet.next()) { long actualTime = resultSet.getLong(1); - double actualNum = resultSet.getDouble(2); + double actualNum = resultSet.getLong(2); double actualFloat = resultSet.getDouble(3); assertEquals(Long.parseLong(RES[ans[i]][0]), actualTime); @@ -351,7 +351,7 @@ public void orderByTest14() { while (resultSet.next()) { long actualTime = resultSet.getLong(1); - double actualNum = resultSet.getDouble(2); + double actualNum = resultSet.getLong(2); assertEquals(Long.parseLong(RES[ans[i]][0]), actualTime); assertEquals( @@ -744,7 +744,7 @@ public void alignByDeviceOrderByTest1() { while (resultSet.next()) { long actualTime = resultSet.getLong(1); String actualDevice = resultSet.getString(2); - double actualNum = resultSet.getDouble(3); + double actualNum = resultSet.getLong(3); assertEquals(device, actualDevice); assertEquals(Long.parseLong(RES[ans[i]][0]), actualTime); diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBArithmeticTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBArithmeticTableIT.java index 27304ad2adac..1dfd5dcc05a0 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBArithmeticTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/query/IoTDBArithmeticTableIT.java @@ -1,20 +1,15 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.apache.iotdb.relational.it.query.old.query; @@ -27,7 +22,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -37,14 +31,15 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; import static org.apache.iotdb.db.it.utils.TestUtils.prepareTableData; import static org.apache.iotdb.db.it.utils.TestUtils.tableAssertTestFail; import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @@ -53,15 +48,27 @@ public class IoTDBArithmeticTableIT { private static final double E = 0.0001; + private static final String DATABASE_NAME = "test"; + + private static final double[][] BASE_ANS = {{1, 1, 1.0, 1.0}, {2, 2, 2.0, 2.0}, {3, 3, 3.0, 3.0}}; + + private static final Map> OPERATIONS = new HashMap<>(); + + static { + OPERATIONS.put(" + ", (a, b) -> a + b); + OPERATIONS.put(" - ", (a, b) -> a - b); + OPERATIONS.put(" * ", (a, b) -> a * b); + OPERATIONS.put(" / ", (a, b) -> a / b); + OPERATIONS.put(" % ", (a, b) -> a % b); + } + private static final String[] INSERTION_SQLS = { - "CREATE DATABASE test", - "USE test", - "CREATE TABLE table1 (device STRING ID, s1 INT32 MEASUREMENT, s2 INT32 MEASUREMENT, s3 INT64 MEASUREMENT, s4 INT32 MEASUREMENT, s5 BOOLEAN MEASUREMENT, s6 TEXT MEASUREMENT, s7 INT32 MEASUREMENT, s8 INT32 MEASUREMENT)", - "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s7) values ('d1', 1, 1, 1, 1, 1, false, '1', 1)", - "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s8) values ('d1', 2, 2, 2, 2, 2, false, '2', 2)", - "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s7) values ('d1', 3, 3, 3, 3, 3, true, '3', 3)", - "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s8) values ('d1', 4, 4, 4, 4, 4, true, '4', 4)", - "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s7, s8) values ('d1', 5, 5, 5, 5, 5, true, '5', 5, 5)", + "CREATE DATABASE " + DATABASE_NAME, + "USE " + DATABASE_NAME, + "CREATE TABLE table1 (device STRING ID, s1 INT32 MEASUREMENT, s2 INT64 MEASUREMENT, s3 FLOAT MEASUREMENT, s4 DOUBLE MEASUREMENT, s5 DATE MEASUREMENT, s6 TIMESTAMP MEASUREMENT, s7 BOOLEAN MEASUREMENT, s8 TEXT MEASUREMENT)", + "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s7, s8) values ('d1', 1, 1, 1, 1.0, 1.0, '2024-01-01', 10, true, 'test')", + "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s7, s8) values ('d1', 2, 2, 2, 2.0, 2.0, '2024-02-01', 20, true, 'test')", + "insert into table1(device, time, s1, s2, s3, s4, s5, s6, s7, s8) values ('d1', 3, 3, 3, 3.0, 3.0, '2024-03-01', 30, true, 'test')", }; @BeforeClass @@ -75,49 +82,56 @@ public static void tearDown() throws Exception { EnvFactory.getEnv().cleanClusterEnvironment(); } + public static double[][] calculateExpectedAns(String operator) { + double[][] expectedAns = new double[BASE_ANS.length][BASE_ANS[0].length * BASE_ANS[0].length]; + BiFunction operation = OPERATIONS.get(operator); + if (operation == null) { + throw new IllegalArgumentException("Unsupported operator: " + operator); + } + + for (int i = 0; i < BASE_ANS.length; i++) { + int baseLength = BASE_ANS[i].length; + for (int j = 0; j < baseLength; j++) { + for (int k = 0; k < baseLength; k++) { + expectedAns[i][j * baseLength + k] = operation.apply(BASE_ANS[i][j], BASE_ANS[i][k]); + } + } + } + return expectedAns; + } + @Test - public void testArithmeticBinary() { + public void testArithmeticBinaryWithoutDateAndTimestamp() { try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); Statement statement = connection.createStatement()) { - statement.execute("USE test"); - String[] operands = new String[] {"s1", "s2", "s3", "s4"}; + + // generate sql + for (String operator : new String[] {" + ", " - ", " * ", " / ", " % "}) { List expressions = new ArrayList<>(); + String[] operands = new String[] {"s1", "s2", "s3", "s4"}; for (String leftOperand : operands) { for (String rightOperand : operands) { expressions.add(leftOperand + operator + rightOperand); } } - String sql = String.format("select %s from table1", String.join(",", expressions)); + String sql = String.format("select %s from table1", String.join(",", expressions)); ResultSet resultSet = statement.executeQuery(sql); + // generate answer + double[][] expectedAns = calculateExpectedAns(operator); + + // Make sure the number of columns in the result set is correct assertEquals(expressions.size(), resultSet.getMetaData().getColumnCount()); - for (int i = 1; i < 6; ++i) { + // check the result + for (double[] expectedAn : expectedAns) { resultSet.next(); - for (int j = 0; j < expressions.size(); ++j) { - double expected = 0; - switch (operator) { - case " + ": - expected = i + i; - break; - case " - ": - expected = i - i; - break; - case " * ": - expected = i * i; - break; - case " / ": - expected = i / i; - break; - case " % ": - expected = i % i; - break; - } - double actual = Double.parseDouble(resultSet.getString(j + 1)); - assertEquals(expected, actual, E); + for (int i = 0; i < expectedAn.length; i++) { + double result = Double.parseDouble(resultSet.getString(i + 1)); + assertEquals(expectedAn[i], result, E); } } } @@ -127,47 +141,55 @@ public void testArithmeticBinary() { } @Test - public void testArithmeticUnary() { + public void testArithmeticBinaryWithDateAndTimestamp() { try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); Statement statement = connection.createStatement()) { statement.execute("USE test"); - String[] expressions = new String[] {"- s1", "- s2", "- s3", "- s4"}; - String sql = String.format("select %s from table1", String.join(",", expressions)); + + String sql = + "select s1+s5,s1+s6,s2+s5,s2+s6,s5+s1,s5+s2,s6+s1,s6+s2,s5-s1,s5-s2,s6-s1,s6-s2 from table1"; ResultSet resultSet = statement.executeQuery(sql); - assertEquals(expressions.length, resultSet.getMetaData().getColumnCount()); + assertEquals(12, resultSet.getMetaData().getColumnCount()); - for (int i = 1; i < 6; ++i) { + int[][] expectedAns = { + {20240101, 11, 20240101, 11, 20240101, 20240101, 11, 11, 20231231, 20231231, 9, 9}, + {20240201, 22, 20240201, 22, 20240201, 20240201, 22, 22, 20240131, 20240131, 18, 18}, + {20240301, 33, 20240301, 33, 20240301, 20240301, 33, 33, 20240229, 20240229, 27, 27} + }; + + for (int[] expectedAn : expectedAns) { resultSet.next(); - for (int j = 0; j < expressions.length; ++j) { - double expected = -i; - double actual = Double.parseDouble(resultSet.getString(j + 1)); - assertEquals(expected, actual, E); + + for (int i = 0; i < expectedAn.length; i++) { + int result = resultSet.getInt(i + 1); + assertEquals(expectedAn[i], result); } } - resultSet.close(); } catch (SQLException throwable) { fail(throwable.getMessage()); } } - // TODO After support 'sin' - @Ignore @Test - public void testHybridQuery() { + public void testArithmeticUnary() { try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); Statement statement = connection.createStatement()) { - String[] expressions = new String[] {"s1", "s1 + s2", "sin(s1)"}; + statement.execute("USE test"); + + String[] expressions = new String[] {"- s1", "- s2", "- s3", "- s4"}; String sql = String.format("select %s from table1", String.join(",", expressions)); ResultSet resultSet = statement.executeQuery(sql); - assertEquals(1 + expressions.length, resultSet.getMetaData().getColumnCount()); + assertEquals(expressions.length, resultSet.getMetaData().getColumnCount()); - for (int i = 1; i < 6; ++i) { + for (int i = 1; i < 4; ++i) { resultSet.next(); - assertEquals(i, Double.parseDouble(resultSet.getString(2)), E); - assertEquals(i + i, Double.parseDouble(resultSet.getString(3)), E); - assertEquals(Math.sin(i), Double.parseDouble(resultSet.getString(4)), E); + for (int j = 0; j < expressions.length; ++j) { + double expected = -i; + double actual = Double.parseDouble(resultSet.getString(j + 1)); + assertEquals(expected, actual, E); + } } resultSet.close(); } catch (SQLException throwable) { @@ -176,51 +198,147 @@ public void testHybridQuery() { } @Test - public void testNonAlign() { - try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); - Statement statement = connection.createStatement()) { - statement.execute("USE test"); - ResultSet resultSet = statement.executeQuery("select s7 + s8 from table1"); - assertEquals(1, resultSet.getMetaData().getColumnCount()); - assertTrue(resultSet.next()); - String curr = null; - while (curr == null) { - curr = resultSet.getString(1); - resultSet.next(); - } - assertEquals(10, Double.parseDouble(resultSet.getString(1)), E); - assertFalse(resultSet.next()); - - resultSet = statement.executeQuery("select s7 + s8 from table1 where time < 5"); - assertEquals(1, resultSet.getMetaData().getColumnCount()); - curr = null; - while (curr == null) { - if (!resultSet.next()) { - break; - } - curr = resultSet.getString(1); - } - assertEquals(null, curr); - resultSet.close(); - } catch (SQLException throwable) { - fail(throwable.getMessage()); - } + public void testBinaryWrongType() { + + testBinaryDifferentCombinationsFail( + new String[] {" * ", " / ", " % "}, + new String[] {"s1", "s2", "s3", "s4"}, + new String[] {"s5", "s6"}, + "table1", + "701: Cannot apply operator", + "test"); + + testBinaryDifferentCombinationsFail( + new String[] {" * ", " / ", " % "}, + new String[] {"s5", "s6"}, + new String[] {"s1", "s2", "s3", "s4"}, + "table1", + "701: Cannot apply operator", + "test"); + } + + @Test + public void testUnaryWrongType() { + tableAssertTestFail("select -s5 from table1", "701: Cannot negate", "test"); + tableAssertTestFail("select -s7 from table1", "701: Cannot negate", "test"); + tableAssertTestFail("select -s8 from table1", "701: Cannot negate", "test"); + } + + @Test + public void testOverflow() { + // int addition overflow + tableAssertTestFail( + String.format("select s1+%d from table1", Integer.MAX_VALUE), + "750: int Addition overflow", + "test"); + + // int subtraction overflow + tableAssertTestFail( + String.format("select s1-(%d) from table1", Integer.MIN_VALUE), + "750: int Subtraction overflow", + "test"); + + // int multiplication overflow + tableAssertTestFail( + String.format("select (s1+1)*%d from table1", Integer.MAX_VALUE), + "750: int Multiplication overflow", + "test"); + + // Date addition overflow + tableAssertTestFail( + String.format("select s5+%d from table1", Long.MAX_VALUE), + "750: long Addition overflow", + "test"); + + // Date subtraction overflow + tableAssertTestFail( + String.format("select s5-(%d) from table1", Long.MIN_VALUE), + "750: long Subtraction overflow", + "test"); + + // long addition overflow + tableAssertTestFail( + String.format("select s2+%d from table1", Long.MAX_VALUE), + "750: long Addition overflow", + "test"); + + // long subtraction overflow + tableAssertTestFail( + String.format("select s2-(%d) from table1", Long.MIN_VALUE), + "750: long Subtraction overflow", + "test"); + + // Timestamp addition overflow + tableAssertTestFail( + String.format("select s6+%d from table1", Long.MAX_VALUE), + "750: long Addition overflow", + "test"); + + // Timestamp subtraction overflow + tableAssertTestFail( + String.format("select s6-(%d) from table1", Long.MIN_VALUE), + "750: long Subtraction overflow", + "test"); } @Test - public void testWrongTypeBoolean() { - tableAssertTestFail("select s1 + s5 from table1", "701: Cannot apply operator", "test"); + public void testFloatDivisionByZeroSpecialCase() { + String[] expectedHeader = new String[5]; + for (int i = 0; i < expectedHeader.length; i++) { + expectedHeader[i] = "_col" + i; + } + String[] expectedAns = { + "Infinity,0.0,NaN,-0.0,-Infinity,", + "Infinity,0.0,NaN,-0.0,-Infinity,", + "Infinity,0.0,NaN,-0.0,-Infinity," + }; + + tableResultSetEqualTest( + "select s3/0.0,0.0/s3,0.0/0.0,0.0/-s3,-s3/0.0 from table1", + expectedHeader, + expectedAns, + "test"); } @Test - public void testWrongTypeText() { - tableAssertTestFail("select s1 + s6 from table1", "701: Cannot apply operator", "test"); + public void testDoubleDivisionByZeroSpecialCase() { + String[] expectedHeader = new String[5]; + for (int i = 0; i < expectedHeader.length; i++) { + expectedHeader[i] = "_col" + i; + } + String[] expectedAns = {"NaN,0.0,NaN,0.0,NaN,", "NaN,0.0,NaN,0.0,NaN,", "NaN,0.0,NaN,0.0,NaN,"}; + + tableResultSetEqualTest( + "select s3%0.0,0.0%s3,0.0%0.0,0.0%-s3,-s3%0.0 from table1", + expectedHeader, expectedAns, "test"); } @Test - public void testNot() { - String[] header = new String[] {"_col0"}; - String[] retArray = new String[] {"true,", "true,", "false,", "false,", "false,"}; - tableResultSetEqualTest("select not(s5) from table1", header, retArray, "test"); + public void testDivisionByZero() { + tableAssertTestFail("select s1/0 from table1", "751: Division by zero", "test"); + tableAssertTestFail("select s2/0 from table1", "751: Division by zero", "test"); + + tableAssertTestFail("select s1%0 from table1", "751: Division by zero", "test"); + tableAssertTestFail("select s2%0 from table1", "751: Division by zero", "test"); + } + + private void testBinaryDifferentCombinationsFail( + String[] operators, + String[] leftOperands, + String[] rightOperands, + String tableName, + String errMsg, + String databaseName) { + for (String operator : operators) { + for (String leftOperand : leftOperands) { + for (String rightOperand : rightOperands) { + tableAssertTestFail( + String.format( + "select %s %s %s from %s", leftOperand, operator, rightOperand, tableName), + errMsg, + databaseName); + } + } + } } } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java index 4964ff4c06bd..49db2987a126 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java @@ -133,6 +133,10 @@ public enum TSStatusCode { OPERATOR_NOT_FOUND(716), + // Arithmetic + NUMERIC_VALUE_OUT_OF_RANGE(750), + DIVISION_BY_ZERO(751), + // Authentication INIT_AUTH_ERROR(800), WRONG_LOGIN_PASSWORD(801), diff --git a/iotdb-core/datanode/src/main/codegen/config.fmpp b/iotdb-core/datanode/src/main/codegen/config.fmpp index 2112c459367e..46b529484ab6 100644 --- a/iotdb-core/datanode/src/main/codegen/config.fmpp +++ b/iotdb-core/datanode/src/main/codegen/config.fmpp @@ -19,7 +19,9 @@ data: { allDataTypes: tdd(../dataModel/AllDataType.tdd), decimalDataTypes: tdd(../dataModel/DecimalDataType.tdd), - compareTypes: tdd(../dataModel/CompareType.tdd) + compareTypes: tdd(../dataModel/CompareType.tdd), + mathematicalOperator: tdd(../dataModel/MathematicalOperator.tdd), + mathematicalDataType: tdd(../dataModel/MathematicalDataType.tdd) } freemarkerLinks: { includes: includes/ diff --git a/iotdb-core/datanode/src/main/codegen/dataModel/MathematicalDataType.tdd b/iotdb-core/datanode/src/main/codegen/dataModel/MathematicalDataType.tdd new file mode 100644 index 000000000000..f60d818c6d91 --- /dev/null +++ b/iotdb-core/datanode/src/main/codegen/dataModel/MathematicalDataType.tdd @@ -0,0 +1,52 @@ +<#-- +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +--> + +{ + "types": [ + { + "type": "IntType", + "dataType": "int", + "instance": "INT" + }, + { + "type": "LongType", + "dataType": "long", + "instance": "LONG" + }, + { + "type": "FloatType", + "dataType": "float", + "instance": "FLOAT" + }, + { + "type": "DoubleType", + "dataType": "double", + "instance": "DOUBLE" + }, + { + "type": "DateType", + "dataType": "int", + "instance": "DATE" + }, + { + "type": "TimestampType", + "dataType": "long", + "instance": "TIMESTAMP" + } + ] +} diff --git a/iotdb-core/datanode/src/main/codegen/dataModel/MathematicalOperator.tdd b/iotdb-core/datanode/src/main/codegen/dataModel/MathematicalOperator.tdd new file mode 100644 index 000000000000..722b32bc43e2 --- /dev/null +++ b/iotdb-core/datanode/src/main/codegen/dataModel/MathematicalOperator.tdd @@ -0,0 +1,52 @@ +<#-- +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +--> + +{ + "binaryOperators": [ + { + "name": "Addition", + "operator": "ADD", + "symbol": "+" + }, + { + "name": "Subtraction", + "operator": "SUBTRACT", + "symbol": "-" + }, + { + "name": "Multiplication", + "operator": "MULTIPLY", + "symbol": "*" + }, + { + "name": "Division", + "operator": "DIVIDE", + "symbol": "/" + }, + { + "name": "Modulus", + "operator": "MODULUS", + "symbol": "%" + } + ], + "unaryOperators": [ + { + "operator": "NEGATION" + } + ] +} \ No newline at end of file diff --git a/iotdb-core/datanode/src/main/codegen/templates/ArithmeticBinaryColumnTransformer.ftl b/iotdb-core/datanode/src/main/codegen/templates/ArithmeticBinaryColumnTransformer.ftl new file mode 100644 index 000000000000..42a6d2006209 --- /dev/null +++ b/iotdb-core/datanode/src/main/codegen/templates/ArithmeticBinaryColumnTransformer.ftl @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +<@pp.dropOutputFile /> +<#list mathematicalOperator.binaryOperators as operator> +<#list mathematicalDataType.types as first> +<#list mathematicalDataType.types as second> +<#--Parting line--> +<#assign className = "${first.type?replace('Type','')}${operator.name}${second.type?replace('Type','')}ColumnTransformer"> + +<#--Main Part--> +<#if (first.instance == "DATE" || first.instance == "TIMESTAMP") && (second.instance == "INT" || second.instance == "LONG")><#if operator.name == "Addition" || operator.name == "Subtraction"> +<@pp.changeOutputFile name="/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/${className}.java" /> +<#--Date + int || Date + long || Timestamp + int || Timestamp + long--> +<#--Date - int || Date - long || Timestamp - int || Timestamp - long--> +package org.apache.iotdb.db.queryengine.transformation.dag.column.binary; + +import org.apache.iotdb.commons.exception.IoTDBRuntimeException; +import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer; +import org.apache.iotdb.db.utils.DateTimeUtils; + +import org.apache.tsfile.block.column.Column; +import org.apache.tsfile.block.column.ColumnBuilder; +import org.apache.tsfile.read.common.type.Type; +import org.apache.tsfile.utils.DateUtils; + +import java.time.ZoneId; + +<#if first.dataType == "int" || second.dataType == "int" || first.dataType == "long" || second.dataType == "long"> +import static org.apache.iotdb.rpc.TSStatusCode.NUMERIC_VALUE_OUT_OF_RANGE; + + +public class ${className} extends BinaryColumnTransformer { + + private static ZoneId zoneId; + + public ${className}( + Type returnType, ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + super(returnType, leftTransformer, rightTransformer); + this.zoneId = zoneId; + } + + @Override + protected void doTransform( + Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) { + for (int i = 0; i < positionCount; i++) { + if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) { + returnType.write${first.dataType?cap_first}( + builder, + transform( + leftTransformer.getType().get${first.dataType?cap_first}(leftColumn, i), + rightTransformer.getType().get${second.dataType?cap_first}(rightColumn, i))); + } else { + builder.appendNull(); + } + } + } + + @Override + protected void checkType() { + // do nothing + } + + public static ${first.dataType} transform(${first.dataType} left, ${second.dataType} right) { + <#switch operator.name> + <#case "Addition"> + <#if first.instance == "DATE"> + <#--Date + int || Date + long--> + try{ + long timestamp = Math.addExact(DateTimeUtils.correctPrecision(DateUtils.parseIntToTimestamp(left,zoneId)), right); + return DateUtils.parseDateExpressionToInt(DateTimeUtils.convertToLocalDate(timestamp, zoneId)); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("long ${operator.name} overflow: %s + %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + <#else> + <#--Timestamp + int || Timestamp + long--> + try{ + return Math.addExact(left, right); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("long ${operator.name} overflow: %s + %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + + <#break> + <#case "Subtraction"> + <#if first.instance == "DATE"> + <#--Date - int || Date - long--> + try{ + long timestamp = Math.subtractExact(DateTimeUtils.correctPrecision(DateUtils.parseIntToTimestamp(left, zoneId)), right); + return DateUtils.parseDateExpressionToInt(DateTimeUtils.convertToLocalDate(timestamp, zoneId)); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("long ${operator.name} overflow: %s - %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + <#else> + <#--Timestamp - int || Timestamp - long--> + try{ + return Math.subtractExact(left, right); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("long ${operator.name} overflow: %s - %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + + <#break> + + } +} + +<#elseif (second.instance == "DATE" || second.instance =="TIMESTAMP") && (first.instance == "INT" || first.instance == "LONG")> + <#if operator.name == "Addition"> +<#--int + Date || long + Date || int + Timestamp || long + Timestamp--> +<@pp.changeOutputFile name="/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/${className}.java" /> +package org.apache.iotdb.db.queryengine.transformation.dag.column.binary; + +import org.apache.iotdb.commons.exception.IoTDBRuntimeException; +import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer; +import org.apache.iotdb.db.utils.DateTimeUtils; + +import org.apache.tsfile.block.column.Column; +import org.apache.tsfile.block.column.ColumnBuilder; +import org.apache.tsfile.read.common.type.Type; +import org.apache.tsfile.utils.DateUtils; + +import java.time.ZoneId; + +<#if first.dataType == "int" || second.dataType == "int" || first.dataType == "long" || second.dataType == "long"> +import static org.apache.iotdb.rpc.TSStatusCode.NUMERIC_VALUE_OUT_OF_RANGE; + + +public class ${className} extends BinaryColumnTransformer { + + private static ZoneId zoneId; + + public ${className}( + Type returnType, ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + super(returnType, leftTransformer, rightTransformer); + this.zoneId = zoneId; + } + + @Override + protected void doTransform( + Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) { + for (int i = 0; i < positionCount; i++) { + if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) { + returnType.write${second.dataType?cap_first}( + builder, + transform( + leftTransformer.getType().get${first.dataType?cap_first}(leftColumn, i), + rightTransformer.getType().get${second.dataType?cap_first}(rightColumn, i))); + } else { + builder.appendNull(); + } + } + } + + @Override + protected void checkType() { + // do nothing + } + + public static ${second.dataType} transform(${first.dataType} left, ${second.dataType} right) { + <#if second.instance == "DATE"> + try{ + long timestamp = Math.addExact(left,DateTimeUtils.correctPrecision(DateUtils.parseIntToTimestamp(right, zoneId))); + return DateUtils.parseDateExpressionToInt(DateTimeUtils.convertToLocalDate(timestamp, zoneId)); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("long ${operator.name} overflow: %s + %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + <#else> + try{ + return Math.addExact(left, right); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("long ${operator.name} overflow: %s + %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + + } +} + +<#elseif first.instance != "DATE" && first.instance != "TIMESTAMP" && second.instance != "DATE" && second.instance != "TIMESTAMP"> +<@pp.changeOutputFile name="/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/${className}.java" /> +<#--int、long、float、double with + - * / %--> +<#--assign resultType--> +<#if first.dataType == "double" || second.dataType == "double"> + <#assign resultType = "double" /> +<#elseif first.dataType == "float" || second.dataType == "float"> + <#assign resultType = "float" /> +<#elseif first.dataType == "long" || second.dataType == "long"> + <#assign resultType = "long" /> +<#else> + <#assign resultType = "int" /> + +<#--Parting line--> +package org.apache.iotdb.db.queryengine.transformation.dag.column.binary; + +import org.apache.iotdb.commons.exception.IoTDBRuntimeException; +import org.apache.iotdb.db.exception.sql.SemanticException; +import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer; + +import org.apache.tsfile.block.column.Column; +import org.apache.tsfile.block.column.ColumnBuilder; +import org.apache.tsfile.read.common.type.Type; + +<#if operator.name == "Division" || operator.name == "Modulus"> +import static org.apache.iotdb.rpc.TSStatusCode.DIVISION_BY_ZERO; + +<#if first.dataType == "int" || second.dataType == "int" || first.dataType == "long" || second.dataType == "long"> +import static org.apache.iotdb.rpc.TSStatusCode.NUMERIC_VALUE_OUT_OF_RANGE; + + +public class ${className} extends BinaryColumnTransformer { + public ${className}( + Type returnType, ColumnTransformer leftTransformer, ColumnTransformer rightTransformer) { + super(returnType, leftTransformer, rightTransformer); + } + + @Override + protected void doTransform( + Column leftColumn, Column rightColumn, ColumnBuilder builder, int positionCount) { + for (int i = 0; i < positionCount; i++) { + if (!leftColumn.isNull(i) && !rightColumn.isNull(i)) { + returnType.write${resultType?cap_first}( + builder, + transform( + leftTransformer.getType().get${first.dataType?cap_first}(leftColumn, i), + rightTransformer.getType().get${second.dataType?cap_first}(rightColumn, i))); + } else { + builder.appendNull(); + } + } + } + + @Override + protected void checkType() { + // do nothing + } + + public static ${resultType} transform(${first.dataType} left, ${second.dataType} right) { + <#if (first.dataType == "int" || first.dataType == "long") && (second.dataType == "int" || second.dataType =="long")> + <#switch operator.name> + <#case "Addition"> + try{ + return Math.addExact(left, right); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("${resultType} ${operator.name} overflow: %s + %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),false); + } + <#break> + <#case "Subtraction"> + try{ + return Math.subtractExact(left, right); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("${resultType} ${operator.name} overflow: %s - %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),false); + } + <#break> + <#case "Multiplication"> + try{ + return Math.multiplyExact(left, right); + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException(String.format("${resultType} ${operator.name} overflow: %s * %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + <#break> + <#case "Division"> + try{ + if (left == <#if first.dataType == "int">Integer.MIN_VALUE<#elseif first.dataType == "long">Long.MIN_VALUE && right == -1) { + throw new IoTDBRuntimeException(String.format("${resultType} overflow: %s / %s", left, right),NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),true); + } + return left / right; + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException("Division by zero",DIVISION_BY_ZERO.getStatusCode(),true); + } + <#break> + <#case "Modulus"> + try{ + return left % right; + }catch (ArithmeticException e){ + throw new IoTDBRuntimeException("Division by zero",DIVISION_BY_ZERO.getStatusCode(),true); + } + <#break> + + <#else> + return left ${operator.symbol} right; + + } +} + +<#--Parting line--> + + + \ No newline at end of file diff --git a/iotdb-core/datanode/src/main/codegen/templates/ArithmeticColumnTransformerApi.ftl b/iotdb-core/datanode/src/main/codegen/templates/ArithmeticColumnTransformerApi.ftl new file mode 100644 index 000000000000..3ec6a9b432c5 --- /dev/null +++ b/iotdb-core/datanode/src/main/codegen/templates/ArithmeticColumnTransformerApi.ftl @@ -0,0 +1,218 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<@pp.dropOutputFile /> +<@pp.changeOutputFile name="/org/apache/iotdb/db/queryengine/transformation/dag/column/binary/ArithmeticColumnTransformerApi.java" /> +package org.apache.iotdb.db.queryengine.transformation.dag.column.binary; + +import org.apache.tsfile.read.common.type.Type; + +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.AdditionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.DivisionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.ModulusResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.MultiplicationResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.SubtractionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.metadata.OperatorNotFoundException; +import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer; +import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.DoubleNegationColumnTransformer; +import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.FloatNegationColumnTransformer; +import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.IntNegationColumnTransformer; +import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.LongNegationColumnTransformer; + +import java.time.ZoneId; +import java.util.Arrays; +import java.util.List; + +public class ArithmeticColumnTransformerApi { + <#list mathematicalOperator.binaryOperators as operator> + + public static ColumnTransformer get${operator.name}Transformer( + ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + switch (leftTransformer.getType().getTypeEnum()) { + case INT32: + return getInt${operator.name}Transformer(leftTransformer, rightTransformer, zoneId); + case INT64: + return getLong${operator.name}Transformer(leftTransformer, rightTransformer, zoneId); + case FLOAT: + return getFloat${operator.name}Transformer(leftTransformer, rightTransformer, zoneId); + case DOUBLE: + return getDouble${operator.name}Transformer(leftTransformer, rightTransformer, zoneId); + <#if operator.name == "Addition" || operator.name == "Subtraction"> + case DATE: + return getDate${operator.name}Transformer(leftTransformer, rightTransformer, zoneId); + case TIMESTAMP: + return getTimestamp${operator.name}Transformer(leftTransformer, rightTransformer, zoneId); + + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } + + + public static ColumnTransformer getNegationTransformer(ColumnTransformer columnTransformer) { + switch (columnTransformer.getType().getTypeEnum()) { + case INT32: + return new IntNegationColumnTransformer(columnTransformer.getType(), columnTransformer); + case INT64: + return new LongNegationColumnTransformer(columnTransformer.getType(), columnTransformer); + case FLOAT: + return new FloatNegationColumnTransformer(columnTransformer.getType(), columnTransformer); + case DOUBLE: + return new DoubleNegationColumnTransformer(columnTransformer.getType(), columnTransformer); + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } + <#-- Parting line --> + <#list mathematicalOperator.binaryOperators as operator> + <#list mathematicalDataType.types as first> + <#assign firstType = first.type?replace("Type","")> + <#-- The getTransformer method without Date and Timesatmp --> + <#if firstType != "Date" && firstType != "Timestamp"> + + private static ColumnTransformer get${firstType}${operator.name}Transformer( + ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + List argumentTypes = + Arrays.asList(leftTransformer.getType(), rightTransformer.getType()); + switch (rightTransformer.getType().getTypeEnum()) { + case INT32: + return new ${firstType}${operator.name}IntColumnTransformer( + ${operator.name}Resolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer); + case INT64: + return new ${firstType}${operator.name}LongColumnTransformer( + ${operator.name}Resolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer); + case FLOAT: + return new ${firstType}${operator.name}FloatColumnTransformer( + ${operator.name}Resolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer); + case DOUBLE: + return new ${firstType}${operator.name}DoubleColumnTransformer( + ${operator.name}Resolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer); + <#if operator.name == "Addition" && (firstType == "Int" || firstType == "Long")> + case DATE: + return new ${firstType}${operator.name}DateColumnTransformer( + ${operator.name}Resolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + case TIMESTAMP: + return new ${firstType}${operator.name}TimestampColumnTransformer( + ${operator.name}Resolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } + + + + + private static ColumnTransformer getDateAdditionTransformer( + ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + List argumentTypes = + Arrays.asList(leftTransformer.getType(), rightTransformer.getType()); + switch (rightTransformer.getType().getTypeEnum()) { + case INT32: + return new DateAdditionIntColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + case INT64: + return new DateAdditionLongColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } + + private static ColumnTransformer getTimestampAdditionTransformer( + ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + List argumentTypes = + Arrays.asList(leftTransformer.getType(), rightTransformer.getType()); + switch (rightTransformer.getType().getTypeEnum()) { + case INT32: + return new TimestampAdditionIntColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + case INT64: + return new TimestampAdditionLongColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } + + private static ColumnTransformer getDateSubtractionTransformer( + ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + List argumentTypes = + Arrays.asList(leftTransformer.getType(), rightTransformer.getType()); + switch (rightTransformer.getType().getTypeEnum()) { + case INT32: + return new DateSubtractionIntColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + case INT64: + return new DateSubtractionLongColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } + + private static ColumnTransformer getTimestampSubtractionTransformer( + ColumnTransformer leftTransformer, ColumnTransformer rightTransformer, ZoneId zoneId) { + List argumentTypes = + Arrays.asList(leftTransformer.getType(), rightTransformer.getType()); + switch (rightTransformer.getType().getTypeEnum()) { + case INT32: + return new TimestampSubtractionIntColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + case INT64: + return new TimestampSubtractionLongColumnTransformer( + AdditionResolver.checkConditions(argumentTypes).get(), + leftTransformer, + rightTransformer, + zoneId); + default: + throw new UnsupportedOperationException("Unsupported Type"); + } + } +} diff --git a/iotdb-core/datanode/src/main/codegen/templates/ArithmeticUnaryColumnTransformer.ftl b/iotdb-core/datanode/src/main/codegen/templates/ArithmeticUnaryColumnTransformer.ftl new file mode 100644 index 000000000000..cfd49a512239 --- /dev/null +++ b/iotdb-core/datanode/src/main/codegen/templates/ArithmeticUnaryColumnTransformer.ftl @@ -0,0 +1,67 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +<@pp.dropOutputFile /> +<#list mathematicalDataType.types as type> + <#assign newType = type.type?replace("Type","")> + <#assign className = "${newType}NegationColumnTransformer"> +<#if newType != "Date" && newType != "Timestamp"> + <@pp.changeOutputFile name="/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/${className}.java" /> +package org.apache.iotdb.db.queryengine.transformation.dag.column.unary; + +import org.apache.iotdb.commons.exception.IoTDBRuntimeException; +import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer; + +import org.apache.tsfile.block.column.Column; +import org.apache.tsfile.block.column.ColumnBuilder; +import org.apache.tsfile.read.common.type.Type; + +import static org.apache.iotdb.rpc.TSStatusCode.NUMERIC_VALUE_OUT_OF_RANGE; + +public class ${className} extends UnaryColumnTransformer { + + public ${className}( + Type returnType, ColumnTransformer childColumnTransformer) { + super(returnType, childColumnTransformer); + } + + @Override + protected void doTransform( + Column column, ColumnBuilder columnBuilder) { + for (int i = 0, n = column.getPositionCount(); i < n; i++) { + if (!column.isNull(i)) { + returnType.write${type.dataType?cap_first}( + columnBuilder, transform(childColumnTransformer.getType().get${type.dataType?cap_first}(column, i))); + } else { + columnBuilder.appendNull(); + } + } + } + + @Override + protected void checkType() { + // do nothing + } + + public static ${type.dataType} transform(${type.dataType} value){ + <#if type.dataType == "Int" || type.dataType == "Long"> + if(value == ${type.dataType}.MIN_VALUE){ + throw new IoTDBRuntimeException(String.format("The %s is out of range of ${type.dataType}.", value), NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(), true); + } + + return -value; + } +} + + diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java index 59150d1a703a..82179fff7465 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java @@ -23,6 +23,11 @@ import org.apache.iotdb.db.queryengine.common.SessionInfo; import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider; import org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.InputLocation; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.AdditionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.DivisionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.ModulusResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.MultiplicationResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.SubtractionResolver; import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata; import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ArithmeticBinaryExpression; @@ -59,13 +64,10 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StringLiteral; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Trim; +import org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager; import org.apache.iotdb.db.queryengine.plan.relational.type.TypeNotFoundException; import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer; -import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.ArithmeticAdditionColumnTransformer; -import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.ArithmeticDivisionColumnTransformer; -import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.ArithmeticModuloColumnTransformer; -import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.ArithmeticMultiplicationColumnTransformer; -import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.ArithmeticSubtractionColumnTransformer; +import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.ArithmeticColumnTransformerApi; import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareEqualToColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareGreaterEqualColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.binary.CompareGreaterThanColumnTransformer; @@ -87,7 +89,6 @@ import org.apache.iotdb.db.queryengine.transformation.dag.column.multi.LogicalAndMultiColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.multi.LogicalOrMultiColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.ternary.BetweenColumnTransformer; -import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.ArithmeticNegationColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.IsNullColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.LogicNotColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.RegularColumnTransformer; @@ -159,7 +160,9 @@ import org.apache.tsfile.read.common.type.TypeEnum; import org.apache.tsfile.utils.Binary; +import java.time.ZoneId; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -195,34 +198,61 @@ protected ColumnTransformer visitArithmeticBinary( ArithmeticBinaryExpression node, Context context) { if (!context.cache.containsKey(node)) { if (context.hasSeen.containsKey(node)) { + ColumnTransformer left = process(node.getLeft(), context); + ColumnTransformer right = process(node.getRight(), context); + List types = Arrays.asList(left.getType(), right.getType()); + Type type; + switch (node.getOperator()) { + case ADD: + type = AdditionResolver.checkConditions(types).get(); + break; + case SUBTRACT: + type = SubtractionResolver.checkConditions(types).get(); + break; + case MULTIPLY: + type = MultiplicationResolver.checkConditions(types).get(); + break; + case DIVIDE: + type = DivisionResolver.checkConditions(types).get(); + break; + case MODULUS: + type = ModulusResolver.checkConditions(types).get(); + break; + default: + throw new UnsupportedOperationException( + String.format(UNSUPPORTED_EXPRESSION, node.getOperator())); + } + TSDataType tsDataType = InternalTypeManager.getTSDataType(type); IdentityColumnTransformer identity = new IdentityColumnTransformer( - DOUBLE, context.originSize + context.commonTransformerList.size()); + type, context.originSize + context.commonTransformerList.size()); ColumnTransformer columnTransformer = context.hasSeen.get(node); columnTransformer.addReferenceCount(); context.commonTransformerList.add(columnTransformer); context.leafList.add(identity); - context.inputDataTypes.add(TSDataType.DOUBLE); + context.inputDataTypes.add(tsDataType); context.cache.put(node, identity); } else { + ZoneId zoneId = context.sessionInfo.getZoneId(); ColumnTransformer left = process(node.getLeft(), context); ColumnTransformer right = process(node.getRight(), context); ColumnTransformer child; switch (node.getOperator()) { case ADD: - child = new ArithmeticAdditionColumnTransformer(DOUBLE, left, right); + child = ArithmeticColumnTransformerApi.getAdditionTransformer(left, right, zoneId); break; case SUBTRACT: - child = new ArithmeticSubtractionColumnTransformer(DOUBLE, left, right); + child = ArithmeticColumnTransformerApi.getSubtractionTransformer(left, right, zoneId); break; case MULTIPLY: - child = new ArithmeticMultiplicationColumnTransformer(DOUBLE, left, right); + child = + ArithmeticColumnTransformerApi.getMultiplicationTransformer(left, right, zoneId); break; case DIVIDE: - child = new ArithmeticDivisionColumnTransformer(DOUBLE, left, right); + child = ArithmeticColumnTransformerApi.getDivisionTransformer(left, right, zoneId); break; case MODULUS: - child = new ArithmeticModuloColumnTransformer(DOUBLE, left, right); + child = ArithmeticColumnTransformerApi.getModulusTransformer(left, right, zoneId); break; default: throw new UnsupportedOperationException( @@ -257,7 +287,8 @@ protected ColumnTransformer visitArithmeticUnary( } else { ColumnTransformer childColumnTransformer = process(node.getValue(), context); context.cache.put( - node, new ArithmeticNegationColumnTransformer(DOUBLE, childColumnTransformer)); + node, + ArithmeticColumnTransformerApi.getNegationTransformer(childColumnTransformer)); } } ColumnTransformer res = context.cache.get(node); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/builtin/helper/CastFunctionHelper.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/builtin/helper/CastFunctionHelper.java index 32e3df941d2b..9a610ba05fc7 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/builtin/helper/CastFunctionHelper.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/builtin/helper/CastFunctionHelper.java @@ -175,7 +175,7 @@ public static Object cast( return castInt(intV, targetType); case DATE: int dateV = value instanceof Integer ? (int) value : ((Long) value).intValue(); - return castDate(dateV, targetType); + return castDate(dateV, targetType, session.getZoneId()); case INT64: long longV = (Long) value; return castLong(longV, targetType); @@ -226,7 +226,7 @@ private static Object castInt(int value, Type targetType) { } } - private static Object castDate(int value, Type targetType) { + private static Object castDate(int value, Type targetType, ZoneId zoneId) { switch (targetType.getTypeEnum()) { case INT32: case DATE: @@ -234,7 +234,7 @@ private static Object castDate(int value, Type targetType) { case INT64: return (long) value; case TIMESTAMP: - return DateTimeUtils.correctPrecision(DateUtils.parseIntToDate(value).getTime()); + return DateTimeUtils.correctPrecision(DateUtils.parseIntToTimestamp(value, zoneId)); case FLOAT: return (float) value; case DOUBLE: diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/AdditionResolver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/AdditionResolver.java new file mode 100644 index 000000000000..b3d1836e687f --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/AdditionResolver.java @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic; + +import org.apache.tsfile.read.common.type.Type; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.tsfile.read.common.type.DateType.DATE; +import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; +import static org.apache.tsfile.read.common.type.FloatType.FLOAT; +import static org.apache.tsfile.read.common.type.IntType.INT32; +import static org.apache.tsfile.read.common.type.LongType.INT64; +import static org.apache.tsfile.read.common.type.TimestampType.TIMESTAMP; + +public class AdditionResolver { + + private static final Map> CONDITION_MAP = new HashMap<>(); + + static { + addCondition(INT32, INT32, INT32); + addCondition(INT32, INT64, INT64); + addCondition(INT32, FLOAT, FLOAT); + addCondition(INT32, DOUBLE, DOUBLE); + addCondition(INT32, DATE, DATE); + addCondition(INT32, TIMESTAMP, TIMESTAMP); + + addCondition(INT64, INT32, INT64); + addCondition(INT64, INT64, INT64); + addCondition(INT64, FLOAT, FLOAT); + addCondition(INT64, DOUBLE, DOUBLE); + addCondition(INT64, DATE, DATE); + addCondition(INT64, TIMESTAMP, TIMESTAMP); + + addCondition(FLOAT, INT32, FLOAT); + addCondition(FLOAT, INT64, FLOAT); + addCondition(FLOAT, FLOAT, FLOAT); + addCondition(FLOAT, DOUBLE, DOUBLE); + + addCondition(DOUBLE, INT32, DOUBLE); + addCondition(DOUBLE, INT64, DOUBLE); + addCondition(DOUBLE, FLOAT, DOUBLE); + addCondition(DOUBLE, DOUBLE, DOUBLE); + + addCondition(DATE, INT32, DATE); + addCondition(DATE, INT64, DATE); + + addCondition(TIMESTAMP, INT32, TIMESTAMP); + addCondition(TIMESTAMP, INT64, TIMESTAMP); + } + + private static void addCondition(Type condition1, Type condition2, Type result) { + CONDITION_MAP.computeIfAbsent(condition1, k -> new HashMap<>()).put(condition2, result); + } + + public static Optional checkConditions(List argumentTypes) { + return Optional.ofNullable( + CONDITION_MAP + .getOrDefault(argumentTypes.get(0), Collections.emptyMap()) + .getOrDefault(argumentTypes.get(1), null)); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/DivisionResolver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/DivisionResolver.java new file mode 100644 index 000000000000..0d6bf4664ec9 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/DivisionResolver.java @@ -0,0 +1,66 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic; + +import org.apache.tsfile.read.common.type.Type; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; +import static org.apache.tsfile.read.common.type.FloatType.FLOAT; +import static org.apache.tsfile.read.common.type.IntType.INT32; +import static org.apache.tsfile.read.common.type.LongType.INT64; + +public class DivisionResolver { + + private static final Map> CONDITION_MAP = new HashMap<>(); + + static { + addCondition(INT32, INT32, INT32); + addCondition(INT32, INT64, INT64); + addCondition(INT32, FLOAT, FLOAT); + addCondition(INT32, DOUBLE, DOUBLE); + + addCondition(INT64, INT32, INT64); + addCondition(INT64, INT64, INT64); + addCondition(INT64, FLOAT, FLOAT); + addCondition(INT64, DOUBLE, DOUBLE); + + addCondition(FLOAT, INT32, FLOAT); + addCondition(FLOAT, INT64, FLOAT); + addCondition(FLOAT, FLOAT, FLOAT); + addCondition(FLOAT, DOUBLE, DOUBLE); + + addCondition(DOUBLE, INT32, DOUBLE); + addCondition(DOUBLE, INT64, DOUBLE); + addCondition(DOUBLE, FLOAT, DOUBLE); + addCondition(DOUBLE, DOUBLE, DOUBLE); + } + + private static void addCondition(Type condition1, Type condition2, Type result) { + CONDITION_MAP.computeIfAbsent(condition1, k -> new HashMap<>()).put(condition2, result); + } + + public static Optional checkConditions(List argumentTypes) { + return Optional.ofNullable( + CONDITION_MAP + .getOrDefault(argumentTypes.get(0), Collections.emptyMap()) + .getOrDefault(argumentTypes.get(1), null)); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/ModulusResolver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/ModulusResolver.java new file mode 100644 index 000000000000..c0e777655206 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/ModulusResolver.java @@ -0,0 +1,66 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic; + +import org.apache.tsfile.read.common.type.Type; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; +import static org.apache.tsfile.read.common.type.FloatType.FLOAT; +import static org.apache.tsfile.read.common.type.IntType.INT32; +import static org.apache.tsfile.read.common.type.LongType.INT64; + +public class ModulusResolver { + + private static final Map> CONDITION_MAP = new HashMap<>(); + + static { + addCondition(INT32, INT32, INT32); + addCondition(INT32, INT64, INT64); + addCondition(INT32, FLOAT, FLOAT); + addCondition(INT32, DOUBLE, DOUBLE); + + addCondition(INT64, INT32, INT64); + addCondition(INT64, INT64, INT64); + addCondition(INT64, FLOAT, FLOAT); + addCondition(INT64, DOUBLE, DOUBLE); + + addCondition(FLOAT, INT32, FLOAT); + addCondition(FLOAT, INT64, FLOAT); + addCondition(FLOAT, FLOAT, FLOAT); + addCondition(FLOAT, DOUBLE, DOUBLE); + + addCondition(DOUBLE, INT32, DOUBLE); + addCondition(DOUBLE, INT64, DOUBLE); + addCondition(DOUBLE, FLOAT, DOUBLE); + addCondition(DOUBLE, DOUBLE, DOUBLE); + } + + private static void addCondition(Type condition1, Type condition2, Type result) { + CONDITION_MAP.computeIfAbsent(condition1, k -> new HashMap<>()).put(condition2, result); + } + + public static Optional checkConditions(List argumentTypes) { + return Optional.ofNullable( + CONDITION_MAP + .getOrDefault(argumentTypes.get(0), Collections.emptyMap()) + .getOrDefault(argumentTypes.get(1), null)); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/MultiplicationResolver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/MultiplicationResolver.java new file mode 100644 index 000000000000..769e0172f8ef --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/MultiplicationResolver.java @@ -0,0 +1,66 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic; + +import org.apache.tsfile.read.common.type.Type; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; +import static org.apache.tsfile.read.common.type.FloatType.FLOAT; +import static org.apache.tsfile.read.common.type.IntType.INT32; +import static org.apache.tsfile.read.common.type.LongType.INT64; + +public class MultiplicationResolver { + + private static final Map> CONDITION_MAP = new HashMap<>(); + + static { + addCondition(INT32, INT32, INT32); + addCondition(INT32, INT64, INT64); + addCondition(INT32, FLOAT, FLOAT); + addCondition(INT32, DOUBLE, DOUBLE); + + addCondition(INT64, INT32, INT64); + addCondition(INT64, INT64, INT64); + addCondition(INT64, FLOAT, FLOAT); + addCondition(INT64, DOUBLE, DOUBLE); + + addCondition(FLOAT, INT32, FLOAT); + addCondition(FLOAT, INT64, FLOAT); + addCondition(FLOAT, FLOAT, FLOAT); + addCondition(FLOAT, DOUBLE, DOUBLE); + + addCondition(DOUBLE, INT32, DOUBLE); + addCondition(DOUBLE, INT64, DOUBLE); + addCondition(DOUBLE, FLOAT, DOUBLE); + addCondition(DOUBLE, DOUBLE, DOUBLE); + } + + private static void addCondition(Type condition1, Type condition2, Type result) { + CONDITION_MAP.computeIfAbsent(condition1, k -> new HashMap<>()).put(condition2, result); + } + + public static Optional checkConditions(List argumentTypes) { + return Optional.ofNullable( + CONDITION_MAP + .getOrDefault(argumentTypes.get(0), Collections.emptyMap()) + .getOrDefault(argumentTypes.get(1), null)); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/SubtractionResolver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/SubtractionResolver.java new file mode 100644 index 000000000000..5b7f4a79022f --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/arithmetic/SubtractionResolver.java @@ -0,0 +1,74 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic; + +import org.apache.tsfile.read.common.type.Type; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.tsfile.read.common.type.DateType.DATE; +import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; +import static org.apache.tsfile.read.common.type.FloatType.FLOAT; +import static org.apache.tsfile.read.common.type.IntType.INT32; +import static org.apache.tsfile.read.common.type.LongType.INT64; +import static org.apache.tsfile.read.common.type.TimestampType.TIMESTAMP; + +public class SubtractionResolver { + + private static final Map> CONDITION_MAP = new HashMap<>(); + + static { + addCondition(INT32, INT32, INT32); + addCondition(INT32, INT64, INT64); + addCondition(INT32, FLOAT, FLOAT); + addCondition(INT32, DOUBLE, DOUBLE); + + addCondition(INT64, INT32, INT64); + addCondition(INT64, INT64, INT64); + addCondition(INT64, FLOAT, FLOAT); + addCondition(INT64, DOUBLE, DOUBLE); + + addCondition(FLOAT, INT32, FLOAT); + addCondition(FLOAT, INT64, FLOAT); + addCondition(FLOAT, FLOAT, FLOAT); + addCondition(FLOAT, DOUBLE, DOUBLE); + + addCondition(DOUBLE, INT32, DOUBLE); + addCondition(DOUBLE, INT64, DOUBLE); + addCondition(DOUBLE, FLOAT, DOUBLE); + addCondition(DOUBLE, DOUBLE, DOUBLE); + + addCondition(DATE, INT32, DATE); + addCondition(DATE, INT64, DATE); + + addCondition(TIMESTAMP, INT32, TIMESTAMP); + addCondition(TIMESTAMP, INT64, TIMESTAMP); + } + + private static void addCondition(Type condition1, Type condition2, Type result) { + CONDITION_MAP.computeIfAbsent(condition1, k -> new HashMap<>()).put(condition2, result); + } + + public static Optional checkConditions(List argumentTypes) { + return Optional.ofNullable( + CONDITION_MAP + .getOrDefault(argumentTypes.get(0), Collections.emptyMap()) + .getOrDefault(argumentTypes.get(1), null)); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java index 04b03e12dce9..8f4d1e23eb0c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java @@ -30,6 +30,11 @@ import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher; import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher; import org.apache.iotdb.db.queryengine.plan.relational.function.OperatorType; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.AdditionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.DivisionResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.ModulusResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.MultiplicationResolver; +import org.apache.iotdb.db.queryengine.plan.relational.function.arithmetic.SubtractionResolver; import org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableDeviceSchemaFetcher; import org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableDeviceSchemaValidator; import org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableHeaderSchemaValidator; @@ -59,6 +64,7 @@ import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_SEPARATOR; import static org.apache.tsfile.read.common.type.BinaryType.TEXT; import static org.apache.tsfile.read.common.type.BooleanType.BOOLEAN; +import static org.apache.tsfile.read.common.type.DateType.DATE; import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; import static org.apache.tsfile.read.common.type.FloatType.FLOAT; import static org.apache.tsfile.read.common.type.IntType.INT32; @@ -104,25 +110,58 @@ public Type getOperatorReturnType(OperatorType operatorType, List argumentTypes) { // Boolean type and Binary Type can not be compared with other types return (isNumericType(left) && isNumericType(right)) || (isCharType(left) && isCharType(right)); } + + public static boolean isArithmeticType(Type type) { + return INT32.equals(type) + || INT64.equals(type) + || FLOAT.equals(type) + || DOUBLE.equals(type) + || DATE.equals(type) + || TIMESTAMP.equals(type); + } + + public static boolean isTwoTypeCalculable(List argumentTypes) { + if (argumentTypes.size() != 2) { + return false; + } + Type left = argumentTypes.get(0); + Type right = argumentTypes.get(1); + return isArithmeticType(left) && isArithmeticType(right); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java index 8a3c02fd1ae4..b1f15a6af2d2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java @@ -137,7 +137,7 @@ private void castDate(ColumnBuilder columnBuilder, int value) { case TIMESTAMP: returnType.writeLong( columnBuilder, - DateTimeUtils.correctPrecision(DateUtils.parseIntToDate(value).getTime())); + DateTimeUtils.correctPrecision(DateUtils.parseIntToTimestamp(value, zoneId))); break; case FLOAT: returnType.writeFloat(columnBuilder, value); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ErrorHandlingUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ErrorHandlingUtils.java index 2ac49494acdb..f527d068ee18 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ErrorHandlingUtils.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ErrorHandlingUtils.java @@ -21,6 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.commons.exception.IoTDBException; +import org.apache.iotdb.commons.exception.IoTDBRuntimeException; import org.apache.iotdb.db.exception.BatchProcessException; import org.apache.iotdb.db.exception.QueryInBatchStatementException; import org.apache.iotdb.db.exception.StorageGroupNotReadyException; @@ -152,6 +153,8 @@ private static TSStatus tryCatchQueryException(Exception e) { ((IoTDBException) t.getCause()).getErrorCode(), rootCause.getMessage()); } return RpcUtils.getStatus(TSStatusCode.SEMANTIC_ERROR, rootCause.getMessage()); + } else if (t instanceof IoTDBRuntimeException) { + return RpcUtils.getStatus(((IoTDBRuntimeException) t).getErrorCode(), t.getMessage()); } else if (t instanceof MemoryNotEnoughException) { return RpcUtils.getStatus(TSStatusCode.QUOTA_MEM_QUERY_NOT_ENOUGH, rootCause.getMessage()); } diff --git a/pom.xml b/pom.xml index eae203cc7e5d..a1713a76d7ca 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ 0.14.1 1.9 1.5.6-3 - 1.2.0-efc8f71d-SNAPSHOT + 1.2.0-0c274ae2-SNAPSHOT