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パッケージ
機能を使用する必要がありました。
問題は、オブジェクトのソースを取得する方法です。
カーソルを使用して、
SYS.SOURCE $テーブルのエントリを
検索できます 。「
|| 」演算子と
行末記号を使用して、各レコードの
SOURCEフィールドを接着し
ます 。 しかし、
GET_DDL関数を備えた
DBMS_METADATAパッケージを使用した簡単な方法があります。
DBMS_METADATA.GET_DDL関数の便利さは、オブジェクトのソーステキスト全体を返すだけでなく、スキーマ名を置き換えて「
CREATE OR REPLACE 」を追加することです。
欠点は、数値が
SYS.OBJ $テーブルに格納されている間、関数が文字列引数を受け入れることです。
プロシージャのソースコードを変更するためのアルゴリズム。
- DBMS_METADATA.GET_DDLを使用してソースを取得します。
- 必要に応じてテキストを変更します(最も単純な場合、REPLACEを使用)。
- EXECUTE IMMEDIATEを使用してプロシージャをコンパイルします。
- 使用して楽しんでください。
練習する
実際には、すべてがそれほど単純ではありません。
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
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
結果を見て、1行は関数「GET_ACTUAL_DATE」の宣言であり、「SYSDATE」の宣言に変換する必要はありませんでした。
他の2行はコメントであり、そのままにしておく必要がありました。 指定した行とオブジェクトを除外できるように、スクリプトを追加しました。
リクエストを見る WITH EXCLUDE_LINE AS ( SELECT 105857 AS OBJ
リクエストを実行し、選択を確認しました-約。
置換を保存する
ここで、置換の「計算」の結果をどこかに保存する必要がありました。 テーブルを追加します。
CREATE TABLE SWAP_SOURCE_CODE ( BATCH NUMBER, OBJ
テーブルSWAP_SOURCE_CODEにデータを入力します。
INSERT INTO SWAP_SOURCE_CODE WITH EXCLUDE_LINE AS ( SELECT 105857 AS OBJ
置換の結果を確認します。
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
手順を実行します。
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
私たちは実施します:
BEGIN PARUS.P_EXECUTE_CODE_UPDATE( N_BATCH_IN => 1 ); END;
トリガーを除くすべてのオブジェクトをコンパイルし、実行からトリガーを選択します。
SELECT * FROM SWAP_SOURCE_CODE SW JOIN SYS.OBJ$ OB ON OB.OBJ
トリガーのスクリプトをパーツで実行します。最初にトリガーが作成されたパーツ、次にトリガーがオンになったパーツです。
おわりに
ソースは必要に応じて変更され、コンパイルされました。 元のソースが保存されたので、DBMS管理者にバックアップコピーのデプロイ要求を送信せずに、元のオブジェクトを復元できます。
ある機能を別の機能に置き換えるのがとても簡単だったのはなぜですか? このERPは20年の歴史を持ち、すぐに使用できるため、コードは監視され、コードは同じスタイルで設計されています。ひざの上のERPであれば、関数名を置き換えるのはそれほど簡単ではありません。
仲間、あなた自身の敵ではなく、自分を愛してください-あなたのコードを見て、同じ基準に従って同じスタイルで書かれてください!
アーメン
参照資料
- テーブルSYS.SOURCE $を読み取る特権
- DBMS_METADATA.GET_DDLファンクションのオブジェクト型
- DBMS_SQLを使用して動的SQLを実行する