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 11197x 11197x 11197x 11197x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 33469x 11197x 11197x 10674x 10674x 11197x 11197x 246x 246x 11197x 11197x 281x 281x 281x 1515x 1497x 1497x 18x 18x 1515x 4x 4x 4x 4x 4x 14x 14x 1515x 6x 6x 6x 6x 1515x 281x 281x 281x 11197x 11197x 1515x 1515x 1515x 1515x 1515x 1515x 1515x 1515x 1515x 1515x 1515x 1515x 11197x 11197x 18x 9x 9x 9x 9x 9x 10x 10x 4x 4x 10x 5x 14x 14x 11197x 11197x 14x 14x 147x 147x 147x 147x 147x 147x 147x 6x 6x 147x 8x 8x 11197x | 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;
}
}
|