| Oracle FAQ | Your Portal to the Oracle Knowledge Grid | |
Home -> Community -> Mailing Lists -> Oracle-L -> Reverse engineering environments from one schema to another
The following scripts can be used to copy a complete environment from
one schema to another. To commence the run see instructions in attached
script DB_RE.SQL. I have attached a sample environment file at the end
(OWNERS.ENV).
Note that view 'ALL_SORCE' and 'CONSTRAINT_DEFS' (also
included) need to be compiled with public synonyms in the SYS schema
first.
Permission has been obtained from the author (owent_at_vodacom.co.za) to distribute these utilities. If you have any problems using the utilities please mail me (agie_at_ctcc.gov.za) direct.
---*********************************************************************
---*********************************************************************
SET ECHO OFF
SET HEADING OFF
SET PAGESIZE 0
SET FEEDBACK OFF
SET VERIFY OFF
SET LINESIZE 110
-- Needed for LONG of trigger/view
SET LONG 10000
-- Needed for LONG of trigger/view
SET LONGC 5000
-- Needed for LONG of trigger/view
SET ARRAYSIZE 3
DEFINE spoolfile = '&1'
-- The name of the spool file which will contain the generated DDL */
DEFINE exec_path = '&2'
-- The path for scripts called by this script
DEFINE copy_schema = '&3'
-- The name of the schema being copied
DEFINE copy_objects = '&4'
--SET TERMOUT OFF
IS
l_exclude_option VARCHAR2(10);
BEGIN
l_exclude_option := p_exclude_option;
INSERT INTO temp_copy_objects
(object_name ,
copy_ch ,
copy_fk ,
copy_uk ,
copy_pk ,
copy_tr ,
copy_nn )
VALUES (UPPER(p_object_name),
decode(instr(l_exclude_option, 'C'), 0, 'C', NULL),
decode(instr(l_exclude_option, 'F'), 0, 'F', NULL),
decode(instr(l_exclude_option, 'U'), 0, 'U', NULL),
'P' ,
decode(instr(l_exclude_option, 'T'), 0, 'T', NULL),
decode(instr(l_exclude_option, 'N'), 0, 'N', NULL));
END;
SET TERMOUT ON
CREATE TABLE temp_dependencies
(name VARCHAR2(30),
referenced_name VARCHAR2(30));
INSERT INTO temp_dependencies
SELECT name, referenced_name
FROM all_dependencies
WHERE referenced_name NOT IN ('STANDARD', 'DBMS_STANDARD')
AND name NOT IN ('STANDARD', 'DBMS_STANDARD')
AND referenced_name <> name
AND type IN
('PROCEDURE', 'FUNCTION', 'PACKAGE','PACKAGE BODY')
AND referenced_type IN
('PROCEDURE','FUNCTION', 'PACKAGE','PACKAGE BODY')
AND owner = upper('©_schema')
AND referenced_owner = upper('©_schema');
INSERT INTO temp_dependencies
SELECT name, referenced_name
FROM all_dependencies
WHERE type = 'VIEW'
AND referenced_type IN ('VIEW','TABLE')
AND owner = upper('©_schema')
AND referenced_owner = upper('©_schema');
INSERT INTO temp_copy_objects
(object_name,
copy_ch,
copy_fk,
copy_uk,
copy_pk,
copy_tr,
copy_nn)
SELECT DISTINCT
referenced_name,
rec.copy_ch,
rec.copy_fk,
rec.copy_uk,
rec.copy_pk,
rec.copy_tr,
rec.copy_nn
FROM temp_dependencies
WHERE referenced_name NOT IN
(select object_name from temp_copy_objects)
START WITH name = rec.object_name
CONNECT BY PRIOR referenced_name = name;
COMMIT;
SET TERMOUT OFF
SPOOL &spoolfile
SELECT 'ALTER TABLE ' || ri.table_name || ' DROP CONSTRAINT ' ||
ri.constraint_name || ';'
FROM constraint_defs ri,
user_constraints ref,
temp_copy_objects copy
WHERE ri.r_constraint_name = ref.constraint_name AND
ref.table_name = copy.object_name AND
ri.owner = user AND
ri.r_owner = user AND
copy.object_type = 'TABLE' AND
ri.constraint_type = 'R';
SELECT 'DROP TABLE ' || user_tables.table_name || ';'
FROM user_tables, temp_copy_objects
WHERE user_tables.table_name = temp_copy_objects.object_name AND
temp_copy_objects.object_type = 'TABLE';
SELECT 'PROMPT Creating selected tables from ©_schema...' FROM DUAL;
SELECT text FROM temp_text
WHERE object_type = 'B'
ORDER BY seq_no;
SELECT 'PROMPT Creating selected views from ©_schema...' FROM DUAL;
SELECT text FROM temp_text
WHERE object_type = 'V'
ORDER BY seq_no;
SELECT 'PROMPT Creating primary key constraints...' FROM DUAL;
SELECT text FROM temp_text
WHERE object_type = 'P'
ORDER BY seq_no;
SELECT 'PROMPT Creating uniqueness constraints...' FROM DUAL;
SELECT text FROM temp_text
WHERE object_type = 'U'
ORDER BY seq_no;
SELECT 'PROMPT Creating foreign key constraints...' FROM DUAL;
SELECT text FROM temp_text
WHERE object_type = 'R'
ORDER BY seq_no;
SELECT text FROM temp_text
WHERE object_type = 'C'
ORDER BY seq_no;
SELECT 'PROMPT Creating database triggers on selected tables...' FROM DUAL;
SELECT text FROM temp_text
WHERE object_type = 'S'
ORDER BY seq_no;
SPOOL OFF --Now drop temporary tables/procedures - no longer needed
DROP TABLE temp_text; DROP TABLE temp_copy_objects; DROP TABLE temp_dependencies;
DECLARE
l_last_table_name CHAR(30) := '@';
l_seq_no NUMBER(3):= 0; -- Sequences output
l_first_table_name BOOLEAN := TRUE; -- Is this first table?
BEGIN FOR rec IN (
SELECT col.table_name,
col.column_name,
col.data_type,
col.data_length len,
col.data_precision prec,
col.data_scale scale,
col.nullable,
copy.copy_nn
FROM all_tab_columns col,
temp_copy_objects copy
WHERE col.table_name = copy.object_name
AND copy.object_type = 'TABLE'
AND col.owner = upper('&1')
ORDER BY col.table_name, col.column_id)
LOOP
IF RTRIM(rec.table_name) <> RTRIM(l_last_table_name) THEN
-- This is a new table */
l_last_table_name := rec.table_name;
IF l_first_table_name THEN
l_first_table_name := FALSE; -- From here on, not first table
ELSE
-- If not very first table, then output the close bracket for
-- the last table
INSERT INTO temp_text VALUES ('B', l_seq_no, ');');
l_seq_no := l_seq_no + 1;
END IF;
-- Create the table header for this row */
INSERT INTO temp_text VALUES ('B', l_seq_no,
'CREATE TABLE ' || rec.table_name || ' (');
l_seq_no := l_seq_no + 1;
-- Create the first column definition.
INSERT INTO temp_text VALUES ('B', l_seq_no,
rec.column_name || ' ' || rec.data_type ||
decode(rec.data_type, 'CHAR', '(' || to_char(rec.len) || ')',
'RAW', '(' || to_char(rec.len) || ')',
'VARCHAR2', '(' || to_char(rec.len) || ')',
'VARCHAR', '(' || to_char(rec.len) || ')',
'NUMBER', '(' || to_char(rec.prec) || ',' ||
to_char(rec.scale) || ')',
'') ||
decode(rec.copy_nn || rec.nullable, 'NN', ' NOT NULL', '') );
l_seq_no := l_seq_no + 1;
ELSE
-- We are still processing previous table - output this column as
-- part of table */
-- Create the first column definition.
INSERT INTO temp_text VALUES ('B', l_seq_no,
',' || rec.column_name || ' ' || rec.data_type ||
decode(rec.data_type, 'CHAR', '(' || to_char(rec.len) || ')',
'RAW', '(' || to_char(rec.len) || ')',
'VARCHAR2', '(' || to_char(rec.len) || ')',
'VARCHAR', '(' || to_char(rec.len) || ')',
'NUMBER', '(' || to_char(rec.prec) || ',' ||
to_char(rec.scale) || ')',
'') ||
decode(rec.copy_nn || rec.nullable, 'NN', ' NOT NULL', '') );
l_seq_no := l_seq_no + 1;
END IF;
END LOOP;
DECLARE
l_last_view_name CHAR(30) := '@';
l_seq_no NUMBER(5); -- Sequences output no
l_base_count NUMBER(5):= 0;
BEGIN FOR rec IN (
SELECT vw.view_name,
col.column_name,
vw.text
FROM all_tab_columns col,
temp_copy_objects copy,
all_views vw
WHERE col.table_name = copy.object_name
AND vw.view_name = copy.object_name
AND copy.object_type = 'VIEW'
AND col.owner = upper('&1')
AND vw.owner = upper('&1')
ORDER BY col.table_name, col.column_id)
LOOP
IF RTRIM(rec.view_name) <> RTRIM(l_last_view_name) THEN
-- This is a new view */
l_last_view_name := rec.view_name;
l_seq_no := 1; -- Start sequence again for this base number.
-- Create the view header for this row */
INSERT INTO temp_text VALUES ('V', l_base_count + l_seq_no,
'CREATE OR REPLACE VIEW ' || rec.view_name );
l_seq_no := l_seq_no + 1;
-- Create the first column definition.
INSERT INTO temp_text VALUES ('V', l_base_count + l_seq_no,
'(' || rec.column_name);
l_seq_no := l_seq_no + 1;
-- Output the view text for the view, at the end of this base count
INSERT INTO temp_text VALUES ('V', l_base_count + 97, ') AS');
INSERT INTO temp_text VALUES ('V', l_base_count + 98, rec.text);
INSERT INTO temp_text VALUES ('V', l_base_count + 99, '/');
l_base_count := l_base_count + 100;
ELSE
-- We are still processing previous view - output this column as
-- part of previous view
INSERT INTO temp_text VALUES ('V', l_base_count + l_seq_no - 100,
',' || rec.column_name);
l_seq_no := l_seq_no + 1;
END IF;
END LOOP;
COMMIT;
END;
/
DECLARE
l_last_cons CHAR(30) := '@';
l_seq_no NUMBER(3):= 0; -- Sequences output
l_first_cons BOOLEAN := TRUE; -- Is this first constraint?
l_constraint_type CHAR(11);
BEGIN
IF '&1' = 'P' THEN
l_constraint_type := 'PRIMARY KEY';
ELSE
IF ('&1' = 'U') THEN
l_constraint_type := 'UNIQUE';
ELSE
raise_application_error(-20000, 'Parameter must be U or P');
END IF;
SELECT ac.constraint_name cons,
ac.table_name tab,
acc.column_name col
FROM all_constraints ac,
all_cons_columns acc,
temp_copy_objects copy
WHERE ac.constraint_name = acc.constraint_name AND
copy.object_name = ac.table_name AND
copy.object_type = 'TABLE' AND
instr( copy_uk || copy_pk, '&1') > 0 AND
ac.constraint_type = '&1' AND
ac.owner = upper('&2') AND
acc.owner = upper('&2')
ORDER BY ac.constraint_name, acc.position)
LOOP
IF RTRIM(rec.cons) <> RTRIM(l_last_cons) THEN
-- This is a new constraint */
l_last_cons := rec.cons;
IF l_first_cons THEN
l_first_cons := FALSE; -- From here on, not first constraint
ELSE
-- If not very first constraint, then output the close bracket for
-- the last constraint
INSERT INTO temp_text VALUES ('&1', l_seq_no, ');');
l_seq_no := l_seq_no + 1;
END IF;
-- Create the constraint header for this column */
INSERT INTO temp_text VALUES ('&1', l_seq_no,
'ALTER TABLE ' || rec.tab || ' ADD CONSTRAINT ');
l_seq_no := l_seq_no + 1;
INSERT INTO temp_text VALUES ('&1', l_seq_no,
rec.cons || ' ' || l_constraint_type || ' (' || rec.col);
ELSE
-- We are still processing previous constraint - output this column as
-- part of constraint */
INSERT INTO temp_text VALUES ('&1', l_seq_no, ',' || rec.col);
END IF;
l_seq_no := l_seq_no + 1;
DECLARE l_last_cons CHAR(30) := '@';
l_seq_no NUMBER(3):= 0; -- Sequences output
l_first_cons BOOLEAN := TRUE; -- Is this first constraint?
l_prev_ref_tab CHAR(30); -- Stores table name
l_prev_ref_col1 CHAR(30); -- previous 1st referenced col
l_prev_cons_complex BOOLEAN; -- More than one column?
l_prev_ref_cons CHAR(30); -- Previous referenced constraint
l_local_tab NUMBER(3);
BEGIN
FOR rec IN (
SELECT
cd.table_name ri_tab,
cd.constraint_name cons ,
ri_col.column_name ri_col,
ref_cons.table_name ref_tab,
ref_col.column_name ref_col1,
ref_cons.constraint_name ref_cons
FROM constraint_defs cd,
all_cons_columns ri_col,
all_constraints ref_cons,
all_tables ref_tab,
all_cons_columns ref_col,
temp_copy_objects copy
WHERE cd.constraint_name = ri_col.constraint_name AND
copy.object_name = cd.table_name AND
copy.copy_fk IS NOT NULL AND
cd.r_constraint_name = ref_cons.constraint_name AND
ref_cons.constraint_name = ref_col.constraint_name AND
ref_col.position = 1 AND
ref_tab.table_name = ref_cons.table_name AND
cd.constraint_type = 'R' AND
copy.object_type = 'TABLE' AND
cd.owner = upper('&1') AND
cd.r_owner = upper('&1') AND
ri_col.owner = upper('&1') AND
ref_cons.owner = upper('&1') AND
ref_tab.owner = upper('&1') AND
ref_col.owner = upper('&1')
ORDER BY ri_col.constraint_name, ri_col.position)
LOOP
IF RTRIM(rec.cons) <> RTRIM(l_last_cons) THEN
-- This is a new constraint */
l_last_cons := rec.cons;
IF l_first_cons THEN
l_first_cons := FALSE; -- From here on, not first constraint
ELSE
-- If not very first constraint, then output 'references' section
-- of the previous constraint.
-- Note - can't implement as stored procedures, because role does
-- not permit stored procedure to access db views.
-- Determine if referencing table is local or remote.
-- First - determine if a selected table
SELECT count(temp_copy_objects.object_name)
INTO l_local_tab
FROM temp_copy_objects
WHERE RTRIM(temp_copy_objects.object_name) = RTRIM(l_prev_ref_tab);
-- Second - if not a selected table, determine if already local
IF l_local_tab = 0 THEN
SELECT count(user_tables.table_name)
INTO l_local_tab
FROM user_tables
WHERE RTRIM(user_tables.table_name) = RTRIM(l_prev_ref_tab);
END IF;
IF l_local_tab = 0 THEN -- ie, not a local referencing table
INSERT INTO temp_text VALUES ('R', l_seq_no,
') REFERENCES &1..' || l_prev_ref_tab);
ELSE -- is a local referencing table
INSERT INTO temp_text VALUES ('R', l_seq_no,
') REFERENCES ' || l_prev_ref_tab);
END IF;
l_seq_no := l_seq_no + 1;
INSERT INTO temp_text VALUES ('R', l_seq_no,
' (' || l_prev_ref_col1);
l_seq_no := l_seq_no + 1;
-- Now we should output referenced columns..., if more than one
IF l_prev_cons_complex THEN
FOR rec1 IN (
SELECT all_cons_columns.column_name ref_col
FROM all_cons_columns
WHERE RTRIM(all_cons_columns.constraint_name)
= RTRIM(l_prev_ref_cons) AND
all_cons_columns.position > 1 AND
all_cons_columns.owner = upper('&1')
ORDER BY all_cons_columns.position)
LOOP
INSERT INTO temp_text VALUES ('R', l_seq_no, ',' || rec1.ref_col);
l_seq_no := l_seq_no + 1;
END LOOP;
END IF;
-- Output close bracket for the previous constraint
INSERT INTO temp_text VALUES ('R', l_seq_no, ');');
l_seq_no := l_seq_no + 1;
END IF;
-- Remember data for next loop iteration.
l_prev_ref_tab := rec.ref_tab; -- previous referenced table
l_prev_ref_col1 := rec.ref_col1; -- previous 1st referenced col
l_prev_cons_complex:= FALSE; -- Assume one column
l_prev_ref_cons := rec.ref_cons; -- Previous referenced constraint
-- Create the constraint header for this column */
INSERT INTO temp_text VALUES ('R', l_seq_no,
'ALTER TABLE ' || rec.ri_tab || ' ADD CONSTRAINT ');
l_seq_no := l_seq_no + 1;
INSERT INTO temp_text VALUES ('R', l_seq_no,
rec.cons || ' FOREIGN KEY (' || rec.ri_col);
l_seq_no := l_seq_no + 1;
ELSE
-- We are still processing previous constraint - output this column as
-- part of constraint */
l_prev_cons_complex:= TRUE; -- More than one column
INSERT INTO temp_text VALUES ('R', l_seq_no, ',' || rec.ri_col);
l_seq_no := l_seq_no + 1;
END IF;
END LOOP;
IF l_local_tab = 0 THEN -- ie, not a local referencing table
INSERT INTO temp_text VALUES ('R', l_seq_no,
') REFERENCES &1..' || l_prev_ref_tab);
ELSE -- is a local referencing table
INSERT INTO temp_text VALUES ('R', l_seq_no,
') REFERENCES ' || l_prev_ref_tab);
END IF;
l_seq_no := l_seq_no + 1;
INSERT INTO temp_text VALUES ('R', l_seq_no,
' (' || l_prev_ref_col1);
l_seq_no := l_seq_no + 1;
-- Now we should output referenced columns..., if more than one
IF l_prev_cons_complex THEN
FOR rec1 IN (
SELECT all_cons_columns.column_name ref_col
FROM all_cons_columns
WHERE RTRIM(all_cons_columns.constraint_name) =
RTRIM(l_prev_ref_cons) AND
all_cons_columns.position > 1 AND
all_cons_columns.owner = upper('&1')
ORDER BY all_cons_columns.position)
LOOP
INSERT INTO temp_text VALUES ('R', l_seq_no, ',' || rec1.ref_col);
l_seq_no := l_seq_no + 1;
END LOOP;
END IF;
-- Output close bracket for the previous constraint
INSERT INTO temp_text VALUES ('R', l_seq_no, ');');
l_seq_no := l_seq_no + 1;
DECLARE
l_last_cons CHAR(30) := '@';
l_seq_no NUMBER(3):= 0; -- Sequences output
l_first_cons BOOLEAN := TRUE; -- Is this first constraint?
BEGIN FOR rec IN (
SELECT oco_name cons,
td_table tab,
txt_text txt
FROM cdi_constraints,
cdi_text,
sdd_tab_defs,
temp_copy_objects copy
WHERE cdi_constraints.oco_ref = cdi_text.txt_ref AND
copy.object_name = sdd_tab_defs.td_table AND
copy.copy_ch IS NOT NULL AND
oco_constraint_type = 'CHECK' AND
copy.object_type = 'TABLE' AND
td_tid = oco_tab_ref AND
txt_type <> 'CDIDSC'
ORDER BY cdi_constraints.oco_name, cdi_text.txt_seq)
LOOP
IF RTRIM(rec.cons) <> RTRIM(l_last_cons) THEN
-- This is a new constraint */
l_last_cons := rec.cons;
IF l_first_cons THEN
l_first_cons := FALSE; -- From here on, not first constraint
ELSE
-- If not very first constraint, then output the close bracket for
-- the last constraint
INSERT INTO temp_text VALUES ('C', l_seq_no, ');');
l_seq_no := l_seq_no + 1;
END IF;
-- Create the constraint header for this column */
INSERT INTO temp_text VALUES ('C', l_seq_no,
'ALTER TABLE ' || rec.tab || ' ADD CONSTRAINT ');
l_seq_no := l_seq_no + 1;
INSERT INTO temp_text VALUES ('C', l_seq_no,
rec.cons || ' CHECK (');
l_seq_no := l_seq_no + 1;
-- first line of constraint text
INSERT INTO temp_text VALUES ('C', l_seq_no, RTRIM(rec.txt));
l_seq_no := l_seq_no + 1;
ELSE
-- We are still processing previous constraint - output this column as
-- part of constraint */
INSERT INTO temp_text VALUES ('C', l_seq_no, RTRIM(rec.txt));
l_seq_no := l_seq_no + 1;
END IF;
END LOOP;
DECLARE
l_seq_no NUMBER(5):= 0; -- Sequences output
l_first_proc BOOLEAN := TRUE; -- Is this first proc?
BEGIN FOR rec IN (
SELECT line, text
FROM all_sorce,
temp_copy_objects copy
WHERE copy.object_name = all_sorce.name AND
copy.object_type IN
('FUNCTION', 'PROCEDURE','PACKAGE','PACKAGE BODY') AND
all_sorce.owner = upper('&1')
ORDER BY type, name, line)
LOOP
IF rec.line = 1 THEN
-- This is a new procedure */
IF l_first_proc THEN
l_first_proc := FALSE; -- From here on, not first constraint
ELSE
-- If not very first routine, then output the 'compile' slash
-- for the previous stored routine
INSERT INTO temp_text VALUES ('S', l_seq_no, '/');
l_seq_no := l_seq_no + 1;
INSERT INTO temp_text VALUES ('S', l_seq_no, 'show errors');
l_seq_no := l_seq_no + 1;
END IF;
INSERT INTO temp_text VALUES ('S', l_seq_no,
'CREATE OR REPLACE ' || rec.text);
ELSE
INSERT INTO temp_text VALUES ('S', l_seq_no, rec.text);
END IF;
l_seq_no := l_seq_no + 1;
create or replace view ALL_SORCE
(OWNER, NAME, TYPE, LINE, TEXT)
as
select u.name, o.name,
decode(o.type, 7, 'PROCEDURE', 8, 'FUNCTION', 9, 'PACKAGE',
11, 'PACKAGE BODY', 'UNDEFINED'),
s.line, s.source
from sys.obj$ o, sys.source$ s, sys.user$ u
where o.obj# = s.obj# and o.owner# = u.user# and o.type in (7, 8, 9, 11)
o.obj# in (select obj# from sys.objauth$
where grantee# in (select kzsrorol from x$kzsro)
and privilege# = 12 /* EXECUTE */)
or
exists (select null from sys.sysauth$
where grantee# in (select kzsrorol from x$kzsro)
and privilege# = -144 /* EXECUTE ANY PROCEDURE */)
)
![]() |
![]() |