datagrip debug oracle tips please - oracle

anyone here with general tips debugging oracle routines and/or packages with DataGrip (even getting them to start/work/debug)?
Issues I have are:
1 Me not understanding the last part of the code dataGrip generates
declare
result NUMBER;
someVar := 300198032;
begin
result := FN_GET_CLIENT_ORG_SEQ(V_someVar => someVar );
open ? for select result as result from dual;
end;
at the end has this " open ? for select result as result from dual; ", what the heck is the open ?
When clicking the button to debug it brings out this dialogue, tried different combinations (numbers, strings, etc.) but oracle complaints and does not run, I end up commenting that line in order to debug.
image of the dialogue
2 When doing stepping, I noticed that after entering some statements, the debug buttons get disabled (step over, step into, etc). Basically DataGrip just keeps thinking/hangs and I cannot continue to debug.
Example, in this case I have to step over in order for debug to keep working, if I do step into, it hangs
SELECT something, something
INTO somethingInto
FROM some table
Another example,
any End statmens (that define the ending of the routine) need to be stepped over if not DataGrip hangs or goes into limbo.
3 Seems to be harder to have DataGrip debug routines contained in packages, either the debug process has issues starting, or step overs are probably the safest way to get it to work.
Any pro tips would be greatly appreciated

I don't know Datagrip so I can't help.
However, see if this helps with
what the heck is the open ?
Looks like a refcursor business. The following code uses the same open you saw in your code. It fetches employees that work in department whose deptno is equal to the result local variable's value.
SQL> set serveroutput on
SQL> declare
2 result number := 10;
3 rc sys_refcursor; --> this is your "?" - a refcursor
4 l_name emp.ename%type;
5 begin
6 open rc for select ename from emp --> this is your "open"
7 where deptno = result;
8
9 -- the following code just displays what's being fetched
10 loop
11 fetch rc into l_name;
12 exit when rc%notfound;
13 dbms_output.put_line(l_name);
14 end loop;
15 close rc;
16 end;
17 /
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL>

Aight, seems that things are now smoother thanks to "stepping over most of the "selects" or "end" lines. (avoids datagrip to hang/enter limbo)
Also replacing the ? by declaring a sys_refcursor, captures/shows the results, while debugging
declare
result NUMBER;
someVar := 300198032;
rc sys_refcursor; -- < -- HERE
begin
result := FN_GET_CLIENT_ORG_SEQ(CLIENT_ID => someVar );
-- HERE (below)
open rc for select result as result from dual;
end;

Related

Can I drop PL/SQL procedure in Anonymous block just after called the same procedure?

I have created a PL/SQL stored procedure which is used to insert row into related table, then in another PL/SQL Anonymous block, I can call and drop it separatly. But when put these two statements togegher, Sql developer was just continuously running there forever. Below are three code snippets:
-- Below code works well
BEGIN
MyProcedure1 (1,70,'Tommy');
END;
-- Below code works well
BEGIN
EXECUTE IMMEDIATE 'drop procedure MyProcedure1';
END;
-- Below code was stuck there forever
BEGIN
MyProcedure1 (1,70,'Tommy');
EXECUTE IMMEDIATE 'drop procedure MyProcedure1';
END;
David, I can still see no reason why after the data is inserted you need to immediately drop the procedure.... what if you want to insert more data tomorrow? Why can you not just manually drop it afterwards if it is just a once off thing?
However if you really must do so...
BEGIN
MyProcedure1 (1,70,'Tommy');
END;
/
drop procedure MyProcedure1;
Then click run as script button in SqlDeveloper... Runs no issue, looking at session manager what is happening is that the anonymous block is putting the procedure in the cache / pinning it (meaning nothing else can compile / drop it) until that block finishes. This is why moving the drop outside the Begin / End allows the code to work.
If you query v$session, this is what you can see (of course, while the anonymous PL/SQL block is still "running" - actually, it is waiting):
SQL> select
2 a.blocking_session,
3 b.username blocking_username,
4 b.osuser blocking_osuser,
5 a.sid,
6 a.serial#,
7 a.seconds_in_wait,
8 a.username,
9 a.wait_class,
10 a.state
11 from v$session a join v$session b on a.blocking_session = b.sid;
BLOCKING_SESSION BLOCKING_USERNAME BLOCKING_OSUSER SID SERIAL# SECONDS_IN_WAIT USERNAME WAIT_CLASS STATE
---------------- ----------------- --------------- ---- -------- --------------- -------- ----------- -------
707 SCOTT littlefoot 707 1245 329 SCOTT Concurrency WAITING
SQL>
Note the last two columns:
state = waiting
wait_class = concurrency
Who caused it? Me, myself. So yes - we have met the enemy, and they is us.
Looks like you can't do it the way you wanted but separately:
call the procedure first
once you're done, drop it
Though, what a strange requirement ... why would you want to drop a procedure? Will you create it again tomorrow? If so, why drop it at all? Saying that "customer requires it" - what the heck customer knows about it? Let them think twice; if that's not enough, think again.

