ソース(DDL)をその場で変更

ERPシステムをエスコートする場合、プロシージャ、関数、トリガー、またはパッケージのコードを大量に変更することが必要になる場合があります。 たとえば、あるプロシージャから別のプロシージャへの呼び出しを置き換える場合。

いくつかの手順を変更する必要がある場合は、手動で変更できますが、数百のオブジェクトを変更する必要がある場合は、プロセスの自動化を検討する必要があります。 この記事では、 ORACLE 11g DBMSの自動化の例を説明しています。



理論



すべてのオブジェクト(ORACLE)のDDLスクリプトは、 SYS.SOURCE $テーブルに格納されています。 それで十分です。

update source$ set source = replace(source,'old_name','new_name') where source like '%old_name%'
      
      





、実際にソースを変更するだけでは十分ではありません。 ソースをコンパイルする必要があります。

コンパイルはEXECUTE IMMEDIATEを使用して実行されます

バージョン11より前は、テキストをVARCHAR2 (32767)で書き込めないクエリの場合、 DBMS_SQLパッケージ機能を使用する必要がありました。

 -- To process a SQL statement, you must have an open cursor nCursorId := DBMS_SQL.OPEN_CURSOR ; -- Every SQL statement must be parsed DBMS_SQL.PARSE (nCursorId , SqlStatement_CLOB, DBMS_SQL.NATIVE); -- DDL statements are run on the parse, which performs the implied commit.
      
      





問題は、オブジェクトのソースを取得する方法です。

カーソルを使用して、 SYS.SOURCE $テーブルのエントリを検索できます 。「 || 」演算子と行末記号を使用して、各レコードのSOURCEフィールドを接着します 。 しかし、 GET_DDL関数を備えたDBMS_METADATAパッケージを使用した簡単な方法があります。

DBMS_METADATA.GET_DDL関数の便利さは、オブジェクトのソーステキスト全体を返すだけでなく、スキーマ名を置き換えて「 CREATE OR REPLACE 」を追加することです。

欠点は、数値がSYS.OBJ $テーブルに格納されている間、関数が文字列引数を受け入れることです。



プロシージャのソースコードを変更するためのアルゴリズム。



  1. DBMS_METADATA.GET_DDLを使用してソースを取得します。
  2. 必要に応じてテキストを変更します(最も単純な場合、REPLACEを使用)。
  3. EXECUTE IMMEDIATEを使用してプロシージャをコンパイルします。
  4. 使用して楽しんでください。




練習する



実際には、すべてがそれほど単純ではありません。

SYSユーザーとしてログインしたとき、テーブルにスキーマ名がなかったため、別のスキーム( PROD )のプロシージャをコンパイルできませんでした。

 SELECT * FROM TABLE_NAME
      
      



、何らかの理由で予想されるコンパイラ
 SELECT * FROM PROD.TABLE_NAME
      
      



DDLスクリプトの冒頭に書かれていますが
 CREATE OR REPLACE PROCEDURE PROD.PROCEDURE_NAME
      
      



また、「 PL / SQL Developer 」または「 TOAD 」で、ログインしたスキーマではなく別のスキーマのオブジェクトをコンパイルすると、すべてがエラーなしでコンパイルされます。

どうやら私にはわからないニュアンスがあるか、手がまっすぐではありません。

PRODユーザーでログインしたときに、 SYS.SOURCE $テーブルへのアクセスでエラーが発生しました。これは特権によって修復されました
 GRANT SELECT ANY DICTIONARY TO PROD;
      
      



デバッグには特権が必要です
 GRANT DEBUG ANY PROCEDURE TO PROD;
      
      







自動化、スクリプト、および手順





ソースデータ分析


私のタスクは、「 GET_ACTUAL_DATE 」関数の呼び出しを「 SYSDATE 」の呼び出しに置き換えることでした。 もちろん、関数コードGET_ACTUAL_DATEを「RETURN SYSDATE」に置き換えることもできますが、この記事では何も書くことはありませんので、始めましょう。

