以下の PL/SQL ストアド プロシージャを作成して、Oracle11g データベース全体で文字列 (srchstr) を検索し、その文字列が見つかったテーブルと列を VALUESEARCHRESULTS というテーブルに返します。
この手順は、ユーザーとしてSQL Developerを介してOracle XEで正常に実行されました。ただし、スキーマ ABC の Oracle11g でユーザー SYS として実行しようとすると、次のエラーが表示されます。
ORA-00911: 無効な文字です 原因: 識別子は、文字と数字以外のASCII文字で開始することはできません。$#_ も最初の文字の後に使用できます。二重引用符で囲まれた識別子には、二重引用符以外の任意の文字を含めることができます。代替引用符 (q"#...#") では、区切り文字としてスペース、タブ、または改行を使用できません。他のすべてのコンテキストについては、SQL 言語リファレンス マニュアルを参照してください。
これがなぜなのか誰か知っていますか?以下の私のコードを見てください。
CREATE OR REPLACE PROCEDURE ABC.FIND_STRING(p_str IN VARCHAR2) authid current_user is
l_query clob;
srchstr varchar2(30) := '';
r_cname varchar2(30) := '';
l_case clob;
l_runquery boolean;
l_tname varchar2(30);
l_cname varchar2(30);
begin
dbms_application_info.set_client_info( '%' || upper(p_str) || '%' );
for x in (select * from user_tables)
loop
l_query := 'select ''' || x.table_name || ''', $$
from ' || x.table_name || '
where rownum = 1 and ( 1=0 ';
l_case := 'case ';
l_runquery := FALSE;
for y in ( select *
from user_tab_columns
where table_name = x.table_name
and (data_type in('CHAR', 'DATE', 'FLOAT', 'NCHAR', 'NUMBER', 'NVARCHAR2', 'VARCHAR2' )
or data_type like 'INTERVAL%' or data_type like 'TIMESTAMP%' )
)
loop
l_runquery := TRUE;
l_query := l_query || ' or upper(' || y.column_name ||
') like userenv(''client_info'') ';
l_case := l_case || ' when upper(' || y.column_name ||
') like userenv(''client_info'') then ''' ||
y.column_name || '''';
end loop;
if ( l_runquery )
then
l_case := l_case || ' else NULL end';
l_query := replace( l_query, '$$', l_case ) || ')';
begin
execute immediate l_query into l_tname, l_cname;
r_cname := l_cname;
dbms_application_info.read_client_info(srchstr);
insert into ABC.ValueSearchResults (resulttable, resultcolumn, searchstring) values (x.table_name, r_cname, srchstr);
dbms_output.put_line
( srchstr || ' found in ' || l_tname || '.' || l_cname );
exception
when no_data_found then
dbms_output.put_line
( srchstr || ' has no hits in ' || x.table_name );
end;
end if;
end loop;
end;
EDIT : 上記のストアド プロシージャはエラーなしでコンパイルされます。次のコードは、テーブルからストアド プロシージャに値を渡すことによって、ストアド プロシージャを実行します。以下のコードを実行すると、エラーが表示されます。
BEGIN
FOR c IN (SELECT ControlValue FROM ABC.ControlValues) LOOP
ABC.FIND_STRING(c.ControlValue);
END LOOP;
END;