Equivalent to SQLERRM when no error? - oracle

Does anyone knows if there is an equivalent to SQLERRM when no error occurred?
I know I can count the affected rows like here, but can I automatically get the message I would get from SQLPLUS e.g. role granted. after an execute immediate in PL/SQL?
I am trying to do
begin
execute immediate 'grant select on s1.tbl1 to user1';
dbms_output.put_line(<some function>);
end;
and get
Grant succeeded.
Thanks,
J

Feedback like "Grant succeeded." is the feature of sqlplus.
If you enable SQL*Net tracing (details http://docs.oracle.com/cd/E11882_01/java.112/e16548/apxtblsh.htm#JJDBC28987 or http://www.juliandyke.com/Diagnostics/Trace/NetTrace.php) you will see that string "Grant succeeded" is NOT something client application sqlplus receives from Oracle.
So how does it know what to display? Because sqlplus has privimitive mechanism of checking command type before sending it to server. If you type non-existend command then it will not be even sent to server (you can check that also in SQL*NET trace).
Moreover you can check list of commands if you open binary of sqlplus as text and search for string "grant", for example (bottom left corner on screenshot).
In below case there will be no exchange with server because command is intentionally wrong.
SQL> some_command
SP2-0734: unknown command beginning "some_comma..." - rest of line
ignored.
So Oracle knows command type before sending SQL text to server and for some commands it receives additional information after execution. Like number of rows affected for DML. This information is enough to display "feedback".
Back to your task, the easiest way would be to implement primitive parsing of first 1-3 words of the command and display correponding message if no errors occured.
Hardcore option is to enable SQL tracing and derive command type from trace file.
=====================
PARSING IN CURSOR #3 len=31 dep=0 uid=91 oct=17 lid=91 tim=2178486867995 hv=3483936374 ad='b967c6a4' sqlid='10y8y7m7uj9mq'
grant execute on <...> to <...>
END OF STMT
PARSE #3:c=0,e=614,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=2178486867994
=====================
oct means Oracle Command Type
SQL> select command_name from v$sqlcommand where command_type = 17;
COMMAND_NAME
----------------------------------------------------------------
GRANT OBJECT
Another option is to enable Audit but my preference would be to keep it simple.

If it is only the output for success message is what we are concerned, then simply using exceptions would help.
SET SERVEROUTPUT ON
BEGIN
execute immediate 'grant select on s1.tbl1 to user1' ;
dbms_output.put_line('Grant succeeded');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Grant Failed');
procedure_to_log_error(SQLERRM);
END;

Related

View results of pl/sql stored procedure in Toad?

I'm new to Oracle, and I use Toad Data Point to create and test stored procedures.
I created this simple stored procedure:
CREATE OR REPLACE PROCEDURE dummy_sp (
p_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN p_recordset FOR
select sysdate, user from dual;
END dummy_sp ;
/
I executed this, and the result from Toad is Executed Successfully.
Now, I would like to view the results of this stored procedure. In Toad Data Point I type the following:
variable mycursor refcursor;
call dummy_sp ( :mycursor );
I get a popup asking for a parameter. I click OK and I get the error ORA-00900: invalid SQL statement.
How can I see the result of SP dummy_sp in Toad Data Point?
In SQL Server I can run exec usp_sales and see the results of a select statement. There has to be something like that in Oracle and Toad, right?
Here you go, using Toad Data Point.
Execute the stored procedure with a bind variable in it, like :mycursor, and then make sure to configure the type as CURSOR and direction as OUT when Toad Data Point prompts you for the bind variable settings.
Here's the result:
Finally, if you wish to avoid the popup for bind variables, you can execute the procedure directly from the object explorer:
Right-click the procedure and choose Operations / Execute Procedure, and Toad will run it, without prompting for data type.
In case you need a workaround while you wait for help with your tool, the default, free IDE for Oracle Database makes this pretty easy.
If you execute the program using the code editor, it will automatically grab any outputs, whether those be OUT params or RETURNs from a function, including your refcursor
Or if your GUI has proper SQLPlus script execution support (SQL Developer does, not sure about your program):
var x refcursor
exec dummy_sp(:x);
print :x;
And the output:
PL/SQL procedure successfully completed.
SYSDATE USER
------------------- --------------------------------------------------------------------------------------------------------------------------------
27-JUN-19 13.58.47 HR

Weblogic JDBC Connections: multi-statement init SQL

When setting up a data source in WLS we can give it an init SQL statement, which is executed immediately after creation of every connection for this data source.
So far we are using..
SQL ALTER SESSION SET current_schema=user01
.. as we are logging in using an application user02 which has less rights than the owner user01, but we still want the data source to see the schema.
Now we'd like to add some session meta information to the DS connections, for debugging purposes on the DB side. The statements..
DBMS_APPLICATION_INFO.set_client_info('bar');
DBMS_APPLICATION_INFO.set_module('qux', 'garp');
.. allow you to set custom strings as identifiers, which will then show up in colums of V_$SESSION, thus giving the DBA some more information about a DB connection.
My problem
How is it possible to have multi-line init SQL statements? Note that the init SQL syntax expects an SQL command which is preceded by SQL and which does not end in a semicolon ;.
Edit:
What I tried so far is something along the lines of..
begin
execute immediate 'ALTER SESSION SET current_schema=uzms01';
DBMS_APPLICATION_INFO.set_client_info('bar');
DBMS_APPLICATION_INFO.set_module('qux', 'garp');
end;
.. but I keep getting errors. :(
Looks like there was a small syntax irregularity which I did not spot because SQL developer executes it without problems...
The following snippet works (note the parentheses after immediate):
SQL BEGIN
execute immediate('alter session set current_schema=user01');
DBMS_APPLICATION_INFO.set_client_info('my client');
DBMS_APPLICATION_INFO.set_module('my module', 'my action');
END;

The Pl/SQL Code doesn't give any output [duplicate]

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.

DDL Statements in DBMS_JOB

I am trying to schedule a job using DBMS_JOB (I can't use DBMS_SCHEDULER for security reasons), which uses a DDL statement.
DECLARE
job_num NUMBER;
BEGIN
DBMS_JOB.SUBMIT(job => job_num,
what => 'BEGIN EXECUTE IMMEDIATE ''CREATE TABLE temp1 (ID NUMBER)''; END;'
);
DBMS_OUTPUT.PUT_LINE('JobID'||job_num);
DBMS_JOB.RUN(job_num);
END;
/
It fails to execute giving me an error message :
ORA-12011: execution of 1 jobs failed
ORA-06512: at "SYS.DBMS_IJOB", line 548
ORA-06512: at "SYS.DBMS_JOB", line 278
ORA-06512: at line 8
On removing the DBMS_JOB.RUN() statement from inside the anonymous block, I am able to at least create (and save) the job. When I check the job, it has saved this as the code to execute
BEGIN EXECUTE IMMEDIATE 'CREATE TABLE temp1 (id NUMBER) '; END;
If I execute it standalone, it obviously executes. The only time it fails it when I try to execute the entire thing through the call to DBMS_JOB.RUN().
Is there a restriction on using DDL statements as a parameter in DBMS_JOB? I can't find any pointer in documentation for this.
While echoing the sentiments of the other commenters-- creating tables on the fly is a red flag that often indicates that you really ought to be using global temporary tables-- a couple of questions.
Is there a reason that you need the DBMS_JOB.RUN call? Your call to DBMS_JOB.SUBMIT is telling Oracle to run the job asynchronously as soon as the parent transaction commits. So, normally, you'd call DBMS_JOB.SUBMIT and then just `COMMIT'.
Does the user that is submitting job have the CREATE TABLE privilege granted directly? My guess is that the user only has the CREATE TABLE privilege granted via a role. That would allow you to run the anonymous PL/SQL block interactively but not in a job. If so, you'll need the DBA to grant you the CREATE TABLE privilege directly, not via a role.
When a job fails, an entry is written to the alert log with the error message. Can you (or, more likely, the DBA) get the error message and the error stack from the alert log and post it here (assuming it is something other than the privileges issue from #2).

Oracle scheduler job log output

I'm using dbms_scheduler to execute a PL/SQL stored procedure. I would like to be able to have that code create some text logging output and associate it with the run to verify it's working, but I can't find anything to do that in the docs. Is there a facility to do this that I'm missing? This is an 11g database running under Unix. It would be real nice if I could use dbms_output so I could also run it from sqlplus and get output.
There are a bunch of Oracle Scheduler data dictionary views that will help you monitor jobs. Here are two documentation pages related to that:
Monitoring Jobs
Monitoring and Managing the Scheduler
Moreover, Oracle Scheduler declares some internal Scheduler variables that you can use like any other PL/SQL identifier in your PL/SQL stored procedure. Here is the list of these variables.
If you want to log application specific information, I suggest you create your own log table. You can then insert into this table from within your stored procedure. You can even insert any of the Scheduler's internal variables there, like job_name and job_scheduled_start.
i make a table JOB_LOG
insert into that table from inside your procedure...
I agree with what the others have said. Here's the actual nuts and bolts, but with a nice interface, too. The way I typically do this:
Make a logging table:
CREATE TABLE job_log (
ts TIMESTAMP DEFAULT SYSTIMESTAMP PRIMARY KEY
, message VARCHAR2(255)
);
Make a stored proc that easily writes into your log table:
CREATE OR REPLACE PROCEDURE job_logger (v_message VARCHAR2)
IS
BEGIN
INSERT INTO job_log(message) VALUES (v_message);
COMMIT;
END;
/
Then within your job, you are probably running a stored procedure. Within your own stored procedure, simply add lines that call the job_logger() procedure to write to your log. This keeps the ugly INSERT ... COMMIT clutter out of your interesting stored proc code.
CREATE OR REPLACE PROCEDURE foo
IS
BEGIN
job_logger('Starting job foo.');
...
{your code here}
...
job_logger('Another message that will be logged.');
...
job_logger('Completed running job foo.');
EXCEPTION
...
job_logger('Oops, something bad happened!');
...
END;
/
Your log table is automatically timestamped and indexed by the primary key. To view the log, you might run this
SELECT * FROM job_log ORDER BY ts DESC;
Now if would rather not use the Oracle scheduler, and want instead to use the DBMS_OUTPUT way of writing output, and want to run this under a Unix shell, that is possible also.
You would make a script that calls sqlplus, somewhat like this. If your user is SCOTT and the stored proc is called FOO,
#!/bin/sh
. /whatever/script/that/sets/your/oracle/environment
echo "
set serveroutput on feedback off
exec foo
" | sqlplus -s -l scott/tiger#orcl
Note, the -s flag suppresses the Oracle SQL Plus banner for cleaner output. The -l flag makes it so that sqlplus will abort if the password is bad or something else wrong, rather than try to prompt for username. Feedback off suppresses the PL/SQL "Anonymous block completed" message.
If you want to schedule this, you can call it from cron like this:
00 00 * * * /path/to/the/above/script.sh > /where/you/want/your/output/saved.log 2>&1

Resources