最初のステップは、サブストリング「GET_ACTUAL_DATE」が見つかった場所を確認することです。

  SELECT SC.SOURCE FROM SYS.USER$ UR JOIN SYS.OBJ$ OB ON UR.USER# = OB.OWNER# JOIN SYS.SOURCE$ SC ON SC.OBJ# = OB.OBJ# WHERE UR.USER# = 50 /* schema id from table USER$ for 'PROD'*/ AND UPPER(SC.SOURCE) LIKE '%' || 'GET_ACTUAL_DATE' || '%' ORDER BY SC.OBJ# , SC.LINE ;
      
      





590個のオブジェクトで1185行が判明しました。

私は選択を見て、変数名またはプロシージャの一部ではなく、関数呼び出しを置き換えるために、検索する必要があると結論付けました
 '(' || 'GET_ACTUAL_DATE'
      
      



、関数呼び出しの前にも他の文字がありました:



これに基づいて、検索パターンを生成するクエリを作成しました。

 WITH PATTERNS AS ( SELECT 'GET_ACTUAL_DATE' AS ERST /*   */ , '(' AS OPENING /*  */ , '' AS CLOSING /*  */ , 'SYSDATE' AS BECOME /*    */ FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ' ' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '=' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ',' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '''' , '' , 'SYSDATE' FROM DUAL ) SELECT PT.OPENING || PT.ERST || PT.CLOSING /*  */ , PT.OPENING || PT.BECOME || PT.CLOSING /*  */ FROM PATTERNS PT ;
      
      





これで、置換(REPLACE)を実行した場合に何が起こったかを確認できます。

リクエストを見る
 WITH PATTERNS AS ( SELECT 'GET_ACTUAL_DATE' AS ERST , '(' AS OPENING , '' AS CLOSING , 'SYSDATE' AS BECOME FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ' ' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '=' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ',' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '''' , '' , 'SYSDATE' FROM DUAL ) SELECT SC.OBJ# AS OBJ# , SC.LINE AS LINE , SC.SOURCE AS SOURCE , REPLACE ( UPPER(SC.SOURCE) , PT.OPENING || PT.ERST || PT.CLOSING , PT.OPENING || PT.BECOME || PT.CLOSING ) AS COMPLETE FROM SYS.USER$ UR JOIN SYS.OBJ$ OB ON UR.USER# = OB.OWNER# JOIN SYS.SOURCE$ SC ON SC.OBJ# = OB.OBJ# , PATTERNS PT WHERE UR.USER# = 50 /* USER PROD */ AND UPPER(SC.SOURCE) LIKE '%' || PT.ERST || '%' AND REPLACE ( UPPER(SC.SOURCE) , PT.OPENING || PT.ERST || PT.CLOSING , PT.OPENING || PT.BECOME || PT.CLOSING ) <> UPPER(SC.SOURCE) ORDER BY OBJ# , LINE ;
      
      







結果を見て、1行は関数「GET_ACTUAL_DATE」の宣言であり、「SYSDATE」の宣言に変換する必要はありませんでした。

他の2行はコメントであり、そのままにしておく必要がありました。 指定した行とオブジェクトを除外できるように、スクリプトを追加しました。

リクエストを見る
 WITH EXCLUDE_LINE AS /*   */ ( SELECT 105857 AS OBJ# , 321 AS LINE FROM DUAL UNION SELECT 82036 , 50 FROM DUAL ) , EXCLUDE_OBJ AS /*   */ ( SELECT 121939 AS OBJ# FROM DUAL ) , PATTERNS AS ( SELECT 'GET_ACTUAL_DATE' AS ERST , '(' AS OPENING , '' AS CLOSING , 'SYSDATE' AS BECOME FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ' ' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '=' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ',' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '''' , '' , 'SYSDATE' FROM DUAL ) SELECT SC.OBJ# AS OBJ# , SC.LINE AS LINE , SC.SOURCE AS SOURCE , REPLACE ( UPPER(SC.SOURCE) , PT.OPENING || PT.ERST || PT.CLOSING , PT.OPENING || PT.BECOME || PT.CLOSING ) AS COMPLETE FROM SYS.USER$ UR JOIN SYS.OBJ$ OB ON UR.USER# = OB.OWNER# JOIN SYS.SOURCE$ SC ON SC.OBJ# = OB.OBJ# , PATTERNS PT WHERE UR.USER# = 50 AND UPPER(SC.SOURCE) LIKE '%' || PT.ERST || '%' AND (SC.OBJ# , SC.LINE ) NOT IN (SELECT EL.OBJ# , EL.LINE FROM EXCLUDE_LINE EL ) AND SC.OBJ# NOT IN (SELECT EO.OBJ# FROM EXCLUDE_OBJ EO ) AND REPLACE ( UPPER(SC.SOURCE) , PT.OPENING || PT.ERST || PT.CLOSING , PT.OPENING || PT.BECOME || PT.CLOSING ) <> UPPER(SC.SOURCE) ORDER BY OBJ# , LINE ;
      
      







リクエストを実行し、選択を確認しました-約。



置換を保存する


ここで、置換の「計算」の結果をどこかに保存する必要がありました。 テーブルを追加します。

 CREATE TABLE SWAP_SOURCE_CODE ( BATCH NUMBER, /*   /      */ OBJ# NUMBER, /*  */ LINE NUMBER, /*  */ SOURCE VARCHAR2(4000 BYTE), /*   SYS.SOURCE$.SOURCE%TYPE */ OUTPUT VARCHAR2(4000 BYTE), /*   */ CONSTRAINT PK_SWAP_SOURCE_CODE PRIMARY KEY (BATCH, OBJ#, LINE) USING INDEX TABLESPACE PROD_INDEX STORAGE (INITIAL 80 K NEXT 1 M MAXEXTENTS UNLIMITED) )
      
      





テーブルSWAP_SOURCE_CODEにデータを入力します。

 INSERT INTO SWAP_SOURCE_CODE WITH EXCLUDE_LINE AS /*   */ ( SELECT 105857 AS OBJ# , 321 AS LINE FROM DUAL UNION SELECT 82036 , 50 FROM DUAL ) , EXCLUDE_OBJ AS /*   */ ( SELECT 121939 AS OBJ# FROM DUAL ) , BATCH_NUMBER AS /*    */ ( SELECT (COALESCE (MAX(BATCH),0) +1) AS BATCH# FROM PROD.SWAP_SOURCE_CODE ) , PATTERNS AS /*   */ ( SELECT 'GET_ACTUAL_DATE' AS ERST , '(' AS OPENING , '' AS CLOSING , 'SYSDATE' AS BECOME FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ' ' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '=' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , ',' , '' , 'SYSDATE' FROM DUAL UNION ALL SELECT 'GET_ACTUAL_DATE' , '''' , '' , 'SYSDATE' FROM DUAL ) SELECT BATCH_NUMBER.BATCH# , SC.OBJ# AS OBJ# , SC.LINE AS LINE , SC.SOURCE AS SOURCE , REPLACE ( UPPER(SC.SOURCE) , PT.OPENING || PT.ERST || PT.CLOSING , PT.OPENING || PT.BECOME || PT.CLOSING ) AS COMPLETE FROM SYS.USER$ UR JOIN SYS.OBJ$ OB ON UR.USER# = OB.OWNER# JOIN SYS.SOURCE$ SC ON SC.OBJ# = OB.OBJ# , PATTERNS PT , BATCH_NUMBER WHERE UR.USER# = 50 /*      PROD */ AND UPPER(SC.SOURCE) LIKE '%' || PT.ERST || '%' AND (SC.OBJ# , SC.LINE ) NOT IN (SELECT EL.OBJ# , EL.LINE FROM EXCLUDE_LINE EL ) AND SC.OBJ# NOT IN (SELECT EO.OBJ# FROM EXCLUDE_OBJ EO ) AND REPLACE ( UPPER(SC.SOURCE) , PT.OPENING || PT.ERST || PT.CLOSING , PT.OPENING || PT.BECOME || PT.CLOSING ) <> UPPER(SC.SOURCE) ORDER BY OBJ# , LINE ;
      
      





置換の結果を確認します。

 SELECT * FROM SWAP_SOURCE_CODE;
      
      





置換条件が毎回異なるため、置換生成手順を実行しませんでした。PL/ SQLを使用して、ソースDDLスクリプトをターゲットスクリプトに変換するアルゴリズムを説明するのが便利なのは事実ではありません。通常、これは外部プログラム(C#、Ruby 、Perl)。

置換


これでテーブルSWAP_SOURCE_CODEに置換があり、置換を実行できます。置換を実行する前にソースコードを保存する必要があります。もちろん、置換後にソースコードを保存する必要があります。 これを行うには、テーブルSOURCE_CODE_BACKUPを追加します。

 CREATE TABLE SOURCE_CODE_BACKUP ( BATCH NUMBER, /*   */ OBJ NUMBER, /*  */ CODE_BACKUP CLOB, /*     */ CODE_UPDATE CLOB, /*    */ CONSTRAINT PK_SOURCE_CODE_BACKUP PRIMARY KEY (BATCH, OBJ) USING INDEX TABLESPACE PROD_INDEX STORAGE (INITIAL 80 K NEXT 1 M MAXEXTENTS NLIMITED) )
      
      





置換は、P_REPLACE_SOURCE_WITH_OUTPUTプロシージャによって実行されます。

 CREATE OR REPLACE PROCEDURE P_REPLACE_SOURCE_WITH_OUTPUT ( N_BATCH_IN IN NUMBER /*      */ ) AS /*     */ CURSOR GetObjFromSwap_Source_Code ( nBatchIn IN NUMBER ) IS SELECT SW.OBJ# AS OBJ FROM SWAP_SOURCE_CODE SW WHERE SW.BATCH = nBatchIn GROUP BY SW.OBJ# ORDER BY SW.OBJ# ; TYPE T_OBJ_TABLE IS TABLE OF GetObjFromSwap_Source_Code%ROWTYPE; OBJ_TABLE T_OBJ_TABLE := T_OBJ_TABLE(); nObjCount NUMBER ; nObjFirstIndex NUMBER ; nObjLastIndex NUMBER ; nObj NUMBER; ObjBackup_CLOB CLOB ; /*   */ ObjUpdate_CLOB CLOB ; /*    */ nBATCH NUMBER; /*      */ CURSOR GetNextBatchNumber IS SELECT COALESCE( MAX(SB.BATCH),0 ) + 1 FROM SOURCE_CODE_BACKUP SB ; nIsEqual NUMBER ; /*         */ /*     */ PROCEDURE PARSE_SOURCE_CODE_WITH_OUTPUT ( nObjIn IN NUMBER /*    */ , nBatchIn IN NUMBER /*     */ , ObjBackupOut_CLOB OUT CLOB /*   */ , ObjUpdateOut_CLOB OUT CLOB /*   */ ) AS /*         */ CURSOR GetObjNameTypeSchema ( nObjIn IN NUMBER ) IS /*           SYS.DBA_OBJECTS ,   DBMS_METADATA.GET_DDL   ,       DBA_OBJECTS       "_" ,      http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_metada.htm#BGBBIEGA */ WITH OBJ_TYPE AS ( SELECT 0 AS TYPE#, 'NEXT_OBJECT' AS NAME FROM DUAL UNION ALL SELECT 1, 'INDEX' FROM DUAL UNION ALL SELECT 2, 'TABLE' FROM DUAL UNION ALL SELECT 3, 'CLUSTER' FROM DUAL UNION ALL SELECT 4, 'VIEW' FROM DUAL UNION ALL SELECT 5, 'SYNONYM' FROM DUAL UNION ALL SELECT 6, 'SEQUENCE' FROM DUAL UNION ALL SELECT 7, 'PROCEDURE' FROM DUAL UNION ALL SELECT 8, 'FUNCTION' FROM DUAL UNION ALL /*      'PACKAGE'         ,        'PACKAGE_SPEC' */ SELECT 9, 'PACKAGE_SPEC' FROM DUAL UNION ALL -- 'PACKAGE' SELECT 11, 'PACKAGE_BODY' FROM DUAL UNION ALL SELECT 12, 'TRIGGER' FROM DUAL UNION ALL /*      'TYPE'        ,        'TYPE_SPEC' */ SELECT 13, 'TYPE_SPEC' FROM DUAL UNION ALL --TYPE SELECT 14, 'TYPE_BODY' FROM DUAL UNION ALL SELECT 19, 'TABLE_PARTITION' FROM DUAL UNION ALL SELECT 20, 'INDEX_PARTITION' FROM DUAL UNION ALL SELECT 21, 'LOB' FROM DUAL UNION ALL SELECT 22, 'LIBRARY' FROM DUAL UNION ALL SELECT 23, 'DIRECTORY' FROM DUAL UNION ALL SELECT 24, 'QUEUE' FROM DUAL UNION ALL SELECT 28, 'JAVA_SOURCE' FROM DUAL UNION ALL SELECT 29, 'JAVA_CLASS' FROM DUAL UNION ALL SELECT 30, 'JAVA_RESOURCE' FROM DUAL UNION ALL SELECT 32, 'INDEXTYPE' FROM DUAL UNION ALL SELECT 33, 'OPERATOR' FROM DUAL UNION ALL SELECT 34, 'TABLE_SUBPARTITION' FROM DUAL UNION ALL SELECT 35, 'INDEX_SUBPARTITION' FROM DUAL UNION ALL SELECT 39, 'LOB_PARTITION' FROM DUAL UNION ALL SELECT 40, 'LOB_SUBPARTITION' FROM DUAL UNION ALL SELECT 43, 'DIMENSION' FROM DUAL UNION ALL SELECT 44, 'CONTEXT' FROM DUAL UNION ALL SELECT 47, 'RESOURCE_PLAN' FROM DUAL UNION ALL SELECT 48, 'CONSUMER_GROUP' FROM DUAL UNION ALL SELECT 51, 'SUBSCRIPTION' FROM DUAL UNION ALL SELECT 52, 'LOCATION' FROM DUAL UNION ALL SELECT 56, 'JAVA_DATA' FROM DUAL ) SELECT OB.NAME , TP.NAME , UR.NAME FROM SWAP_SOURCE_CODE SW JOIN SYS.OBJ$ OB ON SW.OBJ# = OB.OBJ# JOIN SYS.USER$ UR ON UR.USER# = OB.OWNER# LEFT JOIN OBJ_TYPE TP ON OB.TYPE# = TP.TYPE# WHERE SW.OBJ# = nObjIn ; ObjRaw_CLOB CLOB; /*    */ ObjParsed_CLOB CLOB; /* DDL      */ sObjName VARCHAR2(30); /*   */ sTypeName VARCHAR2(30); /*   */ sSchemaName VARCHAR2(30); /*   */ /*       */ CURSOR GetSourceOutputFromSwap_Source ( nObjectNumberIn IN NUMBER , nBatchNumberIn IN NUMBER ) IS SELECT SW.SOURCE AS SOURCE , SW.OUTPUT AS OUTPUT FROM SWAP_SOURCE_CODE SW WHERE SW.BATCH = nBatchNumberIn AND SW.OBJ# = nObjectNumberIn ORDER BY SW.LINE ; TYPE T_SOURCE_AND_OUTPUT_TABLE IS TABLE OF GetSourceOutputFromSwap_Source%ROWTYPE; SourceAndOutput_TABLE T_SOURCE_AND_OUTPUT_TABLE := T_SOURCE_AND_OUTPUT_TABLE(); nSourceCount NUMBER ; nSourceFirstIndex NUMBER ; nSourceLastIndex NUMBER ; sPlaceholder SYS.SOURCE$.SOURCE%TYPE; /*    */ sSubstitute SYS.SOURCE$.SOURCE%TYPE; /*    */ BEGIN /*   GET_DDL   ,      */ OPEN GetObjNameTypeSchema(nObjIn); FETCH GetObjNameTypeSchema INTO sObjName, sTypeName, sSchemaName; CLOSE GetObjNameTypeSchema; /*    */ ObjRaw_CLOB := DBMS_METADATA.GET_DDL ( OBJECT_TYPE => sTypeName , NAME => sObjName , SCHEMA => sSchemaName ); /*    */ ObjBackupOut_CLOB := ObjRaw_CLOB ; /*      */ ObjParsed_CLOB := ObjRaw_CLOB; OPEN GetSourceOutputFromSwap_Source ( nObjectNumberIn => nObjIn , nBatchNumberIn => nBatchIn ); FETCH GetSourceOutputFromSwap_Source BULK COLLECT INTO SourceAndOutput_TABLE; CLOSE GetSourceOutputFromSwap_Source ; nSourceCount := SourceAndOutput_TABLE.COUNT; IF ( nSourceCount > 0 ) THEN nSourceFirstIndex := SourceAndOutput_TABLE.FIRST; nSourceLastIndex := SourceAndOutput_TABLE.LAST; FOR indx IN nSourceFirstIndex .. nSourceLastIndex LOOP sPlaceholder := SourceAndOutput_TABLE(indx).SOURCE ; sSubstitute := SourceAndOutput_TABLE(indx).OUTPUT ; /*   */ ObjParsed_CLOB := REPLACE ( ObjParsed_CLOB , sPlaceholder , sSubstitute ); END LOOP; /*     */ ObjUpdateOut_CLOB := ObjParsed_CLOB ; END IF ; END PARSE_SOURCE_CODE_WITH_OUTPUT ; BEGIN /*    */ OPEN GetNextBatchNumber; FETCH GetNextBatchNumber INTO nBATCH; CLOSE GetNextBatchNumber; /*       */ OPEN GetObjFromSwap_Source_Code(N_BATCH_IN); FETCH GetObjFromSwap_Source_Code BULK COLLECT INTO OBJ_TABLE; CLOSE GetObjFromSwap_Source_Code; nObjCount := OBJ_TABLE.COUNT; IF ( nObjCount > 0 ) THEN nObjFirstIndex := OBJ_TABLE.FIRST; nObjLastIndex := OBJ_TABLE.LAST; FOR indx IN nObjFirstIndex .. nObjLastIndex LOOP /*     */ nObj := OBJ_TABLE(indx).OBJ; /*   */ PARSE_SOURCE_CODE_WITH_OUTPUT ( nObjIn => nObj , nBatchIn => N_BATCH_IN , ObjBackupOut_CLOB => ObjBackup_CLOB , ObjUpdateOut_CLOB => ObjUpdate_CLOB ); /*       */ nIsEqual := DBMS_LOB.COMPARE(ObjBackup_CLOB,ObjUpdate_CLOB); IF( nIsEqual IS NOT NULL /* NULL    CLOB_   */ AND nIsEqual <> 0 /*  CLOB _   0,      0 */ ) THEN /*  CLOB _       SOURCE_CODE_BACKUP */ INSERT INTO SOURCE_CODE_BACKUP (BATCH,OBJ,CODE_BACKUP,CODE_UPDATE) VALUES(nBATCH,nObj,ObjBackup_CLOB,ObjUpdate_CLOB) ; END IF ; END LOOP; END IF ; END P_REPLACE_SOURCE_WITH_OUTPUT ;
      
      





手順を実行します。

 BEGIN P_REPLACE_SOURCE_WITH_OUTPUT( N_BATCH_IN => 1 ); END;
      
      





その後、理論的には、そこで生成されたものを確認できます。

 SELECT * FROM SOURCE_CODE_BACKUP;
      
      





オブジェクトのコンパイル


そして、ここで私たちはフィニッシュラインにいます-すべてのオブジェクトをコンパイルするために残っています-DDLスクリプトを実行します。

次の手順も実行します-P_EXECUTE_CODE_UPDATE:

 CREATE OR REPLACE PROCEDURE P_EXECUTE_CODE_UPDATE ( N_BATCH_IN NUMBER /*      */ ) AS /*       ,       */ CURSOR GetUpdateFromSourceCodeBackup ( nBatchNumberIn IN NUMBER ) IS SELECT SB.CODE_UPDATE AS CodeUpdate , SB.OBJ AS Obj FROM SOURCE_CODE_BACKUP SB JOIN SYS.OBJ$ OB ON SB.OBJ = OB.OBJ# WHERE SB.BATCH = nBatchNumberIn AND OB.TYPE# <> 12 -- 12, 'TRIGGER' /*    DBMS_METADATA.GET_DDL         ,     DDL     ,     ,    DBMS_METADATA           */ ORDER BY SB.BATCH , SB.OBJ ; TYPE T_CodeUpdate IS TABLE OF GetUpdateFromSourceCodeBackup%ROWTYPE; CodeUpdate_TABLE T_CodeUpdate := T_CodeUpdate(); nCodeUpdateCount NUMBER; nCodeUpdateFirst NUMBER; nCodeUpdateLast NUMBER; /*      */ SqlText_CLOB CLOB; nObj NUMBER; /*      */ CURSOR GetObjName( ObjIn IN NUMBER ) IS SELECT OB.NAME AS ObjectName FROM SYS.OBJ$ OB WHERE OB.OBJ# = ObjIn ; /*    ORACLE     30- ,      -   32767 */ sObjectName VARCHAR2(32767); BEGIN /*   " "  ,    */ DBMS_OUTPUT.ENABLE(NULL); /*   DDL    */ OPEN GetUpdateFromSourceCodeBackup(N_BATCH_IN); FETCH GetUpdateFromSourceCodeBackup BULK COLLECT INTO CodeUpdate_TABLE; CLOSE GetUpdateFromSourceCodeBackup; nCodeUpdateCount := CodeUpdate_TABLE.COUNT; IF ( nCodeUpdateCount > 0 ) THEN nCodeUpdateFirst := CodeUpdate_TABLE.FIRST; nCodeUpdateLast := CodeUpdate_TABLE.LAST; FOR indx IN nCodeUpdateFirst .. nCodeUpdateLast LOOP /*   DDL  */ SqlText_CLOB := CodeUpdate_TABLE(indx).CodeUpdate; /*    */ nObj := CodeUpdate_TABLE(indx).Obj; /*    */ OPEN GetObjName(nObj); FETCH GetObjName INTO sObjectName ; CLOSE GetObjName; /*            */ DBMS_OUTPUT.PUT_LINE( '#' || LPAD (indx, 3,'0' )|| ' Process .. ' || sObjectName || ' ' || nObj ); /*  DDL  */ EXECUTE IMMEDIATE SqlText_CLOB; /*       ,             */ DBMS_OUTPUT.PUT_LINE( '#' || LPAD (indx, 3,'0' )|| ' Complete ' || sObjectName || ' ' || nObj ); END LOOP; END IF; END;
      
      





私たちは実施します:

 BEGIN PARUS.P_EXECUTE_CODE_UPDATE( N_BATCH_IN => 1 ); END;
      
      





トリガーを除くすべてのオブジェクトをコンパイルし、実行からトリガーを選択します。

 SELECT * FROM SWAP_SOURCE_CODE SW JOIN SYS.OBJ$ OB ON OB.OBJ# = SW.OBJ# WHERE OB.TYPE# = 12 AND SW.BATCH = 1 ;
      
      





トリガーのスクリプトをパーツで実行します。最初にトリガーが作成されたパーツ、次にトリガーがオンになったパーツです。



おわりに



ソースは必要に応じて変更され、コンパイルされました。 元のソースが保存されたので、DBMS管理者にバックアップコピーのデプロイ要求を送信せずに、元のオブジェクトを復元できます。

ある機能を別の機能に置き換えるのがとても簡単だったのはなぜですか? このERPは20年の歴史を持ち、すぐに使用できるため、コードは監視され、コードは同じスタイルで設計されています。ひざの上のERPであれば、関数名を置き換えるのはそれほど簡単ではありません。

仲間、あなた自身の敵ではなく、自分を愛してください-あなたのコードを見て、同じ基準に従って同じスタイルで書かれてください!

アーメン



参照資料



  1. テーブルSYS.SOURCE $を読み取る特権
  2. DBMS_METADATA.GET_DDLファンクションのオブジェクト型
  3. DBMS_SQLを使用して動的SQLを実行する



All Articles