When and how we should we write the application logs for the execution of stored procedure(Oracle DB)?

I want to know what are the thumb rules/guidlines to write the logs of a stored procedure(application programs). Normally we use 2 methods:
1) Use UTL_FILE package to write the logs into files(separate files for every run).
2) Use Log4pl package to write the the different logs(dignostic,Error,Warning or Fatal) into a table.
Almost for every procedure we use above 2 methods depending on what we are writing. Like for fatal error we use Log4pl and for some information display(like which record its processing we write that in file).
Would like to know how other organizations maintaining logs ? Do they also follow aboe 2 methods or they use only one? on what basis its been decided?
Note: I am looking for logs writting only for application programming not for Databse.
Any suggestions or links to blogs would be great. Thanks.
one more way you can implement logging mechanism in oracle application-
-> splunk
UTL_FILE isn't really going to scale well for writing log files, eg
SQL> create table log_table (
2 s timestamp default systimestamp,
3 m varchar2(1000)
4 );
Table created.
SQL>
SQL> set timing on
SQL> begin
2 for i in 1 .. 10000 loop
3 insert into log_table (m) values ('My message');
4 commit;
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.62
SQL>
SQL> declare
2 f utl_file.file_type;
3 begin
4 f := utl_file.fopen('TMP','logfile.dat','W');
5 for i in 1 .. 10000 loop
6 utl_file.put_line(f,to_char(systimestamp)||' '||'My message');
7 utl_file.fflush(f);
8 end loop;
9 utl_file.fclose(f);
10 end;
11 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:30.58
Now you might be thinking "I'll just remove the utl_file.fflush(f) call" which indeed will make it run in a comparable time to the database table. But the time when you most need that logging information is when your program crashes - and if it crashes, and you have not flushed, then you run the risk of losing the recent logging information that is critical for knowing why your program crashed.

Struggling to write Oracle Sql Query using Substitution Variables

