This question already has an answer here:
Procedure not printing anything
(1 answer)
Closed 10 months ago.
I'm a beginner in PL/SQL Coding.
This is a test program.
Can you please tell the reason for no output.
Please guide me.
create or replace package menu as
procedure show(name varchar2);
end menu;
/
create or replace package body menu as
procedure show(name varchar2) AS
new_number number;
begin
select count(*) into new_number from stock;
dbms_output.put_line('This is output.');
end;
end menu;
/
You need to set Oracle to output lines to the console manually:
set serveroutput on;
This should be the first line in your code.
As others have said, SQL*Plus will only get the output from DBMS_OUTPUT if you first SET SERVEROUT ON.
Your code merely compiles and stores a database package on the database; you haven't actually run it. To run it you'd execute something like this:
BEGIN menu.show('something'); END;
/
Please read the docs
Operational Notes
If you do not call GET_LINE, or if you do not display the messages on your screen in SQL*Plus, the buffered messages are ignored.
SQL*Plus calls GET_LINES after issuing a SQL statement or anonymous PL/SQL calls.
Typing SET SERVEROUTPUT ON in SQL*Plus has the effect of invoking
DBMS_OUTPUT.ENABLE (buffer_size => NULL);
with no limit on the output.
You should generally avoid having application code invoke either the DISABLE Procedure or ENABLE Procedure because this could subvert the attempt of an external tool like SQL*Plus to control whether or not to display output.
Note:
Messages sent using DBMS_OUTPUT are not actually sent until the sending subprogram or trigger completes. There is no mechanism to flush output during the execution of a procedure.
Exceptions
DBMS_OUTPUT subprograms raise the application error ORA-20000, and the output procedures can return the following errors:
Table 68-1 DBMS_OUTPUT Errors
Error Description
ORU-10027: Buffer overflow
ORU-10028: Line length overflow
Rules and Limits
The maximum line size is 32767 bytes.
The default buffer size is 20000 bytes. The minimum size is 2000 bytes and the maximum is unlimited.
So SET SERVEROUTPUT ON is only for SQL*Plus.
Related
I am working on oracle 11g and am new to the PLSQL part of oracle.
I've trying out a program that has to give the output as 'King' but for some reason the dbms_output.put_line does not seem to work for a type variable. I tried checking it out with a normal user number variable just in case to see if the difference and it seems to be working fine for it.
Thank you for the help.
You need to use:
SET SERVEROUTPUT ON;
Before running the anonymous block to tell the SQL/Plus client that you expect it to output the console.
MT0 gave you the answer: run the SQL Plus command SET SERVEROUTPUT ON before you run the procedure.
You should understand a few things from this.
First, the issue has nothing to do with the data type of your variable; it would apply equally well if you didn't have any variables and the entire body of your procedure was simply to print the hard-coded string 'Hello World'.
Second, the important point that put_line writes the "output" to a memory buffer - not directly to the screen. What you do with the data from the buffer is no longer PL/SQL, it's a function of (a task for) your client software, SQL Plus in your case. SET SERVEROUTPUT ON is a SQL Plus command, which instructs SQL Plus to read the data from the buffer and display it on the screen.
You should use command as below:
set server output on ;
After that you will see output .
I have an SQL script that is called from within a shell script and takes a long time to run. It currently contains dbms_output.put_line statements at various points. The output from these print statements appear in the log files, but only once the script has completed.
Is there any way to ensure that the output appears in the log file as the script is running?
Not really. The way DBMS_OUTPUT works is this: Your PL/SQL block executes on the database server with no interaction with the client. So when you call PUT_LINE, it is just putting that text into a buffer in memory on the server. When your PL/SQL block completes, control is returned to the client (I'm assuming SQLPlus in this case); at that point the client gets the text out of the buffer by calling GET_LINE, and displays it.
So the only way you can make the output appear in the log file more frequently is to break up a large PL/SQL block into multiple smaller blocks, so control is returned to the client more often. This may not be practical depending on what your code is doing.
Other alternatives are to use UTL_FILE to write to a text file, which can be flushed whenever you like, or use an autonomous-transaction procedure to insert debug statements into a database table and commit after each one.
If it is possible to you, you should replace the calls to dbms_output.put_line by your own function.
Here is the code for this function WRITE_LOG -- if you want to have the ability to choose between 2 logging solutions:
write logs to a table in an autonomous transaction
CREATE OR REPLACE PROCEDURE to_dbg_table(p_log varchar2)
-- table mode:
-- requires
-- CREATE TABLE dbg (u varchar2(200) --- username
-- , d timestamp --- date
-- , l varchar2(4000) --- log
-- );
AS
pragma autonomous_transaction;
BEGIN
insert into dbg(u, d, l) values (user, sysdate, p_log);
commit;
END to_dbg_table;
/
or write directly to the DB server that hosts your database
This uses the Oracle directory TMP_DIR
CREATE OR REPLACE PROCEDURE to_dbg_file(p_fname varchar2, p_log varchar2)
-- file mode:
-- requires
--- CREATE OR REPLACE DIRECTORY TMP_DIR as '/directory/where/oracle/can/write/on/DB_server/';
AS
l_file utl_file.file_type;
BEGIN
l_file := utl_file.fopen('TMP_DIR', p_fname, 'A');
utl_file.put_line(l_file, p_log);
utl_file.fflush(l_file);
utl_file.fclose(l_file);
END to_dbg_file;
/
WRITE_LOG
Then the WRITE_LOG procedure which can switch between the 2 uses, or be deactivated to avoid performances loss (g_DEBUG:=FALSE).
CREATE OR REPLACE PROCEDURE write_log(p_log varchar2) AS
-- g_DEBUG can be set as a package variable defaulted to FALSE
-- then change it when debugging is required
g_DEBUG boolean := true;
-- the log file name can be set with several methods...
g_logfname varchar2(32767) := 'my_output.log';
-- choose between 2 logging solutions:
-- file mode:
g_TYPE varchar2(7):= 'file';
-- table mode:
--g_TYPE varchar2(7):= 'table';
-----------------------------------------------------------------
BEGIN
if g_DEBUG then
if g_TYPE='file' then
to_dbg_file(g_logfname, p_log);
elsif g_TYPE='table' then
to_dbg_table(p_log);
end if;
end if;
END write_log;
/
And here is how to test the above:
1) Launch this (file mode) from your SQLPLUS:
BEGIN
write_log('this is a test');
for i in 1..100 loop
DBMS_LOCK.sleep(1);
write_log('iter=' || i);
end loop;
write_log('test complete');
END;
/
2) on the database server, open a shell and
tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
Two alternatives:
You can insert your logging details in a logging table by using an autonomous transaction. You can query this logging table in another SQLPLUS/Toad/sql developer etc... session. You have to use an autonomous transaction to make it possible to commit your logging without interfering the transaction handling in your main sql script.
Another alternative is to use a pipelined function that returns your logging information. See here for an example: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html When you use a pipelined function you don't have to use another SQLPLUS/Toad/sql developer etc... session.
the buffer of DBMS_OUTPUT is read when the procedure DBMS_OUTPUT.get_line is called. If your client application is SQL*Plus, it means it will only get flushed once the procedure finishes.
You can apply the method described in this SO to write the DBMS_OUTPUT buffer to a file.
Set session metadata MODULE and/or ACTION using dbms_application_info().
Monitor with OEM, for example:
Module: ArchiveData
Action: xxx of xxxx
If you have access to system shell from PL/SQL environment you can call netcat:
BEGIN RUN_SHELL('echo "'||p_msg||'" | nc '||p_host||' '||p_port||' -w 5'); END;
p_msg - is a log message
v_host is a host running python script that reads data from socket on port v_port.
I used this design when I wrote aplogr for real-time shell and pl/sql logs monitoring.
This question already has answers here:
Parsing PL/SQL code to check against syntax and semantic errors
(4 answers)
Closed 6 years ago.
I would like to be able to validate that a piece of code is correct using only PL/SQL.
For example, I have the following code in a variable, I would like to validate it:
my_code:='BEGIN
package1.get_wordlist_keywords_PG;
package1.get_wordlist_keyword_cat_PG;
END;
'
I would like to do something like:
result:=validate_code(my_code);
and result would be "valid" or "invalid" (or with error message etc.)
I am sure this would be possible, as Oracle Apex allows users to enter PL/SQL and runs a validation on the code when it is saved.
I am on Oracle 12c.
Thanks!
P.S. - I do not need to validate a simple sql select, it needs to be a PL/SQL code block.
Probably put your code in a procedure instead of anonymous block.
CREATE OR REPLACE PROCEDURE p1 AS
BEGIN
package1.get_wordlist_keywords_PG;
package1.get_wordlist_keyword_cat_PG;
END;
/
show errors;
After the execution, the procedure may or may not be created successfully. Though the procedure is created successfully, the code inside the procedure
is not executed.
CREATE OR REPLACE PROCEDURE VALIDATE_PLSQL
(
PLSQL IN VARCHAR2
, MY_RESULT OUT VARCHAR2
) AS
my_code varchar2(31900);
validate_code varchar2(32000);
status varchar2(4000);
BEGIN
my_code:=PLSQL;
validate_code:='create or replace procedure testp1 AS '||my_code;
BEGIN
status:='PASSED';
EXECUTE IMMEDIATE validate_code;
exception
when OTHERS then
status:='FAILED';
END;
EXECUTE IMMEDIATE 'drop procedure testp1';
MY_RESULT:=status;
END VALIDATE_PLSQL;
Pass in the block to be validated in "PLSQL" get the results in "MY_RESULT"
Clunky, but works!
I am using Oracle/MyBatis and trying to debug a stored procedure with an enormous amount of parameters. Inside the stored procedure I get a ORA-01438: value larger than specified precision allowed for this column
So my initial approach would be to do like dbms_output.put_line in the stored procedure to try to see what the values are right before the offending statement. Without MyBatis, I would ordinarily open up a sqlplus script and type set serveroutput on and then run my stored procedure at some later point to see all the debug messages come out. With MyBatis, I cannot figure out how (if possible) to get these debug statements.
I have the ibatis and sql debuggers set for DEBUG and I use log4j to log everything for my Tomcat 6 application.
The DBMS_OUTPUT package has a few other procedures that you could use. DBMS_OUTPUT.ENABLE functions much like the SQL*Plus command set serveroutput on in that it allocates a buffer for DBMS_OUTPUT.PUT_LINE to write to. DBMS_OUTPUT.GET_LINE can be used to fetch the data written to that buffer by previous calls to DBMS_OUTPUT.PUT_LINE. So it should be possible to call the ENABLE function, call the procedure which writes a number of lines to the buffer, and then call GET_LINE (or GET_LINES) to fetch the data that was written to the DBMS_OUTPUT buffer and write that data to your logs.
It may be simpler, however, to redirect the logging to an Oracle database table rather than trying to use DBMS_OUTPUT. One common approach is to create your own package that has a switch to determine whether to write to DBMS_OUTPUT or whether to write to a table. Something like
CREATE OR REPLACE PACKAGE p
AS
procedure l( p_str IN VARCHAR2 );
END;
CREATE OR REPLACE PACKAGE BODY p
AS
g_destination INTEGER;
g_destination_table CONSTANT INTEGER := 1;
g_destination_dbms_out CONSTANT INTEGER := 2;
PROCEDURE l( p_str IN VARCHAR2 )
AS
BEGIN
IF( g_destination = g_destination_dbms_out )
THEN
dbms_output.put_line( p_str );
ELSE
INSERT INTO log_table ...
END IF;
END;
BEGIN
g_destination := <<determine which constant to set it to. This
may involve querying a `SETTINGS` table, looking
at the environment, or something else>>
END;
END;
I'm trying to call an Oracle stored procedure that accepts no input parameters. However, when running the procedure, I get an error back that states
PLS-00306: wrong number or types of arguments in call to 'MY_PROC'
To call the proc, I'm just entering the following text into TOra:
BEGIN
SCHEMA.MY_PROC();
END;
I've also tried (same error though)
EXEC SCHEMA.MY_PROC();
I'm familiar with MSSQL and I'm able to execute SP with no problem using SQL server, but I can't figure out how to do the same with Oracle. I can't view the actual code for the stored procedure, but from the limited documentation I have, it appears it accepts no input parameters and the return value is a ref cursor. I have a feeling that I need to pass in a ref cursor somehow, but everything I've tried in that regard has not worked.
I just want to view the results of the SP as if I had done a SELECT statement, that is, with the records populating the data grid in the results panel in the TOra interface.
It sounds like the procedure does have an OUT parameter (in Oracle, procedures do not return anything but can have OUT and IN OUT parameters, functions return something). So you would have to pass in a variable for that OUT parameter. Something like
DECLARE
l_results SYS_REFCURSOR;
BEGIN
schema.my_proc( l_results );
END;
should successfully call the procedure. But then you want your GUI to display the results from that cursor. That, unfortunately, gets a little more complicated because now you're talking about a GUI-specific issue.
I don't use TOra, so I don't know what you need to do in TOra to get the cursor to display. In SQL*Plus (or SQL Developer, Oracle's free GUI), you could do something like
create or replace procedure my_proc( p_rc OUT SYS_REFCURSOR )
as
begin
open p_rc
for select 1 col1
from dual;
end;
/
variable rc refcursor;
exec my_proc( :rc );
print rc;
This creates a stored procedure with an OUT parameter that is a cursor, declares a host variable that can be passed in, and then prints the results.