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 11712x 11712x 11712x 11712x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 35017x 11712x 11712x 11175x 11175x 11712x 11712x 253x 253x 11712x 11712x 287x 287x 287x 1575x 1557x 1557x 18x 18x 1575x 4x 4x 4x 4x 4x 14x 14x 1575x 6x 6x 6x 6x 1575x 287x 287x 287x 11712x 11712x 1575x 1575x 1575x 1575x 1575x 1575x 1575x 1575x 1575x 1575x 1575x 1575x 11712x 11712x 18x 9x 9x 9x 9x 9x 10x 10x 4x 4x 10x 5x 14x 14x 11712x 11712x 14x 14x 147x 147x 147x 147x 147x 147x 147x 6x 6x 147x 8x 8x 11712x | 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;
}
}
|