Skip to content

Commit

Permalink
Merge pull request #307 from codefori/feature/syntax_checker
Browse files Browse the repository at this point in the history
Implement syntax checking features
  • Loading branch information
worksofliam authored Jan 9, 2025
2 parents d93eaa0 + 7282ae4 commit 268ffb5
Show file tree
Hide file tree
Showing 26 changed files with 6,445 additions and 4,374 deletions.
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

0 comments on commit 268ffb5

Please sign in to comment.