Oracle DBMS_PIPE not working correctly - oracle

I have written a small proc as below:
PROCEDURE write_ToPipe ( i_key1 VARCHAR2,
i_value1 VARCHAR2,
i_key2 VARCHAR2,
i_value2 VARCHAR2,
i_key3 VARCHAR2,
i_value3 VARCHAR2,
i_key4 VARCHAR2,
i_value4 VARCHAR2,
i_key5 VARCHAR2,
i_value5 VARCHAR2 )
IS
result INTEGER;
buffer_overflow EXCEPTION;
PRAGMA EXCEPTION_INIT(buffer_overflow, -06558);
BEGIN
-- Packing the key value paires to the local buffer
dbms_pipe.pack_message(i_key1);
dbms_pipe.pack_message(i_value1);
dbms_pipe.pack_message(i_key2);
dbms_pipe.pack_message(i_value2);
dbms_pipe.pack_message(i_key3);
dbms_pipe.pack_message(i_value3);
dbms_pipe.pack_message(i_key4);
dbms_pipe.pack_message(i_value4);
dbms_pipe.pack_message(i_key5);
dbms_pipe.pack_message(i_value5);
-- sending the message to the pipe
result := dbms_pipe.send_message(pipename => 'DB_PIPE',timeout => 5);
EXCEPTION
WHEN buffer_overflow THEN
-- If the buffer overflow excetion reset the local buffer and pack the messages again
dbms_pipe.reset_buffer;
dbms_pipe.pack_message(i_key1);
dbms_pipe.pack_message(i_value1);
dbms_pipe.pack_message(i_key2);
dbms_pipe.pack_message(i_value2);
dbms_pipe.pack_message(i_key3);
dbms_pipe.pack_message(i_value3);
dbms_pipe.pack_message(i_key4);
dbms_pipe.pack_message(i_value4);
dbms_pipe.pack_message(i_key5);
dbms_pipe.pack_message(i_value5);
-- sending the message to the pipe
result := dbms_pipe.send_message(pipename => 'DB_PIPE',timeout => 5);
END write_ToPipe;
I call this proc from others procs (as below).
proc A
begin
write_ToPipe( 'TEST1','TEST2', 'TEST3','TEST4','TEST5','TEST6','TEST7','TEST8','TEST9','TEST10',);
proc B;
end
proc b
begin
write_ToPipe( 'SOMETEST1','SOMETEST2', 'SOMETEST3','SOMETEST4','SOMETEST5','SOMETEST6',NULL,NULL,NULL,nULL);
end
there is another proc I have written to unpack the msgs and write into the flat file (not shown here)
The issue is content from proc A is getting generated into the flat file but not from proc B
After debugging I found that from proc B the write_ToPipe is called but the control comes out without throwing any exception after the following line.
dbms_pipe.pack_message(i_key1);
Can you please help to solve this?
I am using Oracle 10gR2.
Thanks and Regards,
Chandra

This could be the problem with Oracle 10g. Please check with Oracle support about this.
You may also try the same program in 11g or 12c

Related

Add exception in stored procedure

