Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement syntax checking features #307

Merged
merged 57 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
60cfd97
Initial work for problem provider
worksofliam Aug 26, 2024
a80de11
Merge branch 'main' into feature/syntax_checker
worksofliam Aug 28, 2024
ca218a3
Custom token splitter
worksofliam Aug 28, 2024
71d5d07
Problems now highlight words
worksofliam Aug 28, 2024
1b18170
Merge branch 'main' into feature/syntax_checker
worksofliam Aug 28, 2024
9ff098e
Configurable timeout
worksofliam Aug 28, 2024
b34c810
Correct location of config contribution
worksofliam Aug 28, 2024
443a5ca
Merge branch 'main' into feature/syntax_checker
worksofliam Dec 17, 2024
7ee59bf
Initial work for syntax checking
worksofliam Dec 17, 2024
de32f3b
Correct comment based on the variable content
worksofliam Dec 17, 2024
15d7f7d
Improvements to how syntax checker component is created
worksofliam Dec 17, 2024
34d59d8
Fix broken CI message
worksofliam Dec 18, 2024
79ffbc0
Add status item for language state
worksofliam Dec 18, 2024
b2e1da4
Ability to check entire document
worksofliam Dec 18, 2024
f533a48
Enlarge the max statement size
worksofliam Dec 18, 2024
dc8ee18
Better handling of unknown message IDs
worksofliam Dec 18, 2024
9453d1d
Ability to turn off the automatic syntax checker
worksofliam Dec 18, 2024
49d3b3b
Add configuration option to show SQL syntax warnings in the editor
worksofliam Dec 19, 2024
8ee076e
Set default error type to error
worksofliam Dec 19, 2024
17d5faf
simplify error type determination in syntax checker
worksofliam Dec 19, 2024
ffac453
Better support for prefixes/labels
worksofliam Dec 19, 2024
a436010
Remove all notifications
worksofliam Dec 20, 2024
9c3d98d
Add configuration option to check SQL syntax on file open
worksofliam Dec 20, 2024
1ca97a5
Rename syntax check configuration option and update descriptions for …
worksofliam Dec 20, 2024
5185272
Improve syntax checker descriptions and enhance null safety in compon…
worksofliam Dec 20, 2024
116fe61
Enhance statement range calculation by adding label checks for specif…
worksofliam Dec 20, 2024
c8cce99
Also check unknown statements
worksofliam Dec 20, 2024
96bab44
Validate specific group when editing
worksofliam Dec 20, 2024
2076e36
Progress bar
worksofliam Dec 20, 2024
811f185
Update SQL statement checker to use dynamic message file parameters a…
worksofliam Dec 20, 2024
915b80b
Refactor SQL validation logic to ensure statement ranges are valid be…
worksofliam Dec 20, 2024
73571da
Track diagnostics correctly
worksofliam Dec 20, 2024
c616bff
Disable check button when checker is running
worksofliam Dec 20, 2024
64aee48
Improvements to removing old CL errors
worksofliam Jan 8, 2025
a0e256f
Fix problem finding valid statement range
worksofliam Jan 8, 2025
b8e6406
Better support for not checking long statements
worksofliam Jan 8, 2025
5cb6b13
Increase build version
worksofliam Jan 8, 2025
da907be
Enhance SQL validation to prevent duplicate statement ranges and adju…
worksofliam Jan 8, 2025
e036eba
Refactor error offset calculation for syntax errors outside statement…
worksofliam Jan 8, 2025
18cf39c
Add support for ACS' STOP statement in statement range validation
worksofliam Jan 8, 2025
73cf10f
Add event listener to remove SQL diagnostics on text document close
worksofliam Jan 8, 2025
fab0e33
modify create procedure snippet to include program type and sql data …
worksofliam Jan 8, 2025
43f05a8
Fix issue with depths with ELSE
worksofliam Jan 8, 2025
8586dfa
Add debug logging and bracket depth handling in SQL document parsing
worksofliam Jan 8, 2025
b5e021a
Fix conditional check for ELSE in SQL statement handling
worksofliam Jan 8, 2025
b1f71af
Any prefix is valid
worksofliam Jan 8, 2025
2f0813f
Merge branch 'main' into feature/syntax_checker
worksofliam Jan 8, 2025
5efb6f9
Merge branch 'main' into feature/syntax_checker
worksofliam Jan 8, 2025
184ef2b
update dependencies for Node and Vitest
worksofliam Jan 9, 2025
e24853b
Add handling for ALTER statements with BEGIN in SQL parser
worksofliam Jan 9, 2025
03c8680
Add concept of document safety to disable parsing large files
worksofliam Jan 9, 2025
8fd09c6
update warning message format for large SQL documents
worksofliam Jan 9, 2025
ea9aa99
Add maximum statement count limit to SQL syntax checker
worksofliam Jan 9, 2025
214584d
Reduce maximum statement count limit in SQL syntax checker from 2000 …
worksofliam Jan 9, 2025
e4d298a
Decrease maximum statement count limit in SQL syntax checker from 500…
worksofliam Jan 9, 2025
3bf0cd6
Refactor SQL syntax checker to improve document size handling and err…
worksofliam Jan 9, 2025
7282ae4
Remove invalid errors
worksofliam Jan 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/webpack_ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '👋 A new build is available for this PR based on ${{ github.event.pull_request.head.sha }}.\n * [Download here.](https://github.com/codefori/vscode-ibmi/actions/runs/${{ github.run_id }})\n* [Read more about how to test](https://github.com/codefori/vscode-ibmi/blob/master/.github/pr_testing_template.md)'
body: '👋 A new build is available for this PR based on ${{ github.event.pull_request.head.sha }}.\n * [Download here.](https://github.com/codefori/vscode-db2i/actions/runs/${{ github.run_id }})\n* [Read more about how to test](https://github.com/codefori/vscode-db2i/blob/master/.github/pr_testing_template.md)'
})