I'm trying to take some of our more complicated queries and make them as user friendly as possible. For various reasons, we can't/would prefer not to bake them into the schema. Thus, I'm trying to write a version of a query we have to run regularly to simplify entering some of the parameters. My current option is to find-replace the pertinent values each time I have to run it, which is less than ideal.
I'd like to leverage TOAD's support of substitution variables (where if one of these is present, it prompts the user to enter the intended values then runs the whole query).
I've attempted to set up a test query to familiarize myself with the process, but it's not behaving as expected.
DECLARE
&&v_value VARCHAR2 (200);
v_result VARCHAR2 (200);
BEGIN
select &v_value into v_result from dual;
dbms_output.PUT_LINE('result :'|| to_char(v_result));
END;
The result is
result :
Which is of course less than ideal. My expectation is for it to be
result : some_value
Where 'some_value' was the text I entered into the TOAD prompt window.
The reason I need this to work is so that we can treat this as a procedure and pass it the values it needs once and use it throughout the series of queries we have to run. I'm not very familiar or adept with building these kids of queries, so any help or guidance would be appreciated.
I was planning on running it via TOAD's SQL editor window.
The actual procedure I need to run is actually a series of updates and inserts; I used a select as a test case to ensure I understood how to use them.
It looks like you're having a problem with assigning a value to the parameter. I would use the following syntax as it both avoids doing an unnecessary context switch and allows you to do exception handling on the value passed.
DECLARE
v_value VARCHAR2(200);
v_result VARCHAR2(200);
BEGIN
v_value := '&input';
v_result := v_value;
dbms_output.put_line('result : ' || v_result);
END;
/
Given that you're running your series of select statements in Toad - presumably as a script - I fail to see why you need a procedure at all.
You could just use the parameter in your queries like so (making sure to run as a script):
set verify on;
select '&&v_val' value from dual;
select * from dual
where dummy = '&&v_val';
old: select '&&v_val' value from dual
new: select 'X' value from dual
VALUE
-----
X
1 row selected.
old: select * from dual
where dummy = '&&v_val'
new: select * from dual
where dummy = 'X'
DUMMY
-----
X
1 row selected.
(I deliberately set the verify to be on so that you could see the results of what happens when running the above two statements as a script; you might prefer to switch it off.)

How to test an Oracle Stored Procedure with RefCursor return type?

I'm looking for a good explanation on how to test an Oracle stored procedure in SQL Developer or Embarcardero Rapid XE2. Thank you.
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;
will work in SQL*Plus or SQL Developer. I don't have any experience with Embarcardero Rapid XE2 so I have no idea whether it supports SQL*Plus commands like this.
Something like this lets you test your procedure on almost any client:
DECLARE
v_cur SYS_REFCURSOR;
v_a VARCHAR2(10);
v_b VARCHAR2(10);
BEGIN
your_proc(v_cur);
LOOP
FETCH v_cur INTO v_a, v_b;
EXIT WHEN v_cur%NOTFOUND;
dbms_output.put_line(v_a || ' ' || v_b);
END LOOP;
CLOSE v_cur;
END;
Basically, your test harness needs to support the definition of a SYS_REFCURSOR variable and the ability to call your procedure while passing in the variable you defined, then loop through the cursor result set. PL/SQL does all that, and anonymous blocks are easy to set up and maintain, fairly adaptable, and quite readable to anyone who works with PL/SQL.
Another, albeit similar way would be to build a named procedure that does the same thing, and assuming the client has a debugger (like SQL Developer, PL/SQL Developer, TOAD, etc.) you could then step through the execution.
In SQL Developer you can right-click on the package body then select RUN. The 'Run PL/SQL' window will let you edit the PL/SQL Block. Clicking OK will give you a window pane titled 'Output Variables - Log' with an output variables tab. You can select your output variables on the left and the result is shown on the right side. Very handy and fast.
I've used Rapid with T-SQL and I think there was something similiar to this.
Writing your own delcare-begin-end script where you loop through the cursor, as with DCookie's example, is always a good exercise to do every now and then. It will work with anything and you will know that your code works.
In Toad 10.1.1.8 I use:
variable salida refcursor
exec MY_PKG.MY_PRC(1, 2, 3, :salida) -- 1, 2, 3 are params
print salida
Then, Execute as Script.
I think this link will be enough for you. I found it when I was searching for the way to execute oracle procedures.
The link to the page
Short Description:
--cursor variable declaration
variable Out_Ref_Cursor refcursor;
--execute procedure
execute get_employees_name(IN_Variable,:Out_Ref_Cursor);
--display result referenced by ref cursor.
print Out_Ref_Cursor;
create or replace procedure my_proc( v_number IN number,p_rc OUT SYS_REFCURSOR )
as
begin
open p_rc
for select 1 col1
from dual;
end;
/
and then write a function lie this which calls your stored procedure
create or replace function my_proc_test(v_number IN NUMBER) RETURN sys_refcursor
as
p_rc sys_refcursor;
begin
my_proc(v_number,p_rc);
return p_rc;
end
/
then you can run this SQL query in the SQLDeveloper editor.
SELECT my_proc_test(3) FROM DUAL;
you will see the result in the console right click on it and cilck on single record view and edit the result you can see the all the records that were returned by the ref cursor.

