SYS_REFCURSOR out parameter - running stored procedure fails - oracle

I come from a SQL Server background but I'm struggling with this in Oracle. All of the sprocs in the database that's been configured expect a parameter passed in of type 'sys_refcursor'. In a nutshell, they do this (the sprocs are far more complex, but the whole cursor thing is what I'm getting at) :
CREATE OR REPLACE PROCEDURE xxx_API_TEST
(
TESTCURSOR OUT SYS_REFCURSOR
) AS
BEGIN
OPEN CURS FOR
SELECT * FROM SOMETABLE;
END xxx_API_TEST;
So - in Oracle SQL Developer I can run this no problem - and view the output of the cursor in the Output Variables window.
However, rather than have to keep reloading the dialog each time I want to retest it - I figured it'd be possible to copy the PL/SQL in the dialog to a new worksheet, and then just run that as I needed to - adjusting parameters to suit - so in this case, I'd run :
DECLARE
TESTCURSOR SYS_REFCURSOR;
BEGIN
xxx_API_TEST(
TESTCURSOR => TESTCURSOR
);
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('TESTCURSOR = ' || TESTCURSOR );
*/
:TESTCURSOR := TESTCURSOR; --<-- Cursor
--rollback;
END;
Which is exactly the same as that shown in the Run dialog.
However, if I do this - it just throws an error - stating:
Error starting at line : 1 in command -
<snip>
Error report -
ORA-06550: line 11, column 20:
PLS-00382: expression is of wrong type
ORA-06550: line 11, column 3:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I've no idea how to go about diagnosing this one. The fact it runs fine from the dialog but not the worksheet is puzzling - and inspecting what was sent to the DB I can't see any differences in the SQL it actually used.
Interestingly if I run this code from the worksheet - it pops up a dialog to ask for the value for TESTCURSOR - which the 'Run' dialog doesn't do. I just press OK - but I've tried both ticking and unticking the 'Null' checkbox to no avail.
Any help very much appreciated. It's Oracle 12c. If you need any more info just let me know.
Cheers,
Tony
Update: 20/7/2016
I ended up pulling the values into variables from a fetch, and just dumping to dbms_output - which gives me what I needed to repeatedly run the same sproc.
e.g.
loop
fetch testcursor into Res, ActDate<snip>;
exit when testcursor%notfound;
DBMS_OUTPUT.PUT_LINE(Res || ' | ' || ActDate etc etc);
end loop;
close testcursor;

The Run dialog is generated from the procedure spec and therefore knows the correct type for testcursor, but when you just paste it into a worksheet it doesn't, and it seems to define it as a text string. As of SQL Developer 4.0.3.16 the worksheet bind value prompt doesn't seem to have a way to change the datatype.
As for how to create a reusable test script with a cursor output in SQL Dev, I don't know. (I normally use PL/SQL Developer which can do this, but it's not free software.)
Edit: in this thread a solution was to write a wrapper function and select it from dual. I've just tried and you don't get a grid, but you get a kind of debug output without too much effort:
Oracle SQL Developer: Show REFCURSOR Results in Grid?

Related

Object is invalid PLSQL Procedure

I use a dataset that has billing information:
Table Image
And I want to create a procedure that gives information about a specific bill by giving an invoice id
CREATE OR REPLACE PROCEDURE print_information(
invoiceID varchar(11);
) IS
p_smtable supermarket%ROWTYPE;
BEGIN
SELECT * INTO p_smtable FROM SUPERMARKET
WHERE invoice_id = invoiceID;
DBMS_OUTPUT.PUT_LINE(p_smtable.brancj || p_smtable.city);
END;
The compilation is successful.
Compile
begin
print_information('750-67-8428');
end;
But I get an error that says:
Error starting at line : 12 in command -
begin
print_information('750-67-8428');
end;
Error report -
ORA-06550: line 2, column 1:
PLS-00905: object SYSTEM.PRINT_INFORMATION is invalid
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The code in the screenshot is different to the version in your question, but both have an error at line 2. The parameter should be varchar2 or supermarket.invoice_id%type, with no semicolon.
Also, we normally use a p_ prefix for parameters, not variables. (There are other conventions, but whatever you use, p_ for a variable is just confusing.)
A fixed version might be:
create or replace procedure print_information
( p_invoice_id supermarket.invoice_id%type )
as
l_market supermarket%rowtype;
begin
select * into l_market
from supermarket
where invoice_id = p_invoice_id;
dbms_output.put_line(l_market.brancj || ' '|| l_market.city);
end;
Whatever tool you are using for development, you need to become familiar with how to display compilation errors.
brancj might be a typo for branch.
I've assumed you want a space between branch and city, otherwise the output would be something like TottenhamLondon rather than Tottenham London.
In Oracle a schema belongs to one user, created with the CREATE USER command. An Oracle Database is the entire thing (all users, all data, storage, memory, processes, everything) so you would not normally create one for something like this.

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

