G-3170
🆓Error
Always use DEFAULT ON NULL declarations to assign default values to table columns if you refuse to store NULL values.
Reason
Default values have been nullifiable until Oracle Database 12c. Meaning any tool sending null as a value for a column having a default value bypassed the default value. Starting with Oracle Database 12c default definitions may have an on null
definition in addition, which will assign the default value in case of a null
value too.
Example
Non-Compliant Example
create table null_test ( test_case number(2) not null ,column_defaulted varchar2(10 char) default 'Default' not null) / insert into null_test(test_case,column_defaulted) values (1,'Value'); insert into null_test(test_case,column_defaulted) values (2,default); insert into null_test(test_case,column_defaulted) values (3,null); select test_case,column_defaulted from null_test;
Issues
Line | Column | Message |
---|---|---|
3 | 39 |
TEST_CASE COLUMN_DEF
--------- -----------
1 Value
2 Default
3
★★★★★
Compliant Solution -
create table null_test ( test_case number(2) not null ,column_defaulted varchar2(10 char) default on null 'Default' not null) / insert into null_test(test_case,column_defaulted) values (1,'Value'); insert into null_test(test_case,column_defaulted) values (2,default); insert into null_test(test_case,column_defaulted) values (3,null); select test_case,column_defaulted from null_test;
TEST_CASE COLUMN_DEF
---------- ----------
1 Value
2 Default
3 Default
Tests
Test SQL query
with function alter_table_stmt ( -- NOSONAR G-7460: nondeterministic function in_owner in varchar2, in_table_name in varchar2, in_column_name in varchar2 ) return clob is co_templ constant varchar2(200 char) := 'alter table #OWNER#.#TABLE_NAME# modify #COLUMN_NAME# default on null#FOR_INSERT_AND_UPDATE# #DATA_DEFAULT#;'; l_stmt varchar2(4000 byte) := co_templ; l_data_default varchar2(4000 byte); begin <<get_data_default_to_overcome_long_restrictions>> begin select data_default -- column data_default_vc was introduce in Oracle Database 23ai. into l_data_default from dba_tab_cols where owner = in_owner and table_name = in_table_name and column_name = in_column_name; exception when too_many_rows or no_data_found then raise; end get_data_default_to_overcome_long_restrictions; if dbms_db_version.version >= 23 then l_stmt := replace(l_stmt, '#FOR_INSERT_AND_UPDATE#', ' for insert and update'); else l_stmt := replace(l_stmt, '#FOR_INSERT_AND_UPDATE#', null); end if; l_stmt := replace(l_stmt, '#OWNER#', in_owner); l_stmt := replace(l_stmt, '#TABLE_NAME#', in_table_name); l_stmt := replace(l_stmt, '#COLUMN_NAME#', in_column_name); l_stmt := replace(l_stmt, '#DATA_DEFAULT#', trim(l_data_default)); return l_stmt; end alter_table_stmt; select owner || '.' || table_name || '.' || column_name as identifier, 'Missing DEFAULT ON NULL for ' || column_name || ' in table ' || owner || '.' || table_name || '.' as message, alter_table_stmt(owner, table_name, column_name) as migration from dba_tab_cols where data_default is not null and default_on_null = 'NO' and table_name not like 'BIN$%' and virtual_column = 'NO' and nullable = 'N' and owner in (#SchemaNames#) -- config parameter order by owner, table_name, column_name
Test results
Identifier | Message | Migration |
---|---|---|
DBL_OWNER.NULL_TEST.COLUMN_DEFAULTED | Missing DEFAULT ON NULL for COLUMN_DEFAULTED in table DBL_OWNER.NULL_TEST. | alter table DBL_OWNER.NULL_TEST modify COLUMN_DEFAULTED default on null for insert and update 'Default'; |
Parameters
Use parameters to customize the rule to your needs.
Parameter | Description | Default Value |
---|---|---|
SchemaNames | Comma-separated list of database schemas owning the database objects of an application. | dbl_owner |
References
- same as Trivadis G-3170