PL/SQL Bulk Unwrap

406 days ago I released PL/SQL Unwrapper for SQL Developer version 0.1.1 and blogged about it. With this extension, you can unwrap the content of a SQL Developer window. Time for an update. With the new version 1.0 you can unwrap multiple selected objects with a few mouse clicks. In this blog post, I show how.

1. Install Extensions

I assume that you are already using SQL Developer 4.0.2 or higher. If not then it is about time that you grab the latest version from here and install it. It’s important to note that the extensions won’t run in older versions of SQL Developer.

Configure the update center https://update.salvis.com/ and https://update.oddgen.org/ to install the extensions for SQL Developer:

updates_oddgen_unwrapper

If you cannot use the update center because your company’s network restricts internet access then download oddgen, unwrapper and install them from file.

Why download oddgen for SQL Developer? Because the bulk unwrap feature is implemented as oddgen plugin. Unwrapping an editor content works without oddgen, but for bulk unwrap you need oddgen.

2. Setup Test Environment

If you have a schema in your Oracle database with wrapped code you may skip this step and use this schema for bulk unwrap.

For the test environment, I’ve used Morten Braten’s Alexandria PL/SQL Utility Library. Clone or download the library from GitHub. To install the library you need a dedicated user. Create such a user as SYS on your Oracle database instance as follows:

Create User AX for Alexandria Library
CREATE USER ax IDENTIFIED BY ax 
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp;

ALTER USER ax QUOTA UNLIMITED ON users;

GRANT connect, resource TO ax;
GRANT execute ON dbms_crypto TO ax;

Then run the install.sql script in the setup directory of the Alexandria PL/SQL Utility Library as user AX.

Install Alexandria PL/SQL Utility Library in Schema AX
@install.sql

Wrap the PL/SQL code except package and type specifications in schema AX by running the script wrap_schema.sql:

Wrap PL/SQL Code
SET SERVEROUTPUT ON
DECLARE
   PROCEDURE wrap_and_install(in_code IN CLOB) IS
      co_chunksize INTEGER := 8196;
      l_array      dbms_sql.varchar2a;
      l_lb         INTEGER := 1;
      l_ub         INTEGER;
      l_cursor     PLS_INTEGER;
   BEGIN
      l_ub := ceil(sys.dbms_lob.getlength(in_code) / co_chunksize);
      <<clob_chunks>>
      FOR i IN l_lb .. l_ub
      LOOP
         l_array(i) := sys.dbms_lob.substr(lob_loc => in_code,
                                           offset  => (i - 1) * co_chunksize + 1,
                                           amount  => co_chunksize);
      END LOOP clob_chunks;
      l_cursor := sys.dbms_sql.open_cursor;
      sys.dbms_sql.parse(c             => l_cursor,
                         STATEMENT     => l_array,
                         lb            => l_lb,
                         ub            => l_ub,
                         lfflg         => FALSE,
                         language_flag => sys.dbms_sql.native);
      sys.dbms_ddl.create_wrapped(ddl => l_array, lb => l_lb, ub => l_ub);
      sys.dbms_sql.close_cursor(l_cursor);
   END wrap_and_install;
BEGIN
   <<unwrapped_sources>>
   FOR l_rec IN (SELECT TYPE AS original_type,
                        CASE TYPE
                           WHEN 'PACKAGE' THEN
                            'PACKAGE_SPEC'
                           WHEN 'PACKAGE BODY' THEN
                            'PACKAGE_BODY'
                           WHEN 'TYPE' THEN
                            'TYPE_SPEC'
                           WHEN 'TYPE BODY' THEN
                            'TYPE_BODY'
                           ELSE
                            TYPE
                        END AS object_type,
                        NAME AS object_name
                   FROM user_source
                  WHERE TYPE IN ('FUNCTION',
                                 'PROCEDURE',
                                 -- 'PACKAGE',
                                 'PACKAGE BODY',
                                 -- 'TYPE',
                                 'TYPE BODY',
                                 'LIBRARY')
                        AND line = 1
                        AND lower(text) NOT LIKE '% wrapped%'
                  ORDER BY type, name)
   LOOP
      <<try_to_wrap>>
      DECLARE
         l_ddl  CLOB;
         l_code CLOB;
      BEGIN
         l_ddl := sys.dbms_metadata.get_ddl(object_type => l_rec.object_type,
                                            NAME        => l_rec.object_name,
                                            SCHEMA      => USER);
         -- wrap with EDITIONABLE clause fails on 12.1.0.2.0 with: 
         --    ORA-24230: input to DBMS_DDL.WRAP is not a legal PL/SQL unit
         l_code := REPLACE(l_ddl, 'CREATE OR REPLACE EDITIONABLE ', 'CREATE OR REPLACE ');
         -- wrapping within database supported through DBMS_DDL since 10gR1
         wrap_and_install(in_code => l_code);
         sys.dbms_output.put_line(l_rec.original_type || ' ' || l_rec.object_name ||
                                  ' wrapped.');
      EXCEPTION
         WHEN OTHERS THEN
            sys.dbms_output.put_line(l_rec.original_type || ' ' || l_rec.object_name ||
                                     ' not wrapped because of ' || SQLERRM);
      END try_to_wrap;
   END LOOP unwrapped_sources;
END;
/

3. Bulk Unwrap

Start SQL Developer and open a connection as user AX on your database.

If the oddgen window is not visible then select “Generators” from the “View” menu as shown in the following picture:

menu_view_generators

Afterwards, the Generators window appears in the lower left corner within SQL Developer.

generators

Select the open connection in the combo box of the Generator window. Open the “PL/SQL Unwrapper” node and the “Package Bodies” node to show all wrapped package body names.

generators2

Select some or all package body nodes and press Return to generate the unwrapped code in a new worksheet. Afterwards, you just may execute the generated code. Add “SET DEFINE OFF” at the start of the script to ensure unwrapped code containing ampersand (&) characters is processed correctly. Another option is to configure a connection startup script (login.sql) to change the default behaviour.

The following audio-less video shows in just 56 seconds the whole bulk unwrapping process in detail.

I hope you find this new feature useful.

10 Comments

  1. blank Samar says:

    Hello Sir,

    I have 1000 of plb files in a folder, How do I unwrap all the plsql code at a time and can save in the folder as sql.

     

    Thanks in Advance.

  2. blank Adil says:

    Hi there,

    I have Oracle SQL Developer Version 4.1.4.21 and I have added the oddgen for sqldev extension using “oddgen_for_SQLDev_0.3.1” file; however, I cannot see “PL/SQL Unwrapper” option in “Generators” window, though “Xtend” and “Hello world” exist.

    Can you please let me know what I am missing and doing wrong.

  3. blank AlexRenaps says:

    Hello
    Does this solution work for unwrapping oracle packages body such as DBMS_LOB?

    Thanks

  4. blank PIERRE DETE says:

    Hi, I don’t see the Generators in the view tab.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.