Oracle basic multi-statement block

In SQL Server, multiple statements in SSMS can be performed. In Oracle (using toad), I don't know why I receive certain errors doing the same thing. For example, I assume an Oracle requirement is to place them in a block, but I still get the following:
DECLARE
v_datetime TIMESTAMP := SYSDATE;
BEGIN
insert into sometable_log values (v_datetime, 'this is a test ',1);
select * from sometable_log where event_dt = v_datetime;
END;
produces:
[Error] Execution (5: 1): ORA-06550: line 4, column 1: PLS-00428: an
INTO clause is expected in this SELECT statement
Why would I need to use an into clause? Can someone please help me understand what this is?
Thank you!
When executing the block of code, Oracle expects that the select command should have some code-like effect. That's why it wants you to add the into clause.
To do what you need, just move the select statement outside of the PL/SQL begin/end block.

Running PL/SQL script in PHP

I have a script in PL/SQL , that drop some tables , sequences , triggers, and creating them again in the same script , I need this script in my website for deleting all data from database (and I want to acces this script pressing one button on website) so I tried to do a function / procedure in PL/SQL that read line by line from the script file and executing every line with dynamic sql , everything went ok till one error at:
CREATE OR REPLACE TRIGGER players_bir BEFORE INSERT ON players FOR EACH ROW BEGIN SELECT players_seq.NEXTVAL INTO :new.id FROM dual END
this gave me the error:
ORA-24344: success with compilation error
I searched for solutions, but I didn't find anything.
You are missing the semi-colon after dual on your SELECT statement. This ORA error generally means you compiled some code, but that is has some issue.
CREATE OR REPLACE TRIGGER players_bir
BEFORE INSERT ON players
FOR EACH ROW
BEGIN
SELECT players_seq.nextval
INTO :new.id
FROM dual;
END
Looking in all_errors will show you what the issue is or you could manually compile this trigger in some IDE (like SQL Developer) and that should also make it obvious.
SELECT *
FROM all_errors e
WHERE e.name = 'PLAYERS_BIR'
AND e.type = 'TRIGGER';
Additionally if all you are using your trigger for is to set some identity column and you are on Oracle 12c you can use some of the new features to accomplish this. Triggers are inherently slow and the new identity feature performs about as good as referencing the sequence directly in your INSERT.

How to make Oracle error messages more verbose?

The message that drives me crazy is ORA-01008 - Not all variables bound.
Is there a way to know which one of the 42 possible variable names I have misspelled without staring at the monitor till my eyes pop out?
Update: I use ADO.NET to access the database. Perhaps it does lose some information in Oracle exceptions, as #Justin Cave has suggested. But I'm positive that the parameter name never appears even in SQL Plus.
In general, Oracle provides the line and column number of any errors, but it is up to the particular API you are using (unless you happen to be writing an OCI application, which is probably unlikely) as to whether and how those APIs are called. Since the answer is likely to end up being API-specific, what API are are you using and what does your code look like when the error occurs (i.e. JDBC, ODBC, OLE DB, etc)?
As an example, if I write a PL/SQL block with a misspelled variable name, SQL*Plus will report the line and column number of the error in addition to the error message. Many APIs, on the other hand, will just report the PLS-00201 error by default.
SQL> declare
2 i integer;
3 begin
4 j := 1;
5 end;
6 /
j := 1;
*
ERROR at line 4:
ORA-06550: line 4, column 3:
PLS-00201: identifier 'J' must be declared
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
Similarly, if you execute a SQL statement with an invalid variable name, SQL*Plus will get the column and line position and put a * under the offending character, i.e.
SQL> create table a( col1 number );
Table created.
SQL> insert into a( colN ) values ( 1 );
insert into a( colN ) values ( 1 )
*
ERROR at line 1:
ORA-00904: "COLN": invalid identifier
Most PL/SQL IDE's (TOAD, SQL Developer, etc.) will do something similar by interrogating the appropriate OCI APIs under the covers. Precisely how this is done, however, will depend on the API.
I don't know of any way to get Oracle to make the error more specific. Maybe some future version will improve this error message.
Instead of just staring at it, though, there are other things you can try. For example, convert each variable in the SQL statement to a literal one at a time, until the error goes away. If possible, generate the list of variable names instead of typing them manually.

Resources