Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11452x 11452x 11452x 11452x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 34233x 11452x 11452x 10927x 10927x 11452x 11452x 247x 247x 11452x 11452x 282x 282x 282x 1542x 1524x 1524x 18x 18x 1542x 4x 4x 4x 4x 4x 14x 14x 1542x 6x 6x 6x 6x 1542x 282x 282x 282x 11452x 11452x 1542x 1542x 1542x 1542x 1542x 1542x 1542x 1542x 1542x 1542x 1542x 1542x 11452x 11452x 18x 9x 9x 9x 9x 9x 10x 10x 4x 4x 10x 5x 14x 14x 11452x 11452x 14x 14x 147x 147x 147x 147x 147x 147x 147x 6x 6x 147x 8x 8x 11452x | import * as Expressions from "../abap/2_statements/expressions";
import * as Statements from "../abap/2_statements/statements";
import {ABAPFile} from "../abap/abap_file";
import {StatementNode} from "../abap/nodes/statement_node";
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRuleMetadata, RuleTag} from "./_irule";
export class NoMandtInDatabaseOperationsConf extends BasicRuleConfig {
}
export class NoMandtInDatabaseOperations extends ABAPRule {
private conf = new NoMandtInDatabaseOperationsConf();
public getMetadata(): IRuleMetadata {
return {
key: "no_mandt_in_database_operations",
title: "No MANDT in database operations",
shortDescription: "Do not specify the client in database operations; the ABAP runtime handles it automatically.",
extendedInformation: "Only check for the name MANDT, not for the field type. The rule does not check for dynamic SQL.",
tags: [RuleTag.SingleFile, RuleTag.Syntax],
badExample: `SELECT * FROM zcustomers
CLIENT SPECIFIED
WHERE mandt = @sy-mandt
INTO TABLE @DATA(customers).`,
goodExample: `SELECT * FROM zcustomers
INTO TABLE @DATA(customers).`,
};
}
public getConfig() {
return this.conf;
}
public setConfig(conf: NoMandtInDatabaseOperationsConf): void {
this.conf = conf;
}
public runParsed(file: ABAPFile): readonly Issue[] {
const issues: Issue[] = [];
for (const statement of file.getStatements()) {
if (this.isDatabaseOperation(statement) === false) {
continue;
}
const mandt = this.findMandtInCondition(statement);
if (mandt !== undefined) {
const issue = Issue.atToken(file, mandt.getFirstToken(), this.getMetadata().title,
this.getMetadata().key, this.conf.severity);
issues.push(issue);
continue;
}
const explicitClient = this.findExplicitClient(statement);
if (explicitClient !== undefined) {
const issue = Issue.atToken(file, explicitClient, this.getMetadata().title,
this.getMetadata().key, this.conf.severity);
issues.push(issue);
}
}
return issues;
}
private isDatabaseOperation(statement: StatementNode): boolean {
const type = statement.get();
return type instanceof Statements.DeleteDatabase
|| type instanceof Statements.InsertDatabase
|| type instanceof Statements.MergeDatabase
|| type instanceof Statements.ModifyDatabase
|| type instanceof Statements.OpenCursor
|| type instanceof Statements.Select
|| type instanceof Statements.SelectLoop
|| type instanceof Statements.UpdateDatabase
|| type instanceof Statements.With
|| type instanceof Statements.WithLoop;
}
private findMandtInCondition(statement: StatementNode) {
for (const condition of statement.findAllExpressions(Expressions.SQLCond)) {
const fields = condition.findAllExpressionsMulti([
Expressions.SQLFieldName,
Expressions.SQLAliasField,
]);
for (const field of fields) {
const name = field.concatTokens().toUpperCase();
if (name === "MANDT" || name.endsWith("~MANDT")) {
return field;
}
}
}
return undefined;
}
private findExplicitClient(statement: StatementNode) {
const tokens = statement.getTokens();
for (let index = 0; index < tokens.length; index++) {
const current = tokens[index].getStr().toUpperCase();
const next = tokens[index + 1]?.getStr().toUpperCase();
const afterNext = tokens[index + 2]?.getStr().toUpperCase();
if ((current === "CLIENT" && next === "SPECIFIED")
|| (current === "USING" && (next === "CLIENT" || next === "CLIENTS"))
|| (current === "USING" && next === "ALL" && afterNext === "CLIENTS")) {
return current === "CLIENT" ? tokens[index] : tokens[index + (next === "ALL" ? 2 : 1)];
}
}
return undefined;
}
}
|