how do oracle stored procedures (w/ cursors) work?

I have a following oracle stored procedure
CREATE OR REPLACE
PROCEDURE getRejectedReasons
(
p_cursor IN OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_cursor FOR SELECT * FROM reasons_for_rejection;
END;
However, when I run this stored procedure in sql-developer then I dont see anything. I just see something like this:
Connecting to the database oracleLocal.
Process exited.
Disconnecting from the database oracleLocal.
I'm coming from MS sql server and am used to seeing actual results when running a stored procedure like this. Is this stored procedure not returning results because I am using a cursor??
The stored procedure is returning something it's just you aren't doing anything with the results.
You can do this simply by running the following script in SQLDeveloper:
VARIABLE csr REFCURSOR;
EXEC getRejectedReasons(:csr); -- the colon identifies the parameter as a variable
PRINT csr;
Another method is to fetch each row and do some sort of processing:
DECLARE
-- sys_refcursor is weakly typed
refcsr SYS_REFCURSOR;
-- define a record so we can reference the fields
rej_rec Reasons_for_Rejection%ROWTYPE;
BEGIN
getRejectedReasons(refcsr);
-- loop through the results
LOOP
-- gets one row at a time
FETCH refcsr INTO rej_rec;
-- if the fetch doesn't find any more rows exit the loop
EXIT WHEN refcsr%NOTFOUND;
-- Do something here.
-- For example : DBMS_OUTPUT.PUT_LINE(rej_rec.reason_desc);
END LOOP;
END;
You opened the cursor. You didn't select anything from it, update it, or advance it.
All open does, effectively, to select the matching rows into temporary memory, so you can advance the cursor row by row. Which you didn't do.
One of the differences between Oracle and SQL Server is that the latter returns result sets naturally. I'd use a function, by the way.
In Oracle, functions typically return a single element. Cursors came later.
There's some documentation online that will help you understand the use of refcursor bind variables. Here's one such for SQL*Plus:
http://download.oracle.com/docs/cd/B19306_01/server.102/b14357/ch5.htm#sthref1122
I think in SQL Developer you can do the same thing with autoprint on, although I haven't tested that.
Found a blog that also discusses something similar:
http://vadimtropashko.wordpress.com/cursors/
ETA: Ok. Ignore what I wrote. Listen to someone else. Apparently it's wrong, as I got down voted.
What tpdi said is correct. You have to do something with the cursor after you declare it.
Here's an example using two cursors in nested loops
PROCEDURE update_insert_tree (exid_in IN NUMBER, outvar_out OUT VARCHAR2)
IS
nxtid NUMBER;
phaseid NUMBER;
rowcounter1 NUMBER;
BEGIN
rowcounter1 := 0;
outvar_out := 0;
FOR acur IN (SELECT dept_exercise_id, phase
FROM ep_dept_exercise
WHERE exercise_id = exid_in)
LOOP
<<dept_loop>>
FOR thecur IN (SELECT document_name, thelevel, sortnum, type_flag,
ex_save_id
FROM ep_exercise_save
WHERE exercise_id = exid_in)
LOOP
phaseid := acur.phase;
IF phaseid = 0
THEN
phaseid := 10;
UPDATE ep_dept_exercise
SET phase = 10
WHERE dept_exercise_id = acur.dept_exercise_id;
END IF;
<<doc_loop>>

Resources