Cursor Declaration Error - stored-procedures

I'm new to writing stored procedures. I have the following package:
create or replace PACKAGE STATUS_QUEUE AS
procedure get_errd (in_cd in char, in_sys in varchar2, out_info_cur out user_types.ref_cursor);
END STATUS_QUEUE;
and a package body of:
create or replace
PACKAGE BODY STATUS_QUEUE AS
procedure get_errd (in_cd in char, in_sys in varchar2, out_info_cur out user_types.ref_cursor)
is dttmFormat varchar2(21);
BEGIN
dttmFormat := common_functions.get_timestamp_format(in_stts_dttm);
open out_info_cur for
select email_frmt_name, bdy_text, sbjt_text, sys_id, crte_mdl_name, rtrn_email_addr_name,
to_char(stts_dttm, common_functions.get_dttm_pattern()) as stts_dttm, stts_cd
from pih.email_last_status
where stts_cd = in_cd AND sys_id = in_sys
order by STTS_DTTM desc;
END get_errd;
END STATUS_QUEUE;
I receive the following error when I run it:
Connecting to the database hwvaldd3051.
ORA-06550: line 5, column 27:
PLS-00302: component 'REF_CURSOR' must be declared
ORA-06550: line 5, column 16:
PL/SQL: Item ignored
ORA-06550: line 15, column 21:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 11, column 3:
PL/SQL: Statement ignored
ORA-06550: line 20, column 20:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 20, column 3:
PL/SQL: Statement ignored
Process exited.
Disconnecting from the database hwvaldd3051.
The PL/SQL Block is:
DECLARE
IN_STTS_CD CHAR(200);
IN_STTS_SYS VARCHAR2(200);
IN_STTS_DTTM VARCHAR2(200);
OUT_INFO_CUR user_types.ref_cursor;
BEGIN
IN_STTS_CD := 'ERRD';
IN_STTS_SYS := 'jwg';
IN_STTS_DTTM := NULL;
JWG.STATUS_QUEUE.GET_ERRD(
IN_STTS_CD => IN_STTS_CD,
IN_STTS_SYS => IN_STTS_SYS,
IN_STTS_DTTM => IN_STTS_DTTM,
OUT_INFO_CUR => OUT_INFO_CUR
);
/* Legacy output: DBMS_OUTPUT.PUT_LINE('OUT_INFO_CUR = ' || OUT_INFO_CUR); */
:OUT_INFO_CUR := OUT_INFO_CUR; --<-- Cursor
END;
I'm not sure why I'm getting the error on the Ref_cursor.

Try the type SYS_REFCURSOR as per the example below:
declare
recieving_cur sys_refcursor;
procedure rc_test (out_cur out sys_refcursor)
is
begin
open out_cur for
select * from user_tables;
end rc_test;
begin
rc_test(recieving_cur);
end;

Related

Ruby - Oci8 - Call funtion with rowtype not working

I have an oracle function like this:
CREATE OR REPLACE FUNCTION MY_FUNCTION (MY_ID IN VARCHAR2)
RETURN vendedor%rowtype AS
res vendedor%rowtype;
BEGIN
select * into res
from vendedor
where id = MY_ID;
return res;
END MY_FUNCTION;
And I want to call this function from my ruby code using oci8 gem. This is my ruby code:
connectString = ENV['DB_CONNECTION']
conn = OCI8.new(connectString)
cursor = conn.parse ('begin :ret := MY_FUNCTION(:MY_ID); end;')
cursor.bind_param(':MY_ID', '123', String)
cursor.bind_param(':ret', nil, OCI8::RAW) # This is the question
cursor.exec()
result = cursor[':ret']
cursor.close
conn.logoff
What is the parameter's bind type of :ret variable?
To execute this code throw this error:
ORA-06550: line 1, column 15: PLS-00382: expression is of wrong type ORA-06550: line 1,
column 7: PL/SQL: Statement ignored
Replacing cursor.bind_param(':ret', nil, OCI8::RAW)
with
cursor.bind_param(':ret', OCI8::Cursor) would do the trick,
but you need to convert your function to
CREATE OR REPLACE FUNCTION MY_FUNCTION (MY_ID IN VARCHAR2) RETURN sys_refcursor AS
res sys_refcursor;
BEGIN
open res for
select *
from vendedor
where id = MY_ID;
return res;
END MY_FUNCTION;
to prepare to return sys_refcursor type
For get the result in ruby code:
result = cursor[':ret']
while r = result.fetch_hash
retFinal = r
end
retFinal variable has the cursor's last result

