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

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
33 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
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)
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 19 additions & 2 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-syntaxcheck2",
"engines": {
"vscode": "^1.95.0"
},
Expand Down Expand Up @@ -64,6 +64,11 @@
"description": "Saved configs for",
"default": {},
"additionalProperties": true
},
"vscode-db2i.syntaxCheckInterval": {
"type": "number",
"description": "Time between editing (ms) and sending a request to syntax check on the server",
"default": 1500
}
}
},
Expand Down Expand Up @@ -655,6 +660,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",
"icon": "$(check-all)"
}
],
"menus": {
Expand Down Expand Up @@ -1040,6 +1052,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 @@ -1264,7 +1281,7 @@
},
"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/vscode": "^1.95.0",
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);
}
147 changes: 147 additions & 0 deletions src/connection/syntaxChecker/checker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
export const VALIDATOR_NAME = `VALIDATE_STATEMENT`;
export const WRAPPER_NAME = `CHECKSTMTWRAPPED`

export function getValidatorSource(schema: string, version: number) {
return /*sql*/`
create or replace procedure ${schema}.${WRAPPER_NAME} (
IN statementText char(15000) 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(15000) 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('QSYS', 'QSQLMSG'))
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