Skip to content

Commit a271fe9

Browse files
committed
Better support for THEN and LOOP
Signed-off-by: worksofliam <[email protected]>
1 parent 5b6e17c commit a271fe9

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

src/language/sql/document.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ export default class Document {
5050

5151
case `keyword`:
5252
switch (tokens[i].value?.toUpperCase()) {
53+
case `LOOP`:
54+
// This handles the case that 'END LOOP' is supported.
55+
if (currentStatementType === StatementType.End) {
56+
break;
57+
}
5358
case `BEGIN`:
5459
case `DO`:
60+
case `THEN`:
5561
// We include BEGIN in the current statement
5662
// then the next statement beings
5763
const statementTokens = tokens.slice(statementStart, i+1);
@@ -96,6 +102,7 @@ export default class Document {
96102
let depth = 0;
97103

98104
for (const statement of this.statements) {
105+
console.log(currentGroup);
99106
if (statement.isBlockEnder()) {
100107
if (depth > 0) {
101108
currentGroup.push(statement);

src/language/sql/statement.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default class Statement {
4343
// These statements can end with BEGIN, which signifies a block starter
4444
if ([StatementType.Create, StatementType.Declare].includes(this.type)) {
4545
const last = this.tokens[this.tokens.length-1];
46-
if (tokenIs(last, `keyword`, `BEGIN`) || tokenIs(last, `keyword`, `DO`)) {
46+
if (tokenIs(last, `keyword`, `BEGIN`)) {
4747
return true;
4848
}
4949
}

src/language/sql/tests/statements.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,76 @@ describe(`Object references`, () => {
10131013
expect(refs[1].object.name).toBe(`OBJECT_STATISTICS`);
10141014
expect(refs[1].object.schema).toBe(`QSYS2`);
10151015
expect(refs[1].alias).toBe(`b`);
1016+
});
1017+
1018+
test('LOOP statements', () => {
1019+
const lines = [
1020+
`CREATE OR REPLACE PROCEDURE KRAKEN917.Wait_For_Kraken(kraken_job_name varchar(10), delay_time bigint default 30)`,
1021+
`BEGIN`,
1022+
` DECLARE v_sql_stmt CLOB(1M) CCSID 37;`,
1023+
``,
1024+
` DECLARE number_of_active_jobs INT;`,
1025+
``,
1026+
` CALL systools.lprintf('Waiting for job to finish...');`,
1027+
``,
1028+
` fetch_loop: LOOP`,
1029+
` SET v_sql_stmt ='values(SELECT COUNT(*) FROM TABLE (qsys2.active_job_info(subsystem_list_filter => ''QBATCH'')) WHERE JOB_NAME_SHORT LIKE ''' CONCAT kraken_job_name CONCAT ''') into ?';`,
1030+
``,
1031+
` PREPARE values_st FROM v_sql_stmt;`,
1032+
``,
1033+
` EXECUTE values_st USING number_of_active_jobs;`,
1034+
``,
1035+
` IF number_of_active_jobs = 0 THEN`,
1036+
` CALL SYSTOOLS.LPRINTF(kraken_job_name CONCAT ' JOB DONE');`,
1037+
``,
1038+
` LEAVE fetch_loop;`,
1039+
``,
1040+
` END IF;`,
1041+
``,
1042+
` CALL qsys2.qcmdexc('DLYJOB ' CONCAT delay_time);`,
1043+
``,
1044+
` END LOOP fetch_loop;`,
1045+
``,
1046+
`END;`,
1047+
].join(`\n`);
1048+
1049+
const document = new Document(lines);
1050+
1051+
const groups = document.getStatementGroups();
1052+
expect(groups.length).toBe(1);
1053+
1054+
const group = groups[0];
1055+
1056+
// console.log(group.statements.map((s, so) => `${so} ` + s.type.padEnd(10) + ` ` + s.tokens.map(t => t.value).join(' ')));
1057+
1058+
expect(group.statements.length).toBe(16);
1059+
expect(group.statements.map(s => s.type)).toEqual([
1060+
'Create', 'Declare',
1061+
'Declare', 'Call',
1062+
'Unknown', 'Unknown',
1063+
'Unknown', 'Unknown',
1064+
'Unknown', 'Call',
1065+
'Unknown', 'End',
1066+
'Call', 'End',
1067+
'Unknown', 'End'
1068+
]);
1069+
1070+
let refs;
1071+
1072+
const firstCall = group.statements[3];
1073+
refs = firstCall.getObjectReferences();
1074+
expect(refs.length).toBe(1);
1075+
expect(refs[0].object.name).toBe(`lprintf`);
1076+
1077+
const secondCall = group.statements[9];
1078+
refs = secondCall.getObjectReferences();
1079+
expect(refs.length).toBe(1);
1080+
expect(refs[0].object.name).toBe(`LPRINTF`);
1081+
1082+
const thirdCall = group.statements[12];
1083+
refs = thirdCall.getObjectReferences();
1084+
expect(refs.length).toBe(1);
1085+
expect(refs[0].object.name).toBe(`qcmdexc`);
10161086
})
10171087
});
10181088

src/language/sql/tokens.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export default class SQLTokeniser {
7474
{
7575
name: `KEYWORD`,
7676
match: [{ type: `word`, match: (value: string) => {
77-
return [`AS`, `FOR`, `OR`, `REPLACE`, `BEGIN`, `DO`, `END`, `CURSOR`, `DEFAULT`, `HANDLER`, `REFERENCES`, `ON`, `UNIQUE`, `SPECIFIC`, `EXTERNAL`].includes(value.toUpperCase());
77+
return [`AS`, `FOR`, `OR`, `REPLACE`, `BEGIN`, `DO`, `THEN`, `LOOP`, `END`, `CURSOR`, `DEFAULT`, `HANDLER`, `REFERENCES`, `ON`, `UNIQUE`, `SPECIFIC`, `EXTERNAL`].includes(value.toUpperCase());
7878
} }],
7979
becomes: `keyword`,
8080
},

0 commit comments

Comments
 (0)