Julie Kurpa
asked on
Trigger to record SQL when constraint error encountered
I am trying to get a trigger to work when a user gets a constraint error. It is supposed to record the SQL being executed by the user.
The trigger is working fine until I try to combine the multiple lines of the SQL statement into a variable so that it's all one line.
But when I put in the line to do the combine, only the first two utl_file.put_line commands performed prior to the loop will work. All others fail.
Here is my combine command: sql_stmt_text := sql_stmt_text || l_text(i);
Here is the trigger:
create or replace trigger test_trigger
after servererror on database
declare
l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;
begin
v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_O UTPUT','fa iling_SQL_ Stmt.txt', 'W');
if ( is_servererror(0001) )
then
utl_file.put_line(v_output _file1,'-- ---------- --------') ;
utl_file.put_line(v_output _file1,'st atement causing error: ');
l_n := ora_sql_txt( l_text );
for i in 1 .. nvl(l_n,0) loop
-- this statement works when it is the only one in the loop.
-- also all following utl_file.put_line commands are successful.
utl_file.put_line(v_output _file1,l_t ext(i));
-- when I include this statement, none of the utl_file.put_line commands work except
-- for the two just before the loop.
sql_stmt_text := sql_stmt_text || l_text(i);
end loop;
utl_file.put_line(v_output _file1,sql _stmt_text );
utl_file.put_line(v_output _file1,'er ror text: ');
for i in 1 .. ora_server_error_depth
loop
utl_file.put_line(v_output _file1,ora _server_er ror_msg(i) );
end loop;
utl_file.put_line(v_output _file1,'-- ---------- --------') ;
end if;
utl_file.fclose_all;
end;
/
The trigger is working fine until I try to combine the multiple lines of the SQL statement into a variable so that it's all one line.
But when I put in the line to do the combine, only the first two utl_file.put_line commands performed prior to the loop will work. All others fail.
Here is my combine command: sql_stmt_text := sql_stmt_text || l_text(i);
Here is the trigger:
create or replace trigger test_trigger
after servererror on database
declare
l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;
begin
v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_O
if ( is_servererror(0001) )
then
utl_file.put_line(v_output
utl_file.put_line(v_output
l_n := ora_sql_txt( l_text );
for i in 1 .. nvl(l_n,0) loop
-- this statement works when it is the only one in the loop.
-- also all following utl_file.put_line commands are successful.
utl_file.put_line(v_output
-- when I include this statement, none of the utl_file.put_line commands work except
-- for the two just before the loop.
sql_stmt_text := sql_stmt_text || l_text(i);
end loop;
utl_file.put_line(v_output
utl_file.put_line(v_output
for i in 1 .. ora_server_error_depth
loop
utl_file.put_line(v_output
end loop;
utl_file.put_line(v_output
end if;
utl_file.fclose_all;
end;
/
ASKER
Thanks Slightwv. :)
I'm using Oracle 11g running on Oracle LInux.
Perhaps it would help if I included the output without the "offending" line and then with it so you see what I see. Am putting it together now.
I'm using Oracle 11g running on Oracle LInux.
Perhaps it would help if I included the output without the "offending" line and then with it so you see what I see. Am putting it together now.
ASKER
In breaking down the changes, I see that it's actually the "utl_file.put_line(v_outpu t_file1,sq l_stmt_tex t);" that is causing the problem, not the "sql_stmt_text := sql_stmt_text || l_text(i);".
Here is the output WITHOUT the "utl_file.put_line(v_outpu t_file1,sq l_stmt_tex t);"
--------------------
statement causing error:
INSERT INTO myuser.tab1(column1,column 2,column3, column4,co lumn5,
column6,column7,column8,co lumn9,colu mn10,colum n11,column 12,colum
m13) VALUES (1111,2222,3333,4444,5555, 6666,7777, 8888,9999, 1010,1
111,1212,1313)
error text:
ORA-00001: unique constraint (MYUSER.PK_TAB1) violated
This is the output when I include the "utl_file.put_line(v_outpu t_file1,sq l_stmt_tex t);" statement. Notice it doesn't write anything after it's supposed to writethe contents of varable sql_stmt_text:
--------------------
statement causing error:
INSERT INTO myuser.tab1(column1,column 2,column3, column4,co lumn5,
column6,column7,column8,co lumn9,colu mn10,colum n11,column 12,colum
m13) VALUES (1111,2222,3333,4444,5555, 6666,7777, 8888,9999, 1010,1
111,1212,1313)
I tried sending the contents of variable sql_stmt_text to different file altogether.
When doing that, I get the full constraint information written to the first location but never the content of the sql_stmt_text variable in the 2nd file. The 2nd location stays blank.
Here is the output WITHOUT the "utl_file.put_line(v_outpu
--------------------
statement causing error:
INSERT INTO myuser.tab1(column1,column
column6,column7,column8,co
m13) VALUES (1111,2222,3333,4444,5555,
111,1212,1313)
error text:
ORA-00001: unique constraint (MYUSER.PK_TAB1) violated
This is the output when I include the "utl_file.put_line(v_outpu
--------------------
statement causing error:
INSERT INTO myuser.tab1(column1,column
column6,column7,column8,co
m13) VALUES (1111,2222,3333,4444,5555,
111,1212,1313)
I tried sending the contents of variable sql_stmt_text to different file altogether.
When doing that, I get the full constraint information written to the first location but never the content of the sql_stmt_text variable in the 2nd file. The 2nd location stays blank.
I can only go with what I can personally test. The code I posted worked for me.
If you want me to run some other test, post the code you wish me to test. I don't have access to an 11g database any more but can test on 12.2 right now and 18c later today.
>>Here is the output WITHOUT the "utl_file.put_line(v_outpu t_file1,sq l_stmt_tex t);
If you are getting the output you want, what are you trying to accomplish by changing it? I'm not understanding why you need the SQL on a single line. What happens when you get SQL larger than 32k?
If you want me to run some other test, post the code you wish me to test. I don't have access to an 11g database any more but can test on 12.2 right now and 18c later today.
>>Here is the output WITHOUT the "utl_file.put_line(v_outpu
If you are getting the output you want, what are you trying to accomplish by changing it? I'm not understanding why you need the SQL on a single line. What happens when you get SQL larger than 32k?
ASKER
It seems your code is exactly like mine so I don't really have any changes to make. If it runs in 12.2 then I'm not sure what else to try.
I wanted to get the SQL into a single line because I plan to extract certain elements from it and use it in a procedure. If it's wrapping like it is, then certain elements I need may be split between lines.
I wanted to get the SQL into a single line because I plan to extract certain elements from it and use it in a procedure. If it's wrapping like it is, then certain elements I need may be split between lines.
OK, I think I've been able to reproduce this using longer SQL. Let me dig into this a little more.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I really appreciate your help.
On a whim, I directed that variable to a table instead of to a file and it seems to work. The entire SQL is being written into one column. This is where I eventually wanted to end up but was just writting to the file so I could see what I was getting.
Here's the adjusted code.
create or replace trigger test_trigger
after servererror on database
declare
l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;
begin
v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_O UTPUT','fa iling_SQL_ Stmt.txt', 'W');
if ( is_servererror(0001) )
then
utl_file.put_line(v_output _file1,'-- ---------- --------') ;
utl_file.put_line(v_output _file1,'st atement causing error: ');
l_n := ora_sql_txt( l_text );
for i in 1 .. nvl(l_n,0) loop
utl_file.put_line(v_output _file1,l_t ext(i));
sql_stmt_text := sql_stmt_text || l_text(i);
end loop;
INSERT INTO myuser.sql_event VALUES (sql_stmt_text);
utl_file.put_line(v_output _file1,'er ror text: ');
for i in 1 .. ora_server_error_depth
loop
utl_file.put_line(v_output _file1,ora _server_er ror_msg(i) );
end loop;
utl_file.put_line(v_output _file1,'-- ---------- --------') ;
end if;
utl_file.fclose_all;
end;
/
On a whim, I directed that variable to a table instead of to a file and it seems to work. The entire SQL is being written into one column. This is where I eventually wanted to end up but was just writting to the file so I could see what I was getting.
Here's the adjusted code.
create or replace trigger test_trigger
after servererror on database
declare
l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;
begin
v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_O
if ( is_servererror(0001) )
then
utl_file.put_line(v_output
utl_file.put_line(v_output
l_n := ora_sql_txt( l_text );
for i in 1 .. nvl(l_n,0) loop
utl_file.put_line(v_output
sql_stmt_text := sql_stmt_text || l_text(i);
end loop;
INSERT INTO myuser.sql_event VALUES (sql_stmt_text);
utl_file.put_line(v_output
for i in 1 .. ora_server_error_depth
loop
utl_file.put_line(v_output
end loop;
utl_file.put_line(v_output
end if;
utl_file.fclose_all;
end;
/
ASKER
oh I just saw your post. am reading it now.
ASKER
That worked great slighwv! You are wonderful!
I set the FOPEN size to 32767 and I'm getting the full SQL text on one line in the file.
Now I have many options on how to handle the rest of my project.
I set the FOPEN size to 32767 and I'm getting the full SQL text on one line in the file.
Now I have many options on how to handle the rest of my project.
ASKER
Here's the working product with the writing of the SQL on all one line to the output file outside the loop.
create or replace trigger test_trigger
after servererror on database
declare
l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(10000);
v_output_file1 utl_file.file_type;
begin
v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_O UTPUT','fa iling_SQL_ Stmt.txt', 'W',32767) ;
if ( is_servererror(0001) )
then
utl_file.put_line(v_output _file1,'-- ---------- --------') ;
utl_file.put_line(v_output _file1,'st atement causing error: ');
l_n := ora_sql_txt( l_text );
for i in 1 .. nvl(l_n,0) loop
utl_file.put_line(v_output _file1,l_t ext(i));
sql_stmt_text := sql_stmt_text || l_text(i);
end loop;
-- write the combined SQL to a table
INSERT INTO myuser.sql_event VALUES (sql_stmt_text);
-- write the combined SQL to the file
utl_file.put_line(v_output _file1,'er ror text: ');
for i in 1 .. ora_server_error_depth
loop
utl_file.put_line(v_output _file1,ora _server_er ror_msg(i) );
end loop;
utl_file.put_line(v_output _file1,'-- ---------- --------') ;
end if;
utl_file.fclose_all;
end;
/
create or replace trigger test_trigger
after servererror on database
declare
l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(10000);
v_output_file1 utl_file.file_type;
begin
v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_O
if ( is_servererror(0001) )
then
utl_file.put_line(v_output
utl_file.put_line(v_output
l_n := ora_sql_txt( l_text );
for i in 1 .. nvl(l_n,0) loop
utl_file.put_line(v_output
sql_stmt_text := sql_stmt_text || l_text(i);
end loop;
-- write the combined SQL to a table
INSERT INTO myuser.sql_event VALUES (sql_stmt_text);
-- write the combined SQL to the file
utl_file.put_line(v_output
for i in 1 .. ora_server_error_depth
loop
utl_file.put_line(v_output
end loop;
utl_file.put_line(v_output
end if;
utl_file.fclose_all;
end;
/
>>SQL on all one line to the output file outside the loop.
Why when it isn't necessary?
Why when it isn't necessary?
ASKER
Just to show it as part of the solution. I won't continue to do it now that I'm writing it to a table.
ASKER
slightwv didn't have to do further research when his SQL worked fine. Went the extra mile to reproduce the problem and found the solution.
Works for me using 18.0.
I modified your PUT_LINES to add location1 and location2 tothem so I know what wrote what.
Open in new window
My test run output:
Open in new window
My file contents:
Open in new window