diff --git a/docs/4-language-usage/4-control-structures/3-flow-control/g-4387.md b/docs/4-language-usage/4-control-structures/3-flow-control/g-4387.md new file mode 100644 index 00000000..92820c79 --- /dev/null +++ b/docs/4-language-usage/4-control-structures/3-flow-control/g-4387.md @@ -0,0 +1,58 @@ +# G-4387: Never use a FOR LOOP for a query that should return not more than one row. + +!!! bug "Blocker" + Reliability, Efficiency, Readability + +!!! missing "Unsupported in db\* CODECOP Validators" + Without access to the Oracle Data Dictionary, we cannot determine the number of rows to be processed. + +## Reason + +A `for loop` can hide a `too_many_rows` exception. The more complex a query is, the higher is the risk that more than one row will be processed. +This affects performance and can lead to a wrong result. + +A `for loop` can also hide a `no_data_found` exception and the reader cannot determine whether this is intentional or not. + +## Example (bad) + +``` sql +create or replace package body employee_api is + function emp_name(in_empno in integer) return varchar2 is -- NOSONAR: non-deterministic + l_ename emp.ename%type; + begin + <> + for r in ( + select ename + from emp + where empno = in_empno + ) + loop + l_ename := r.ename; + end loop fetch_name; + return l_ename; + end emp_name; +end employee_api; +/ +``` + +## Example (good) + +``` sql +create or replace package body employee_api is + function emp_name(in_empno in integer) return varchar2 is -- NOSONAR: non-deterministic + l_ename emp.ename%type; + begin + select ename + into l_ename + from emp + where empno >= in_empno; + return l_ename; + exception + when no_data_found then + return null; + when too_many_rows then + raise; + end emp_name; +end employee_api; +/ +``` \ No newline at end of file diff --git a/docs/9-appendix/appendix.md b/docs/9-appendix/appendix.md index 953ec1d9..6b93d095 100644 --- a/docs/9-appendix/appendix.md +++ b/docs/9-appendix/appendix.md @@ -87,6 +87,7 @@ n/a | 4365 | Never use unconditional CONTINUE or EXIT in a loop. | Major | | | 46 | 4375 | Always use EXIT WHEN instead of an IF statement to exit from a loop. | Minor | | | ✘ | | | | | 47 | 4380 | Try to label your EXIT WHEN statements. | Minor | | | ✘ | | | | | 48 | 4385 | Never use a cursor for loop to check whether a cursor returns data. | Critical | | ✘ | | | | | | +n/a | 4387 | !!!CHARACTERISTIC ERROR!!! | Blocker | | ✘ | | | ✘ | | | 49 | 4390 | Avoid use of unreferenced FOR loop indexes. | Major | | ✘ | | | | | | 50 | 4395 | Avoid hard-coded upper or lower bound values with FOR loops. | Minor | ✘ | | ✘ | | | | | n/a | 5010 | Try to use a error/logging framework for your application. | Critical | | | | | ✘ | ✘ | | ✘