Oracle Stored Procedure that copies and compiles database objects between schemas
We have a single ORACLE server that contains production as well as development environments, each one uses two schemas -
SCHEMA_1 / SCHEMA_2 and SCHEMA_1_DEV / SCHEMA_2_DEV respectively. First we design everything in _DEV environment and then
copy all database structure to production. The problem is that the development stored procedures point to tables and
other procedures in schema ending with "_DEV". However, in production all schema calls should have no "_DEV".
The following procedure copies (and compiles) any object from development environment to production after removing the "_DEV"
call from everywhere. This way we save time and avoid any human error on doing such replacements by hand.
Note: We are using DBMS_SQL so that package or procedure of any size can be compiled.
EXECUTE IMMEDIATE cannot run queries whose length is greater than 32 KB
- Read the script needed to generate the object from USER_SOURCE table.
- Execute each line of this script with DBMS_SQL
instead of
EXECUTE IMMEDIATE which cannot run queries whose length is greater than 32 KB
Scroll to the bottom to copy the source code from a textarea.
|
Call to procedure:
EXEC MIGRATE_OBJECT_TO_PRODUCTION ('NEW_SCHEMA', 'PKG_TO_COPY', 'PACKAGE')
Procedure Source Code:
CREATE
OR
REPLACE
PROCEDURE MIGRATE_OBJECT_TO_PRODUCTION
(
IN_SCHEMA_TO IN VARCHAR2,
IN_OBJECT_NAME IN VARCHAR2,
IN_OBJECT_TYPE IN VARCHAR2
)
IS
--
LOCAL STORED PROCEDURE
PROCEDURE
PRC_CREATE_OBJECT (
IN_SCHEMA_TO
IN VARCHAR2,
IN_OBJECT_NAME
IN VARCHAR2,
IN_OBJECT_TYPE
IN VARCHAR2
)
IS
L_SQL_TABLE
DBMS_SQL.VARCHAR2A;
--
COLLECTION OF VARCHAR2(32767) INDEX BY BINARY_INTEGER
L_CURRENT_ROW BINARY_INTEGER :=
0;
L_CUR
PLS_INTEGER;
L_ROWS_PROCESSED
PLS_INTEGER;
CURSOR
CRS_OBJECT_SCRIPT (
IN_OBJECT_NAME
IN VARCHAR2,
IN_OBJECT_TYPE
IN VARCHAR2
)
IS
--
CURSOR RETRIEVES ALL LINES OF CODE TO CREATE THE OBJECT
--
REPLACE ALL CALLS TO SCHEMA NAME ENDING WITH _DEV
SELECT REPLACE
(UPPER
(TEXT),
'_DEV.',
'.')
AS
TEXT,
LINE
FROM
USER_SOURCE
WHERE
UPPER
(NAME)
=
UPPER
(IN_OBJECT_NAME)
AND
UPPER
(TYPE)
=
UPPER
(IN_OBJECT_TYPE)
ORDER
BY
LINE;
BEGIN
FOR
CODE_LINE IN
CRS_OBJECT_SCRIPT (IN_OBJECT_NAME,
IN_OBJECT_TYPE)
LOOP
IF
CODE_LINE.LINE
=
1
THEN
--
ADD NEW SCHEMA NAME AND CREATE OR REPLACE COMMAND
CODE_LINE.TEXT
:=
'
CREATE OR REPLACE '
|| REPLACE
(CODE_LINE.TEXT,
IN_OBJECT_NAME,
IN_SCHEMA_TO || '.'
|| IN_OBJECT_NAME
);
END
IF;
L_CURRENT_ROW :=
NVL
(L_SQL_TABLE.LAST,
0)
+
1;
L_SQL_TABLE (L_CURRENT_ROW)
:=
CODE_LINE.TEXT;
END
LOOP;
IF
L_CURRENT_ROW =
0
THEN
RAISE
NO_DATA_FOUND;
END
IF;
--
PARSE THE PL/SQL AND EXECUTE IT
L_CUR
:=
DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE (L_CUR,
L_SQL_TABLE,
L_SQL_TABLE.FIRST,
L_SQL_TABLE.LAST,
FALSE,
DBMS_SQL.NATIVE
);
L_ROWS_PROCESSED
:=
DBMS_SQL.EXECUTE (L_CUR);
DBMS_SQL.CLOSE_CURSOR (L_CUR);
L_SQL_TABLE.DELETE
(0,
L_CURRENT_ROW);
--
CLEAR THE COLLECTION OF QUERY LINES
DBMS_OUTPUT.PUT_LINE (
IN_OBJECT_TYPE
|| '
'
|| IN_OBJECT_NAME
|| '
successfully created.'
);
EXCEPTION
--
EXCEPTION HANDLERS BEGIN
WHEN
NO_DATA_FOUND
THEN
DBMS_OUTPUT.PUT_LINE ( 'There
is no '
|| IN_OBJECT_TYPE
|| '
'
|| IN_OBJECT_NAME
|| '.'
);
WHEN
OTHERS
THEN
--
HANDLES ALL OTHER ERRORS
DBMS_OUTPUT.PUT_LINE (DBMS_UTILITY.FORMAT_ERROR_STACK);
ROLLBACK;
END
PRC_CREATE_OBJECT;
BEGIN
DBMS_OUTPUT.ENABLE
(1000000);
IF
IN_OBJECT_TYPE =
'PACKAGE'
THEN
--
PACKAGE NEEDS PACKAGE AND PACKAGE BODY DECLARATIONS
PRC_CREATE_OBJECT (IN_SCHEMA_TO,
IN_OBJECT_NAME,
'PACKAGE');
PRC_CREATE_OBJECT (IN_SCHEMA_TO,
IN_OBJECT_NAME,
'PACKAGE
BODY');
ELSE
--
FOR ALL OTHER OBJECTS
PRC_CREATE_OBJECT (IN_SCHEMA_TO,
IN_OBJECT_NAME,
IN_OBJECT_TYPE);
END
IF;
COMMIT;
END
MIGRATE_OBJECT_TO_PRODUCTION;
|
To copy the source code, click inside the textbox => Ctrl-A => Ctrl-C
|