Я пытаюсь создать список МН зависимостей от пакета / зависимостей от пакета SQL так, чтобы я мог помочь настроить автоматизированный сценарий сборки для своих пакетов для работы тестового сервера. Существует ли способ запуститься с единственного пакета ("корневой" пакет, определенный по имени, идеально) и затем найти все зависимости и порядок, в котором они должны быть скомпилированы? Зависимости уже полностью разрешены в моей персональной схеме (так, по крайней мере, я должен где-нибудь запустить - но куда я иду затем?).
(Oracle 10.2)
Править:
Инструмент сборки, который используется, будет использовать порядок сборки и получит те файлы в порядке от управления исходным кодом и затем передаст их Oracle для компиляции (сам фактический инструмент сборки записан в Python или Java или обоих - у меня нет доступа к источнику). В основном инструменту сборки нужен, как введено список файлов для компиляции в порядке, они должны быть скомпилированы в, и доступ к тем файлам в управлении исходным кодом. Если это будет иметь это, то все будет работать вполне приятно.
Править:
Спасибо за аккуратные сценарии. К сожалению, процесс сборки главным образом вне моих рук. Процесс базируется вокруг инструмента сборки, который был создан поставщиком продукта, с которым мы интегрируемся, который является, почему единственные исходные данные, которые я могу дать процессу сборки, являются списком файлов в порядке, они должны быть встроены. Если существует ошибка компилятора, сбои инструмента сборки, мы должны вручную отправить запрос для новой сборки. Таким образом, список файлов в порядке, они должны быть скомпилированы, важен.
Править:
Найденный этим: http://www.oracle.com/technology/oramag/code/tips2004/091304.html Дает мне зависимости любого объекта. Теперь я просто должен разобраться в упорядочивании... Если я получу что-то работа, то я отправлю ее здесь.
Править: (с кодом!)
Я знаю, что в целом, этот вид вещи не необходим для Oracle, но ни для кого, кто все еще заинтересовал...
Я починил немного сценария, который, кажется, может добраться, сборка заказывают таким образом, что все пакеты будут созданы в правильном порядке без связанных с зависимостью ошибок (относительно pacakges) в первый раз вокруг:
declare
type t_dep_list is table of varchar2(40) index by binary_integer;
dep_list t_dep_list;
i number := 1;
cursor c_getObjDepsByNameAndType is
--based on a query found here: http://www.oracle.com/technology/oramag/code/tips2004/091304.html
select lvl, u.object_id, u.object_type, LPAD(' ', lvl) || object_name obj
FROM (SELECT level lvl, object_id
FROM SYS.public_dependency s
START WITH s.object_id = (select object_id
from user_objects
where object_name = UPPER(:OBJECT_NAME)
and object_type = UPPER(:OBJECT_TYPE))
CONNECT BY s.object_id = PRIOR referenced_object_id
GROUP BY level, object_id) tree, user_objects u
WHERE tree.object_id = u.object_id
and u.object_type like 'PACKAGE%' --only look at packages, not interested in other types of objects
ORDER BY lvl desc;
function fn_checkInList(in_name in varchar2) return boolean is
begin
for j in 1 .. dep_list.count loop
if dep_list(j) = in_name then
return true;
end if;
end loop;
return false;
end;
procedure sp_getDeps(in_objID in user_objects.object_id%type, in_name in varchar2) is
cursor c_getObjDepsByID(in_objID in user_objects.object_id%type) is
--based on a query found here: http://www.oracle.com/technology/oramag/code/tips2004/091304.html
select lvl, u.object_id, u.object_type, LPAD(' ', lvl) || object_name obj
FROM (SELECT level lvl, object_id
FROM SYS.public_dependency s
START WITH s.object_id = (select uo.object_id
from user_objects uo
where uo.object_name =
(select object_name from user_objects uo where uo.object_id = in_objID)
and uo.object_type = 'PACKAGE BODY')
CONNECT BY s.object_id = PRIOR referenced_object_id
GROUP BY level, object_id) tree, user_objects u
WHERE tree.object_id = u.object_id
and u.object_id <> in_objID --exclude self (requested Object ID) from list.
ORDER BY lvl desc;
begin
--loop through the dependencies
for r in c_getObjDepsByID(in_objID) loop
if fn_checkInList(trim(r.obj)) = false and (r.object_type = 'PACKAGE' or r.object_type = 'PACKAGE BODY') and
trim(r.obj) <> trim(in_name) then
dbms_output.put_line('checking deps of: ' || r.obj || ' ' || r.object_id || ' level: ' || r.lvl);
--now for each dependency, check the sub-dependency
sp_getDeps(r.object_id, trim(r.obj));
--add the object to the dependency list.
dep_list(i) := trim(r.obj);
i := i + 1;
end if;
end loop;
exception
when NO_DATA_FOUND then
dbms_output.put_line('no more data for: ' || in_objID);
end;
begin
for r in c_getObjDepsByNameAndType loop
dbms_output.put_line('top-level checking deps of: ' || r.obj || ' ' || r.object_id || ' level: ' || r.lvl);
sp_getDeps(r.object_id, trim(r.obj));
end loop;
dbms_output.put_line('dep count: ' || dep_list.count);
for j in 1 .. dep_list.count loop
dbms_output.put_line('obj: ' || j || ' ' || dep_list(j));
end loop;
end;
Я знаю, что это не самый симпатичный код (globals повсеместно, и т.д.... тьфу), и я, вероятно, повторно отправлю его, если я могу заставить шанс этим днем очищать его, но прямо сейчас, это производит порядок сборки, который, кажется, работает в первый раз без проблем.
:OBJECT_NAME
должен быть корневой объект, из которого Вы хотите проследить все зависимости и порядок сборки. Для меня это - основной пакет с отдельным методом, который является точкой входа к остальной части системы.
:OBJECT_TYPE
Я главным образом ограничил PACKAGE BODY
, но это не должно быть слишком много работы для включения других типов, таких как триггеры.
Одна последняя вещь, объект, указанный :OBJECT_NAME
не появится в выводе, но это должен быть последний объект, таким образом, необходимо будет добавить, что к сборке перечисляют вручную.
ОБНОВЛЕНИЕ: Я просто обнаружил user_dependencies
и all_dependencies
, этот код мог, вероятно, быть сделан намного более простым теперь.
реальное решение: Похоже, скрипт, приведённый выше, даёт правильный порядок сборки. Возможно, его можно переписать "лучше", но я оставлю это как упражнение для читателя. ;)
После некоторого обсуждения инструмент сборки выполнит n (4, на самом деле) сборки подряд перед тем, как сообщить об ошибках. Это также поможет разрешить ошибки компиляции зависимостей, если порядок сборки неправильный, но я бы предпочел, чтобы порядок сборки был правильным с первого раза.
Посмотрите на следующий скрипт из http://www.orcle-base.com/articles/misc/recompilinginvalidschemabjects.php
SET SERVEROUTPUT ON SIZE 1000000
BEGIN
FOR cur_rec IN (SELECT owner,
object_name,
object_type,
DECODE(object_type, 'PACKAGE', 1,
'PACKAGE BODY', 2, 2) AS recompile_order
FROM dba_objects
WHERE object_type IN ('PACKAGE', 'PACKAGE BODY')
AND status != 'VALID'
ORDER BY 4)
LOOP
BEGIN
IF cur_rec.object_type = 'PACKAGE' THEN
EXECUTE IMMEDIATE 'ALTER ' || cur_rec.object_type ||
' "' || cur_rec.owner || '"."' || cur_rec.object_name || '" COMPILE';
ElSE
EXECUTE IMMEDIATE 'ALTER PACKAGE "' || cur_rec.owner ||
'"."' || cur_rec.object_name || '" COMPILE BODY';
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(cur_rec.object_type || ' : ' || cur_rec.owner ||
' : ' || cur_rec.object_name);
END;
END LOOP;
END;
/
Вам не нужен порядок сборки - просто постройте пакеты с помощью «Создать или заменить ...» на файловой основе, а затем составьте их в двухуровневом вложенном цикле - каждый проход во внутреннем Цикл компилирует все, что все еще неверно, и внешний цикл используется для проверки количества оставшихся неверных объектов и установить какой-то порог для максимальных исполнений внутреннего цикла. На практике я никогда не видел, что количество проходов необходимо превышать трех.
Если у вас есть несколько схем, участвующих в зависимостях, посмотрите на скрипт Oracles utlrp.sql, который работает через схемы и устанавливает некоторую инфраструктуру для управления процессом - однако требуется привилегированная учетная запись.
Кроме того, если вы продлите свой исходный элемент управления, чтобы включить представления, убедитесь, что сценарии используют «Создать или заменить принудительный вид ...» для создания представлений, которые имеют неудовлетворенные зависимости во время их создания.
Пример скрипта, который я использую:
set serveroutput on
declare
cursor invalidObjCur is
select object_name, object_type
from user_objects
where status <> 'VALID'
;
compileStmt varchar2(4000);
passCount pls_integer := 0;
maxPasses pls_integer := 5;
lastInvalidCount pls_integer := 32000;
objectCount pls_integer;
continue boolean := TRUE;
begin
dbms_output.enable(1000000);
while (continue) loop
passCount := passCount + 1;
dbms_output.put_line('Pass '||passCount);
objectCount := 0;
for curRow in InvalidObjCur loop
if curRow.object_type = 'PACKAGE BODY' then
compileStmt := 'alter PACKAGE '||curRow.object_name||' compile body';
else
compileStmt := 'alter '||curRow.object_type||' '||
chr(34)||curRow.object_name||chr(34)||' compile';
end if;
begin
execute immediate compileStmt;
exception when others then
null;
end;
objectCount := objectCount + 1;
end loop;
dbms_output.put_line('Recompilations attempted: '||objectCount);
continue := (passCount < maxPasses) and (objectCount < lastInvalidCount);
lastInvalidCount := objectCount;
end loop;
dbms_output.put_line('***** Remaining Invalid ********');
for curRow in InvalidObjCur loop
dbms_output.put_line(curRow.object_type||' '||curRow.object_name);
end loop;
dbms_output.put_line('********************************');
end;
/
Добавьте следующую команду в начало вашего скрипта:
SET VERIFY OFF
это позволит вашим скриптам запускаться без проверки и, следовательно, может быть запущен в любом заказывать.
Вы можете позже запросить DBA_ERRORS, чтобы получить все ошибки и предупреждения в ваших пакетах, представлениях и типах.
Если вы действительно имеете дело только с пакетами PL / SQL, вам не нужно попотеть над порядком сборки. Просто сначала соберите все спецификации пакета. Затем вы можете развернуть все тела пакета, и они будут скомпилированы, потому что их зависимости являются спецификациями пакета.
Если у вас есть спецификации пакета, которые зависят от других спецификаций - если у вас есть пакеты, которые объявляют, скажем, константы, подтипы или ссылочные курсоры, которые используются в сигнатурах упакованных процедур - тогда вам необходимо собрать этот пакет. спецификации в первую очередь. Но их должно быть достаточно, чтобы вы могли вручную расположить их в скрипте сборки.
править
Похоже, они будут делать инкрементные и "чистые" сборки, поэтому порядок сборки будет иметь наибольшее значение , когда они будут очищать среду и перестройте ее.
Это ничего не меняет.
Вот расширенный пример. У меня есть схема с тремя пакетами ....
SQL> select object_name, object_type, status
2 from user_objects
3 order by 1, 2
4 /
OBJECT_NAME OBJECT_TYPE STATUS
--------------- --------------- -------
PKG1 PACKAGE VALID
PKG1 PACKAGE BODY VALID
PKG2 PACKAGE VALID
PKG2 PACKAGE BODY VALID
PKG3 PACKAGE VALID
PKG3 PACKAGE BODY VALID
6 rows selected.
SQL>
Интересно то, что процедура в PKG1 вызывает процедуру из PKG2, процедура в PKG2 вызывает процедуру из PKG3, а процедура в PKG3 вызывает процедуру из PKG1.
В. Как работает эта циклическая зависимость?
A. Это не циклическая зависимость ....
SQL> select name, type, referenced_name, referenced_type
2 from user_dependencies
3 where referenced_owner = user
4 /
NAME TYPE REFERENCED_NAME REFERENCED_TYPE
--------------- --------------- --------------- ---------------
PKG1 PACKAGE BODY PKG1 PACKAGE
PKG1 PACKAGE BODY PKG2 PACKAGE
PKG2 PACKAGE BODY PKG2 PACKAGE
PKG2 PACKAGE BODY PKG3 PACKAGE
PKG3 PACKAGE BODY PKG3 PACKAGE
PKG3 PACKAGE BODY PKG1 PACKAGE
6 rows selected.
SQL>
Все зависимые объекты являются телами пакетов, все объекты, на которые есть ссылки, являются упакованными спецификациями. Следовательно, если я перестраиваю схему, не имеет значения, какой порядок я использую. Сначала мы мусор ...
SQL> drop package pkg1
2 /
Package dropped.
SQL> drop package pkg2
2 /
Package dropped.
SQL> drop package pkg3
2 /
Package dropped.
SQL>
Затем мы перестраиваем ...
SQL> create or replace package pkg3 is
2 procedure p5;
3 procedure p6;
4 end pkg3;
5 /
Package created.
SQL> create or replace package pkg2 is
2 procedure p3;
3 procedure p4;
4 end pkg2;
5 /
Package created.
SQL> create or replace package pkg1 is
2 procedure p1;
3 procedure p2;
4 end pkg1;
5 /
Package created.
SQL> create or replace package body pkg2 is
2 procedure p3 is
3 begin
4 pkg3.p5;
5 end p3;
6 procedure p4 is
7 begin
8 dbms_output.put_line('PKG2.P4');
9 end p4;
10 end pkg2;
11 /
Package body created.
SQL> create or replace package body pkg3 is
2 procedure p5 is
3 begin
4 dbms_output.put_line('PKG3.P5');
5 end p5;
6 procedure p6 is
7 begin
8 pkg1.p1;
9 end p6;
10 end pkg3;
11 /
Package body created.
SQL> create or replace package body pkg1 is
2 procedure p1 is
3 begin
4 dbms_output.put_line('PKG1.P1');
5 end p1;
6 procedure p2 is
7 begin
8 pkg2.p4;
9 end p2;
10 end pkg1;
11 /
Package body created.
SQL>
Порядок отдельных объектов не имеет значения. Просто создайте спецификации пакета перед телами пакетов. Хотя даже это на самом деле не имеет значения ...
SQL> create or replace package pkg4 is
2 procedure p7;
3 end pkg4;
4 /
Package created.
SQL> create or replace package body pkg4 is
2 procedure p7 is
3 begin
4 dbms_output.put_line('PKG4.P7::'||constants_pkg.whatever);
5 end p7;
6 end pkg4;
7 /
Warning: Package Body created with compilation errors.
SQL> show errors
Errors for PACKAGE BODY PKG4:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/9 PL/SQL: Statement ignored
4/43 PLS-00201: identifier 'CONSTANTS_PKG.WHATEVER' must be declared
SQL>
PKG4
НЕВЕРНО, потому что мы еще не построили CONSTANTS_PKG
.
SQL> create or replace package constants_pkg is
2 whatever constant varchar2(20) := 'WHATEVER';
3 end constants_pkg;
4 /
Package created.
SQL> select object_name, object_type, status
2 from user_objects
3 where status != 'VALID'
4 order by 1, 2
5 /
OBJECT_NAME OBJECT_TYPE STATUS
--------------- --------------- -------
PKG4 PACKAGE BODY INVALID
SQL>
SQL> set serveroutput on size unlimited
SQL> exec pkg4.p7
PKG4.P7::WHATEVER
PL/SQL procedure successfully completed.
SQL> select object_name, object_type, status
2 from user_objects
3 where status != 'VALID'
4 order by 1, 2
5 /
no rows selected
SQL>
Все, что создано с использованием CREATE OR REPLACE
, создается всегда, оно просто помечается как INVALID, если есть ошибки. Как только мы его выполняем, прямо или косвенно, база данных компилирует его для нас. Итак, порядок не имеет значения. На самом деле это не так.
Если вас беспокоит идея завершить сборку с недействительными объектами - и я немного симпатизирую этому, нам говорят не жить с разбитыми окнами - вы можете использовать скрипт utlrp
или в 11g пакет UTL_RECOMP ; для любого подхода требуется учетная запись SYSDBA.
править 2
Процесс основан на инструменте сборки , который был построен поставщиком продукта, с которым мы интегрируемся, поэтому единственный входные данные, которые я могу передать процессу сборки, представляют собой список файлов в том порядке, в котором они должны быть встроены. Если есть ошибка компилятора , инструмент сборки не работает, нам нужно вручную отправить запрос на новую сборку .
Это политическая проблема, а не техническая. Это не означает, что политические проблемы не могут быть решены с помощью технического исправления, просто техническое исправление - не лучший инструмент для работы. Удачи.
Одна мелочь, на которую нужно обратить внимание, когда ходишь по дереву иждивенцев. Зависимости для некомпилированных программ не показывают...
SQL> drop package constants_pkg
2 /
Package dropped.
SQL> create or replace package body pkg4 is
2 procedure p7 is
3 begin
4 dbms_output.put_line('PKG4.P7::'||zzz_constants_pkg.whatever);
5 end p7;
6 end pkg4;
7 /
Warning: Package Body created with compilation errors.
SQL> show errors
Errors for PACKAGE BODY PKG4:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/9 PL/SQL: Statement ignored
4/43 PLS-00201: identifier 'ZZZ_CONSTANTS_PKG.WHATEVER' must be
declared
SQL>
Итак, тело для PKG4
является ИНВАЛИДНЫМ, потому что ZZZ_CONSTANTS_PKG
не существует.
SQL> create or replace package zzz_constants_pkg is
2 whatever constant varchar2(20) := 'WHATEVER';
3 end zzz_constants_pkg;
4 /
Package created.
SQL>
Но тело для PKG4
все еще INVALID, поэтому следующий запрос не возвращает его зависимость от ZZZ_CONSTANTS_PKG
.....
SQL> select name, type, referenced_name, referenced_type
2 from user_dependencies
3 where referenced_owner = user
4 /
NAME TYPE REFERENCED_NAME REFERENCED_TYPE
--------------- --------------- ----------------- ---------------
PKG1 PACKAGE BODY PKG1 PACKAGE
PKG1 PACKAGE BODY PKG2 PACKAGE
PKG2 PACKAGE BODY PKG2 PACKAGE
PKG2 PACKAGE BODY PKG3 PACKAGE
PKG3 PACKAGE BODY PKG3 PACKAGE
PKG3 PACKAGE BODY PKG1 PACKAGE
PKG4 PACKAGE BODY PKG4 PACKAGE
7 rows selected.
SQL>
Теперь скомпилируем PKG4
и повторно запросим зависимости .....
SQL> alter package pkg4 compile body;
Package body altered.
SQL> select name, type, referenced_name, referenced_type
2 from user_dependencies
3 where referenced_owner = user
4 /
NAME TYPE REFERENCED_NAME REFERENCED_TYPE
--------------- --------------- ----------------- ---------------
PKG1 PACKAGE BODY PKG1 PACKAGE
PKG1 PACKAGE BODY PKG2 PACKAGE
PKG2 PACKAGE BODY PKG2 PACKAGE
PKG2 PACKAGE BODY PKG3 PACKAGE
PKG3 PACKAGE BODY PKG3 PACKAGE
PKG3 PACKAGE BODY PKG1 PACKAGE
PKG4 PACKAGE BODY PKG4 PACKAGE
PKG4 PACKAGE BODY ZZZ_CONSTANTS_PKG PACKAGE
8 rows selected.
SQL>