Oracle 8i | Oracle 9i | Oracle 10g | Oracle 11g | Oracle 12c | Miscellaneous | PL/SQL | SQL | Oracle RAC | Oracle Apps | Linux

The WRAP Utility and the DBMS_DDL Package

On occasion it is necessary to hide (obfuscate) your PL/SQL source code. Traditionally this has been done using the WRAP utility, but Oracle 10g Release 2 also allows this to be done dynamically using the DBMS_DDL package. This article presents examples of both methods of PL/SQL source obfuscation.

The WRAP Utility

The wrap utility is a command line utility that obfuscates the contents of a PL/SQL source file. The syntax for the wrap utility is shown below.

wrap iname=input_file [oname=output_file]

The iname parameter specifies the source file, while the oname parameter specifies the destination file. If the destination file is not specified it defaults to the source file name with a ".pld" extension.

To see how the wrap utility works we must create a dummy source file called get_date_string.sql with the following contents.

CREATE OR REPLACE FUNCTION get_date_string RETURN VARCHAR2 AS
BEGIN
  RETURN TO_CHAR(SYSDATE, 'DD-MON-YYYY');
END get_date_string;
/

We can then run the two variants of the wrap utility, specifying our source file.

wrap iname=get_date_string.sql

PL/SQL Wrapper: Release 10.2.0.1.0- Production on Wed Oct 05 10:54:14 2005

Copyright (c) 1993, 2004, Oracle.  All rights reserved.

Processing get_date_string.sql to get_date_string.plb


wrap iname=get_date_string.sql oname=get_date_string_wrap.sql

PL/SQL Wrapper: Release 10.2.0.1.0- Production on Wed Oct 05 10:55:01 2005

Copyright (c) 1993, 2004, Oracle.  All rights reserved.

Processing get_date_string.sql to /tmp/get_date_string_wrap.sql

Notice that the output file name is defaulted as expected when it is not specified on the command line. The resulting output files contain the wrapped code which is listed below.

CREATE OR REPLACE FUNCTION get_date_string wrapped
a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
71 ae
P29RDhRZX0orO0ED/mMF8i12Glkwg8eZgcfLCNL+XlquYvSuoVah8JbRPpdHDOrnwLK9spte
58d0wDO4dGUJuHSLwMAy/tKGCamhAs7G1hohrO/WTHaEcTKOd0xx9RBzc/XvN2dM6+zZPXLp
r1UqFBwU/Sx2010pwUjXpqZCvywG

/

The DBMS_DDL package for Dynamic Wrapping

The DBMS_DDL package contains three overloaded functions called WRAP, the simplest of which accepts a VARCHAR2 input parameter containing a PL/SQL CREATE OR REPLACE statement and returns the obfuscated PL/SQL, which can be written to a file or stored in a table. The following example shows how the basic WRAP function is used from PL/SQL.

SET SERVEROUTPUT ON SIZE UNLIMITED
DECLARE
  l_source  VARCHAR2(32767);
  l_wrap    VARCHAR2(32767);
BEGIN
  l_source := 'CREATE OR REPLACE FUNCTION get_date_string RETURN VARCHAR2 AS' ||
              'BEGIN ' ||
              'RETURN TO_CHAR(SYSDATE, ''DD-MON-YYYY''); ' ||
              'END get_date_string;';

  l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source);
  DBMS_OUTPUT.put_line(l_wrap);
END;
/
CREATE OR REPLACE FUNCTION get_date_string wrapped

a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
6f
aa
mV4eMSJ8EqqgErJT91l6UZ0pdDUwgyr6LZ5GfHSmUPiJfkEObQpeDb6D7glajI+ONulxdqC1
0HvOPP4eJpQs5zxsKXpj6XL1
fvieXyWCr3BTzXTqcGYhfXrtqDVPztR/o+9UZ8l5OijDSsRW
ZPv6rISzFyqeEsCBweFUFyxd


PL/SQL procedure successfully completed.

SQL>

This works fine for PL/SQL source that is less than or equal to 32K in size, but the VARCHAR2 input parameter means it can't cope with source larger than this. Fortunately the other overloads of this function allow us to work with source greater than 32K in size.

