Skip to content

Commit 7131dab

Browse files
authored
feat: Add 36 new built-in scalar functions about BLOB type
1 parent 25c86c2 commit 7131dab

File tree

100 files changed

+17695
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+17695
-3
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.relational.it.query.recent.scalar;
21+
22+
import org.apache.iotdb.it.env.EnvFactory;
23+
import org.apache.iotdb.it.framework.IoTDBTestRunner;
24+
import org.apache.iotdb.itbase.category.TableClusterIT;
25+
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
26+
import org.apache.iotdb.rpc.TSStatusCode;
27+
28+
import org.junit.AfterClass;
29+
import org.junit.BeforeClass;
30+
import org.junit.Test;
31+
import org.junit.experimental.categories.Category;
32+
import org.junit.runner.RunWith;
33+
34+
import static org.apache.iotdb.db.it.utils.TestUtils.prepareTableData;
35+
import static org.apache.iotdb.db.it.utils.TestUtils.tableAssertTestFail;
36+
import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest;
37+
38+
@RunWith(IoTDBTestRunner.class)
39+
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
40+
public class IoTDBCRC32FunctionIT {
41+
42+
private static final String DATABASE_NAME = "test_crc32_function";
43+
private static final String[] createSqls =
44+
new String[] {
45+
"CREATE DATABASE " + DATABASE_NAME,
46+
"USE " + DATABASE_NAME,
47+
"CREATE TABLE table1(c_text TEXT FIELD, c_string STRING FIELD, c_blob BLOB FIELD, c_int INT32 FIELD)",
48+
// 1. Test standard string 'hello'
49+
"INSERT INTO table1(time, c_text, c_string) VALUES (1, 'hello', 'hello')",
50+
// 2. Test Chinese characters '你好' (UTF-8)
51+
"INSERT INTO table1(time, c_text, c_string) VALUES (2, '你好', '你好')",
52+
// 3. Test empty string
53+
"INSERT INTO table1(time, c_text, c_string) VALUES (3, '', '')",
54+
// 4. Test null values
55+
"INSERT INTO table1(time, c_int) VALUES (4, 404)",
56+
// 5. Test special characters and spaces
57+
"INSERT INTO table1(time, c_text, c_string) VALUES (5, 'Hello, World!', 'Hello, World!')",
58+
// 6. Test blob data (hex representation of 'test')
59+
"INSERT INTO table1(time, c_blob) VALUES (6, x'74657374')",
60+
// 7. Test standard benchmark string '123456789'
61+
"INSERT INTO table1(time, c_text) VALUES (7, '123456789')"
62+
};
63+
64+
@BeforeClass
65+
public static void setUp() throws Exception {
66+
EnvFactory.getEnv().initClusterEnvironment();
67+
prepareTableData(createSqls);
68+
}
69+
70+
@AfterClass
71+
public static void tearDown() throws Exception {
72+
EnvFactory.getEnv().cleanClusterEnvironment();
73+
}
74+
75+
/** Validate the CRC32 checksum for TEXT/STRING types */
76+
@Test
77+
public void testCrc32OnTextString() {
78+
79+
String[] expectedHeader = new String[] {"time", "crc32(c_text)", "crc32(c_string)"};
80+
String[] retArray =
81+
new String[] {
82+
// 'hello' -> 907060870
83+
"1970-01-01T00:00:00.001Z,907060870,907060870,",
84+
// '你好' (UTF-8) -> 3690463373
85+
"1970-01-01T00:00:00.002Z,1352841281,1352841281,",
86+
// '' -> 0
87+
"1970-01-01T00:00:00.003Z,0,0,",
88+
// null -> null
89+
"1970-01-01T00:00:00.004Z,null,null,",
90+
// 'Hello, World!' -> 4158428615
91+
"1970-01-01T00:00:00.005Z,3964322768,3964322768,"
92+
};
93+
tableResultSetEqualTest(
94+
"SELECT time, crc32(c_text) as \"crc32(c_text)\", crc32(c_string) as \"crc32(c_string)\" FROM table1 where time < 6",
95+
expectedHeader,
96+
retArray,
97+
DATABASE_NAME);
98+
}
99+
100+
/** Validate the CRC32 checksum for BLOB type */
101+
@Test
102+
public void testCrc32OnBlob() {
103+
String[] expectedHeader = new String[] {"time", "crc32(c_blob)"};
104+
String[] retArray =
105+
new String[] {
106+
// blob x'74657374' ('test') -> 3632233996
107+
"1970-01-01T00:00:00.006Z,3632233996,"
108+
};
109+
tableResultSetEqualTest(
110+
"SELECT time, crc32(c_blob) as \"crc32(c_blob)\" FROM table1 where time = 6",
111+
expectedHeader,
112+
retArray,
113+
DATABASE_NAME);
114+
}
115+
116+
/** Validate against a known industry-standard value */
117+
@Test
118+
public void testCrc32KnownValue() {
119+
String[] expectedHeader = new String[] {"time", "crc32(c_text)"};
120+
String[] retArray =
121+
new String[] {
122+
// '123456789' -> 3421780262
123+
"1970-01-01T00:00:00.007Z,3421780262,"
124+
};
125+
tableResultSetEqualTest(
126+
"SELECT time, crc32(c_text) as \"crc32(c_text)\" FROM table1 where time = 7",
127+
expectedHeader,
128+
retArray,
129+
DATABASE_NAME);
130+
}
131+
132+
/** Test that invalid input types or number of arguments are rejected */
133+
@Test
134+
public void testCrc32FunctionOnInvalidInputs() {
135+
String expectedErrorMessage =
136+
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
137+
+ ": Scalar function crc32 only accepts one argument and it must be TEXT, STRING, or BLOB data type.";
138+
139+
// Test with invalid data type (INT32)
140+
tableAssertTestFail("SELECT crc32(c_int) FROM table1", expectedErrorMessage, DATABASE_NAME);
141+
142+
// Test with multiple arguments
143+
tableAssertTestFail(
144+
"SELECT crc32(c_text, 'another_arg') FROM table1", expectedErrorMessage, DATABASE_NAME);
145+
146+
// Test with no arguments
147+
tableAssertTestFail("SELECT crc32() FROM table1", expectedErrorMessage, DATABASE_NAME);
148+
}
149+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.relational.it.query.recent.scalar;
21+
22+
import org.apache.iotdb.it.env.EnvFactory;
23+
import org.apache.iotdb.it.framework.IoTDBTestRunner;
24+
import org.apache.iotdb.itbase.category.TableClusterIT;
25+
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
26+
import org.apache.iotdb.rpc.TSStatusCode;
27+
28+
import org.junit.AfterClass;
29+
import org.junit.BeforeClass;
30+
import org.junit.Test;
31+
import org.junit.experimental.categories.Category;
32+
import org.junit.runner.RunWith;
33+
34+
import static org.apache.iotdb.db.it.utils.TestUtils.prepareTableData;
35+
import static org.apache.iotdb.db.it.utils.TestUtils.tableAssertTestFail;
36+
import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest;
37+
38+
@RunWith(IoTDBTestRunner.class)
39+
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
40+
public class IoTDBFromBase32ColumnFunctionIT {
41+
42+
private static final String DATABASE_NAME = "test_from_base32_function";
43+
44+
private static final String[] createSqls =
45+
new String[] {
46+
"CREATE DATABASE " + DATABASE_NAME,
47+
"USE " + DATABASE_NAME,
48+
"CREATE TABLE table1(c_text TEXT, c_string STRING, c_int INT32)",
49+
50+
// Case 1: Basic ASCII string
51+
// 'IoTDB is fun!' -> Base32: JBCGC3LFN5ZGIIDUNBSSA3LSEI====== -> BLOB:
52+
"INSERT INTO table1(time, c_text, c_string) VALUES (1, 'JBCGC3LFN5ZGIIDUNBSSA3LSEI======', 'JBCGC3LFN5ZGIIDUNBSSA3LSEI======')",
53+
54+
// Case 2: UTF-8 string
55+
// '你好, 世界!' -> Base32: 2W4V625443J56W4S4E73H5BUMM4A====== -> BLOB:
56+
// X'e4bda0e5a5bd2c20e4b896e7958c21'
57+
"INSERT INTO table1(time, c_text, c_string) VALUES (2, '2W4V625443J56W4S4E73H5BUMM4A======', '2W4V625443J56W4S4E73H5BUMM4A======')",
58+
59+
// Case 3: Empty string
60+
// '' -> Base32: '' -> BLOB: X''
61+
"INSERT INTO table1(time, c_text, c_string) VALUES (3, '', '')",
62+
63+
// Case 4: Null value
64+
"INSERT INTO table1(time, c_int) VALUES (4, 100)",
65+
66+
// Case 5: Padding scenarios for 1-4 bytes
67+
// 'f' (0x66) -> Base32: MY======
68+
"INSERT INTO table1(time, c_text, c_string) VALUES (5, 'MY======', 'MY======')",
69+
// 'fo' (0x666f) -> Base32: MZXQ====
70+
"INSERT INTO table1(time, c_text, c_string) VALUES (6, 'MZXQ====', 'MZXQ====')",
71+
// 'foo' (0x666f6f) -> Base32: MZXW6===
72+
"INSERT INTO table1(time, c_text, c_string) VALUES (7, 'MZXW6===', 'MZXW6===')",
73+
// 'foob' (0x666f6f62) -> Base32: MZXW6YQ=
74+
"INSERT INTO table1(time, c_text, c_string) VALUES (8, 'MZXW6YQ=', 'MZXW6YQ=')",
75+
76+
// Case 9: No padding needed (5 bytes)
77+
// 'fooba' -> Base32: MZXW6YQB
78+
"INSERT INTO table1(time, c_text, c_string) VALUES (9, 'MZXW6YQB', 'MZXW6YQB')",
79+
80+
// Case 10: Optional padding test (decoder should handle missing padding)
81+
// 'foo' (0x666f6f) -> Base32 without padding: MZXW6
82+
"INSERT INTO table1(time, c_text, c_string) VALUES (10, 'MZXW6', 'MZXW6')",
83+
};
84+
85+
@BeforeClass
86+
public static void setUp() throws Exception {
87+
EnvFactory.getEnv().initClusterEnvironment();
88+
prepareTableData(createSqls);
89+
}
90+
91+
@AfterClass
92+
public static void tearDown() throws Exception {
93+
EnvFactory.getEnv().cleanClusterEnvironment();
94+
}
95+
96+
/** Validates the from_base32() function on various supported and valid inputs. */
97+
@Test
98+
public void testFromBase32OnValidInputs() {
99+
String[] expectedHeader = new String[] {"time", "from_base32(c_text)", "from_base32(c_string)"};
100+
String[] retArray =
101+
new String[] {
102+
// 1. Basic ASCII
103+
"1970-01-01T00:00:00.001Z,0x4844616d656f726420746865206d7222,0x4844616d656f726420746865206d7222,",
104+
// 2. UTF-8
105+
"1970-01-01T00:00:00.002Z,0xd5b95f6bbce6d3df5b92e13fb3f4346338,0xd5b95f6bbce6d3df5b92e13fb3f4346338,",
106+
// 3. Empty string
107+
"1970-01-01T00:00:00.003Z,0x,0x,",
108+
// 4. Null input
109+
"1970-01-01T00:00:00.004Z,null,null,",
110+
// 5. 1 byte with padding
111+
"1970-01-01T00:00:00.005Z,0x66,0x66,",
112+
// 6. 2 bytes with padding
113+
"1970-01-01T00:00:00.006Z,0x666f,0x666f,",
114+
// 7. 3 bytes with padding
115+
"1970-01-01T00:00:00.007Z,0x666f6f,0x666f6f,",
116+
// 8. 4 bytes with padding
117+
"1970-01-01T00:00:00.008Z,0x666f6f62,0x666f6f62,",
118+
// 9. 5 bytes, no padding
119+
"1970-01-01T00:00:00.009Z,0x666f6f6201,0x666f6f6201,",
120+
// 10. Optional padding
121+
"1970-01-01T00:00:00.010Z,0x666f6f,0x666f6f,",
122+
};
123+
124+
tableResultSetEqualTest(
125+
"SELECT time, from_base32(c_text) as \"from_base32(c_text)\", from_base32(c_string) as \"from_base32(c_string)\" FROM table1",
126+
expectedHeader,
127+
retArray,
128+
DATABASE_NAME);
129+
}
130+
131+
/** Tests for invalid arguments passed to the from_base32() function. */
132+
@Test
133+
public void testFromBase32FunctionOnInvalidArguments() {
134+
String expectedErrorMessage =
135+
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
136+
+ ": Scalar function from_base32 only accepts one argument and it must be TEXT or STRING data type.";
137+
138+
// Test with invalid parameter type (INT32)
139+
tableAssertTestFail(
140+
"SELECT from_base32(c_int) FROM table1", expectedErrorMessage, DATABASE_NAME);
141+
142+
// Test with invalid parameter count (0)
143+
tableAssertTestFail("SELECT from_base32() FROM table1", expectedErrorMessage, DATABASE_NAME);
144+
145+
// Test with invalid parameter count (>1)
146+
tableAssertTestFail(
147+
"SELECT from_base32(c_text, c_string) FROM table1", expectedErrorMessage, DATABASE_NAME);
148+
}
149+
150+
/** Validates that from_base32() fails when given incorrectly formatted Base32 strings. */
151+
@Test
152+
public void testFromBase32FunctionOnInvalidDataFormat() {
153+
String baseErrorMessage =
154+
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
155+
+ ": Failed to execute function 'from_base32' due to an invalid input format. Problematic value:";
156+
157+
// Invalid character: '0' (not in Base32 alphabet)
158+
tableAssertTestFail(
159+
"SELECT from_base32('JBCGC3LFN5ZGIIDUNBSSA3LSE0==') FROM table1", // [FIXED] Added FROM
160+
// clause
161+
baseErrorMessage + " JBCGC3LFN5ZGIIDUNBSSA3LSE0==",
162+
DATABASE_NAME);
163+
164+
// Invalid character: '1' (not in Base32 alphabet)
165+
tableAssertTestFail(
166+
"SELECT from_base32('JBCGC3LFN5ZGIIDUNBSSA3LSE1==') FROM table1", // [FIXED] Added FROM
167+
// clause
168+
baseErrorMessage + " JBCGC3LFN5ZGIIDUNBSSA3LSE1==",
169+
DATABASE_NAME);
170+
171+
// Invalid character: '8' (not in Base32 alphabet)
172+
tableAssertTestFail(
173+
"SELECT from_base32('JBCGC3LFN5ZGIIDUNBSSA3LSE8==') FROM table1", // [FIXED] Added FROM
174+
// clause
175+
baseErrorMessage + " JBCGC3LFN5ZGIIDUNBSSA3LSE8==",
176+
DATABASE_NAME);
177+
178+
// Invalid character: '9' (not in Base32 alphabet)
179+
tableAssertTestFail(
180+
"SELECT from_base32('JBCGC3LFN5ZGIIDUNBSSA3LSE9==') FROM table1", // [FIXED] Added FROM
181+
// clause
182+
baseErrorMessage + " JBCGC3LFN5ZGIIDUNBSSA3LSE9==",
183+
DATABASE_NAME);
184+
185+
// Invalid character: '-' (from Base64URL)
186+
tableAssertTestFail(
187+
"SELECT from_base32('MZXW6YQ-') FROM table1", // [FIXED] Added FROM clause
188+
baseErrorMessage + " MZXW6YQ-",
189+
DATABASE_NAME);
190+
191+
// Invalid padding: padding character in the middle
192+
tableAssertTestFail(
193+
"SELECT from_base32('MZXW6=Q=') FROM table1", // [FIXED] Added FROM clause
194+
baseErrorMessage + " MZXW6=Q=",
195+
DATABASE_NAME);
196+
}
197+
}

0 commit comments

Comments
 (0)