diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4165940f..6512debf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,13 +18,13 @@ jobs: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: db* CODECOP Issues run: | - export COP=4.3.0 - export VALIDATOR=4.3.0 + export COP=4.3.1 + export VALIDATOR=4.3.1 wget https://github.com/Trivadis/plsql-cop-cli/releases/download/v$COP/tvdcc-$COP.zip unzip tvdcc-$COP.zip -d . wget -P tvdcc-$COP/plugin/ https://github.com/Trivadis/plsql-cop-validators/releases/download/v$VALIDATOR/sonar-plsql-cop-custom-validators-plugin-$VALIDATOR.jar echo $TVDCC_LIC | base64 -d > tvdcc-$COP/tvdcc.lic - tvdcc-$COP/tvdcc.sh path=docs skip=none html=false excel=false validator=com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus + tvdcc-$COP/tvdcc.sh path=docs skip=0 html=false excel=false validator=com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus env: TVDCC_LIC: ${{ secrets.TVDCC_LIC }} - name: SonarCloud Scan diff --git a/.gitignore b/.gitignore index 75677133..888964f3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,9 @@ /pdf /docs/9-appendix/PLSQL-and-SQL-Coding-Guidelines.pdf +# Files generated by tvdcc +/tvdcc_report.json + # Distribution files /dist /mkdocs_material.egg-info diff --git a/docs/3-coding-style/coding-style.md b/docs/3-coding-style/coding-style.md index bdc73278..dea4e0e1 100644 --- a/docs/3-coding-style/coding-style.md +++ b/docs/3-coding-style/coding-style.md @@ -19,33 +19,37 @@ Rule | Description ### Example ``` sql -create or replace procedure set_salary(in_employee_id in employees.employee_id%type) is - cursor c_employees(p_employee_id in employees.employee_id%type) is - select last_name - ,first_name - ,salary - from employees - where employee_id = p_employee_id - order by last_name - ,first_name; - - r_employee c_employees%rowtype; - l_new_salary employees.salary%type; -begin - open c_employees(p_employee_id => in_employee_id); - fetch c_employees into r_employee; - close c_employees; - - new_salary(in_employee_id => in_employee_id - ,out_salary => l_new_salary); - - -- Check whether salary has changed - if r_employee.salary <> l_new_salary then - update employees - set salary = l_new_salary - where employee_id = in_employee_id; - end if; -end set_salary; +create or replace package body employee_api is + procedure set_salary(in_employee_id in integer) is + co_employee_id constant employees.employee_id%type := in_employee_id; + + cursor c_employees(p_employee_id in employees.employee_id%type) is + select last_name + ,first_name + ,salary + from employees + where employee_id = p_employee_id + order by last_name + ,first_name; + + r_employee c_employees%rowtype; + l_new_salary employees.salary%type; + begin + open c_employees(p_employee_id => co_employee_id); + fetch c_employees into r_employee; + close c_employees; + + new_salary(in_employee_id => in_employee_id + ,out_salary => l_new_salary); + + -- Check whether salary has changed + if r_employee.salary <> l_new_salary then + update employees + set salary = l_new_salary + where employee_id = in_employee_id; + end if; + end set_salary; +end employee_api; ``` ## Code Commenting diff --git a/docs/4-language-usage/1-general/g-1020.md b/docs/4-language-usage/1-general/g-1020.md index 55b05e98..9304972a 100644 --- a/docs/4-language-usage/1-general/g-1020.md +++ b/docs/4-language-usage/1-general/g-1020.md @@ -38,7 +38,7 @@ begin <> loop - exit basic_loop; + exit basic_loop when true; end loop; <> @@ -78,7 +78,7 @@ begin <> loop - exit basic_loop; + exit basic_loop when true; end loop basic_loop; <> diff --git a/docs/4-language-usage/1-general/g-1040.md b/docs/4-language-usage/1-general/g-1040.md index cd83ba99..bca2fbe4 100644 --- a/docs/4-language-usage/1-general/g-1040.md +++ b/docs/4-language-usage/1-general/g-1040.md @@ -13,7 +13,7 @@ Any part of your code, which is no longer used or cannot be reached, should be e declare co_dept_purchasing constant departments.department_id%type := 30; begin - if 2 = 3 then + if 2 = 3 then -- G-1050 violated, dead code detection works with literals only null; -- some dead code here end if; @@ -21,14 +21,14 @@ begin <> loop - exit my_loop; + exit my_loop when true; null; -- some dead code here end loop my_loop; null; -- some other enabled code here case - when 1 = 1 and 'x' = 'y' then + when 1 = 1 and 'x' = 'y' then -- G-1050 violated, dead code detection works with literals only null; -- some dead code here else null; -- some further enabled code here @@ -40,7 +40,7 @@ begin from employees where department_id = co_dept_purchasing or commission_pct is not null - and 5 = 6 + and 5 = 6 -- G-1050 violated, dead code detection works with literals only ) -- "or commission_pct is not null" is dead code loop diff --git a/docs/4-language-usage/1-general/g-1080.md b/docs/4-language-usage/1-general/g-1080.md index bf7256a3..3013c9b0 100644 --- a/docs/4-language-usage/1-general/g-1080.md +++ b/docs/4-language-usage/1-general/g-1080.md @@ -12,24 +12,34 @@ This rule ignores operators `+`, `*` and `||`, and expressions: `1=1`, `1<>1`, ` ## Example (bad) ``` sql -select emp.first_name - ,emp.last_name - ,emp.salary - ,emp.hire_date - from employees emp - where emp.salary > 3000 - or emp.salary > 3000 - order by emp.last_name,emp.first_name; +declare + co_max_salary constant emp.salary%type := 3000; +begin + select emp.first_name + ,emp.last_name + ,emp.salary + ,emp.hire_date + from employees emp + where emp.salary > co_max_salary + or emp.salary > co_max_salary + order by emp.last_name,emp.first_name; +end; +/ ``` ## Example (good) ``` sql -select emp.first_name - ,emp.last_name - ,emp.salary - ,emp.hire_date - from employees emp - where emp.salary > 3000 - order by emp.last_name,emp.first_name; +declare + co_max_salary constant emp.salary%type := 3000; +begin + select emp.first_name + ,emp.last_name + ,emp.salary + ,emp.hire_date + from employees emp + where emp.salary > co_max_salary + order by emp.last_name,emp.first_name; +end; +/ ``` \ No newline at end of file diff --git a/docs/4-language-usage/2-variables-and-types/1-general/g-2135.md b/docs/4-language-usage/2-variables-and-types/1-general/g-2135.md index ca9892a3..c9a82a34 100644 --- a/docs/4-language-usage/2-variables-and-types/1-general/g-2135.md +++ b/docs/4-language-usage/2-variables-and-types/1-general/g-2135.md @@ -13,15 +13,16 @@ Expending resources calculating and assigning values to a local variable and nev create or replace package body my_package is procedure my_proc is co_employee_id constant employees.employee_id%type := 1042; + co_hello constant type_up.text := 'Hello, '; l_last_name employees.last_name%type; - l_message varchar2(100 char); + l_message types_up.text; begin select emp.last_name into l_last_name from employees emp where emp.employee_id = co_employee_id; - l_message := 'Hello, ' || l_last_name; + l_message := co_hello || l_last_name; exception when no_data_found then null; -- handle_no_data_found; @@ -38,15 +39,16 @@ end my_package; create or replace package body my_package is procedure my_proc is co_employee_id constant employees.employee_id%type := 1042; + co_hello constant type_up.text := 'Hello, '; l_last_name employees.last_name%type; - l_message varchar2(100 char); + l_message types_up.text; begin select emp.last_name into l_last_name from employees emp where emp.employee_id = co_employee_id; - l_message := 'Hello, ' || l_last_name; + l_message := co_hello || l_last_name; message_api.send_message(l_message); exception diff --git a/docs/4-language-usage/2-variables-and-types/1-general/g-2145.md b/docs/4-language-usage/2-variables-and-types/1-general/g-2145.md index e5f24eaa..5dca2b3e 100644 --- a/docs/4-language-usage/2-variables-and-types/1-general/g-2145.md +++ b/docs/4-language-usage/2-variables-and-types/1-general/g-2145.md @@ -11,12 +11,15 @@ There is no reason to assign a variable to itself. It is either a redundant stat ``` sql declare - l_function_result pls_integer; - l_parallel_degree pls_integer; + co_parallel_degree constant types_up.name%type := 'parallel_degree'; + l_function_result pls_integer; + l_parallel_degree pls_integer; begin - l_function_result := maintenance.get_config('parallel_degree'); - l_parallel_degree := l_parallel_degree; - do_something(l_parallel_degree); + l_function_result := maintenance.get_config(co_parallel_degree); + if l_function_result is not null then + l_parallel_degree := l_parallel_degree; + do_something(l_parallel_degree); + end if; end; / ``` @@ -25,12 +28,15 @@ end; ``` sql declare - l_function_result pls_integer; - l_parallel_degree pls_integer; + co_parallel_degree constant types_up.name%type := 'parallel_degree'; + l_function_result pls_integer; + l_parallel_degree pls_integer; begin - l_function_result := maintenance.get_config('parallel_degree'); - l_parallel_degree := l_function_result; - do_something(l_parallel_degree); + l_function_result := maintenance.get_config(co_parallel_degree); + if l_function_result is not null then + l_parallel_degree := l_function_result; + do_something(l_parallel_degree); + end if; end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/2-variables-and-types/1-general/g-2180.md b/docs/4-language-usage/2-variables-and-types/1-general/g-2180.md index 873ba4da..58e78e9a 100644 --- a/docs/4-language-usage/2-variables-and-types/1-general/g-2180.md +++ b/docs/4-language-usage/2-variables-and-types/1-general/g-2180.md @@ -11,11 +11,12 @@ Quoted identifiers make your code hard to read and maintain. ``` sql declare - "sal+comm" integer; - "my constant" constant integer := 1; - "my exception" exception; + "sal+comm" integer; -- violates also naming conventions (G-9102) + "my constant" constant integer := 1; -- violates also naming conventions (G-9114) + "my exception" exception; -- violates also naming conventsion (G-9113) begin "sal+comm" := "my constant"; + do_something("sal+comm"); exception when "my exception" then null; @@ -32,6 +33,7 @@ declare e_my_exception exception; begin l_sal_comm := co_my_constant; + do_something(l_sal_comm); exception when e_my_exception then null; diff --git a/docs/4-language-usage/2-variables-and-types/1-general/g-2185.md b/docs/4-language-usage/2-variables-and-types/1-general/g-2185.md index 3e22f7bf..7bb3dca2 100644 --- a/docs/4-language-usage/2-variables-and-types/1-general/g-2185.md +++ b/docs/4-language-usage/2-variables-and-types/1-general/g-2185.md @@ -12,10 +12,11 @@ You should ensure that the name you have chosen well defines its purpose and usa ``` sql declare i integer; - c constant integer := 1; - e exception; + c constant integer := 1; -- violates also naming conventions (G-9114) + e exception; -- violates also naming conventions (G-9113) begin i := c; + do_something(i); exception when e then null; @@ -32,6 +33,7 @@ declare e_my_exception exception; begin l_sal_comm := co_my_constant; + do_something(l_sal_comm); exception when e_my_exception then null; diff --git a/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2210.md b/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2210.md index 6903bcbc..4a1ff713 100644 --- a/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2210.md +++ b/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2210.md @@ -10,27 +10,17 @@ If you do not specify precision `number` is defaulted to 38 or the maximum suppo ## Example (bad) ``` sql -create or replace package body constants_up is - co_small_increase constant number := 0.1; - - function small_increase return number is - begin - return co_small_increase; - end small_increase; -end constants_up; +create or replace package types_up is + subtype salary_type is number; +end types_up; / ``` ## Example (good) ``` sql -create or replace package body constants_up is - co_small_increase constant number(5,1) := 0.1; - - function small_increase return number is - begin - return co_small_increase; - end small_increase; -end constants_up; +create or replace package types_up is + subtype salary_type is number(5,1); +end types_up; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2220.md b/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2220.md index a8659619..11c65595 100644 --- a/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2220.md +++ b/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2220.md @@ -15,27 +15,37 @@ There are many reasons to use `pls_integer` instead of `number`: ## Example (bad) ``` sql -create or replace package body constants_up is - co_big_increase constant number(5,0) := 1; - - function big_increase return number is - begin - return co_big_increase; - end big_increase; -end constants_up; +declare + l_result number(9,0) := 0; -- violates also G-2130, G-2230 + co_upper_bound constant pls_integer := 1e8; +begin + <> + for i in 1..co_upper_bound + loop + if i > 0 then + l_result := l_result + 1; + end if; + end loop burning_cpu; + sys.dbms_output.put_line(l_result); +end; / ``` ## Example (good) ``` sql -create or replace package body constants_up is - co_big_increase constant pls_integer := 1; - - function big_increase return pls_integer is - begin - return co_big_increase; - end big_increase; -end constants_up; +declare + l_result pls_integer := 0; + co_upper_bound constant pls_integer := 1e8; +begin + <> + for i in 1..co_upper_bound + loop + if i > 0 then + l_result := l_result + 1; + end if; + end loop burning_less_cpu; + sys.dbms_output.put_line(l_result); +end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2230.md b/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2230.md index f0019bf9..826e9428 100644 --- a/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2230.md +++ b/docs/4-language-usage/2-variables-and-types/2-numeric-data-types/g-2230.md @@ -13,31 +13,37 @@ With Oracle Database 11g, the new data type `simple_integer` has been introduced ## Example (bad) ``` sql -create or replace package body constants_up is - co_big_increase constant number(5,0) := 1; - - function big_increase return number - deterministic - is - begin - return co_big_increase; - end big_increase; -end constants_up; +declare + l_result number(9,0) := 0; -- violates also G-2130, G-2220 + co_upper_bound constant pls_integer := 1e8; +begin + <> + for i in 1..co_upper_bound + loop + if i > 0 then + l_result := l_result + 1; + end if; + end loop burning_cpu; + sys.dbms_output.put_line(l_result); +end; / ``` ## Example (good) ``` sql -create or replace package body constants_up is - co_big_increase constant simple_integer := 1; - - function big_increase return simple_integer - deterministic - is - begin - return co_big_increase; - end big_increase; -end constants_up; +declare + l_result simple_integer := 0; + co_upper_bound constant pls_integer := 1e8; +begin + <> + for i in 1..co_upper_bound + loop + if i > 0 then + l_result := l_result + 1; + end if; + end loop burning_cpu; + sys.dbms_output.put_line(l_result); +end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/2-variables-and-types/3-character-data-types/g-2330.md b/docs/4-language-usage/2-variables-and-types/3-character-data-types/g-2330.md index 27114ae3..72ada8dc 100644 --- a/docs/4-language-usage/2-variables-and-types/3-character-data-types/g-2330.md +++ b/docs/4-language-usage/2-variables-and-types/3-character-data-types/g-2330.md @@ -11,9 +11,11 @@ Today zero-length strings and `null` are currently handled identical by the Orac ``` sql create or replace package body constants_up is - co_null_string constant varchar2(1 char) := ''; + co_null_string constant types_up.text := ''; - function null_string return varchar2 is + function null_string return varchar2 + deterministic + is begin return co_null_string; end null_string; @@ -25,8 +27,9 @@ end constants_up; ``` sql create or replace package body constants_up is - - function empty_string return varchar2 is + function empty_string return varchar2 + deterministic + is begin return null; end empty_string; diff --git a/docs/4-language-usage/2-variables-and-types/4-boolean-data-types/g-2410.md b/docs/4-language-usage/2-variables-and-types/4-boolean-data-types/g-2410.md index 616ada77..6072a302 100644 --- a/docs/4-language-usage/2-variables-and-types/4-boolean-data-types/g-2410.md +++ b/docs/4-language-usage/2-variables-and-types/4-boolean-data-types/g-2410.md @@ -20,6 +20,7 @@ begin else l_bigger := constants_up.co_numeric_false; end if; + do_something(l_bigger); end; / ``` @@ -37,6 +38,7 @@ begin else l_bigger := false; end if; + do_something(l_bigger); end; / ``` @@ -50,6 +52,7 @@ declare l_bigger boolean; begin l_bigger := nvl(co_newfile < co_oldfile,false); + do_something(l_bigger); end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/2-variables-and-types/5-large-objects/g-2510.md b/docs/4-language-usage/2-variables-and-types/5-large-objects/g-2510.md index f6415905..a2d076b4 100644 --- a/docs/4-language-usage/2-variables-and-types/5-large-objects/g-2510.md +++ b/docs/4-language-usage/2-variables-and-types/5-large-objects/g-2510.md @@ -12,39 +12,25 @@ There are many constraints to `long` datatypes in comparison to the `lob` types. ## Example (bad) ``` sql -create or replace package example_package is - g_long long; - g_raw long raw; - - procedure do_something; -end example_package; -/ - -create or replace package body example_package is - procedure do_something is - begin - null; - end do_something; -end example_package; +declare + l_long long; -- violates also G-2130 + l_raw long raw; -- violates also G-2130 +begin + do_something(l_long); + do_something(l_raw); +end; / ``` ## Example (good) ``` sql -create or replace package example_package is - procedure do_something; -end example_package; -/ - -create or replace package body example_package is - g_long clob; - g_raw blob; - - procedure do_something is - begin - null; - end do_something; -end example_package; +declare + l_long clob; + l_raw blob; +begin + do_something(l_long); + do_something(l_raw); +end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/3-dml-and-sql/1-general/g-3110.md b/docs/4-language-usage/3-dml-and-sql/1-general/g-3110.md index 2f89273c..12874e8d 100644 --- a/docs/4-language-usage/3-dml-and-sql/1-general/g-3110.md +++ b/docs/4-language-usage/3-dml-and-sql/1-general/g-3110.md @@ -10,25 +10,40 @@ Data structures often change. Having the target columns in your insert statement ## Example (bad) ``` sql -insert into departments -values ( - departments_seq.nextval - ,'Support' - ,100 - ,10); +create or replace package body dept_api is + procedure ins_dept(in_dept_row in dept%rowtype) is + begin + insert into departments + values ( + departments_seq.nextval + ,in_dept_row.department_name + ,in_dept_row.manager_id + ,in_dept_row.location_id + ); + end ins_dept; +end dept_api; +/ ``` ## Example (good) ``` sql -insert into departments ( - department_id - ,department_name - ,manager_id - ,location_id) -values ( - departments_seq.nextval - ,'Support' - ,100 - ,10); +create or replace package body dept_api is + procedure ins_dept(in_dept_row in dept%rowtype) is + begin + insert into departments ( + department_id + ,department_name + ,manager_id + ,location_id + ) + values ( + departments_seq.nextval + ,in_dept_row.department_name + ,in_dept_row.manager_id + ,in_dept_row.location_id + ); + end ins_dept; +end dept_api; +/ ``` \ No newline at end of file diff --git a/docs/4-language-usage/3-dml-and-sql/3-transaction-control/g-3320.md b/docs/4-language-usage/3-dml-and-sql/3-transaction-control/g-3320.md index 4b387421..ddf7f588 100644 --- a/docs/4-language-usage/3-dml-and-sql/3-transaction-control/g-3320.md +++ b/docs/4-language-usage/3-dml-and-sql/3-transaction-control/g-3320.md @@ -10,18 +10,35 @@ Commit inside a non-cursor loop (other loop types than loops over cursors - see ## Example (bad) ``` sql +declare + co_upper_bound constant integer := 5; + co_max_level constant integer := 3; + co_number constant types_up.short_string := 'Number'; + co_line constant types_up.short_string := 'Line'; + co_space constant types_up.short_string := ' '; + l_counter integer := 0; begin <> - for l_counter in 1..5 loop - insert into headers (id,text) values (l_counter,'Number ' || l_counter); + insert into headers (id,text) + values ( + l_counter,co_number + || co_space + || l_counter + ); insert into lines (header_id,line_no,text) - select l_counter,rownum,'Line ' || rownum + select l_counter + ,rownum + ,co_line + || co_space + || rownum from dual - connect by level <= 3; + connect by level <= co_max_level; commit; + l_counter := l_counter + 1; + exit create_headers when l_counter > co_upper_bound; end loop create_headers; end; / @@ -31,22 +48,35 @@ end; ``` sql declare + co_upper_bound constant integer := 5; + co_max_level constant integer := 3; + co_number constant types_up.short_string := 'Number'; + co_line constant types_up.short_string := 'Line'; + co_space constant types_up.short_string := ' '; procedure create_rows( in_header_id in headers.id%type ) is + co_header_id constant headers.id%type := in_header_id; begin - insert into headers (id,text) values (in_header_id,'Number ' || in_header_id); + insert into headers (id,text) + values (in_header_id,co_number + || co_space + || co_header_id); insert into lines (header_id,line_no,text) - select in_header_id,rownum,'Line ' || rownum + select co_header_id + ,rownum + ,co_line + || co_space + || rownum from dual - connect by level <= 3; + connect by level <= co_max_level; commit; - end; + end create_rows; begin <> - for l_counter in 1..5 + for l_counter in 1..co_upper_bound loop create_rows(l_counter); end loop create_headers; diff --git a/docs/4-language-usage/4-control-structures/1-cursor/g-4110.md b/docs/4-language-usage/4-control-structures/1-cursor/g-4110.md index cd3417af..727b303c 100644 --- a/docs/4-language-usage/4-control-structures/1-cursor/g-4110.md +++ b/docs/4-language-usage/4-control-structures/1-cursor/g-4110.md @@ -12,20 +12,28 @@ The readability of your code will be higher when you avoid negative sentences. ``` sql declare cursor c_employees is - select last_name - ,first_name + select * from employees - where commission_pct is not null; + order by employee_id; - r_employee c_employees%rowtype; + type t_employees_type is table of c_employees%rowtype; + t_employees t_employees_type; + co_bulk_size constant simple_integer := 10; begin open c_employees; - <> + <> loop - fetch c_employees into r_employee; - exit read_employees when not c_employees%found; - end loop read_employees; + fetch c_employees bulk collect into t_employees limit co_bulk_size; + + <> + for i in 1..t_employees.count() + loop + sys.dbms_output.put_line(t_employees(i).last_name); + end loop display_employees; + + exit process_employees when not c_employees%found; + end loop process_employees; close c_employees; end; @@ -37,20 +45,28 @@ end; ``` sql declare cursor c_employees is - select last_name - ,first_name + select * from employees - where commission_pct is not null; + order by employee_id; - r_employee c_employees%rowtype; + type t_employees_type is table of c_employees%rowtype; + t_employees t_employees_type; + co_bulk_size constant simple_integer := 10; begin open c_employees; - <> + <> loop - fetch c_employees into r_employee; - exit read_employees when c_employees%notfound; - end loop read_employees; + fetch c_employees bulk collect into t_employees limit co_bulk_size; + + <> + for i in 1..t_employees.count() + loop + sys.dbms_output.put_line(t_employees(i).last_name); + end loop display_employees; + + exit process_employees when c_employees%notfound; + end loop process_employees; close c_employees; end; diff --git a/docs/4-language-usage/4-control-structures/1-cursor/g-4130.md b/docs/4-language-usage/4-control-structures/1-cursor/g-4130.md index cee5a3f2..624a36db 100644 --- a/docs/4-language-usage/4-control-structures/1-cursor/g-4130.md +++ b/docs/4-language-usage/4-control-structures/1-cursor/g-4130.md @@ -11,15 +11,16 @@ Any cursors left open can consume additional memory space (i.e. SGA) within the ``` sql create or replace package body employee_api as - function department_salary(in_dept_id in departments.department_id%type) + function department_salary(in_dept_id in integer) -- NOSONAR: non-deterministic return number is cursor c_department_salary(p_dept_id in departments.department_id%type) is select sum(salary) as sum_salary from employees where department_id = p_dept_id; r_department_salary c_department_salary%rowtype; + co_dept_id constant departments.department_id%type := in_dept_id; begin - open c_department_salary(p_dept_id => in_dept_id); + open c_department_salary(p_dept_id => co_dept_id); fetch c_department_salary into r_department_salary; return r_department_salary.sum_salary; @@ -32,15 +33,16 @@ end employee_api; ``` sql create or replace package body employee_api as - function department_salary(in_dept_id in departments.department_id%type) + function department_salary(in_dept_id in integer) -- NOSONAR: non-deterministic return number is cursor c_department_salary(p_dept_id in departments.department_id%type) is select sum(salary) as sum_salary from employees where department_id = p_dept_id; r_department_salary c_department_salary%rowtype; + co_dept_id constant departments.department_id%type := in_dept_id; begin - open c_department_salary(p_dept_id => in_dept_id); + open c_department_salary(p_dept_id => co_dept_id); fetch c_department_salary into r_department_salary; close c_department_salary; return r_department_salary.sum_salary; diff --git a/docs/4-language-usage/4-control-structures/1-cursor/g-4140.md b/docs/4-language-usage/4-control-structures/1-cursor/g-4140.md index 5830b1c7..c0c8f2c0 100644 --- a/docs/4-language-usage/4-control-structures/1-cursor/g-4140.md +++ b/docs/4-language-usage/4-control-structures/1-cursor/g-4140.md @@ -17,17 +17,20 @@ In the following example, a procedure call is inserted between the `delete` stat ``` sql create or replace package body employee_api as co_one constant simple_integer := 1; + co_msg constant types_up.text := 'Do something based on '; procedure process_dept(in_dept_id in departments.department_id%type) is + co_dept_id constant departments.department_id%type := in_dept_id; begin - null; + sys.dbms_output.put_line(co_msg || co_dept_id); end process_dept; procedure remove_employee(in_employee_id in employees.employee_id%type) is - l_dept_id employees.department_id%type; + co_employee_id constant departments.department_id%type := in_employee_id; + l_dept_id employees.department_id%type; begin delete from employees - where employee_id = in_employee_id + where employee_id = co_employee_id returning department_id into l_dept_id; process_dept(in_dept_id => l_dept_id); @@ -46,18 +49,21 @@ end employee_api; ``` sql create or replace package body employee_api as co_one constant simple_integer := 1; + co_msg constant types_up.text := 'Do something based on '; procedure process_dept(in_dept_id in departments.department_id%type) is + co_dept_id constant departments.department_id%type := in_dept_id; begin - null; + sys.dbms_output.put_line(co_msg || co_dept_id); end process_dept; procedure remove_employee(in_employee_id in employees.employee_id%type) is + co_employee_id constant departments.department_id%type := in_employee_id; l_dept_id employees.department_id%type; l_deleted_emps simple_integer; begin delete from employees - where employee_id = in_employee_id + where employee_id = co_employee_id returning department_id into l_dept_id; l_deleted_emps := sql%rowcount; diff --git a/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4260.md b/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4260.md index ca4dc672..cb3ec5a0 100644 --- a/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4260.md +++ b/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4260.md @@ -11,7 +11,7 @@ It is more readable to use the opposite comparison operator instead of inverting ``` sql declare - l_color varchar2(7 char); + l_color types_up.color_code_type; begin if not l_color != constants_up.co_red then my_package.do_red(); diff --git a/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4270.md b/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4270.md index ed101cd8..e4ac66d2 100644 --- a/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4270.md +++ b/docs/4-language-usage/4-control-structures/2-case-if-decode-nvl-nvl2-coalesce/g-4270.md @@ -11,10 +11,10 @@ It is more readable to simply use the boolean value as a condition itself, rathe ``` sql declare - l_string varchar2(10 char) := '42'; + co_string constant types_up.text := '42'; l_is_valid boolean; begin - l_is_valid := my_package.is_valid_number(l_string); + l_is_valid := my_package.is_valid_number(co_string); if l_is_valid = true then my_package.convert_number(l_string); end if; @@ -26,10 +26,10 @@ end; ``` sql declare - l_string varchar2(10 char) := '42'; + co_string constant types_up.text := '42'; l_is_valid boolean; begin - l_is_valid := my_package.is_valid_number(l_string); + l_is_valid := my_package.is_valid_number(co_string); if l_is_valid then my_package.convert_number(l_string); end if; diff --git a/docs/4-language-usage/4-control-structures/3-flow-control/g-4310.md b/docs/4-language-usage/4-control-structures/3-flow-control/g-4310.md index c0a06fac..72f6d439 100644 --- a/docs/4-language-usage/4-control-structures/3-flow-control/g-4310.md +++ b/docs/4-language-usage/4-control-structures/3-flow-control/g-4310.md @@ -16,15 +16,16 @@ ``` sql create or replace package body my_package is procedure password_check(in_password in varchar2) is - co_digitarray constant string(10 char) := '0123456789'; - co_lower_bound constant simple_integer := 1; - co_errno constant simple_integer := -20501; - co_errmsg constant string(100 char) := 'Password must contain a digit.'; - l_isdigit boolean := false; + co_password constant dba_users.password%type := in_password; + co_digitarray constant string(10 char) := '0123456789'; + co_lower_bound constant simple_integer := 1; + co_errno constant simple_integer := -20501; + co_errmsg constant string(100 char) := 'Password must contain a digit.'; + l_isdigit boolean := false; l_len_pw pls_integer; l_len_array pls_integer; begin - l_len_pw := length(in_password); + l_len_pw := length(co_password); l_len_array := length(co_digitarray); <> @@ -33,7 +34,7 @@ create or replace package body my_package is <> for j in co_lower_bound..l_len_pw loop - if substr(in_password,j,1) = substr(co_digitarray,i,1) then + if substr(co_password,j,1) = substr(co_digitarray,i,1) then l_isdigit := true; goto check_other_things; end if; @@ -56,15 +57,16 @@ end my_package; ``` sql create or replace package body my_package is procedure password_check(in_password in varchar2) is - co_digitarray constant string(10 char) := '0123456789'; - co_lower_bound constant simple_integer := 1; - co_errno constant simple_integer := -20501; - co_errmsg constant string(100 char) := 'Password must contain a digit.'; - l_isdigit boolean := false; + co_password constant dba_users.password%type := in_password; + co_digitarray constant string(10 char) := '0123456789'; + co_lower_bound constant simple_integer := 1; + co_errno constant simple_integer := -20501; + co_errmsg constant string(100 char) := 'Password must contain a digit.'; + l_isdigit boolean := false; l_len_pw pls_integer; l_len_array pls_integer; begin - l_len_pw := length(in_password); + l_len_pw := length(co_password); l_len_array := length(co_digitarray); <> @@ -73,9 +75,8 @@ create or replace package body my_package is <> for j in co_lower_bound..l_len_pw loop - if substr(in_password,j,1) = substr(co_digitarray,i,1) then + if substr(co_password,j,1) = substr(co_digitarray,i,1) then l_isdigit := true; - exit check_digit; -- early exit condition end if; end loop check_pw_char; end loop check_digit; @@ -96,11 +97,12 @@ end my_package; ``` sql create or replace package body my_package is procedure password_check(in_password in varchar2) is - co_digitpattern constant string(10 char) := '\d'; - co_errno constant simple_integer := -20501; - co_errmsg constant string(100 char) := 'Password must contain a digit.'; + co_password constant dba_users.password%type := in_password; + co_digitpattern constant string(10 char) := '\d'; + co_errno constant simple_integer := -20501; + co_errmsg constant string(100 char) := 'Password must contain a digit.'; begin - if not regexp_like(in_password,co_digitpattern) then + if not regexp_like(co_password,co_digitpattern) then raise_application_error(co_errno,co_errmsg); end if; end password_check; diff --git a/docs/4-language-usage/5-exception-handling/g-5010.md b/docs/4-language-usage/5-exception-handling/g-5010.md index f0a1dcf0..f22edad4 100644 --- a/docs/4-language-usage/5-exception-handling/g-5010.md +++ b/docs/4-language-usage/5-exception-handling/g-5010.md @@ -21,10 +21,13 @@ This kind of framework should include ## Example (bad) ``` sql +declare + co_start constant logger_logs.text%type := 'start'; + co_end constant logger_logs.text%type := 'end'; begin - sys.dbms_output.put_line('START'); + sys.dbms_output.put_line(co_start); -- some processing - sys.dbms_output.put_line('END'); + sys.dbms_output.put_line(co_end); end; / ``` @@ -34,11 +37,13 @@ end; ``` sql declare -- see https://github.com/OraOpenSource/Logger - l_scope logger_logs.scope%type := 'DEMO'; + co_start constant logger_logs.text%type := 'start'; + co_end constant logger_logs.text%type := 'end'; + co_scope constant logger_logs.scope%type := 'demo'; begin - logger.log('START',l_scope); + logger.log(co_start,co_scope); -- some processing - logger.log('END',l_scope); + logger.log(co_end,co_scope); end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/5-exception-handling/g-5030.md b/docs/4-language-usage/5-exception-handling/g-5030.md index e773f7e3..c99a335a 100644 --- a/docs/4-language-usage/5-exception-handling/g-5030.md +++ b/docs/4-language-usage/5-exception-handling/g-5030.md @@ -24,7 +24,7 @@ begin where rownum = co_rownum; if l_dummy is null then - raise no_data_found; + raise no_data_found; -- NOSONAR: consequential error, violates G-5070 end if; exception when no_data_found then @@ -35,7 +35,7 @@ end; ``` Error report - ORA-01403: no data found -ORA-06512: at line 5 +ORA-06512: at line 7 01403. 00000 - "no data found" *Cause: No data was found from the objects. *Action: There was no data from the objects which may be due to end of fetch. diff --git a/docs/4-language-usage/5-exception-handling/g-5050.md b/docs/4-language-usage/5-exception-handling/g-5050.md index e3a07455..3c28a0b9 100644 --- a/docs/4-language-usage/5-exception-handling/g-5050.md +++ b/docs/4-language-usage/5-exception-handling/g-5050.md @@ -10,8 +10,10 @@ If you are not very organized in the way you allocate, define and use the error ## Example (bad) ``` sql +declare + co_invalid_emp_text constant types_up.text := 'Invalid employee_id'; begin - raise_application_error(-20501,'Invalid employee_id'); + raise_application_error(-20501 /* violates also G-1010 */,co_invalid_emp_text); end; / ``` diff --git a/docs/4-language-usage/5-exception-handling/g-5060.md b/docs/4-language-usage/5-exception-handling/g-5060.md index 19d7ca1b..d83fe8a9 100644 --- a/docs/4-language-usage/5-exception-handling/g-5060.md +++ b/docs/4-language-usage/5-exception-handling/g-5060.md @@ -15,14 +15,15 @@ The form that this failure takes does not necessarily need to be an exception. W ``` sql create or replace package body department_api is - function name_by_id(in_id in departments.department_id%type) + function name_by_id(in_id in departments.department_id%type) -- NOSONAR: non-deterministic return departments.department_name%type is + co_id constant departments.department_id%type := in_id; l_department_name departments.department_name%type; begin select department_name into l_department_name from departments - where department_id = in_id; + where department_id = co_id; return l_department_name; end name_by_id; @@ -34,14 +35,15 @@ end department_api; ``` sql create or replace package body department_api is - function name_by_id(in_id in departments.department_id%type) + function name_by_id(in_id in departments.department_id%type) -- NOSONAR: non-deterministic return departments.department_name%type is + co_id constant departments.department_id%type := in_id; l_department_name departments.department_name%type; begin select department_name into l_department_name from departments - where department_id = in_id; + where department_id = co_id; return l_department_name; exception diff --git a/docs/4-language-usage/5-exception-handling/g-5080.md b/docs/4-language-usage/5-exception-handling/g-5080.md index f378dfa7..6837c59f 100644 --- a/docs/4-language-usage/5-exception-handling/g-5080.md +++ b/docs/4-language-usage/5-exception-handling/g-5080.md @@ -14,17 +14,23 @@ If you use `sqlerrm` or `format_error_stack` to log/display error, you should al ``` sql create or replace package body order_api as procedure discount_and_recalculate( - in_customer_id in customer.id%type - ,in_discount in customer.discount_percentage%type + in_customer_id in integer + ,in_discount in number ) is + co_customer_id constant customer.id%type := in_customer_id; + co_discount constant customer.discount_percentage%type := in_discount; + co_error_label constant type_up.text := 'Error: '; begin - customer_api.apply_discount(in_customer_id,in_discount); - customer_api.in_customer_id(10293847); + customer_api.apply_discount( + in_customer_id => co_customer_id + ,in_discount => co_discount + ); + customer_api.calc(co_customer_id); exception when zero_divide then null; -- ignore when others then - logging_package.log_error('Error: ' || sqlerrm); + logging_package.log_error(co_error_label || sqlerrm); raise; end discount_and_recalculate; end order_api; @@ -36,20 +42,27 @@ end order_api; ``` sql create or replace package body order_api as procedure discount_and_recalculate( - in_customer_id in customer.id%type - ,in_discount in customer.discount_percentage%type + in_customer_id in integer + ,in_discount in number ) is + co_customer_id constant customer.id%type := in_customer_id; + co_discount constant customer.discount_percentage%type := in_discount; + co_error_label constant type_up.text := 'Error: '; + co_backtrace_label constant type_up.text := ' - Backtrace: '; begin - customer_api.apply_discount(in_customer_id,in_discount); - customer_api.in_customer_id(10293847); + customer_api.apply_discount( + in_customer_id => co_customer_id + ,in_discount => co_discount + ); + customer_api.calc(co_customer_id); exception when zero_divide then null; -- ignore when others then logging_package.log_error( - 'Error: ' + co_error_label || sqlerrm - || ' - Backtrace: ' + || co_backtrace_label || sys.dbms_utility.format_error_backtrace ); raise; diff --git a/docs/4-language-usage/6-dynamic-sql/g-6010.md b/docs/4-language-usage/6-dynamic-sql/g-6010.md index 9d28d280..bfe57ffb 100644 --- a/docs/4-language-usage/6-dynamic-sql/g-6010.md +++ b/docs/4-language-usage/6-dynamic-sql/g-6010.md @@ -13,7 +13,8 @@ Having the executed statement in a variable makes it easier to debug your code ( declare l_next_val employees.employee_id%type; begin - execute immediate 'select employees_seq.nextval from dual' into l_next_val; + execute immediate 'select employees_seq.nextval from dual' -- violates also G-1050 + into l_next_val; end; / ``` diff --git a/docs/4-language-usage/6-dynamic-sql/g-6020.md b/docs/4-language-usage/6-dynamic-sql/g-6020.md index dceb8d46..e9da6941 100644 --- a/docs/4-language-usage/6-dynamic-sql/g-6020.md +++ b/docs/4-language-usage/6-dynamic-sql/g-6020.md @@ -14,17 +14,21 @@ You should use the `returning into` clause for values returned from a DML operat ``` sql create or replace package body employee_api is - procedure upd_salary(in_employee_id in employees.employee_id%type - ,in_increase_pct in types_up.percentage - ,out_new_salary out employees.salary%type) + procedure upd_salary( + in_employee_id in employees.employee_id%type + ,in_increase_pct in types_up.percentage + ,out_new_salary out employees.salary%type + ) is - co_sql_stmt constant types_up.big_string_type := ' + co_employee_id constant employees.employee_id%type := in_employee_id; + co_increase_pct constant types_up.percentage := in_increase_pct; + co_sql_stmt constant types_up.big_string_type := ' update employees set salary = salary + (salary / 100 * :1) where employee_id = :2 returning salary into :3'; begin execute immediate co_sql_stmt - using in_increase_pct,in_employee_id,out out_new_salary; + using co_increase_pct,co_employee_id,out out_new_salary; end upd_salary; end employee_api; / @@ -34,17 +38,21 @@ end employee_api; ``` sql create or replace package body employee_api is - procedure upd_salary(in_employee_id in employees.employee_id%type - ,in_increase_pct in types_up.percentage - ,out_new_salary out employees.salary%type) + procedure upd_salary( + in_employee_id in employees.employee_id%type + ,in_increase_pct in types_up.percentage + ,out_new_salary out employees.salary%type + ) is - co_sql_stmt constant types_up.big_string_type := - 'update employees set salary = salary + (salary / 100 * :1) + co_employee_id constant employees.employee_id%type := in_employee_id; + co_increase_pct constant types_up.percentage := in_increase_pct; + co_sql_stmt constant types_up.big_string_type := ' + update employees set salary = salary + (salary / 100 * :1) where employee_id = :2 returning salary into :3'; begin execute immediate co_sql_stmt - using in_increase_pct,in_employee_id + using co_increase_pct,co_employee_id returning into out_new_salary; end upd_salary; end employee_api; diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7110.md b/docs/4-language-usage/7-stored-objects/1-general/g-7110.md index 6a0a8997..4c332bfc 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7110.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7110.md @@ -28,7 +28,10 @@ declare r_employee employees%rowtype; co_id constant employees.employee_id%type := 107; begin - employee_api.employee_by_id(out_row => r_employee,in_employee_id => co_id); + employee_api.employee_by_id( + out_row => r_employee + ,in_employee_id => co_id + ); end; / ``` \ No newline at end of file diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7120.md b/docs/4-language-usage/7-stored-objects/1-general/g-7120.md index aabcbccc..a51a9c5f 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7120.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7120.md @@ -11,14 +11,16 @@ It's a good alternative for comments to indicate the end of program units, espec ``` sql create or replace package body employee_api is - function employee_by_id(in_employee_id in employees.employee_id%type) + function -- NOSONAR: non-deterministic + employee_by_id(in_employee_id in integer) return employees%rowtype is - r_employee employees%rowtype; + co_employee_id constant employees.employee_id%type := in_employee_id; + r_employee employees%rowtype; begin select * into r_employee from employees - where employee_id = in_employee_id; + where employee_id = co_employee_id; return r_employee; exception @@ -35,14 +37,15 @@ end; ``` sql create or replace package body employee_api is - function employee_by_id(in_employee_id in employees.employee_id%type) + function employee_by_id(in_employee_id in integer) -- NOSONAR: non-deterministic return employees%rowtype is - r_employee employees%rowtype; + co_employee_id constant employees.employee_id%type := in_employee_id; + r_employee employees%rowtype; begin select * into r_employee from employees - where employee_id = in_employee_id; + where employee_id = co_employee_id; return r_employee; exception diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7125.md b/docs/4-language-usage/7-stored-objects/1-general/g-7125.md index b9c432d0..a257e0c7 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7125.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7125.md @@ -11,14 +11,15 @@ Using `create` alone makes your scripts give an error if the program unit alread ``` sql create package body employee_api is - function employee_by_id(in_employee_id in employees.employee_id%type) + function employee_by_id(in_employee_id in integer) -- NOSONAR: non-deterministic return employees%rowtype is - r_employee employees%rowtype; + co_employee_id constant employees.employee_id%type := in_employee_id; + r_employee employees%rowtype; begin select * into r_employee from employees - where employee_id = in_employee_id; + where employee_id = co_employee_id; return r_employee; exception @@ -35,14 +36,15 @@ end employee_api; ``` sql create or replace package body employee_api is - function employee_by_id(in_employee_id in employees.employee_id%type) + function employee_by_id(in_employee_id in integer) -- NOSONAR: non-deterministic return employees%rowtype is - r_employee employees%rowtype; + co_employee_id constant employees.employee_id%type := in_employee_id; + r_employee employees%rowtype; begin select * into r_employee from employees - where employee_id = in_employee_id; + where employee_id = co_employee_id; return r_employee; exception diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7130.md b/docs/4-language-usage/7-stored-objects/1-general/g-7130.md index e4eb5874..b119e783 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7130.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7130.md @@ -13,10 +13,11 @@ This external dependency is hidden, and may cause problems in the future. You sh ``` sql create or replace package body employee_api is - procedure calc_salary(in_employee_id in employees.employee_id%type) is - r_emp employees%rowtype; + procedure calc_salary(in_employee_id in integer) is + co_employee_id constant employees.employee_id%type := in_employee_id; + r_emp employees%rowtype; - function commission return number is + function commission return number is -- NOSONAR: non-deterministic l_commission employees.salary%type := 0; begin if r_emp.commission_pct is not null then @@ -29,7 +30,7 @@ create or replace package body employee_api is select * into r_emp from employees - where employee_id = in_employee_id; + where employee_id = co_employee_id; sys.dbms_output.put_line(r_emp.salary + commission()); exception @@ -46,16 +47,23 @@ end employee_api; ``` sql create or replace package body employee_api is - procedure calc_salary(in_employee_id in employees.employee_id%type) is - r_emp employees%rowtype; + procedure calc_salary(in_employee_id in integer) is + co_employee_id constant employees.employee_id%type := in_employee_id; + r_emp employees%rowtype; - function commission(in_salary in employees.salary%type - ,in_comm_pct in employees.commission_pct%type) - return number is - l_commission employees.salary%type := 0; + function commission( + in_salary in number + ,in_comm_pct in number + ) + return number + deterministic + is + co_salary constant employees.salary%type := in_salary; + co_comm_pct constant employees.commission_pct%type := in_comm_pct; + l_commission employees.salary%type := 0; begin if in_comm_pct is not null then - l_commission := in_salary * in_comm_pct; + l_commission := co_salary * co_comm_pct; end if; return l_commission; @@ -64,7 +72,7 @@ create or replace package body employee_api is select * into r_emp from employees - where employee_id = in_employee_id; + where employee_id = co_employee_id; sys.dbms_output.put_line( r_emp.salary + commission(in_salary => r_emp.salary diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7140.md b/docs/4-language-usage/7-stored-objects/1-general/g-7140.md index f16b0b46..8b77cdfc 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7140.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7140.md @@ -16,7 +16,9 @@ There is never a better time to review all the steps you took, and to understand ``` sql create or replace package body my_package is procedure my_procedure is - function my_func return number is + function my_func return number + deterministic + is co_true constant integer := 1; begin return co_true; @@ -33,7 +35,9 @@ end my_package; ``` sql create or replace package body my_package is procedure my_procedure is - function my_func return number is + function my_func return number + deterministic + is co_true constant integer := 1; begin return co_true; diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7150.md b/docs/4-language-usage/7-stored-objects/1-general/g-7150.md index 20a7c025..e8efaa62 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7150.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7150.md @@ -11,9 +11,12 @@ You should go through your programs and remove any parameter that is no longer u ``` sql create or replace package body department_api is - function name_by_id(in_department_id in departments.department_id%type - ,in_manager_id in departments.manager_id%type) + function name_by_id( -- NOSONAR: non-deterministic + in_department_id in integer + ,in_manager in employees%rowtype + ) return departments.department_name%type is + co_department_id constant departments.department_id%type := in_department_id; l_department_name departments.department_name%type; begin <> @@ -21,7 +24,7 @@ create or replace package body department_api is select department_name into l_department_name from departments - where department_id = in_department_id; + where department_id = co_department_id; exception when no_data_found or too_many_rows then l_department_name := null; @@ -37,8 +40,11 @@ end department_api; ``` sql create or replace package body department_api is - function name_by_id(in_department_id in departments.department_id%type) + function name_by_id( -- NOSONAR: non-deterministic + in_department_id in integer + ) return departments.department_name%type is + co_department_id constant departments.department_id%type := in_department_id; l_department_name departments.department_name%type; begin <> @@ -46,7 +52,7 @@ create or replace package body department_api is select department_name into l_department_name from departments - where department_id = in_department_id; + where department_id = co_department_id; exception when no_data_found or too_many_rows then l_department_name := null; diff --git a/docs/4-language-usage/7-stored-objects/1-general/g-7170.md b/docs/4-language-usage/7-stored-objects/1-general/g-7170.md index 75a7572e..92b8401c 100644 --- a/docs/4-language-usage/7-stored-objects/1-general/g-7170.md +++ b/docs/4-language-usage/7-stored-objects/1-general/g-7170.md @@ -14,24 +14,29 @@ Avoid using parameter mode `in out` unless you actually use the parameter both a ``` sql create or replace package body employee_up is - procedure rcv_emp(io_first_name in out employees.first_name%type - ,io_last_name in out employees.last_name%type - ,io_email in out employees.email%type - ,io_phone_number in out employees.phone_number%type - ,io_hire_date in out employees.hire_date%type - ,io_job_id in out employees.job_id%type - ,io_salary in out employees.salary%type - ,io_commission_pct in out employees.commission_pct%type - ,io_manager_id in out employees.manager_id%type - ,io_department_id in out employees.department_id%type - ,in_wait in integer) is + procedure rcv_emp( + io_first_name in out employees.first_name%type + ,io_last_name in out employees.last_name%type + ,io_email in out employees.email%type + ,io_phone_number in out employees.phone_number%type + ,io_hire_date in out employees.hire_date%type + ,io_job_id in out employees.job_id%type + ,io_salary in out employees.salary%type + ,io_commission_pct in out employees.commission_pct%type + ,io_manager_id in out employees.manager_id%type + ,io_department_id in out employees.department_id%type + ,in_wait in integer + ) is l_status pls_integer; co_dflt_pipe_name constant string(30 char) := 'MyPipe'; co_ok constant pls_integer := 1; + co_wait constant pls_integer := in_wait; begin -- Receive next message and unpack for each column. - l_status := sys.dbms_pipe.receive_message(pipename => co_dflt_pipe_name - ,timeout => in_wait); + l_status := sys.dbms_pipe.receive_message( + pipename => co_dflt_pipe_name + ,timeout => co_wait + ); if l_status = co_ok then sys.dbms_pipe.unpack_message(io_first_name); sys.dbms_pipe.unpack_message(io_last_name); @@ -53,24 +58,29 @@ end employee_up; ``` sql create or replace package body employee_up is - procedure rcv_emp(out_first_name out employees.first_name%type - ,out_last_name out employees.last_name%type - ,out_email out employees.email%type - ,out_phone_number out employees.phone_number%type - ,out_hire_date out employees.hire_date%type - ,out_job_id out employees.job_id%type - ,out_salary out employees.salary%type - ,out_commission_pct out employees.commission_pct%type - ,out_manager_id out employees.manager_id%type - ,out_department_id out employees.department_id%type - ,in_wait in integer) is + procedure rcv_emp( + out_first_name out employees.first_name%type + ,out_last_name out employees.last_name%type + ,out_email out employees.email%type + ,out_phone_number out employees.phone_number%type + ,out_hire_date out employees.hire_date%type + ,out_job_id out employees.job_id%type + ,out_salary out employees.salary%type + ,out_commission_pct out employees.commission_pct%type + ,out_manager_id out employees.manager_id%type + ,out_department_id out employees.department_id%type + ,in_wait in integer + ) is l_status pls_integer; co_dflt_pipe_name constant string(30 char) := 'MyPipe'; co_ok constant pls_integer := 1; + co_wait constant pls_integer := in_wait; begin -- Receive next message and unpack for each column. - l_status := sys.dbms_pipe.receive_message(pipename => co_dflt_pipe_name - ,timeout => in_wait); + l_status := sys.dbms_pipe.receive_message( + pipename => co_dflt_pipe_name + ,timeout => co_wait + ); if l_status = co_ok then sys.dbms_pipe.unpack_message(out_first_name); sys.dbms_pipe.unpack_message(out_last_name); diff --git a/docs/4-language-usage/8-patterns/1-checking-the-number-of-rows/g-8120.md b/docs/4-language-usage/8-patterns/1-checking-the-number-of-rows/g-8120.md index 7125646d..66103b04 100644 --- a/docs/4-language-usage/8-patterns/1-checking-the-number-of-rows/g-8120.md +++ b/docs/4-language-usage/8-patterns/1-checking-the-number-of-rows/g-8120.md @@ -14,7 +14,7 @@ create or replace package body department_api is procedure ins(in_r_department in departments%rowtype) is l_count pls_integer; begin - select count(*) + select count(*) -- NOSONAR: a violation of G-8110 is a prerequisite for G-8120 into l_count from departments where department_id = in_r_department.department_id; diff --git a/docs/4-language-usage/8-patterns/3-validating-input-parameter-size/g-8310.md b/docs/4-language-usage/8-patterns/3-validating-input-parameter-size/g-8310.md index d4dbe67b..c5d671de 100644 --- a/docs/4-language-usage/8-patterns/3-validating-input-parameter-size/g-8310.md +++ b/docs/4-language-usage/8-patterns/3-validating-input-parameter-size/g-8310.md @@ -11,20 +11,30 @@ This technique raises an error (`value_error`) which may not be handled in the c ``` sql create or replace package body department_api is - function dept_by_name(in_dept_name in departments.department_name%type) + function dept_by_name( -- NOSONAR: non-deterministic + in_dept_name in departments.department_name%type + ) return departments%rowtype is - r_return departments%rowtype; + r_return departments%rowtype; + co_max_dept_name_length constant integer := 20; begin - if in_dept_name is null or length(in_dept_name) > 20 then + if in_dept_name is null or length(in_dept_name) > co_max_dept_name_length then raise err.e_param_to_large; end if; -- get the department by name - select * - into r_return - from departments - where department_name = in_dept_name; - - return r_return; + <> + begin + select * + into r_return + from departments + where department_name = in_dept_name; + return r_return; + exception + when no_data_found then + return null; + when too_many_rows then + raise; + end trap; end dept_by_name; end department_api; / @@ -34,18 +44,27 @@ end department_api; ``` sql create or replace package body department_api is - function dept_by_name(in_dept_name in departments.department_name%type) + function dept_by_name( -- NOSONAR: non-deterministic + in_dept_name in departments.department_name%type + ) return departments%rowtype is - l_dept_name departments.department_name%type not null := in_dept_name; - r_return departments%rowtype; + co_dept_name constant departments.department_name%type not null := in_dept_name; + r_return departments%rowtype; begin -- get the department by name - select * - into r_return - from departments - where department_name = l_dept_name; - - return r_return; + <> + begin + select * + into r_return + from departments + where department_name = co_dept_name; + return r_return; + exception + when no_data_found then + return null; + when too_many_rows then + raise; + end trap; end dept_by_name; end department_api; / @@ -54,9 +73,11 @@ end department_api; The exception should be handled where the function is called, like this: ``` sql +declare + co_dept_name constant type_up.text := 'Far to long name of a department'; begin pre_processing; - r_department := department_api.dept_by_name('Far to long name of a department'); + r_department := department_api.dept_by_name(co_dept_name); post_processing; exception when value_error then diff --git a/docs/4-language-usage/8-patterns/4-ensure-single-execution-at-a-time-of-a-program-unit/g-8410.md b/docs/4-language-usage/8-patterns/4-ensure-single-execution-at-a-time-of-a-program-unit/g-8410.md index 4db1663b..43041921 100644 --- a/docs/4-language-usage/8-patterns/4-ensure-single-execution-at-a-time-of-a-program-unit/g-8410.md +++ b/docs/4-language-usage/8-patterns/4-ensure-single-execution-at-a-time-of-a-program-unit/g-8410.md @@ -15,7 +15,6 @@ The alternative using a table where a “Lock-Row” is stored has the disadvant ## Example (bad) ``` sql --- Bad /* Example */ create or replace package body lock_up is -- manage locks in a dedicated table created as follows: @@ -24,28 +23,34 @@ create or replace package body lock_up is -- ); procedure request_lock(in_lock_name in varchar2) is + co_lock_name constant app_locks.lock_name%type := in_lock_name; begin -- raises dup_val_on_index - insert into app_locks (lock_name) values (in_lock_name); + insert into app_locks (lock_name) values (co_lock_name); end request_lock; procedure release_lock(in_lock_name in varchar2) is + co_lock_name constant app_locks.lock_name%type := in_lock_name; begin - delete from app_locks where lock_name = in_lock_name; + delete from app_locks where lock_name = co_lock_name; end release_lock; end lock_up; / /* Call bad example */ declare - co_lock_name constant varchar2(30 char) := 'APPLICATION_LOCK'; + co_lock_name constant app_locks.lock_name%type := 'APPLICATION_LOCK'; begin lock_up.request_lock(in_lock_name => co_lock_name); -- processing lock_up.release_lock(in_lock_name => co_lock_name); exception + when dup_val_on_index then + -- expected exception + lock_up.release_lock(in_lock_name => co_lock_name); + raise; when others then - -- log error + -- unexpected exception, logging is recommended lock_up.release_lock(in_lock_name => co_lock_name); raise; end; @@ -57,14 +62,17 @@ end; ``` sql /* Example */ create or replace package body lock_up is - function request_lock( + function request_lock( -- NOSONAR: non-deterministic in_lock_name in varchar2 - ,in_release_on_commit in boolean := false) + ,in_release_on_commit in boolean default false + ) return varchar2 is - l_lock_handle varchar2(128 char); + co_lock_name constant type_up.lock_name := in_lock_name; + co_release_on_commit constant boolean := in_release_on_commit; + l_lock_handle type_up.lock_handle; begin sys.dbms_lock.allocate_unique( - lockname => in_lock_name + lockname => co_lock_name ,lockhandle => l_lock_handle ,expiration_secs => constants_up.co_one_week ); @@ -72,7 +80,7 @@ create or replace package body lock_up is lockhandle => l_lock_handle ,lockmode => sys.dbms_lock.x_mode ,timeout => sys.dbms_lock.maxwait - ,release_on_commit => coalesce(in_release_on_commit,false) + ,release_on_commit => co_release_on_commit ) > 0 then raise err.e_lock_request_failed; @@ -81,8 +89,9 @@ create or replace package body lock_up is end request_lock; procedure release_lock(in_lock_handle in varchar2) is + co_lock_type constant type_up.lock_handle := in_lock_handle; begin - if sys.dbms_lock.release(lockhandle => in_lock_handle) > 0 then + if sys.dbms_lock.release(lockhandle => co_lock_type) > 0 then raise err.e_lock_request_failed; end if; end release_lock; @@ -91,16 +100,20 @@ end lock_up; /* Call good example */ declare - l_handle varchar2(128 char); - co_lock_name constant varchar2(30 char) := 'APPLICATION_LOCK'; + l_handle type_up.lock_handle; + co_lock_name constant type_up.lock_name := 'APPLICATION_LOCK'; begin l_handle := lock_up.request_lock(in_lock_name => co_lock_name); -- processing lock_up.release_lock(in_lock_handle => l_handle); exception + when err.e_lock_request_failed then + -- expected exception + lock_up.release_lock(in_lock_name => co_lock_name); + raise; when others then - -- log error - lock_up.release_lock(in_lock_handle => l_handle); + -- unexpected exception, logging is recommended + lock_up.release_lock(in_lock_name => co_lock_name); raise; end; / diff --git a/docs/4-language-usage/8-patterns/5-use-dbms-application-info-package-to-follow-progress-of-a-process/g-8510.md b/docs/4-language-usage/8-patterns/5-use-dbms-application-info-package-to-follow-progress-of-a-process/g-8510.md index 80fe853d..4187dc4d 100644 --- a/docs/4-language-usage/8-patterns/5-use-dbms-application-info-package-to-follow-progress-of-a-process/g-8510.md +++ b/docs/4-language-usage/8-patterns/5-use-dbms-application-info-package-to-follow-progress-of-a-process/g-8510.md @@ -23,7 +23,8 @@ create or replace package body employee_api is order by employee_id ) loop - null; -- some processing + -- some processing + sys.dbms_output.put_line(emp_rec.employee_id); end loop employees; end process_emps; end employee_api; @@ -35,9 +36,13 @@ end employee_api; ``` sql create or replace package body employee_api is procedure process_emps is + co_action_name constant v$session.action%type := 'init'; + co_label constant v$session.action%type := 'Processing '; begin - sys.dbms_application_info.set_module(module_name => $$plsql_unit - ,action_name => 'Init'); + sys.dbms_application_info.set_module( + module_name => $$plsql_unit + ,action_name => co_action_name + ); <> for emp_rec in ( select employee_id @@ -45,7 +50,8 @@ create or replace package body employee_api is order by employee_id ) loop - sys.dbms_application_info.set_action('Processing ' || emp_rec.employee_id); + -- some processing + sys.dbms_application_info.set_action(co_label || emp_rec.employee_id); end loop employees; end process_emps; end employee_api; diff --git a/docs/4-language-usage/9-function-usage/g-9010.md b/docs/4-language-usage/9-function-usage/g-9010.md index 085dd904..fddffeb7 100644 --- a/docs/4-language-usage/9-function-usage/g-9010.md +++ b/docs/4-language-usage/9-function-usage/g-9010.md @@ -13,12 +13,16 @@ Using an explicit format model for string to `date` or `timestamp` conversion av ``` sql create or replace package body employee_api is - procedure set_dob(in_employee_id in employees.employee_id%type - ,in_dob_str in varchar2) is + procedure set_dob( + in_employee_id in employees.employee_id%type + ,in_dob_str in varchar2 + ) is + co_employee_id constant employees.employee_id%type := in_employee_id; + co_dob_str constant type_up.date_string := in_dob_str; begin update employees - set date_of_birth = to_date(in_dob_str) - where employee_id = in_employee_id; + set date_of_birth = to_date(co_dob_str default null on conversion error) + where employee_id = co_employee_id; end set_dob; end employee_api; / @@ -28,12 +32,19 @@ end employee_api; ``` sql create or replace package body employee_api is - procedure set_dob(in_employee_id in employees.employee_id%type - ,in_dob_str in varchar2) is + procedure set_dob( + in_employee_id in employees.employee_id%type + ,in_dob_str in varchar2 + ) is + co_employee_id constant employees.employee_id%type := in_employee_id; + co_dob_str constant type_up.date_string := in_dob_str; begin update employees - set date_of_birth = to_date(in_dob_str,'FXYYYY-MM-DD') - where employee_id = in_employee_id; + set date_of_birth = to_date( + co_dob_str default null on conversion error + ,'FXYYYY-MM-DD' -- NOSONAR: G-1050 must be a literal + ) + where employee_id = co_employee_id; end set_dob; end employee_api; / diff --git a/docs/4-language-usage/9-function-usage/g-9020.md b/docs/4-language-usage/9-function-usage/g-9020.md index fd8190b2..29645077 100644 --- a/docs/4-language-usage/9-function-usage/g-9020.md +++ b/docs/4-language-usage/9-function-usage/g-9020.md @@ -13,12 +13,16 @@ To avoid an inappropriate dependability on configurable NLS parameters, try to u ``` sql create or replace package body employee_api is - procedure set_salary(in_employee_id in employees.employee_id%type - ,in_salary in varchar2) is + procedure set_salary( + in_employee_id in employees.employee_id%type + ,in_salary in varchar2 + ) is + co_employee_id constant eployees.employee_id%type := in_employee_id; + co_salary constant type_up.date_string := in_salary; begin update employees - set salary = to_number(in_salary) - where employee_id = in_employee_id; + set salary = to_number(co_salary default null on conversion error) + where employee_id = co_employee_id; end set_dob; end employee_api; / @@ -28,13 +32,20 @@ end employee_api; ``` sql create or replace package body employee_api is - procedure set_salary(in_employee_id in employees.employee_id%type - ,in_salary in varchar2) is + procedure set_salary( + in_employee_id in employees.employee_id%type + ,in_salary in varchar2 + ) is + co_employee_id constant eployees.employee_id%type := in_employee_id; + co_salary constant type_up.string := in_salary; begin update employees - set salary = to_number(in_salary,'99999999999999999999.99999',q'[nls_numeric_characters='.,']') - where employee_id = in_employee_id; + set salary = to_number( + co_salary default null on conversion error + ,'99999999999999999999.99999' -- NOSONAR: G-1050 must be a literal + ,q'[nls_numeric_characters='.,']' -- NOSONAR: G-1050 must be a literal + ) + where employee_id = co_employee_id; end set_dob; end employee_api; -/ -``` \ No newline at end of file +``` diff --git a/docs/4-language-usage/9-function-usage/g-9030.md b/docs/4-language-usage/9-function-usage/g-9030.md index c218f227..0ba0404c 100644 --- a/docs/4-language-usage/9-function-usage/g-9030.md +++ b/docs/4-language-usage/9-function-usage/g-9030.md @@ -15,12 +15,17 @@ When converting from strings to other datatypes using a conversion function that ``` sql create or replace package body employee_api is - procedure set_dob(in_employee_id in employees.employee_id%type - ,in_dob_str in varchar2) is + procedure set_dob( + in_employee_id in employees.employee_id%type + ,in_dob_str in varchar2 + ) is + co_employee_id constant employees.employee_id%type := in_employee_id; + co_dob_str constant type_up.date_string := in_dob_str; begin update employees - set date_of_birth = to_date(in_dob_str,'YYYY-MM-DD') - where employee_id = in_employee_id; + set date_of_birth = to_date(co_dob_str,'FXYYYY-MM-DD' -- NOSONAR: G-1050 must be a literal +) + where employee_id = co_employee_id; end set_dob; end employee_api; / @@ -30,12 +35,19 @@ end employee_api; ``` sql create or replace package body employee_api is - procedure set_dob(in_employee_id in employees.employee_id%type - ,in_dob_str in varchar2) is + procedure set_dob( + in_employee_id in employees.employee_id%type + ,in_dob_str in varchar2 + ) is + co_employee_id constant employees.employee_id%type := in_employee_id; + co_dob_str constant type_up.date_string := in_dob_str; begin update employees - set date_of_birth = to_date(in_dob_str default null on conversion error,'YYYY-MM-DD') - where employee_id = in_employee_id; + set date_of_birth = to_date( + co_dob_str default null on conversion error + ,'FXYYYY-MM-DD' -- NOSONAR: G-1050 must be a literal + ) + where employee_id = co_employee_id; end set_dob; end employee_api; / diff --git a/docs/4-language-usage/9-function-usage/g-9040.md b/docs/4-language-usage/9-function-usage/g-9040.md index 247baaf3..557c5647 100644 --- a/docs/4-language-usage/9-function-usage/g-9040.md +++ b/docs/4-language-usage/9-function-usage/g-9040.md @@ -15,12 +15,19 @@ The exception to this rule can be if you are converting textual input typed by a ``` sql create or replace package body employee_api is - procedure set_dob(in_employee_id in employees.employee_id%type - ,in_dob_str in varchar2) is + procedure set_dob( + in_employee_id in employees.employee_id%type + ,in_dob_str in varchar2 + ) is + co_employee_id constant employees.employee_id%type := in_employee_id; + co_dob_str constant type_up.date_string := in_dob_str; begin update employees - set date_of_birth = to_date(in_dob_str,'YYYY-MM-DD') - where employee_id = in_employee_id; + set date_of_birth = to_date( + co_dob_str default null on conversion error + ,'YYYY-MM-DD' -- violates also G-1050, must be a literal + ) + where employee_id = co_employee_id; end set_dob; end employee_api; / @@ -30,12 +37,19 @@ end employee_api; ``` sql create or replace package body employee_api is - procedure set_dob(in_employee_id in employees.employee_id%type - ,in_dob_str in varchar2) is + procedure set_dob( + in_employee_id in employees.employee_id%type + ,in_dob_str in varchar2 + ) is + co_employee_id constant employees.employee_id%type := in_employee_id; + co_dob_str constant type_up.date_string := in_dob_str; begin update employees - set date_of_birth = to_date(in_dob_str,'FXYYYY-MM-DD') - where employee_id = in_employee_id; + set date_of_birth = to_date( + co_dob_str default null on conversion error + ,'FXYYYY-MM-DD' -- NOSONAR: G-1050 must be a literal + ) + where employee_id = co_employee_id; end set_dob; end employee_api; / diff --git a/docs/5-complexity-analysis/complexity-analysis.md b/docs/5-complexity-analysis/complexity-analysis.md index 70e469b8..72d10e20 100644 --- a/docs/5-complexity-analysis/complexity-analysis.md +++ b/docs/5-complexity-analysis/complexity-analysis.md @@ -55,17 +55,23 @@ where Take, for example, a control flow graph of a simple program. The program begins executing at the red node, then enters a loop (group of three nodes immediately below the red node). On exiting the loop, there is a conditional statement (group below the loop), and finally the program exits at the blue node. For this graph, $E = 9$, $N = 8$ and $P = 1$, so the cyclomatic complexity of the program is $3$.

``` sql +declare + co_upper_bound constant integer := 3; + co_msg constant user_objects.object_name%type := 'in loop '; + co_yes constant user_objects.object_name%type := 'yes'; + co_end constant user_objects.object_name%type := 'end'; begin - for i in 1..3 + <> + for i in 1..co_upper_bound loop - sys.dbms_output.put_line('in loop'); - end loop; + sys.dbms_output.put_line(co_msg || i); + end loop print_in_loop; -- if 1 = 1 then - sys.dbms_output.put_line('yes'); + sys.dbms_output.put_line(co_yes); end if; -- - sys.dbms_output.put_line('end'); + sys.dbms_output.put_line(co_end); end; / ```