Out parameter undefined

I'm currently stuck in creating two tasks inside of a procedure adding numbers of an array passed to the respective procedure.
My generic package looks like this:
generic
type Item_Type is private;
with function "+"(Left: Item_Type; Right: Item_Type) return Item_Type;
package Parallel_Algorithms is
type Array_Type is array(Natural range <>) of Item_Type;
type Array_Access_Type is access all Array_Type;
procedure Parallel_Sum(Input: Array_Access_Type; Result: out Item_Type);
end Parallel_Algorithms;
I implemented the Parallel_Sum Method the following way, being aware that the implementation is not perfect, nor thread safe.
procedure Parallel_Sum(Input: Array_Access_Type; Result: out Item_Type) is
Loop_Var: Integer:= 0;
task type T;
Task1, Task2 : T;
task body T is
begin
while Loop_Var < Input'Length loop
Result := Result + Input(Loop_Var);
Loop_Var := Loop_Var + 1;
end loop;
end T;
begin
-- Result := Temp;
end Parallel_Sum;
If I now run my main program the output of Result always ends up being something like 1918988326. Considering the elements inside of my array (1,2,3,4) that result is obviously wrong.
I read in another post that non altering an out type may result in undefined behaviour of the respective variable.
What would be the proper way to get the 'real' Result?
Upon looking at the problem more closely I see there are several issues to overcome. The tasks must accumulate their own totals, then those totals must be combined. Adding totals to an unprotected Result variable will produce a race condition which will result in undefined results.
Following is my approach to the problem.
------------------------------------------------------------------
-- Parallel Addition of Array Elements --
------------------------------------------------------------------
generic
type Element_Type is range <>;
package Parallel_Addition is
type Array_Type is array(Natural range <>) of Element_Type;
type Array_Access is access all Array_Type;
task type Adder is
Entry Set_Slice(Low, High : in Natural;
Item : in not null Array_Access);
end Adder;
protected Result is
procedure Accumulate(Item : in Element_Type);
function Report return Element_Type;
private
Sum : Integer := 0;
end Result;
end Parallel_Addition;
package body Parallel_Addition is
-----------
-- Adder --
-----------
task body Adder is
My_Array : Array_Access;
Id_Low, Id_High : Natural;
Sum : Integer := 0;
begin
accept Set_Slice(Low, High : in Natural;
Item : in not null Array_Access) do
Id_Low := Low;
Id_High := High;
My_Array := Item;
end Set_Slice;
for I in Id_Low..Id_High loop
Sum := Sum + Integer(My_Array(I));
end loop;
Result.Accumulate(Element_Type(Sum));
end Adder;
------------
-- Result --
------------
protected body Result is
----------------
-- Accumulate --
----------------
procedure Accumulate (Item : in Element_Type) is
begin
Sum := Sum + Integer(Item);
end Accumulate;
------------
-- Report --
------------
function Report return Element_Type is
begin
return Element_Type(Sum);
end Report;
end Result;
end Parallel_Addition;
------------------------------------------------------------------
-- Parallel_Addition Test --
------------------------------------------------------------------
with Ada.Text_IO; use Ada.Text_IO;
with Parallel_Addition;
procedure PA_Test is
package adders is new Parallel_Addition(Natural);
use adders;
Data : aliased Array_Type := (1,2,3,4,5,6,7,8,9,10);
T1, T2 : Adder;
begin
T1.Set_Slice(Low => 0, High => 4, Item => Data'Access);
T2.Set_Slice(Low => 5, High => 9, Item => Data'Access);
loop
if T1'Terminated and then T2'Terminated then
exit;
end if;
end loop;
put_Line("The sum is " & Integer'Image(Result.Report));
end PA_Test;

Error handling in Teradata Stored Procedure

I am trying to develop a stored procedure within TERADATA to handle and manage exceptions.
The stored procedure should raise the error to the caller, which is an SSIS Package.
I am trying to illustrate this by creating a stored procedure for illustration only.
I have these tables:
Table_A:
- ID INT
- ITEM_NUM INT
- DESC VARCHAR(20)
- CREATE_DTTM VARCHAR(2O)
Table_B:
- ID INT
- ITEM_NUM INT
- DESC VARCHAR(20)
- CREATE_DTTM VARCHAR(2O)
I have two tables that will be inserting data from two SELECT statements.
REPLACE PROCEDURE csTest2()
SQL SECURITY OWNER
BEGIN
DECLARE varErrorMessage char(256);
DECLARE varSQLState char(5);
DECLARE varReturnCode char(5);
DECLARE varRollbackNeededInd char(1); /* transaction mgt */
SET varRollbackNeededInd = 'N';
SET varReturnCode = '00000';
SET varErrorMessage = '';
BEGIN TRANSACTION;
-- USING A SINGLE HANDLER WITH MULTIPLE STATEMENTS
-- PLANING TO CHANGE ERROR MESSAGE IN EACH STATEMENT.
ins6: BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
H99:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'This message should not be displayed'; --
end H99;
-- IMAGINE THAT I AM GETTING THE VALUES AS INPUT PARAMERS IN THE PROCEDURE
INSERT INTO "Table_A"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '222', 'SOME DESC',CURRENT_TIMESTAMP;
H98:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'This message is displayed, ITEM_NUM invalid characters';
end H98;
-- NOW I AM DOING A SECOND INSERT TO table b WITH INVALID DATA
-- THE VALUE FOR THE ITEM NUMBER CONTAINS ALPHANUMERICE CHARACTERS
INSERT INTO "Table_b"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '333F', 'SOME DESC',CURRENT_TIMESTAMP;
END ins6;
EndTrans: BEGIN
IF varSQLState <> '0' THEN
SET varRollbackNeededInd = 'Y';
SET varReturnCode = '9999';
END IF;
IF varRollbackNeededInd = 'Y' THEN
ROLLBACK; -- ROLLBACK AND SEND ERROR TO CALLER
SIGNAL SQLSTATE 'U0123' SET MESSAGE_TEXT = 'SQlState is - ' || varSQLSTATE || ' - and error is - ' || varErrorMessage;
ELSE
END TRANSACTION; -- COMMIT TRANSACTION
END IF;
END EndTrans;
END;
The problem that I am facing with the above stored procedure is that error message that I get is not the one that I am expecting. Since error is intentionally created in my second statement I am expecting to get: This message is displayed, ITEM_NUM invalid characters but I am getting This message should not be displayed
Now if I modify the PROCEDURE to have multiple handlers, one for each statement, I do get the correct error message, but now since I am intentionally generating the error in the first statement it does not terminate the procedure, it handles the error and sets the proper message but continues to process the next statement which I am not expecting to do this, so how can I terminate this procedure?
REPLACE PROCEDURE csTest2()
SQL SECURITY OWNER
BEGIN
DECLARE varErrorMessage char(256);
DECLARE varSQLState char(5);
DECLARE varReturnCode char(5);
DECLARE varRollbackNeededInd char(1); /* transaction mgt */
SET varRollbackNeededInd = 'N';
SET varReturnCode = '00000';
SET varErrorMessage = '';
BEGIN TRANSACTION;
ins6: BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
H99:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'Error is displayed in this case because ITEM_NUM';
-- ERROR IS PRESENT IN THIS STATEMENT AND SHOULD TERMINATE THE PROCEDURE.
INSERT INTO "Table_A"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '222F', 'SOME DESC',CURRENT_TIMESTAMP;
END ins6;
ins7: BEGIN
H98:Begin
set varSQLState = SQLSTATE;
set varErrorMessage= 'no error is displayed in this case';
end H98;
-- NO ERROR IS EXPECTED, BUT IT SHOULD NOT REACH HERE SINCE WE HAD ERROR ON FIRST STATEMENT.
INSERT INTO "Table_b"
(ID , ITEM_NUM, DESC, CREATE_DTTM)
SELECT 1, '333', 'SOME DESC',CURRENT_TIMESTAMP;
END ins7;
EndTrans: BEGIN
IF varSQLState <> '0' THEN
SET varRollbackNeededInd = 'Y';
SET varReturnCode = '9999';
END IF;
IF varRollbackNeededInd = 'Y' THEN
ROLLBACK; -- ROLLBACK AND SEND ERROR TO CALLER
SIGNAL SQLSTATE 'U0123' SET MESSAGE_TEXT = 'SQlState is - ' || varSQLSTATE || ' - and error is - ' || varErrorMessage;
ELSE
END TRANSACTION; -- COMMIT TRANSACTION
END IF;
END EndTrans;
END;

Golang oci8 Stored Procedure query produces error

I want to query using golang oci8, and this is my setup in oracle xe;
CREATE OR REPLACE PACKAGE user_mgt
IS
PROCEDURE login(u_mail_in IN VARCHAR2,
u_pwd_in IN VARCHAR2,
retval OUT VARCHAR2) ;
END user_mgt;
CREATE OR REPLACE PACKAGE BODY user_mgt
is
PROCEDURE login(u_mail_in IN VARCHAR2,
u_pwd_in IN VARCHAR2,
retval OUT VARCHAR2)
AS
l_count NUMBER ;
BEGIN
SELECT Count(*)
INTO l_count
FROM USERTABLE
WHERE u_mail= u_mail_in;
IF l_count=1 then
SELECT u_pwd
INTO retval
FROM usertable
WHERE u_mail= u_mail_in;
ELSE
retval:='NotFound';
END IF ;
END login;
END user_mgt
My test below has no error and returns the expected result;
DECLARE
em VARCHAR2(50);
pwd VARCHAR2(200);
retval VARCHAR2(200);
BEGIN
em:='blow';
pwd:='pwd';
user_mgt.login(em,pwd,retval);
Dbms_Output.put_line(retval);
END;
Now when i try to query in my golang setup i get an error;
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-oci8"
)
func main() {
db, err := sql.Open("oci8", "user/password#XE")
if err != nil {
fmt.Println(err)
return
}
defer db.Close()
loginStmt,err:=db.Prepare("begin user_mgt.login(:1,:2,:3);end;")
defer loginStmt.Close()
mail:="ofoe"
pwd:="testing"
var retVal string
var retStatus string
er:=loginStmt.QueryRow(mail,pwd,retVal).Scan(&retStatus)
if er!=nil{
panic(er)
}
fmt.Println("retval")
fmt.Println(retStatus)
}
I will appreciate any help, am really stuck, the error i get is;
panic: ORA-06502: PL/SQL: numeric or value error: character string buffer too sm
all
ORA-06512: at "BLOW.USER_MGT", line 20
ORA-06512: at line 1
goroutine 1 [running]:
main.main()
C:/Users/pc/Documents/goPlayground/src/blow.com/oracle_test/main.go:27 +
0x3ab
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
c:/go/src/runtime/asm_386.s:2287 +0x1
goroutine 5 [runnable]:
database/sql.(*DB).connectionOpener(0x12252460)
c:/go/src/database/sql/sql.go:589 +0x43
created by database/sql.Open
c:/go/src/database/sql/sql.go:452 +0x256
exit status 2

ERROR at line 29: PL/SQL: Statement ignored

Package
create or replace package PKG_PROJECT AS
type cur IS REF CURSOR;
procedure SP_PREPARESALARY(v_yr in number,v_mn in number);
END PKG_PROJECT;
PACKAGE BODY
PL/SQL statement ignored at line 29(just before the relevant insert query)
create or replace package body PKG_PROJECT AS
procedure SP_PREPARESALARY(v_yr in number,v_mn in number) AS
V_EMPNO INTEGER;
V_EMPNAME VARCHAR2(30);
V_BASICSALARY INTEGER;
V_DAYSPRESENT INTEGER;
V_YEAR INTEGER;
V_MONTH INTEGER;
V_PF INTEGER;
V_TAX INTEGER;
V_MON_SAL INTEGER;
V_NET_SAL INTEGER;
V_MAXDAYS INTEGER;
CURSOR EMP_VALUES IS
SELECT EMPNO, EMPNAME, BASICSALARY, YEAR, MONTH, DAYSPRESENT
FROM DELL_EMPLOYEE, DELL_ATTENDANCE
WHERE EMPNO=ENO AND YEAR = V_YR AND MONTH = V_MN;
BEGIN
OPEN EMP_VALUES;
LOOP
FETCH EMP_VALUES INTO V_EMPNO,V_EMPNAME,V_BASICSALARY,V_YEAR,V_MONTH,V_DAYSPRESENT;
EXIT WHEN EMP_VALUES%NOTFOUND;
V_YEAR := V_YR;
V_MONTH := V_MN;
V_MAXDAYS := FN_GETMAXDAYS(V_YEAR,V_MONTH);
V_MON_SAL:= FN_GETGROSSMONTHLYSALARY(V_BASICSALARY, V_DAYSPRESENT, V_MAXDAYS);
V_PF:= FN_GETPF(V_MON_SAL);
V_TAX:= FN_GETTAX(V_MON_SAL,V_PF);
V_NET_SAL:= FN_GETNETSALARY(V_MON_SAL, V_PF, V_TAX);
INSERT INTO DELL_SALARY (EMPNO, YEAR,MONTH,EMPNAME,DAYSPRESENT,BASICSALARY,MONTHSALARY,PF,TAX,NETSALARY)
VALUES (V_EMPNO,V_YEAR,V_MONTH,V_EMPNAME,V_DAYSPRESENT,V_BASICSALARY,V_MON_SAL,
V_PF,V_TAX, V_NET_SAL);
END LOOP;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
UPDATE DELL_SALARY
SET EMPNAME=V_EMPNAME,DAYSPRESENT=V_DAYSPRESENT,BASICSALARY=V_BASICSALARY,
MONTHSALARY=V_MON_SAL,PF=V_PF,TAX=V_TAX,NETSALARY=V_NET_SAL
WHERE EMPNO=V_EMPNO AND YEAR=V_YEAR AND MONTH=V_MONTH;
END SP_PREPARESALARY;
END PKG_PROJECT;
Created the DELL_EMPLOYEE, DELL_ATTENDANCE, DELL_SALARY tables. But I don't know why am kepp getting the unwanted error.
I do not have your functions,so I have commented or removed that part and created your package without any errors.
CREATE OR REPLACE PACKAGE BODY PKG_PROJECT
AS
PROCEDURE SP_PREPARESALARY (v_yr IN NUMBER, v_mn IN NUMBER)
AS
V_EMPNO VARCHAR2(30);
V_EMPNAME VARCHAR2(30);
V_BASICSALARY NUMBER;
V_DAYSPRESENT NUMBER;
V_YEAR NUMBER;
V_MONTH NUMBER;
V_PF NUMBER;
V_TAX NUMBER;
V_MON_SAL NUMBER;
V_NET_SAL NUMBER;
V_MAXDAYS NUMBER;
CURSOR EMP_VALUES
IS
SELECT E.EMPNO,
E.EMPNAME,
E.BASICSALARY,
E.YEAR,
E.MONTH,
E.DAYSPRESENT
FROM DELL_EMPLOYEE E, DELL_ATTENDANCE A
WHERE E.EMPNO = A.ENO AND E.YEAR = V_YR AND E.MONTH = V_MN;
BEGIN
OPEN EMP_VALUES;
LOOP
FETCH EMP_VALUES
INTO V_EMPNO,
V_EMPNAME,
V_BASICSALARY,
V_YEAR,
V_MONTH,
V_DAYSPRESENT;
EXIT WHEN EMP_VALUES%NOTFOUND;
V_YEAR := V_YR;
V_MONTH := V_MN;
V_MAXDAYS := 0;
-- V_MON_SAL :=
-- FN_GETGROSSMONTHLYSALARY (V_BASICSALARY,
-- V_DAYSPRESENT,
-- V_MAXDAYS);
V_PF := 0;
V_TAX := 0;
V_NET_SAL := 0;
-- INSERT INTO DELL_SALARY (EMPNO,
-- YEAR,
-- MONTH,
-- EMPNAME,
-- DAYSPRESENT,
-- BASICSALARY,
-- MONTHSALARY,
-- PF,
-- TAX,
-- NETSALARY)
-- VALUES (V_EMPNO,
-- V_YEAR,
-- V_MONTH,
-- V_EMPNAME,
-- V_DAYSPRESENT,
-- V_BASICSALARY,
-- V_MON_SAL,
-- V_PF,
-- V_TAX,
-- V_NET_SAL);
END LOOP;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
null;
-- UPDATE DELL_SALARY
-- SET EMPNAME = V_EMPNAME,
-- DAYSPRESENT = V_DAYSPRESENT,
-- BASICSALARY = V_BASICSALARY,
-- MONTHSALARY = V_MON_SAL,
-- PF = V_PF,
-- TAX = V_TAX,
-- NETSALARY = V_NET_SAL
-- WHERE EMPNO = V_EMPNO AND YEAR = V_YEAR AND MONTH = V_MONTH;
END SP_PREPARESALARY;
END PKG_PROJECT;
Try commenting out part by part to identify where are the problems, that way you could easily find out the problem.

Resources