@abaplint/core
Version:
abaplint - Core API
123 lines (122 loc) • 5.43 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SelectPerformance = exports.SelectPerformanceConf = void 0;
const Expressions = require("../abap/2_statements/expressions");
const Statements = require("../abap/2_statements/statements");
const Structures = require("../abap/3_structures/structures");
const _basic_rule_config_1 = require("./_basic_rule_config");
const issue_1 = require("../issue");
const _irule_1 = require("./_irule");
const _abap_object_1 = require("../objects/_abap_object");
const syntax_1 = require("../abap/5_syntax/syntax");
const structure_type_1 = require("../abap/types/basic/structure_type");
const DEFAULT_COLUMNS = 10;
class SelectPerformanceConf extends _basic_rule_config_1.BasicRuleConfig {
constructor() {
super(...arguments);
/** Detects ENDSELECT */
this.endSelect = true;
/** Detects SELECT * */
this.selectStar = true;
/** "SELECT" * is considered okay if the table is less than X columns, the table must be known to the linter
* @default 10
*/
this.starOkayIfFewColumns = DEFAULT_COLUMNS;
}
}
exports.SelectPerformanceConf = SelectPerformanceConf;
class SelectPerformance {
constructor() {
this.conf = new SelectPerformanceConf();
}
getMetadata() {
return {
key: "select_performance",
title: "SELECT performance",
shortDescription: `Various checks regarding SELECT performance.`,
extendedInformation: `ENDSELECT: not reported when the corresponding SELECT has PACKAGE SIZE
SELECT *: not reported if using INTO/APPENDING CORRESPONDING FIELDS OF`,
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Performance],
badExample: `SELECT field1, field2 FROM table
INTO UP TO 1 ROWS ORDER BY field3 DESCENDING.
ENDSELECT.`,
goodExample: `SELECT field1, field2 FROM table UP TO 1 ROWS
INTO TABLE ORDER BY field3 DESCENDING`,
};
}
initialize(reg) {
this.reg = reg;
return this;
}
getConfig() {
if (this.conf.starOkayIfFewColumns === undefined) {
this.conf.starOkayIfFewColumns = DEFAULT_COLUMNS;
}
return this.conf;
}
setConfig(conf) {
this.conf = conf;
}
run(obj) {
if (!(obj instanceof _abap_object_1.ABAPObject)) {
return [];
}
const issues = [];
for (const file of obj.getABAPFiles()) {
const stru = file.getStructure();
if (stru === undefined) {
return issues;
}
if (this.conf.endSelect) {
for (const s of stru.findAllStructures(Structures.Select) || []) {
const select = s.findDirectStatement(Statements.SelectLoop);
if (select === undefined || select.concatTokens().toUpperCase().includes("PACKAGE SIZE")) {
continue;
}
const message = "Avoid use of ENDSELECT";
issues.push(issue_1.Issue.atStatement(file, select, message, this.getMetadata().key, this.conf.severity));
}
}
if (this.conf.selectStar) {
const spaghetti = new syntax_1.SyntaxLogic(this.reg, obj).run().spaghetti;
const selects = stru.findAllStatements(Statements.Select);
selects.push(...stru.findAllStatements(Statements.SelectLoop));
for (const s of selects) {
const concat = s.concatTokens().toUpperCase();
if (concat.startsWith("SELECT * ") === false
&& concat.startsWith("SELECT SINGLE * ") === false) {
continue;
}
else if (concat.includes(" INTO CORRESPONDING FIELDS OF ")
|| concat.includes(" APPENDING CORRESPONDING FIELDS OF ")) {
continue;
}
const columnCount = this.findNumberOfColumns(s, file, spaghetti);
if (columnCount
&& columnCount <= this.getConfig().starOkayIfFewColumns) {
continue;
}
const message = "Avoid use of SELECT *";
issues.push(issue_1.Issue.atToken(file, s.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
}
}
}
return issues;
}
findNumberOfColumns(s, file, spaghetti) {
const dbnames = s.findAllExpressions(Expressions.DatabaseTable);
if (dbnames.length === 1) {
const start = dbnames[0].getFirstToken().getStart();
const scope = spaghetti.lookupPosition(start, file.getFilename());
const name = scope === null || scope === void 0 ? void 0 : scope.findTableReference(start);
const tabl = this.reg.getObject("TABL", name);
const parsed = tabl === null || tabl === void 0 ? void 0 : tabl.parseType(this.reg);
if (parsed instanceof structure_type_1.StructureType) {
return parsed.getComponents().length;
}
}
return undefined;
}
}
exports.SelectPerformance = SelectPerformance;
//# sourceMappingURL=select_performance.js.map