- name: Update comment
Expand All @@ -69,5 +69,5 @@ jobs:
body: |
👋 A new build is available for this PR based on ${{ github.event.pull_request.head.sha }}.

* [Download here.](https://github.com/codefori/vscode-ibmi/actions/runs/${{ github.run_id }})
* [Read more about how to test](https://github.com/codefori/vscode-ibmi/blob/master/.github/pr_testing_template.md)
* [Download here.](https://github.com/codefori/vscode-db2i/actions/runs/${{ github.run_id }})
* [Read more about how to test](https://github.com/codefori/vscode-db2i/blob/master/.github/pr_testing_template.md)
9,584 changes: 5,272 additions & 4,312 deletions package-lock.json

Large diffs are not rendered by default.

46 changes: 42 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-db2i",
"displayName": "Db2 for IBM i",
"description": "Db2 for IBM i tools in VS Code",
"version": "1.7.0",
"version": "1.7.0-syntaxcheck12",
"engines": {
"vscode": "^1.95.0"
},
Expand Down Expand Up @@ -199,6 +199,32 @@
"default": false
}
}
},
{
"id": "vscode-db2i.syntax",
"title": "SQL Syntax Checking",
"properties": {
"vscode-db2i.syntax.checkOnOpen": {
"type": "boolean",
"description": "If enabled, will check the syntax of the SQL file when it is opened",
"default": false
},
"vscode-db2i.syntax.checkOnEdit": {
"type": "boolean",
"description": "Whether the syntax checker should run automatically when the document is edited",
"default": true
},
"vscode-db2i.syntax.checkInterval": {
"type": "number",
"description": "Time between editing (ms) and sending a request to syntax check on the server",
"default": 1500
},
"vscode-db2i.syntax.showWarnings": {
"type": "boolean",
"description": "Whether SQL syntax warnings should show in the editor",
"default": false
}
}
}
],
"viewsContainers": {
Expand Down Expand Up @@ -660,6 +686,13 @@
"title": "Export",
"category": "IBM i Notebooks",
"icon": "$(save)"
},
{
"command": "vscode-db2i.syntax.checkDocument",
"title": "Check SQL syntax",
"category": "Db2 for IBM i",
"enablement": "code-for-ibmi:connected == true && vscode-db2i:jobManager.hasJob && vscode-db2i:statementCanCancel != true && vscode-db2i.syntax.checkerAvailable == true && vscode-db2i.syntax.checkerRunning != true",
"icon": "$(check-all)"
}
],
"menus": {
Expand Down Expand Up @@ -1050,6 +1083,11 @@
"command": "vscode-db2i.statement.cancel",
"when": "editorLangId == sql && vscode-db2i:statementCanCancel == true",
"group": "navigation@1"
},
{
"command": "vscode-db2i.syntax.checkDocument",
"when": "editorLangId == sql && code-for-ibmi:connected == true",
"group": "navigation"
}
],
"sql/editor/context": [
Expand Down Expand Up @@ -1274,9 +1312,9 @@
},
"devDependencies": {
"@continuedev/core": "^1.0.13",
"@halcyontech/vscode-ibmi-types": "^2.0.0",
"@halcyontech/vscode-ibmi-types": "^2.14.0",
"@types/glob": "^7.1.3",
"@types/node": "14.x",
"@types/node": "18.x",
"@types/vscode": "^1.95.0",
"esbuild-loader": "^3.0.1",
"eslint": "^7.32.0",
Expand All @@ -1285,7 +1323,7 @@
"raw-loader": "^4.0.2",
"ts-loader": "^9.3.1",
"typescript": "^4.3.2",
"vitest": "^0.33.0",
"vitest": "^2.1.8",
"vscd": "^1.1.0",
"vscode-test": "^1.5.2",
"webpack": "^5.91.0",
Expand Down
3 changes: 1 addition & 2 deletions snippets/create.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
"prefix": "create procedure",
"body": [
"create or replace procedure ${1:procedure_name}($2)",
" program type sub modifies sql data",
" set option usrprf = *user, dynusrprf = *user, commit = *none",
" program type sub",
" modifies sql data",
"begin",
" $0",
"end;"
Expand Down
15 changes: 13 additions & 2 deletions src/base.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { CodeForIBMi } from "@halcyontech/vscode-ibmi-types";
import Instance from "@halcyontech/vscode-ibmi-types/api/Instance";
import {CustomUI} from "@halcyontech/vscode-ibmi-types/api/CustomUI";
import { Extension, extensions } from "vscode";
import { Extension, ExtensionContext, extensions } from "vscode";
import { SQLStatementChecker } from "./connection/syntaxChecker";

let baseExtension: Extension<CodeForIBMi>|undefined;

export function loadBase(): CodeForIBMi|undefined {
export function loadBase(context: ExtensionContext): CodeForIBMi|undefined {
if (!baseExtension) {
baseExtension = (extensions ? extensions.getExtension(`halcyontechltd.code-for-ibmi`) : undefined);

if (baseExtension) {
baseExtension.activate().then(() => {
baseExtension.exports.componentRegistry.registerComponent(context, new SQLStatementChecker());
});
}
}

return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports : undefined);
}

export function getBase(): CodeForIBMi|undefined {
return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports : undefined);
}

export function getInstance(): Instance|undefined {
return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports.instance : undefined);
}
149 changes: 149 additions & 0 deletions src/connection/syntaxChecker/checker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
export const VALIDATOR_NAME = `VALIDATE_STATEMENT`;
export const WRAPPER_NAME = `CHECKSTMTWRAPPED`;
export const VALID_STATEMENT_LENGTH = 32740;
export const MAX_STATEMENT_COUNT = 200;

