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 15470x 15470x 15470x 15470x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 76108x 15470x 15470x 14908x 14908x 15470x 15470x 264x 264x 15470x 15470x 307x 307x 307x 1664x 1646x 1646x 18x 18x 1664x 4x 4x 4x 4x 4x 14x 14x 1664x 6x 6x 6x 6x 1664x 307x 307x 307x 15470x 15470x 1664x 1664x 1664x 1664x 1664x 1664x 1664x 1664x 1664x 1664x 1664x 1664x 15470x 15470x 18x 9x 9x 9x 9x 9x 10x 10x 4x 4x 10x 5x 14x 14x 15470x 15470x 14x 14x 147x 147x 147x 147x 147x 147x 147x 6x 6x 147x 8x 8x 15470x | 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;
}
}
|