In order to facilitate Out of Place Patching, Datapatch stores all previously applied Patch Content in the form of BLOB Objects in the Table - registry$sqlpatch_ru_info. The BLOB Object is called into action in case of Out of Place Patching OR Patch Rollback Scenarios. So, This makes the $ORACLE_HOME/sqlpatch/<DB RU Patch Number> Location mostly redundant or Non-Useful,as the same content is now stored inside the DB in SQL registry table registry$sqlpatch_ru_info. However, Before any action can be taken on the Physical Location - $ORACLE_HOME/sqlpatch/<DB RU Patch Number>, Kindly -

1. Verify that a minimum of 19.15 DB RU(or higher) is applied to the concerned/affected Home.

$ opatch lspatches

2.Verify that all previous RU Patches are applied successfully i,e Each DB RU has a SUCCESS Entry in registry$sqlpatch. In the case of a Multitenant Environment, Each Container should have a SUCCESS Entry against each DB RU.

SQL> select patch_id,patch_uid, action,status, action_time, description from dba_registry_sqlpatch order by ACTION_TIME;
SQL> select con_id,patch_id,patch_uid, action,status, action_time, description from cdb_registry_sqlpatch order by ACTION_TIME;

3. Verify that the BLOB Object exists for all historical DB RUs(listed in registry$sqlpatch in Step 2 above) in SQL registry table registry$sqlpatch_ru_info-

SQL> select a.owner, a.segment_name "ObjectName", b.SEGMENT_TYPE "ObjectType", b.bytes "SizeBytes", a.table_name, a.column_name
from dba_lobs a, dba_segments b
where a.segment_name = b.segment_name
and a.owner = b.owner
and a.owner='SYS'
and a.column_name='PATCH_DIRECTORY'
order by b.bytes desc;

SQL> SELECT
patch_id,
ru_version,
ru_build_timestamp,
round(dbms_lob.getlength(patch_directory) / 1024 / 1024) lob_size_mb
FROM
sys.registry$sqlpatch_ru_info;

If above conditions are met, then $ORACLE_HOME/sqlpatch/<DB RU Patch Number> Folder and it's contents can be cleared.