export function getValidatorSource(schema: string, version: number) {
return /*sql*/`
create or replace procedure ${schema}.${WRAPPER_NAME} (
IN statementText char(${VALID_STATEMENT_LENGTH}) FOR SBCS DATA,
IN statementLength int,
IN recordsProvided int,
IN statementLanguage char(10),
IN options char(24),
OUT statementInfo char(1000),
IN statementInfoLength int,
OUT recordsProcessed int,
OUT errorCode char(1000)
)
LANGUAGE RPGLE
NOT DETERMINISTIC
MODIFIES SQL DATA
EXTERNAL NAME QSYS/QSQCHKS
PARAMETER STYLE GENERAL;

comment on procedure ${schema}/${WRAPPER_NAME} is '${version} - QSQCHKS Wrapper';

create or replace function ${schema}.${VALIDATOR_NAME}(statementText char(${VALID_STATEMENT_LENGTH}) FOR SBCS DATA) --todo: support 1208 parms
returns table (
messageFileName char(10),
messageFileLibrary char(10),
numberOfStatementsBack int,
curStmtLength int,
errorFirstRecordNumber int,
errorFirstColumnNumber int,
errorLastRecordNumber int,
errorLastColumnNumber int,
errorSyntaxRecordNumber int,
errorSyntaxColumnNumber int,
errorSQLMessageID char(7),
errorSQLSTATE char(5),
errorReplacementText char(1000),
messageText char(132)
)
modifies sql data
begin
-- Variables required for parameters
declare stmtLength int default 0;
declare recordsProvided int default 1;
declare statementLanguage char(10) default '*NONE';
declare options char(24) default '000000000000000000000000';
declare statementInfo char(1000) for bit data default '';
declare statementInfoLength int default 1000;
declare recordsProcessed int default 0;
declare errorCode char(1000) default '';
--

-- Variables required for parsing the error list
declare messageFileName char(10);
declare messageFileLibrary char(10);
declare numberOfStatementsBack int default 0;
declare currentStatementIndex int default 0;

-- Variables for each error
declare errorOffset int default 25;
declare curStmtLength int default 0;
declare errorFirstRecordNumber int default 0;
declare errorFirstColumnNumber int default 0;
declare errorLastRecordNumber int default 0;
declare errorLastColumnNumber int default 0;
declare errorSyntaxRecordNumber int default 0;
declare errorSyntaxColumnNumber int default 0;
declare errorSQLMessageID char(7) default '';
declare errorSQLSTATE char(5) default '';
declare errorRepLen int default 0;
declare errorReplacementText char(1000) default '';
declare messageText char(132) default '';

set stmtLength = length(rtrim(statementText));
set options = x'00000001' concat x'00000001' concat x'0000000A' concat '*NONE '; --No naming convention
-- set options = x'00000001' concat x'00000008' concat x'00000004' concat x'000004B0'; -- ccsid

call ${schema}.${WRAPPER_NAME}( statementText, stmtLength, recordsProvided, statementLanguage, options, statementInfo, statementInfoLength, recordsProcessed, errorCode);

-- set ${schema}.outlog = statementInfo;
-- set ${schema}.outlog = substr(statementInfo, 21, 4);

-- Parse the output
set messageFileName = rtrim(substr(statementInfo, 1, 10));
set messageFileLibrary = rtrim(substr(statementInfo, 11, 10));
set numberOfStatementsBack = interpret(substr(statementInfo, 21, 4) as int);
set errorOffset = 25;

while currentStatementIndex < numberOfStatementsBack do
set curStmtLength = interpret(substr(statementInfo, errorOffset, 4) as int);
set errorFirstRecordNumber = interpret(substr(statementInfo, errorOffset + 4, 4) as int);
set errorFirstColumnNumber = interpret(substr(statementInfo, errorOffset + 8, 4) as int);
set errorLastRecordNumber = interpret(substr(statementInfo, errorOffset + 12, 4) as int);
set errorLastColumnNumber = interpret(substr(statementInfo, errorOffset + 16, 4) as int);
set errorSyntaxRecordNumber = interpret(substr(statementInfo, errorOffset + 20, 4) as int);
set errorSyntaxColumnNumber = interpret(substr(statementInfo, errorOffset + 24, 4) as int);
set errorSQLMessageID = rtrim(substr(statementInfo, errorOffset + 28, 7));
set errorSQLSTATE = rtrim(substr(statementInfo, errorOffset + 35, 5));
set errorRepLen = interpret(substr(statementInfo, errorOffset + 40, 4) as int);
set errorReplacementText = rtrim(substr(statementInfo, errorOffset + 44, errorRepLen));

set errorOffset = errorOffset + 44 + errorRepLen;

set currentStatementIndex = currentStatementIndex + 1;

select message_text
into messageText
from table(qsys2.message_file_data(messageFileLibrary, messageFileName))
where message_id = errorSQLMessageID;

pipe (
messageFileName,
messageFileLibrary,
numberOfStatementsBack,
curStmtLength,
errorFirstRecordNumber,
errorFirstColumnNumber,
errorLastRecordNumber,
errorLastColumnNumber,
errorSyntaxRecordNumber,
errorSyntaxColumnNumber,
errorSQLMessageID,
errorSQLSTATE,
errorReplacementText,
messageText
);
end while;

return;
end;

comment on function ${schema}/${VALIDATOR_NAME} is '${version} - SQL Syntax Checker';

--select *
--from table(${schema}.validate_statement('select from sample.employee order by a')) x;
--
--select * from table(qsys2.message_file_data('QSYS', 'QSQLMSG'));
--
--values hex(substr(${schema}.outlog, 21, 4));
--values interpret(hex(substr(${schema}.outlog, 21, 4)) as int);
--values hex(1) concat hex(1) concat hex(10) concat '*NONE ';
--values length(x'000004B8');
--values hex(1200);
`;
}
Loading
Loading