Skip to content

Commit d1b1429

Browse files
committed
test: generic sql
1 parent 987d5b7 commit d1b1429

26 files changed

+2972
-0
lines changed

test/parser/sql/contextCollect/entityCollector.test.ts

+450
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
CREATE TABLE IF NOT EXISTS new_tb1 like like_old_tb;
2+
3+
CREATE TABLE new_tb2 (new_col1 INT COMMENT 'this is new col1', new_col2 STRING)
4+
PARTITIONED BY (YEAR STRING)
5+
CLUSTERED BY (new_col1, NAME)
6+
SORTED BY (new_col1 ASC)
7+
INTO 3 BUCKETS
8+
STORED AS PARQUET
9+
COMMENT 'this is new_tb2 comment';
10+
11+
CREATE TABLE student_copy USING CSV AS SELECT * FROM student;
12+
13+
CREATE VIEW new_view1 (ID COMMENT 'Unique identification number', Name)
14+
COMMENT 'View for experienced employees'
15+
AS SELECT id, name FROM old_tb_1 WHERE working_years > 5;
16+
17+
SELECT id, name, em.deptno, deptname FROM employee AS em CROSS JOIN department AS dept;
18+
19+
INSERT INTO insert_tb (address, name, student_id) VALUES ('Hangzhou, China', 'Kent Yao', 11215016);
20+
21+
INSERT OVERWRITE target_tb TABLE source_tb;
22+
23+
INSERT OVERWRITE DIRECTORY '/path/to/output/directory' SELECT * FROM from_tb WHERE condition;
24+
25+
CREATE DATABASE IF NOT EXISTS customer_db COMMENT 'this is database comment';
26+
27+
USE NAMESPACE ns1;
28+
29+
CREATE OR REPLACE FUNCTION simple_udf AS 'SimpleUdfR';
30+
31+
CREATE FUNCTION simple_udf AS 'SimpleUdfR';

test/parser/sql/errorListener.test.ts

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Sql } from 'src/parser/sql';
2+
3+
const randomText = `dhsdansdnkla ndjnsla ndnalks`;
4+
const sql1 = `ALTER VIEW`;
5+
const sql2 = `SELECT * FROM `;
6+
const sql3 = `DROP SCHEMA aaa aaa`;
7+
8+
describe('Sql validate invalid sql and test msg', () => {
9+
const sql = new Sql();
10+
11+
test('validate random text', () => {
12+
const errors = sql.validate(randomText);
13+
expect(errors.length).toBe(1);
14+
expect(errors[0].message).toBe(
15+
`'dhsdansdnkla' is not valid at this position, expecting a keyword`
16+
);
17+
});
18+
19+
test('validate unComplete sql1', () => {
20+
const errors = sql.validate(sql1);
21+
expect(errors.length).toBe(1);
22+
expect(errors[0].message).toBe('Statement is incomplete');
23+
});
24+
25+
test('validate unComplete sql2', () => {
26+
const errors = sql.validate(sql2);
27+
expect(errors.length).toBe(1);
28+
expect(errors[0].message).toBe(
29+
'Statement is incomplete, expecting an existing table or an existing view or an existing function or a keyword'
30+
);
31+
});
32+
33+
test('validate unComplete sql3', () => {
34+
const errors = sql.validate(sql3);
35+
expect(errors.length).toBe(1);
36+
expect(errors[0].message).toBe(
37+
`'aaa' is not valid at this position, expecting an existing namespace or a keyword`
38+
);
39+
});
40+
41+
test('validate random text cn', () => {
42+
sql.locale = 'zh_CN';
43+
const errors = sql.validate(randomText);
44+
expect(errors.length).toBe(1);
45+
expect(errors[0].message).toBe(`'dhsdansdnkla' 在此位置无效,期望一个关键字`);
46+
});
47+
48+
test('validate unComplete sql1 cn', () => {
49+
const errors = sql.validate(sql1);
50+
expect(errors.length).toBe(1);
51+
expect(errors[0].message).toBe('语句不完整');
52+
});
53+
54+
test('validate unComplete sql2 cn', () => {
55+
const errors = sql.validate(sql2);
56+
expect(errors.length).toBe(1);
57+
expect(errors[0].message).toBe(
58+
'语句不完整,期望一个存在的table或者一个存在的view或者一个存在的function或者一个关键字'
59+
);
60+
});
61+
62+
test('validate unComplete sql3 cn', () => {
63+
const errors = sql.validate(sql3);
64+
expect(errors.length).toBe(1);
65+
expect(errors[0].message).toBe(`'aaa' 在此位置无效,期望一个存在的namespace或者一个关键字`);
66+
});
67+
});