DBMS_DDL.WRAP(
   ddl      DBMS_SQL.VARCHAR2S,
   lb       PLS_INTEGER,
   ub       PLS_INTEGER)
  RETURN DBMS_SQL.VARCHAR2S;

DBMS_DDL.WRAP(
   ddl      DBMS_SQL.VARCHAR2A,
   lb       PLS_INTEGER,
   ub       PLS_INTEGER)
  RETURN DBMS_SQL.VARCHAR2A;

In both overloads the source is passed in and out using an associative array (index-by table). The difference between the two is that the DBMS_SQL.VARCHAR2S type is limited to 256 bytes per line, while the DBMS_SQL.VARCHAR2A type can hold a maximum of 32K per line. The following example uses the DBMS_SQL.VARCHAR2A version to shows how these overloads work.

SET SERVEROUTPUT ON SIZE UNLIMITED
DECLARE
  l_source  DBMS_SQL.VARCHAR2A;
  l_wrap    DBMS_SQL.VARCHAR2A;
BEGIN
  l_source(1) := 'CREATE OR REPLACE FUNCTION get_date_string RETURN VARCHAR2 AS ';
  l_source(2) := 'BEGIN ';
  l_source(3) := 'RETURN TO_CHAR(SYSDATE, ''DD-MON-YYYY''); ';
  l_source(4) := 'END get_date_string;';

  l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source,
                              lb  => 1,
                              ub  => l_source.count);

  FOR i IN 1 .. l_wrap.count LOOP
    DBMS_OUTPUT.put_line(l_wrap(i));
  END LOOP;
END;
/
CREATE OR REPLACE FUNCTION get_date_string wrapped

a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
6f
aa
mV4eMSJ8EqqgErJT91l6UZ0pdDUwgyr6LZ5GfHSmUPiJfkEObQpeDb6D7glajI+ONulxdqC1
0HvOPP4eJpQs5zxsKXpj6XL1
fvieXyWCr3BTzXTqcGYhfXrtqDVPztR/o+9UZ8l5OijDSsRW
ZPv6rISzFyqeEsCBweFUFyxd


PL/SQL procedure successfully completed.

SQL>

In addition to the WRAP functions, the DBMS_DDL package also contains three overloaded procedures called CREATE_WRAPPED. These procedure have the same parameter lists as the three WRAP function overloads, and are used to wrap and compile the specified source. The following example shows how the DBMS_SQL.VARCHAR2A version is used.

SET SERVEROUTPUT ON SIZE UNLIMITED
DECLARE
  l_source  DBMS_SQL.VARCHAR2A;
  l_wrap    DBMS_SQL.VARCHAR2A;
BEGIN
  l_source(1) := 'CREATE OR REPLACE FUNCTION get_date_string RETURN VARCHAR2 AS ';
  l_source(2) := 'BEGIN ';
  l_source(3) := 'RETURN TO_CHAR(SYSDATE, ''DD-MON-YYYY''); ';
  l_source(4) := 'END get_date_string;';

  SYS.DBMS_DDL.CREATE_WRAPPED(ddl => l_source,
                              lb  => 1,
                              ub  => l_source.count);
END;
/

PL/SQL procedure successfully completed.

SET PAGESIZE 100
SELECT text
FROM   user_source
WHERE  name = 'GET_DATE_STRING'
AND    type = 'FUNCTION';

TEXT
------------------------------------------------------------------------
FUNCTION get_date_string wrapped
a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
6f aa
mV4eMSJ8EqqgErJT91l6UZ0pdDUwgyr6LZ5GfHSmUPiJfkEObQpeDb6D7glajI+ONulxdqC1
0HvOPP4eJpQs5zxsKXpj6XL1fvieXyWCr3BTzXTqcGYhfXrtqDVPztR/o+9UZ8l5OijDSsRW
ZPv6rISzFyqeEsCBweFUFyxd


1 row selected.

SQL>

The CREATE_WRAPPED procedures are the equivalent of passing the wrapped source returned from the WRAP function into an EXECUTE IMMEDIATE or DBMS_SQL.PARSE call, but they are optimized to give better performance.

For more information see:

Hope this helps. Regards Tim...

Back to the Top.