Abap
BREAK-POINT statement should not be used in production
BREAK-POINT statement should not be used in production
A BREAK-POINT
statement is used when debugging an application with help of the ABAP Debugger. But such debugging statements could make an application vulnerable to attackers, and should not be left in the source code.
Jump statements should not be redundant
Jump statements should not be redundant
Jump statements, such as CHECK and CONTINUE
let you change the default flow of program execution, but jump statements that direct the control flow to the original direction are just a waste of keystrokes.
An internal table should be sorted before duplicates are deleted
An internal table should be sorted before duplicates are deleted
Calling DELETE ADJACENT DUPLICATES won’t reliably do any good if the table hasn’t first been sorted to put duplicates side by side, since the ADJACENT
part of the command looks for multiple rows side-by-side with the same content.
FORM... ENDFORM and PERFORM should not be used
FORM... ENDFORM and PERFORM should not be used
Procedural development in general, and FORM… ENDFORM, and PERFORM
specifically, have been been classified as obsolete by SAP and should be avoided. Classes and methods should be used for all new development.
LOOP ASSIGNING with field-symbols should be used instead of LOOP INTO with MODIFY
LOOP ASSIGNING with field-symbols should be used instead of LOOP INTO with MODIFY
Using `LOOP…INTO with MODIFY statements will put the required record in a work area, process it and put it back in the internal table. It is more efficient to modify the internal table directly by using LOOP…ASSIGNING and field-symbols.
This rule raises an issue when a LOOP…INTO contains one or more MODIFY` statements.
Standard tables should be searched using BINARY SEARCH
Standard tables should be searched using BINARY SEARCH
The `READ TABLE … WITH KEY … statement performs a linear search of STANDARD tables, which is very inefficient in most cases.
This rule raises an issue when a READ TABLE … WITH KEY … statement does not finish with BINARY SEARCH. No issue will be raised for HASHED and SORTED` tables.
SAP standard tables should not be modified via Open SQL statements
SAP standard tables should not be modified via Open SQL statements
Modifying SAP standard tables via an Open SQL statement can result in data corruption and unexpected behavior. This is because a direct modification bypasses all validation mechanisms.
Instead, the use of standard functions or SAP Business Add-Ins (BAdIs) is recommended.
This rule raises an issue on Open SQL statements INSERT, UPDATE, MODIFY, or SELECT … FOR UPDATE
which target an SAP table, i.e. a table with a name starting with a character between “A” and “X”, case insensitive.
SYSTEM-CALL statement should not be used
SYSTEM-CALL statement should not be used
The ABAP documentation is pretty clear on this subject :
Expressions should not be too complex
Expressions should not be too complex
The complexity of an expression is defined by the number of AND, OR, XOR and EQUIV
operators it contains.
A single expression’s complexity should not become too high to keep the code readable.
Subqueries and JOIN clauses should not be used
Subqueries and JOIN clauses should not be used
`JOIN bypasses the SAP table buffer. Buffered tables should be accessed with the simplest SELECT statements possible so as not to risk bypassing the buffer.
If one of the tables in a JOIN is buffered, it would be an advantage to first import the required entries using a SELECT into an internal table itab, and then for example, using the statement SELECT … FOR ALL ENTRIES IN itab` to access further tables.
Asterisks should be used for headers and to comment out code
Asterisks should be used for headers and to comment out code
For readability, SAP recommends that asterisks (*) only be used to comment out header lines and code. Commentary should be commented using a double quote (“
)
Driver tables should be sorted before use
Driver tables should be sorted before use
In SELECT … FOR ALL ENTRIES
queries there are two internal tables: the driver internal table, and the target internal table. For each entry in the driver table some data from a database table is stored in the target internal table.
Most of the time, starting by sorting the content of the driver internal table offers improved performance. Indeed in such cases, from one request to another, the data read from the database tends to be much the same, and so for instance the use of database caching is maximised.
SQL BYPASSING BUFFER clause should not be used
SQL BYPASSING BUFFER clause should not be used
This BYPASSING BUFFER clause explicitly switches off SAP table buffering, so the SELECT
reads data directly from the database.
By definition, using this clause can lead to performance issues, which is why its use must be strongly indicated.
Loops should not contain more than a single CONTINUE, EXIT, CHECK statement
Loops should not contain more than a single CONTINUE, EXIT, CHECK statement
Restricting the number of `CONTINUE, EXIT and CHECK statements in a loop is done in the interest of good structured programming.
One CONTINUE, EXIT and CHECK` statement is acceptable in a loop, since it facilitates optimal coding. If there is more than one, the code should be refactored to increase readability.
SELECT INTO TABLE should be used
SELECT INTO TABLE should be used
SELECT INTO TABLE is much more efficient than SELECT … ENDSELECT. SELECT INTO TABLE
needs more memory to hold the result set, but in normal situations, this is not a concern. When memory is a concern, the result set can be divided into smaller sets.
CATCH clauses should not be empty
CATCH clauses should not be empty
Leaving a CATCH
block empty means that the exception in question is neither handled nor passed forward to callers for handling at a higher level. Suppressing errors rather than handling them could lead to unpredictable system behavior and should be avoided.
Loops with at most one iteration should be refactored
Loops with at most one iteration should be refactored
A loop with at most one iteration is equivalent to the use of an `IF statement to conditionally execute one piece of code. No developer expects to find such usage of a loop statement. If the initial intention of the author was really to conditionally execute one piece of code, an IF statement should be used in place.
At worst that was not the initial intention of the author and so the body of the loop should be fixed to use the nested STOP, RETURN or EXIT` statements in a more appropriate way.
JOIN should be used instead of nested SELECT statements
JOIN should be used instead of nested SELECT statements
SELECT with JOIN
always performs better than nested selects.
Duplications in driver tables should deleted before the tables are used
Duplications in driver tables should deleted before the tables are used
Removing duplicate entries from driver tables enables OPEN SQL
to generate fewer queries for getting the same data, giving a performance boost.
EXIT and CHECK statements should not be used in SELECT loops
EXIT and CHECK statements should not be used in SELECT loops
Using EXIT and CHECK in SELECT statements to stop the execution of SELECT loop is an expensive and ineffective way to filter data. Filtering should be part of the SELECT loop themselves. Most of the time conditions located in a CHECK statement should be moved to the WHERE clause, and the EXIT statement should typically be replaced by an UP TO 1 ROW
clause.
SORTED or HASHED internal tables should be accessed with a key
SORTED or HASHED internal tables should be accessed with a key
Internal tables can quickly become a source of performance problems if not accessed correctly, SORTED and HASHED
tables should always be accessed with the appropriate key or partial key.
Sort fields should be provided for an internal table sort
Sort fields should be provided for an internal table sort
Internal tables can be sorted without specifying the specific fields on which to sort. However, doing so is inefficient because when a sort key is not specified, the entire row is used in the sort, which can be markedly inefficient.
Forms should be documented
Forms should be documented
Every subroutine(FORM
) should be commented to explain its goal and how it works. This comment can be located just before or after the form definition.
Authorization checks should not rely on hardcoded user properties
Authorization checks should not rely on hardcoded user properties
Mass operations should be used with internal tables instead of loops
Mass operations should be used with internal tables instead of loops
When several lines must be inserted/updated into an internal table, instead of doing those changes line by line, mass operations should be used because they offer better performance by design.
This rule raises an issue when a single line operation like APPEND, CONCATENATE, and INSERT
is performed on an internal table in a loop.
WHEN OTHERS clauses should be last
WHEN OTHERS clauses should be last
`CASE can contain a WHEN OTHERS clause for various reasons: to handle unexpected values, to show that all the cases were properly considered, etc.
For readability purposes, to help a developer quickly spot the default behavior of a CASE statement, it is recommended to put the WHEN OTHERS clause at the end of the CASE statement.
This rule raises an issue if the WHEN OTHERS clause is not the last one of the CASE’s cases.
System C functions should not be used
System C functions should not be used
According to the SAP documentation:
So calling system C functions using a CALL
statement should be avoided.
The operator = should be used to copy the content of an internal table
The operator = should be used to copy the content of an internal table
Using the = operator to copy the content of an internal table is more efficient than using LOOP + APPEND
statements.
SY-SUBRC should be checked after an AUTHORITY-CHECK statement
SY-SUBRC should be checked after an AUTHORITY-CHECK statement
CX_ROOT should not be caught
CX_ROOT should not be caught
Because CX_ROOT is the base exception type, catching it directly probably casts a wider net than you intended. Catching CX_ROOT could mask far more serious system errors that your CATCH
logic was intended to deal with.
Some smaller, more specific exception type should be caught instead.
Subroutine parameters should be passed by reference rather than by value
Subroutine parameters should be passed by reference rather than by value
Passing parameters by reference instead of by value avoids the overhead of making a copy. Passing arguments via copy should only be done when it is technically mandated, as it is for example with RFC function modules.
Method parameters should follow a naming convention
Method parameters should follow a naming convention
Shared naming conventions allow teams to collaborate efficiently. This rule checks that all method parameters follow a naming convention.
To SELECT, INSERT or DELETE several lines in databases, internal tables should be used in place of loop control structure
To SELECT, INSERT or DELETE several lines in databases, internal tables should be used in place of loop control structure
Whenever more than one line needs to be read, inserted or deleted from a database table, it is more efficient to work with an internal table than to read, insert or delete the lines one by one inside a loop.
CASE statements should have at least 3 WHEN clauses
CASE statements should have at least 3 WHEN clauses
`CASE statements are useful when there are many different cases depending on the value of the same expression.
For just one or two cases however, the code will be more readable with IF` statements.
IF ... ELSEIF constructs should end with ELSE clauses
IF ... ELSEIF constructs should end with ELSE clauses
This rule applies whenever an `IF statement is followed by one or
more ELSEIF statements; the final ELSEIF should be followed by an ELSE statement.
The requirement for a final ELSE statement is defensive programming.
The ELSE statement should either take appropriate action or contain
a suitable comment as to why no action is taken. This is consistent with the
requirement to have a final OTHERS clause in a CASE`
statement.
DATA BEGIN OF OCCURS should not be used
DATA BEGIN OF OCCURS should not be used
DATA BEGIN OF … OCCURS
has been deprecated and will eventually be removed. All usages should be replaced.
Method names should comply with a naming convention
Method names should comply with a naming convention
Shared naming conventions allow teams to collaborate efficiently.
This rule raises an issue when a method name does not match a provided regular expression.
For example, with the default provided regular expression ^([A-Z0-9_]|[a-z0-9_])$, the method:
Control flow statements IF, CASE, DO, LOOP, SELECT, WHILE and PROVIDE should not be nested too deeply
Control flow statements IF, CASE, DO, LOOP, SELECT, WHILE and PROVIDE should not be nested too deeply
Nested control flow statements IF, CASE, DO, LOOP, SELECT, WHILE and PROVIDE
are often key ingredients in creating
what’s known as “Spaghetti code”. This code smell can make your program difficult to understand and maintain.
When numerous control structures are placed inside one another, the code becomes a tangled, complex web. This significantly reduces the code’s readability and maintainability, and it also complicates the testing process.
Functions should be documented
Functions should be documented
Every function should be commented to explain its goal and how it works. This non-empty comment must be located before the function definition.
SY-SUBRC should be tested after each statement setting it.
SY-SUBRC should be tested after each statement setting it.
The system field `SY-SUBRC must be tested immediately after any statement setting this variable. Reading this variable informs on previous operation success or errors. Such errors should be handled properly so that the program continues in a consistent state.
This rule raises an issue when the field SY-SUBRC is not checked just after performing one of the following operations:
Calling a function or method which can throw exceptions.
Calling one of the file access operation OPEN DATASET, READ DATASET or DELETE DATASET.
SY-SUBRC check must be done either with the CASE, IF or CHECK` statement.
REFRESH itab should not be used
REFRESH itab should not be used
This statement deletes all rows of an internal table itab. This REFRESH
statement is deprecated and usage should be avoided.
Form names should comply with a naming convention
Form names should comply with a naming convention
Naming conventions are an important tool in efficient team collaboration. This rule checks that all form names match a regular expression naming convention.
SQL UPDATE dbtab SET ... statements should have a WHERE clause
SQL UPDATE dbtab SET ... statements should have a WHERE clause
UPDATE dbtab SET … without a WHERE condition changes all the entries of the table. Check whether dataset to be changed can be limited by a suitable WHERE
condition.
Keywords should not be used as variable names
Keywords should not be used as variable names
Using keywords as variable names may yield incomprehensible code, and should be avoided.
Empty driver tables should not be used in a SELECT/FOR ALL ENTRIES clause
Empty driver tables should not be used in a SELECT/FOR ALL ENTRIES clause
Using an empty driver table in a SELECT/FOR ALL ENTRIES table has a very important side effect: the complete WHERE clause is not taken into account because a NO WHERE
condition is generated. Thus a full table scan is unexpectedly executed.
Macros should be documented
Macros should be documented
Every macro should be commented to explain its goal and how it works. This comment can be located just before or after the macro definition.
Internal source code processing statements should not be used
Internal source code processing statements should not be used
ABAP provides the ability to manipulate programs dynamically during execution for instance with statements like `INSERT REPORT and GENERATE SUBROUTINE POOL. Most of those statements are for internal use within SAP Technology Development and incompatible changes are possible at any time without prior warning or notice.
This rule raises an issue when any of the following source code processing statements is used: INSERT REPORT, READ REPORT, DELETE REPORT, EDITOR-CALL FOR REPORT, SYNTAX-CHECK FOR itab, GENERATE REPORT/SUBROUTINE POOL, LOAD REPORT, SCAN, INSERT TEXTPOOL, READ TEXTPOOL, DELETE TEXTPOOL, EXPORT DYNPRO, IMPORT DYNPRO, DELETE DYNPRO, SYNTAX-CHECK FOR DYNPRO, and GENERATE DYNPRO`.
DELETE FROM dbtab statements should have a WHERE clause
DELETE FROM dbtab statements should have a WHERE clause
DELETE FROM dbtab without a WHERE
condition deletes all the entries of the table. Check whether dataset to be deleted can be limited by a suitable WHERE condition.
Using CALL TRANSACTION statements without an authority check is security-sensitive
Using CALL TRANSACTION statements without an authority check is security-sensitive
REFRESH itab FROM TABLE should not be used
REFRESH itab FROM TABLE should not be used
This variant of the `REFRESH statement is deprecated and should be avoided.
This REFRESH statement initializes the internal table itab, reads several rows from the database table dbtab, and adds their contents to the internal table itab. A SELECT` statement should be used instead.
SQL aggregate functions should not be used to prevent bypassing the SAP buffer
SQL aggregate functions should not be used to prevent bypassing the SAP buffer
SQL COUNT(..), MIN(..), MAX(..), SUM(..), AVG(..)
aggregate functions cause the SAP table buffer to be bypassed, so the use of these functions can lead to performance issues.
All branches in a conditional structure should not have exactly the same implementation
All branches in a conditional structure should not have exactly the same implementation
Having all branches of a CASE or IF chain with the same implementation indicates a problem.
In the following code:
Unnecessary chain syntax should not be used
Unnecessary chain syntax should not be used
When there is only one statement in a chain, the chain syntax can be omitted, which simplifies the code.
Native SQL should not be statically embedded
Native SQL should not be statically embedded
The `EXEC SQL … END-EXEC statement can be used to embed Native SQL statically in ABAP programs.
According to the SAP documentation:
%_HINTS should not be used
%_HINTS should not be used
ABAP hints can be used to override the default behavior of the SAP Cost Based Optimizer (CBO). When the execution plan provided by the CBO is not optimal, it is possible to “drive” the CBO by providing the main index to be used to filter rows.
Such optimizations are not portable from one database to another, such as when migrating from Oracle to DB2. Therefore hard coding an optimization should be done only when it is strongly indicated.
Operational statements should not be chained
Operational statements should not be chained
The main reason for using chained statements is to increase readability, but when used with operational statements, chaining can have the opposite effect. Even worse, it can lead to unexpected program behavior.
Open SQL SELECT statements should have an ORDER BY clause
Open SQL SELECT statements should have an ORDER BY clause
An Open SQL SELECT statement without an explicit ORDER BY clause will retrieve rows in an unpredictable order. On pool/cluster tables, the current implementation of Open SQL SELECT returns the result set in the primary key order, but that’s not the case for transparent tables. That’s why it’s safer to always use an ORDER BY
clause.
SELECT SINGLE or Up to 1 ROW should be used when retrieving one record
SELECT SINGLE or Up to 1 ROW should be used when retrieving one record
SAP recommends to keep the result set of any request as small as possible for performance reasons.
A `SELECT…ENDSELECT request will retrieve multiple records at the same time. Stopping immediately such a request with a CHECK, RETURN or EXIT statement will not reduce the number of retrieved records. If the goal is to retrieve a single record, or check that at least one record exists, it is recommended to add UP TO 1 ROWS or to use SELECT SINGLE.
Even if the request already retrieved only one record, adding UP TO 1 ROWS or to using SELECT SINGLE will make the code easier to read.
This rule raises an issue when a SELECT…ENDSELECT which has neither SINGLE nor UP TO 1 ROWS and:
contains only one statement and it is a CHECK, RETURN or EXIT`
or when it is completely empty.
CASE statements should have WHEN OTHERS clauses
CASE statements should have WHEN OTHERS clauses
The requirement for an OTHERS
clause is defensive programming. The clause should either take appropriate action, or contain a suitable comment as to why no action is taken.
SQL DISTINCT operator should not be used to prevent bypassing the SAP buffering
SQL DISTINCT operator should not be used to prevent bypassing the SAP buffering
DISTINCT operator causes the SELECT
statement to avoid the SAP buffering and to read directly from the database and not from the buffer on the application server.
Statements should be on separate lines
Statements should be on separate lines
Putting multiple statements on a single line lowers the code readability and makes debugging the code more complex.
Unresolved directive in <stdin> - include::{noncompliant}[]
Write one statement per line to improve readability.
Unresolved directive in <stdin> - include::{compliant}[]
Exception handlers should preserve the original exceptions
Exception handlers should preserve the original exceptions
When handling a caught exception, the original exception’s message and stack trace should be logged or passed forward.
Magic numbers should not be used
Magic numbers should not be used
Magic numbers make the code more complex to understand as it requires the reader to have knowledge about the global context to understand the number itself. Their usage may seem obvious when writing the code, but it may not be the case for another developer or later once the context faded away. -1, 0, and 1 are not considered magic numbers.
SQL EXISTS subqueries should not be used
SQL EXISTS subqueries should not be used
SQL queries that use EXISTS subqueries are inefficient because the subquery is re-run for every row in the outer query’s table. There are more efficient ways to write most queries, ways that do not use the EXISTS
condition.
Mergeable if statements should be combined
Mergeable if statements should be combined
Nested code - blocks of code inside blocks of code - is eventually necessary, but increases complexity. This is why keeping the code as flat as possible, by avoiding unnecessary nesting, is considered a good practice.
Merging if statements when possible will decrease the nesting of the code and improve its readability.
Macro names should comply with a naming convention
Macro names should comply with a naming convention
Sharing some naming conventions is a key point to make it possible for a team to efficiently collaborate. This rule allows to check that all macro names match a provided regular expression.
Redundant pairs of parentheses should be removed
Redundant pairs of parentheses should be removed
The use of parentheses, even those not required to enforce a desired order of operations, can clarify the intent behind a piece of code. However, redundant pairs of parentheses could be misleading and should be removed.
Using shell interpreter when executing OS commands is security-sensitive
Using shell interpreter when executing OS commands is security-sensitive
Arbitrary OS command injection vulnerabilities are more likely when a shell is spawned rather than a new process, indeed shell meta-chars can be used (when parameters are user-controlled for instance) to inject OS commands.
Related if/else if statements should not have the same condition
Related if/else if statements should not have the same condition
Class names should comply with a naming convention
Class names should comply with a naming convention
Shared naming conventions allow teams to collaborate efficiently.
This rule raises an issue when a class name does not match a provided regular expression.
DATA variable names should comply with a naming convention
DATA variable names should comply with a naming convention
Sharing some naming conventions is a key point to make it possible for a team to efficiently collaborate. This rule allows to check that all variable names match a provided regular expression.
String literals should not be duplicated
String literals should not be duplicated
Duplicated string literals make the process of refactoring complex and error-prone, as any change would need to be propagated on all occurrences.
switch case clauses should not have too many lines of code
switch case clauses should not have too many lines of code
The switch statement should be used only to clearly define some new branches in the control flow. As soon as a case clause contains too many statements this highly decreases the readability of the overall control flow statement. In such case, the content of the case
clause should be extracted into a dedicated method.
Function names should comply with a naming convention
Function names should comply with a naming convention
Shared coding conventions allow teams to collaborate efficiently. This rule checks that all function names match a provided regular expression.
Using hardcoded IP addresses is security-sensitive
Using hardcoded IP addresses is security-sensitive
Hardcoding IP addresses is security-sensitive. It has led in the past to the following vulnerabilities:
Today’s services have an ever-changing architecture due to their scaling and redundancy needs. It is a mistake to think that a service will always have the same IP address. When it does change, the hardcoded IP will have to be modified too. This will have an impact on the product development, delivery, and deployment:
The developers will have to do a rapid fix every time this happens, instead of having an operation team change a configuration file.
It misleads to use the same address in every environment (dev, sys, qa, prod).
Last but not least it has an effect on application security. Attackers might be able to decompile the code and thereby discover a potentially sensitive address. They can perform a Denial of Service attack on the service, try to get access to the system, or try to spoof the IP address to bypass security checks. Such attacks can always be possible, but in the case of a hardcoded IP address solving the issue will take more time, which will increase an attack’s impact.
Interface names should comply with a naming convention
Interface names should comply with a naming convention
Sharing some naming conventions is a key point to make it possible for a team to efficiently collaborate. This rule allows to check that all interface names match a provided regular expression.
Unused local variables should be removed
Unused local variables should be removed
An unused local variable is a variable that has been declared but is not used anywhere in the block of code where it is defined. It is dead code, contributing to unnecessary complexity and leading to confusion when reading the code. Therefore, it should be removed from your code to maintain clarity and efficiency.
Source code should be indented consistently
Source code should be indented consistently
Consistent indentation is a simple and effective way to improve the code’s readability. It reduces the differences that are committed to source control systems, making code reviews easier.
This rule raises an issue when the indentation does not match the configured value. Only the first line of a badly indented section is reported.
Two branches in a conditional structure should not have exactly the same implementation
Two branches in a conditional structure should not have exactly the same implementation
Having two WHEN in a CASE statement or two branches in an IF chain with the same implementation is at best duplicate code, and at worst a coding error.