test/parser/sql/errorStrategy.test.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Sql, SqlSplitListener } from 'src/parser/sql';
2+
import { SqlParserListener } from 'src/lib/sql/SqlParserListener';
3+
4+
const validSQL1 = `INSERT INTO country_page_view
5+
VALUES ('Chinese', 'mumiao', 18),
6+
('Amercian', 'georage', 22);`;
7+
const validSQL2 = 'SELECT * FROM tb;';
8+
const inValidSQL = 'CREATE TABLE;';
9+
10+
describe('Sql ErrorStrategy test', () => {
11+
const sql = new Sql();
12+
13+
// TODO: handle unexpected case
14+
// test('begin inValid', () => {
15+
// const sqlText = [inValidSQL, validSQL1, validSQL2].join('\n');
16+
// // parse with empty errorListener
17+
// const parseTree = sql.parse(sqlText, () => {});
18+
// const splitListener = new SqlSplitListener();
19+
// sql.listen(splitListener as SqlParserListener, parseTree);
20+
21+
// const statementCount = splitListener.statementsContext.length;
22+
// splitListener.statementsContext.map((item, index) => {
23+
// if (index !== statementCount - 1 && index !== statementCount - 2) {
24+
// expect(item.exception).not.toBe(null);
25+
// } else {
26+
// expect(item.exception).toBe(null);
27+
// }
28+
// });
29+
// });
30+
31+
// TODO: handle unexpected case
32+
// test('middle inValid', () => {
33+
// const sqlText = [validSQL1, inValidSQL, validSQL2].join('\n');
34+
// // parse with empty errorListener
35+
// const parseTree = sql.parse(sqlText, () => {});
36+
// const splitListener = new SqlSplitListener();
37+
// sql.listen(splitListener as SqlParserListener, parseTree);
38+
39+
// const statementCount = splitListener.statementsContext.length;
40+
// splitListener.statementsContext.map((item, index) => {
41+
// if (index !== statementCount - 1 && index !== 0) {
42+
// expect(item.exception).not.toBe(null);
43+
// } else {
44+
// expect(item.exception).toBe(null);
45+
// }
46+
// });
47+
// });
48+
49+
test('end inValid', () => {
50+
const sqlText = [validSQL1, validSQL2, inValidSQL].join('\n');
51+
// parse with empty errorListener
52+
const parseTree = sql.parse(sqlText, () => {});
53+
const splitListener = new SqlSplitListener();
54+
sql.listen(splitListener as SqlParserListener, parseTree);
55+
56+
splitListener.statementsContext.map((item, index) => {
57+
if (index !== 0 && index !== 1) {
58+
expect(item.exception).not.toBe(null);
59+
} else {
60+
expect(item.exception).toBe(null);
61+
}
62+
});
63+
});
64+
});

test/parser/sql/lexer.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Sql } from 'src/parser/sql';
2+
3+
describe('Sql Lexer tests', () => {
4+
const sql = new Sql();
5+
6+
test('select id,name from user1;', () => {
7+
const sqlText = `select id,name from user1;`;
8+
const tokens = sql.getAllTokens(sqlText);
9+
expect(tokens.length).toBe(10);
10+
});
11+
12+
test('SELECT * FROM t WHERE x = 1 AND y = 2;', () => {
13+
const sqlText = `SELECT * FROM t WHERE x = 1 AND y = 2;`;
14+
const tokens = sql.getAllTokens(sqlText);
15+
expect(tokens.length).toBe(24);
16+
});
17+
});