I want to handle exception using oracle as I haven't done it before. below is my stored procedure.
create or replace
PROCEDURE GET_VALID_LATLONG
(
P_XYCORDINATE IN VARCHAR2,
P_SAPID IN VARCHAR2,
OUTR4GSTATENAME OUT SYS_REFCURSOR
)
AS
v_counter number:=0;
BEGIN
DBMS_OUTPUT.ENABLE;
OPEN OUTR4GSTATENAME FOR
SELECT DISTINCT(R4GSTATECODE),R4GSTATENAME
FROM R4G_LB.R4GSTATEBOUNDARY_EVW
WHERE SDE.ST_INTERSECTS(SDE.ST_GEOMETRY('POINT
('||P_XYCORDINATE||')', 3),SHAPE) = 1;
END GET_VALID_LATLONG;
how to handle the exception?
UPDATE
I added like this, is it fine when error occurs ??
create or replace
PROCEDURE GET_VALID_LATLONG
(
P_XYCORDINATE IN VARCHAR2,
P_SAPID IN VARCHAR2,
OUTR4GSTATENAME OUT SYS_REFCURSOR
)
AS
v_counter number:=0;
BEGIN
DBMS_OUTPUT.ENABLE;
OPEN OUTR4GSTATENAME FOR
SELECT DISTINCT(R4GSTATECODE),R4GSTATENAME
FROM R4G_LB.R4GSTATEBOUNDARY_EVW
WHERE SDE.ST_INTERSECTS(SDE.ST_GEOMETRY('POINT
('||P_XYCORDINATE||')', 3),SHAPE) = 1;
EXCEPTION
WHEN OTHERS THEN
NULL;
END GET_VALID_LATLONG;
A list of pre-defined exceptions can be found in the Oracle docs, for example here.
https://docs.oracle.com/cd/A97630_01/appdev.920/a96624/07_errs.htm
You can use this list of exception names in your exception clause, for example
WHEN TOO_MANY_ROWS THEN
NULL; -- whatever you wish to do here.

PLSQL - Creating procedure with parameter, but only allowing 2 values

First off, I'm a DBA that dabbles in PL/SQL Programming. I have some knowledge, but some is most certainly lacking.
CREATE OR REPLACE PROCEDURE TRIGGER_PRC (P_TRGNAME IN VARCHAR2, P_STATUS IN VARCHAR2)
AS ....
I'd like to allow the P_STATUS parameter only be allowed values of 'E' or 'D' for enabling or disabling a trigger. I've done some searching, but can't seem to find the solution for this. Any help is greatly appreciated!
Thanks!
Jeremy
You could use an IF to check if the values is either E or D. If not, raise an error using raise_application_error:
CREATE OR REPLACE PROCEDURE TRIGGER_PRC (P_TRGNAME IN VARCHAR2, P_STATUS IN VARCHAR2)
AS
begin
if P_STATUS not in ('E', 'D') then
raise_application_error(-20001, 'Invalid P_STATUS value - ' || P_STATUS);
end if;
. . .
. . .
end;
/
I'd rather take the following approach:
CREATE OR REPLACE PROCEDURE ENABLE_TRIGGER_PRC (P_TRGNAME IN VARCHAR2)
AS ....
BEGIN
-- Enable the trigger P_TRGNAME here
END;
CREATE OR REPLACE PROCEDURE DISABLE_TRIGGER_PRC (P_TRGNAME IN VARCHAR2)
AS ....
BEGIN
-- Disable the trigger P_TRGNAME here
END;
You can make the second to call the first etc., but you should always have the IF statement (as GurV mentioned), to validate it once inside the Procedure. In the future, you might want to add drop as well. I suggest you put those into a package, so that they are all consolidated there, having one procedure to execute the actual statement, say in execute immediate, so that all the other procedures can reuse the same code.
Cheers
A solution would also be to use a Boolean, since you have only two choices.
CREATE OR REPLACE PROCEDURE TRIGGER_PRC (P_TRGNAME IN VARCHAR2, P_STATUS IN BOOLEAN)
AS ....
From this interesting article, it is advise to create a separate function to validate your input if you want some kind of ENUM in PLSQL (externalize the if GurV suggests).
So what is a guy to do?
If you want to use enum in a table, use a check constraint.
If you want to use enum in a stored procedure, write a separate procedure to validate the input.
What you could also do, if more than 2 values:
If you can afford to store global variables in a package and also advise your developers to look for constants in a defined package (GUI like PLSQL Developer or alike make it very easy to use):
CREATE OR REPLACE PACKAGE global_vars IS
P_STATUS_enable CONSTANT varchar2(2) := 'E';
P_STATUS_disable CONSTANT varchar2(2) := 'D';
P_STATUS_drop CONSTANT varchar2(2) := 'Dr';
end global_vars;
/
create or replace procedure TRIGGER_PRC (P_TRGNAME IN VARCHAR2, P_STATUS IN varchar2)
AS
begin
if P_STATUS = global_vars.P_STATUS_enable then
-- do something
dbms_output.put_line('ENABLE');
elsif P_STATUS = global_vars.P_STATUS_disable then
-- p_status = P_STATUS_disable
dbms_output.put_line('DISABLE');
elsif P_STATUS = global_vars.P_STATUS_drop then
-- do other stuff
dbms_output.put_line('DROP?');
end if;
end TRIGGER_PRC;
/
begin
TRIGGER_PRC ('TRIG', global_vars.P_STATUS_enable);
end;
/

how to call oracle procedure that has in out cursor

I have this procedure and I want to know how to execute it in PL/SQL. Can someone please help me?
create or replace PROCEDURE "P_TEST"
(
c$inchidere IN OUT softys.pk_utils.GenericCursor,
p_OLD IN empl.code%type,
p_NEW IN empl.code%type,
p_NXT IN empl.code%type,
p_ORGID IN empl.ORGID%type
)
is
begin
open c$inchidere for
select
...
end
Calling a procedure in PL/SQL is easy. The tricky part is reading the REF CURSOR. We need to fetch it into variables or a record type which match the projection of the executed query. That your code uses something called softys.pk_utils.GenericCursor makes me think you might have problems with that bit.
Anyway, this example presumes the result set returns a single numeric column. You will need to adjust the target variables to match the actual projection.
declare
rc sys_refcursor;
l_id number;
begin
P_TEST (
c$inchidere => rc,
p_OLD => 'whatever',
p_NEW => 'meh',
p_NXT => 'ABC',
p_ORGID => 123456 );
loop
fetch rc into l_id;
exit when rc%notfound;
end loop;
end;
Not sure why the ref cursor parameter is defined as IN OUT. As you open it immediately it only needs to be OUT.

Oracle cast PL/SQL table to SYS_REFCURSOR

I am trying to access one my Stored Procedure from java code, where the procedure is returing a PL/SQL table(PACKAGE TABLE) type, as it is easy to handle SYS_REFCURSOR in my java code, I am trying to convert the PL/SQL table to SYS_REFCURSOR in my Stored Procedure. After googling I didn't got any appropriate answer for this conversion. Can someone help me out for this conversion logic?
create or replace PROCEDURE TESTPROC(
INPUT1 IN VARCHAR2,
INPUT2 IN VARCHAR2,
P_PRC OUT SYS_REFCURSOR) AS
PACKAGE_TABLE PACKAGE.TESTTABLE;
BEGIN
PACKAGE_TABLE := FUNCTION_RETURN_PACKAGE_TABLE(INPUT1, INPUT2);
-- **LOGIC TO CONVERT PACAKGE_TABLE TO SYS_REFCURSOR GOES HERE**
END TESTPROC;
You can use TABLE operator for this
create or replace PROCEDURE TESTPROC(
INPUT1 IN VARCHAR2,
INPUT2 IN VARCHAR2,
P_PRC OUT SYS_REFCURSOR) AS
BEGIN
OPEN P_PRC FOR
SELECT * FROM TABLE(FUNCTION_RETURN_PACKAGE_TABLE(INPUT1, INPUT2));
END TESTPROC;
But you should keep in mind that you have to have schema level pl\sql table type (for oracle <12c). Also notice that SELECT * FROM brings you one-feild rows with your-plsql-table-row-type value.

Cannot read value from SYS_CONTEXT

I have a PL/SQL procedure which sets some variable in user session, like the following:-
Dbms_Session.Set_Context(
NAMESPACE =>'MY_CTX',
ATTRIBUTE => 'FLAG_NAME',
Value => 'some value');
Just after this (in the same procedure), I try to read the value of this flag, using:-
SYS_CONTEXT('MY_CTX', 'FLAG_NAME');
The above returns nothing. How did the DB lose this value? The weirder part is that if I invoke this proc directly from Oracle SQL Developer then it works. It doesn't work when I invoke this proc from my web application from callable statement.
--EDIT--
Added an example as to how we are invoking the proc from our Java code.
String statement = "Begin package_name.proc_name( flag_val => :1); END;";
OracleCallableStatement st = <some object by some framework>
.createCallableStatement(statement);
st.setString(1, 'flag value');
st.execute();
st.close();
Here is a minimalistic implementation of your scenario:
create or replace package my_ctx
as
procedure set_flag_name (str varchar2);
function get_flag_name return varchar2;
end my_ctx;
/
create or replace package body my_ctx
as
procedure set_flag_name (str varchar2)
is
begin
dbms_session.set_context(
NAMESPACE =>'MY_CTX',
ATTRIBUTE => 'FLAG_NAME',
Value => str);
end set_flag_name;
function get_flag_name return varchar2
is
begin
return SYS_CONTEXT('MY_CTX', 'FLAG_NAME');
end get_flag_name;
end my_ctx;
/
As you can see, it works:
SQL> exec my_ctx.set_flag_name('Jolly Roger')
PL/SQL procedure successfully completed.
SQL> select my_ctx.get_flag_name from dual
2 /
GET_FLAG_NAME
--------------------------------------------------------------------------------
Jolly Roger
SQL>
So, the issue must lie somewhere in your code. You will need to examine your program looking for the problem. Alternatively, post an entire sample here. Please make sure it's the smallest working test case possible. None of us wants to sift through hundreds of lines of shonky source looking for a bug. We get enough of that with our own code :)

Resources