今週の名言
「宇宙でもっとも強い力は、幅広い興味である。」
アルベルト・アインシュタイン
oerrとは?
前回からのつながりで、今回もエラー・メッセージについて考えてみたいと思います。
oerrという非常に便利なツールがあります。「ORA-4031」について意味を調べたい時は、以下の要領でエラーメッセージの意味だけでなく、原因や対処についての説明をシェルから次のコマンドで確認することができます。
$ oerr ora 4031 04031, 00000, "unable to allocate %s bytes of shared memory (\"%s\",\"%s\",\"%s\",\"%s\")" // *Cause: More shared memory is needed than was allocated in the shared // pool or Streams pool. // *Action: If the shared pool is out of memory, either use the // DBMS_SHARED_POOL package to pin large packages, // reduce your use of shared memory, or increase the amount of // available shared memory by increasing the value of the // initialization parameters SHARED_POOL_RESERVED_SIZE and // SHARED_POOL_SIZE. // If the large pool is out of memory, increase the initialization // parameter LARGE_POOL_SIZE. // If the error is issued from an Oracle Streams or XStream process, // increase the initialization parameter STREAMS_POOL_SIZE or increase // the capture or apply parameter MAX_SGA_SIZE.
ORA-以外のエラーメッセージ、例えば「TNS-12541」も以下のように確認することができます。
$ oerr tns 12541 12541, 00000, "TNS:no listener" // *Cause: The connection request could not be completed because the listener // is not running. // *Action: Ensure that the supplied destination address matches one of // the addresses used by the listener - compare the TNSNAMES.ORA entry with // the appropriate LISTENER.ORA file (or TNSNAV.ORA if the connection is to // go by way of an Interchange). Start the listener on the remote machine.
oerrコマンドの正体は?
oerrは実はシェル・スクリプトで、$ORACLE_HOME/bin 以下にあります。
$ which oerr /u01/app/oracle/product/11.2.0.4/db_1/bin/oerr
スクリプトの内容は以下の110行から成るリストのとおりですが
- 35行目に定義されたfacility.lisから接頭語と製品名の関連を取得
- 93行目で製品名ディレクトリ配下にあるmsgファイルを指定
- 104行目以下のawkコマンドにより該当メッセージの取得
という仕様になっています。
$ cat /u01/app/oracle/product/11.2.0.4/db_1/bin/oerr #!/bin/sh # # $Id: oerr.sh /st_buildtools_11.2.0/1 2012/02/28 11:07:18 mrmehta Exp $ # Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. # # Usage: oerr facility error # # This shell script is used to get the description and the cause and action # of an error from a message text file when a list of error numbers are passed # to it. It supports different language environments and errors from different # facilities. # # # Turn on script tracing if, requested [ "$ORACLE_TRACE" = "T" ] && set -x # # If ORACLE_HOME is not set, we will not be able to locate # the message text file. if [ ! "$ORACLE_HOME" ] then echo "ORACLE_HOME not set. Please set ORACLE_HOME and try again." 1>&2 exit 1 fi # # Ignore user locale LC_ALL=C export LC_ALL # # Definition script "constants" Facilities_File=$ORACLE_HOME/lib/facility.lis # # Check script usage if [ "$#" != "2" ] then exec 1>&2 echo 'Usage: oerr facility error' echo echo 'Facility is identified by the prefix string in the error message.' echo 'For example, if you get ORA-7300, "ora" is the facility and "7300"' echo 'is the error. So you should type "oerr ora 7300".' echo echo 'If you get LCD-111, type "oerr lcd 111", and so on.' exit 1 fi # # Pickup the command line arguments Facility="$1" Platform=`/bin/uname` case $Platform in SunOS) SedPath='/usr/xpg4/bin/sed' ;; *) SedPath='/bin/sed' ;; esac Code=`echo $2|$SedPath 's/^[0]*//'` # # Get the facility information from the oerr data file Fac_Info=`grep -i "^${Facility}:" $Facilities_File 2> /dev/null` if [ $? -ne 0 ] then echo "oerr: Unknown facility '$Facility'" 1>&2 exit 1 fi # # Parse the components from the Fac_Info string into Shell variables eval `echo "$Fac_Info" | awk -F: '{ if (index ($3, "*") == 0) printf ("Facility=%s\n", $3); else printf ("Facility=%s\n", $1); printf ("Component=%s\n", $2); }'` if [ -z "$Facility" -o -z "$Component" ] then echo "oerr: Invalid facilities entry '$Fac_Info'" 1>&2 exit 1 fi # # The message file searched is always the US English file Msg_File=$ORACLE_HOME/$Component/mesg/${Facility}us.msg if [ ! -r $Msg_File ] then echo "oerr: Cannot access the message file $Msg_File" 1>&2 exit 1 fi # # Search the message file for the error code, printing the message text # and any following comments which should give the cause and action for # the error. awk "BEGIN { found = 0; } /^[0]*$Code/ { found = 1; print ; next;} /^\/\// { if (found) { print; } next; } { if (found) { exit; } }" $Msg_File exit 0
例えば、$OEACLE_HOME/rdbms/mesg/oraus.msg ファイルの内容は以下のようになっています。
1865 00000, 00000, "normal, successful completion" 1866 // *Cause: Normal exit. 1867 // *Action: None. 1868 00001, 00000, "unique constraint (%s.%s) violated" 1869 // *Cause: An UPDATE or INSERT statement attempted to insert a duplicatee key. 1870 // For Trusted Oracle configured in DBMS MAC mode, you may see 1871 // this message if a duplicate entry exists at a different levell. 1872 // *Action: Either remove the unique restriction or do not insert the key. 1873 /0002 reserved for v2 compatibility (null column) 1874 /0003 reserved for v2 compatibility (column value truncated) 1875 /0004 reserved for v2 compatibility (end-of-fetch) 1876 /0009 reserved for v2 compatibility 1877 / 1878 / 10 - 49 user session and session switching errors 1879 / 1880 00017, 00000, "session requested to set trace event" 1881 // *Cause: The current session was requested to set a trace event by another 1882 // session. 1883 // *Action: This is used internally; no action is required.
oerrは英語圏の人にとっては非常に便利なツールですが、Oracle 8.1.6を最後に各国語サポートへは対応されなくなっています。
エラー・メッセージだけでも日本語化してみる
原因や対処までは無理としても、せめてエラー・メッセージの意味だけでも日本語で表示させるツールを作ってみたいと思いましたので、以下のようなストアド・ファンクションを作ってみました。
試作版なのですべての接頭語には対応していませんし、エラーハンドリングも考慮していません。(存在しないメッセージ番号を指定すると「該当メッセージはありません」という表示をさせています。)
SQL> CREATE OR REPLACE FUNCTION show_errmsg (err_fac IN VARCHAR2,err_num IN PLS_INTEGER) 2 RETURN VARCHAR2 3 IS 4 wrk_fac VARCHAR2(8); 5 err_lan VARCHAR2(20) := 'japanese'; 6 err_msg VARCHAR2(512); 7 i PLS_INTEGER; 8 BEGIN 9 wrk_fac := UPPER(err_fac); 10 CASE wrk_fac 11 WHEN 'CRS' THEN i := UTL_LMS.GET_MESSAGE(err_num,'crs', err_fac,err_lan,err_msg); 12 WHEN 'TNS' THEN i := UTL_LMS.GET_MESSAGE(err_num,'network',err_fac,err_lan,err_msg); 13 ELSE i := UTL_LMS.GET_MESSAGE(err_num,'rdbms', err_fac,err_lan,err_msg); 14 END CASE; 15 IF err_msg LIKE 'Message%not found%' 16 THEN err_msg := wrk_fac || '-' || TO_CHAR(err_num,'FM00000') || ': 該当メッセージはありません'; 17 ELSE err_msg := wrk_fac || '-' || TO_CHAR(err_num,'FM00000') || ': ' || err_msg; 18 END IF; 19 RETURN err_msg; 20 END; 21 / ファンクションが作成されました。
このファンクションの使用例は以下のようになります。
SQL> SELECT show_errmsg('ora',4031) ERROR_MESSAGE from dual; ERROR_MESSAGE ---------------------------------------------------------------------------------------------------- ORA-04031: 共有メモリーの%sバイトを割当てできません("%s"、"%s"、"%s"、"%s") SQL> SELECT show_errmsg('crs',214) ERROR_MESSAGE from dual; ERROR_MESSAGE ---------------------------------------------------------------------------------------------------- CRS-00214: リソース'%s'を登録解除できません。 SQL> SELECT show_errmsg('&fac',&num) ERROR_MESSAGE from dual; facに値を入力してください: rman numに値を入力してください: 567 旧 1: SELECT show_errmsg('&fac',&num) ERROR_MESSAGE from dual 新 1: SELECT show_errmsg('rman',567) ERROR_MESSAGE from dual ERROR_MESSAGE -------------------------------------------------------------------------------- RMAN-00567: Recovery Managerで印刷できなかったエラー・メッセージがあります SQL> / facに値を入力してください: tns numに値を入力してください: 12541 旧 1: SELECT show_errmsg('&fac',&num) ERROR_MESSAGE from dual 新 1: SELECT show_errmsg('tns',12541) ERROR_MESSAGE from dual ERROR_MESSAGE -------------------------------------------------------------------------------- TNS-12541: TNS: リスナーがありません。 SQL> / facに値を入力してください: ora numに値を入力してください: 2 旧 1: SELECT show_errmsg('&fac',&num) ERROR_MESSAGE from dual 新 1: SELECT show_errmsg('ora',2) ERROR_MESSAGE from dual ERROR_MESSAGE -------------------------------------------------------------------------------- ORA-00002: 該当メッセージはありません SQL> / facに値を入力してください: abc numに値を入力してください: 1 旧 1: SELECT show_errmsg('&fac',&num) ERROR_MESSAGE from dual 新 1: SELECT show_errmsg('abc',1) ERROR_MESSAGE from dual ERROR_MESSAGE -------------------------------------------------------------------------------- ABC-00001: 該当メッセージはありません
UTL_LMS.GET_MESSAGEはどこからメッセージを取得しているのか?
oerrが参照していたmsgファイルと同じディレクトリに「msb」という拡張子が付いたバイナリファイルがあるのですが、これらのファイルの中にメッセージが格納されているようです。
それでは、日本語と英語メッセージが格納されているであろうファイルをRenameして、メッセージが取得できなくなるかどうか確認してみましょう。
$ cd $ORACLE_HOME/rdbms/mesg $ mv oraja.msb oraja.msb.bak $ mv oraus.msb oraus.msb.bak
SQL> SELECT show_errmsg('ora',4031) ERROR_MESSAGE from dual; ERROR_MESSAGE -------------------------------------------------------------------------------- ORA-04031: 該当メッセージはありません
やはり、msbファイルが関係していました。
oerrは単純なテキストファイルの内容を表示させる仕様でしたが、Oracle9i以降は英語以外の言語でエラー・メッセージを取得するインターフェースはUTL_LMS.GET_MESSAGEだけになりました。
msbファイルの中にはmsgファイルのような原因や対処に関する説明は書いてあるのでしょうか?こればかりはOracle社の中の人でなければわかりませんが、将来そのような情報が使えるようになるといいですね。
今日はここまで