test/parser/sql/listener.test.ts

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Sql } from 'src/parser/sql';
2+
import { SqlParserListener } from 'src/lib/sql/SqlParserListener';
3+
4+
describe('Sql Listener Tests', () => {
5+
const expectTableName = 'user1';
6+
const sqlText = `select id,name,sex from ${expectTableName};`;
7+
const sql = new Sql();
8+
9+
const parseTree = sql.parse(sqlText);
10+
11+
test('Listener exitTableName', () => {
12+
class MyListener extends SqlParserListener {
13+
result = '';
14+
exitTableName = (ctx): void => {
15+
this.result = ctx.getText().toLowerCase();
16+
};
17+
}
18+
const listener = new MyListener();
19+
20+
sql.listen(listener, parseTree);
21+
expect(listener.result).toBe(expectTableName);
22+
});
23+
24+
test('Split sql listener', async () => {
25+
const singleStatementArr = [
26+
`SELECT /*+ REPARTITION(zip_code) */ name, age, zip_code FROM person SORT BY name ASC, age DESC;`,
27+
28+
`INSERT INTO students FROM applicants SELECT name, address, student_id WHERE qualified = true;`,
29+
30+
`CREATE TABLE student_bucket
31+
USING parquet
32+
CLUSTERED BY (id) INTO 4 buckets (
33+
WITH tmpTable AS (
34+
SELECT * FROM student WHERE id > 100
35+
)
36+
SELECT * FROM tmpTable
37+
);`,
38+
];
39+
40+
const sqlText = singleStatementArr.join('\n');
41+
const sqlSlices = sql.splitSQLByStatement(sqlText);
42+
43+
expect(sqlSlices).not.toBeNull();
44+
45+
// check text in result
46+
expect(sqlSlices.map((item) => item.text)).toEqual(singleStatementArr);
47+
48+
// check startIndex and endIndex in result
49+
sqlSlices.forEach((slice, index) => {
50+
expect(sqlText.slice(slice.startIndex, slice.endIndex + 1)).toBe(
51+
singleStatementArr[index]
52+
);
53+
});
54+
55+
// check lineNumber in result
56+
expect(sqlSlices[0].startLine).toBe(1);
57+
expect(sqlSlices[0].endLine).toBe(1);
58+
expect(sqlSlices[1].startLine).toBe(2);
59+
expect(sqlSlices[1].endLine).toBe(2);
60+
expect(sqlSlices[2].startLine).toBe(3);
61+
expect(sqlSlices[2].endLine).toBe(10);
62+
});
63+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CREATE TABLE VALUES -- unfinished
2+
3+
CREATE TABLE student (id INT, name STRING, age INT) STORED AS ORC;
4+
5+
CREATE SCHEMA customer_db WITH DBPROPERTIES (ID=001, Name='John');
6+
7+
ALTER TABLE StudentInfo ADD COLUMNS (LastName string, DOB timestamp);
8+
9+
SELECT * FROM db. ; -- unfinished
10+
11+
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37);
12+
13+
DESC EXTENDED students name;
14+
15+
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37); -- unfinished
16+
17+
DROP TABLE IF EXISTS employable;
18+
19+
DROP TEMPORARY FUNCTION test_avg;
20+
21+
INSERT INTO products (product_no, name, price) SELECT * FROM db. ; -- unfinished
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SELECT FROM my_db.tb;
2+
3+
SELECT name, calculate_age(birthdate) AS age, FROM students;
4+
5+
INSERT INTO insert_tb SELECT FROM from_tb;
6+
7+
INSERT INTO insert_tb SELECT id, age, FROM from_tb;
8+
9+
CREATE TABLE sorted_census_data AS SELECT FROM unsorted_census_data;
10+
11+
CREATE TABLE sorted_census_data AS SELECT id, age, FROM unsorted_census_data;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
INSERT INTO db.tb ;
2+
3+
SELECT * FROM db.;
4+
5+
CREATE TABLE db. VALUES;
6+
7+
DROP TABLE IF EXISTS db.a;
8+
9+
CREATE OR REPLACE VIEW db.v;
10+
11+
DROP VIEW db.v ;
12+
13+
CREATE FUNCTION fn1;
14+
15+
SELECT name, calculate_age(birthday) AS age FROM students;
16+
17+
CREATE DATABASE db;
18+
19+
DROP SCHEMA IF EXISTS sch;
20+
21+
ANALYZE TABLE students COMPUTE STATISTICS FOR COLUMNS name, co ;
22+
23+
ALTER TABLE StudentInfo ADD COLUMNS (LastName string, );
24+
25+
ALTER TABLE StudentInfo RENAME COLUMN ;
26+
27+
ALTER TABLE StudentInfo RENAME COLUMN name TO t;
28+
29+
ALTER TABLE StudentInfo DROP COLUMNS (LastName, );
30+
31+
ALTER TABLE StudentInfo CHANGE FirstName;
32+
33+
INSERT INTO students ( );
34+
35+
INSERT INTO students ( id, n );
36+
37+
SELECT ;
38+
39+
SELECT id, n;
40+
41+
SELECT FROM tbl;
42+
43+
SELECT id, n FROM tbl;
44+
45+
SELECT id, n FROM tbl GROUP BY ;
46+
47+
SELECT id, n FROM tbl ORDER BY name, i ;
48+
49+
SELECT id FROM tb1 GROUP BY ROLLUP( );
50+
51+
OPTIMIZE db.tb;
52+
53+
OPTIMIZE db.tb ZORDER BY ;
54+
55+
OPTIMIZE db.tb ZORDER BY name, i;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
ALTER
2+
;
3+
CREATE
4+
;
5+
DELETE
6+
;
7+
DESCRIBE
8+
;
9+
DROP
10+
;
11+
INSERT
12+
;
13+
LOAD
14+
;
15+
SHOW
16+
;
17+
EXPORT
18+
;

0 commit comments

Comments
 (0)