I have a TABLE sec.sec_secret_tab in the SEC schema
OWNER
SERVICE_NAME
SECRET
ALPHA
service_1
A1
ALPHA
service_2
A2
BETA
service_1
B1
BETA
service_2
B2
and this function:
FUNCTION sec.sec_get_secret (p_service_name VARCHAR2)
IS
vc_onwer VARCHAR2(32767);
vc_secret VARCHAR2(32767);
BEGIN
vc_onwer := sec.mystery_func;
SELECT secret
INTO vc_secret
FROM sec.sec_secret_tab
WHERE service_name = p_service_name
AND onwer = vc_onwer;
RETURN vc_secret;
END sec_get_secret;
In the schema alpha, there is this procedure:
PROCEDURE alpha.show
IS
vc_secret VARCHAR2(32767);
BEGIN
vc_secret := sec.sec_get_secret('service_1');
dbms_output.put_line(vc_secret);
vc_secret := sec.sec_get_secret('service_2');
dbms_output.put_line(vc_secret);
END show;
In the schema beta, there is this procedure:
PROCEDURE beta.show
IS
vc_secret VARCHAR2(32767);
BEGIN
vc_secret := sec.sec_get_secret('service_1');
dbms_output.put_line(vc_secret);
vc_secret := sec.sec_get_secret('service_2');
dbms_output.put_line(vc_secret);
END show;
Knowing that
the alpha and beta schemas have EXECUTE right on sec.sec_get_secret
the user connected (lets call him OMEGA) has the EXECUTE rights on alpha.show and beta.show
How can I make the function sec.mystery_func to get the following output:
if OMEGA calls alpha.show, 'A1' and 'A2' are displayed
if OMEGA calls beta.show, 'B1' and 'B2' are displayed
You can use the UTL_CALL_STACK package, specifically the OWNER function:
This function returns the owner name of the unit of the subprogram at the specified dynamic depth.
You want the owner of the calling package, so that's level 2:
vc_onwer := utl_call_stack.owner(2);
That package is available from Oracle 12cR1.
Related
I'm working on a PLSQL package that calls another PLSQL package that returns separated results (i.e OUT variables) as follows:
(1) SYS_REFCURSOR
(1) NUMBER
(1) VARCHAR2
This is the dbfiddle I build.
Full code of the linked dbfiddle:
/* Main table - it contains the data to use in a cursor: */
CREATE TABLE tpos_retbenf
(
id_serial NUMBER (9,0),
serial_nmb NUMBER(12,0)
);
/* Destination of the records detected on "tpos_retbenf": */
CREATE TABLE tbl_debug
(
msg_text VARCHAR2(1000),
record_date DATE
);
/* Add values to the main table: */
INSERT INTO tpos_retbenf (id_serial, serial_nmb)
VALUES (1, 202108311635);
/* Package that contains the code to execute: */
create or replace PACKAGE PCK_POS_UNO is
PROCEDURE SP_POS_UNO (ID_RECORD IN NUMBER,
CUR_RET_BENF OUT SYS_REFCURSOR,
IDERROR OUT NUMBER,
DSERROR OUT VARCHAR2);
end PCK_POS_UNO;
/
create or replace PACKAGE BODY PCK_POS_UNO is
/* This is the procedure that returns results in separated variables: */
PROCEDURE SP_POS_UNO (ID_RECORD IN NUMBER,
CUR_RET_BENF OUT SYS_REFCURSOR,
IDERROR OUT NUMBER,
DSERROR OUT VARCHAR2) AS
v_temp number(6) := 0;
v_S varchar2(1) := 'S';
BEGIN
if ID_RECORD is null or ID_RECORD <= 0 then
IDERROR := -1;
DSERROR := 'Id no valido para la operacion';
goto finalizar;
end if;
select count(1) into v_temp
from tpos_retbenf r
where r.id_serial = ID_RECORD;
if v_temp = 0 then
IDERROR := -1;
DSERROR := 'Id no encontrado';
goto finalizar;
end if;
OPEN CUR_RET_BENF FOR
select r.id_serial, r.serial_nmb
from tpos_retbenf r
where r.id_serial = ID_RECORD;
<<finalizar>>
null;
END SP_POS_UNO;
END PCK_POS_UNO;
/
/* Package that calls the "SP_POS_UNO" procedure from the "PCK_POS_UNO" package: */
create or replace PACKAGE PKG_BH_ONLINE_INFORMATION IS
PROCEDURE ONLINENOVELTYBEN
(
V_NID_DEV IN NUMBER,
CV_1 IN OUT SYS_REFCURSOR
);
END PKG_BH_ONLINE_INFORMATION;
/
create or replace PACKAGE BODY PKG_BH_ONLINE_INFORMATION IS
PROCEDURE ONLINENOVELTYBEN
(
V_NID_DEV IN NUMBER,
CV_1 IN OUT SYS_REFCURSOR
) IS
V_USER VARCHAR2(10 CHAR) := 'INTERNET';
V_QUERY VARCHAR2(10000 CHAR);
-- Variables:
V_OUT_CUR_RET_BENF SYS_REFCURSOR;
V_OUT_IDERROR NUMBER;
V_OUT_DSERROR VARCHAR2(10000 CHAR);
BEGIN
/*
Here, the "PCK_POS_UNO.SP_POS_UNO" is called
from "PKG_BH_ONLINE_INFORMATION" as follows:
*/
V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
EXECUTE IMMEDIATE V_QUERY INTO V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR USING V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR ;
/*
An this error occurs:
Error: ORA-00904: "PCK_POS_UNO"."SP_POS_UNO": invalid identifier - StackTrace: ORA-06512: in line 24
*/
-- After getting the results in (V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR) variables,
-- a LOOP is executed for retrieve the records in "V_OUT_CUR_RET_BENF" cursor...
-- It doesn't continue here due to error shown above.
END ONLINENOVELTYBEN;
END PKG_BH_ONLINE_INFORMATION;
/
When the following code is going to be executed:
V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
EXECUTE IMMEDIATE V_QUERY INTO V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR USING V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR ;
The error says:
Error: ORA-00904: "APPLICATION_POS"."PCK_POS_UNO"."SP_POS_UNO": invalid identifier -
StackTrace: ORA-06512: in line 24
I've tried so far:
Search for ORA-00904 error - in this answer says "proper permissions on objects involved in the query" - which I share, but, I don't know how to argument this option (since I can do a simple SELECT to that table and the results are shwon, hence, they might not accept this argument). Related to this argument, I can't get listed the PCK_POS_UNO package "since the OWNER is different from the one I'm usually using (that is APPLICATION)".
I made a copy of this package/procedure and was able to execute the procedure/package via SQL Developer - see screenshot, but, the same error ORA-00904 occurs.
Screentshot of the execution of the package:
Results:
Change the code that calls the procedure that has OUT parameters, but, I'm unable to get a successful combination that allows the compilation and execution of the code as a whole.
Examples - all based on internet searchs and my own "instinct":
(1): Added (;) at the end of the dynamic-sql string:
V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO((:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL;';
(2): Removing the OWNER - in this case "APPLICATION_POS":
V_QUERY := 'SELECT PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
(3): Calling the procedure directly - it shows SP2-0552: bind variable "V_NID_DEV" not declared - but, how?, in a separated sample, the variable "V_NID_DEV" is declared and with value "2462013":
PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR);
(4): Calling the procedure directly (removing also the points) - in this case, ORA-01001 - invalid cursor error is generated - which I think it doesn't make sense - since the OUT cursor is not being opened for read or operated somehow.
PCK_POS_UNO.SP_POS_UNO(V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR);
I'm really run out of ideas - since I'm not familiar with this type of creating packages and passing values between packages and I didn't created this code.
Is there any way to make this code work?
Package modified to call procedure SP_POS_UNO:
CREATE OR REPLACE PACKAGE BODY PKG_BH_ONLINE_INFORMATION
IS
PROCEDURE ONLINENOVELTYBEN(V_NID_DEV IN NUMBER,
CV_1 IN OUT SYS_REFCURSOR
)
IS
V_USER VARCHAR2(10 CHAR) := 'INTERNET';
V_QUERY VARCHAR2(10000 CHAR);
-- Variables:
V_OUT_CUR_RET_BENF SYS_REFCURSOR;
V_OUT_IDERROR NUMBER;
V_OUT_DSERROR VARCHAR2(10000 CHAR);
BEGIN
/*
Here, the "PCK_POS_UNO.SP_POS_UNO" is called
from "PKG_BH_ONLINE_INFORMATION" as follows:
*/
V_QUERY:='Begin
PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR);
End;';
--
EXECUTE IMMEDIATE V_QUERY
USING V_NID_DEV,
out V_OUT_CUR_RET_BENF,
out V_OUT_IDERROR,
out V_OUT_DSERROR ;
Dbms_Output.Put_Line('V_OUT_IDERROR='||V_OUT_IDERROR);
Dbms_Output.Put_Line('V_OUT_DSERROR='||V_OUT_DSERROR);
--
CV_1:=V_OUT_CUR_RET_BENF;
END ONLINENOVELTYBEN;
--
END PKG_BH_ONLINE_INFORMATION;
So I am trying to compile this trigger that prints some lines as outputs ( have the variables declared because i will be building onto this trigger using these variables later on). There's an existing trigger in the same database that does the same exact thing with a different table passing the same data, but my trigger seems to throw an error saying that 'new.PROCESSED is an invalid identifier'. What am I doing wrong? I may just not know what is fully going on here in my code... (thanks in advance!) value_value_id_se and cALCULATION_VALUE_CALCULATI329 are both functions in the system...
create or replace TRIGGER CAL_VAL
AFTER INSERT
ON XML_HOURS_LOAD
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
WHEN (
NEW.processed = 'N'
)
DECLARE
Value_ID Number;
pValue_ID Number;
pCalculation_ID NUMBER;
Calculation_ID Number;
Calculation_Value_ID Number;
p_Entity_Address_ID Varchar2(50);
New_Value_ID Number;
New_Calculation_ID Number;
New_Calculation_Value_ID Number;
BEGIN
Value_ID := value_value_id_seq.NEXTVAL;
New_Value_ID := Value_id ;
Calculation_Value_ID:=CALCULATION_VALUE_CALCULATI329.NEXTVAL;
calculation_id := Calculation_Calculation_ID_SEQ.NEXTVAL;
p_Entity_Address_ID := :New.EIA_ID_TX;
DBMS_OUTPUT.PUT_LINE(Get_energy_product_id(:NEW.Product_Name_Cd));
DBMS_OUTPUT.PUT_LINE(Get_Data_Source_Id(:NEW.Data_Source_Tx));
DBMS_OUTPUT.PUT_LINE(Get_Supply_Type_Id(:NEW.Supply_Type_Tx));
DBMS_OUTPUT.PUT_LINE(Get_State_CD(Get_entity_Id(p_Entity_Address_ID)));
DBMS_OUTPUT.PUT_LINE(Get_Entity_Address_ID(Get_Entity_ID(p_Entity_Address_ID)));
DBMS_OUTPUT.PUT_LINE('Value_ID' || Value_ID);
END;
I have created a function in Oracle with 2 parameters. So when I run the query I want to pass multiple values to each parameter.
I tried using below changes in the query:
coul_1 in ('||par1||') and colu_2 in ('||par2||')
But it is not fetching the data.
How to fetch the data when I give multiple values to different declared parameters.Eg:
select * from table(fun_name('val1','val2'))
val1 will have a1,a2,a3
val2 will have b1,b2,b3
Here is the function code:
CREATE OR REPLACE FUNCTION JOBRUN_STATUS_MONITOR_F(
own_name IN VARCHAR2,
status IN VARCHAR2)
RETURN JOBRUN_STATUS_EDW_1 PIPELINED
IS
L_TAB JOBRUN_STATUS_MONITOR_EDW_1;
JR_STATUS NUMBER (38);
CURSOR jobrun_1_cr (OW_N VARCHAR2, STS VARCHAR2)
IS
SELECT *
FROM JOBRUN A,
JOBMST B,
owner C
WHERE A.JOBMST_ID = B.JOBMST_ID
AND C.OWNER_NAME = OW_N
AND A.JOBRUN_STATUS = STS ;
BEGIN V_OWN_NAME := own_name;
V_STATUS := status;
IF jobrun_1_cr%ISOPEN THEN
CLOSE jobrun_1_cr;
END IF;
OPEN jobrun_1_cr (own_name, JR_STATUS);
CLOSE jobrun_1_cr;
END JOBRUN_STATUS_MONITOR_F;
/
It sounds like you want to call the function three times, passing (a1, b1), (a2, b2) and (a3, b3). One way would be to generate an inline view containing the values you want to pass, and query it including a call to your function.
Demo pipelined function:
create or replace function demo_pipefunc
( p_own_name in varchar2
, p_status in varchar2 )
return sys.dbms_debug_vc2coll
pipelined
as
l_result long;
begin
for i in 1..3 loop
l_result := p_own_name ||';'|| p_status ||';'|| i;
pipe row (l_result);
end loop;
return;
end demo_pipefunc;
Demo call:
with params (own_name, status) as
( select 'a1', 'b1' from dual union all
select 'a2', 'b2' from dual union all
select 'a3', 'b3' from dual
)
select t.*
from params
cross join table(demo_pipefunc(own_name, status)) t
Output:
COLUMN_VALUE
a1;b1;1
a1;b1;2
a1;b1;3
a2;b2;1
a2;b2;2
a2;b2;3
a3;b3;1
a3;b3;2
a3;b3;3
try this:
CREATE OR REPLACE FUNCTION JOBRUN_STATUS_MONITOR_F (own_name IN VARCHAR2, status IN VARCHAR2) RETURN JOBRUN_STATUS_EDW_1 PIPELINED
IS L_TAB JOBRUN_STATUS_MONITOR_EDW_1;
JR_STATUS NUMBER (38);
CURSOR jobrun_1_cr (OW_N VARCHAR2, STS VARCHAR2)
IS SELECT *
FROM JOBRUN A, JOBMST B, owner C
WHERE A.JOBMST_ID = B.JOBMST_ID
AND C.OWNER_NAME = OW_N
AND A.JOBRUN_STATUS = STS;
BEGIN
V_OWN_NAME := REPLACE(own_name,'"','''');
V_STATUS := REPLACE(status,'"','''');
IF jobrun_1_cr%ISOPEN THEN
CLOSE jobrun_1_cr;
END IF;
OPEN jobrun_1_cr (own_name, JR_STATUS);
CLOSE jobrun_1_cr;
END JOBRUN_STATUS_MONITOR_F;
then call the procedure like this:
select * from table(fun_name('"a1","b1","c1"','"a1","b1","c1"'));
Your procedure may have other issues with the use of undeclared variables.
My purpose is to fetch data in the output variable "c" of the stored procedure. This variable is of type SYS_REFCURSOR. But I am having issues. It says: "results do not match with query".
Here is the code
PROCEDURE SP_BUSCAR_AL(VE_PROGRAM IN VARCHAR2,
VE_TIPO_CAMPO_ESTUDIO IN NUMBER,
VE_CODE_ESCUELA IN VARCHAR2,
VE_NOMBRE_ALTERNATIVA IN VARCHAR2,
c OUT SYS_REFCURSOR) IS
BEGIN
DECLARE
VL_PROGRAM VARCHAR2(100);
VL_TIPO_CAMPO_ESTUDIO NUMBER;
VL_CODE_ESCUELA VARCHAR2(100);
VL_NOMBRE_ALTERNATIVA VARCHAR2(100);
aa SYS_REFCURSOR;
BEGIN
VL_PROGRAM := VE_PROGRAM;
VL_TIPO_CAMPO_ESTUDIO := VE_TIPO_CAMPO_ESTUDIO;
VL_CODE_ESCUELA := VE_CODE_ESCUELA;
VL_NOMBRE_ALTERNATIVA := VE_NOMBRE_ALTERNATIVA;
BEGIN
OPEN aa FOR
SELECT stvmjr.stvmajr_code,stvmjr.stvmajr_desc
FROM smrprle,
sobcurr,
sorccon,
stvmajr stvmjr,
govsdav
WHERE
govsdav_pk_parenttab = stvmajr_code
AND stvmajr_code = sorccon_majr_code_conc
AND sorccon_curr_rule = sobcurr_curr_rule
AND sobcurr_program = smrprle_program
AND govsdav_table_name LIKE '%STVMAJR%'
AND govsdav_attr_name = 'TIPO_CAMPO_ESTUDIO'
AND govsdav_value_as_char = 1
AND smrprle_program = VL_PROGRAM
;
loop
fetch aa into c; --It says results do not match here
exit when aa%notfound;
end loop;
END SP_BUSCAR_AL;
I appreciate it.
Ref Cursors are not variables, they're pointers. So we cannot fetch into them.
In your situation all you need to do is use the OUT parameter when you open the cursor...
OPEN c FOR
SELECT stvmjr.stvmajr_code,stvmjr.stvmajr_desc
Alternatively you could just assign it...
c := aa;
A cursor is simply a reference to a SELECT statement which has been opened. You need to fetch the results of the cursor into appropriate variables so you can use them. So let's update your procedure to do this:
PROCEDURE SP_BUSCAR_AL(VE_PROGRAM IN VARCHAR2
c OUT SYS_REFCURSOR)
IS
BEGIN
OPEN c FOR
SELECT stvmjr.stvmajr_code,stvmjr.stvmajr_desc
FROM smrprle,
sobcurr,
sorccon,
stvmajr stvmjr,
govsdav
WHERE govsdav_pk_parenttab = stvmajr_code
AND stvmajr_code = sorccon_majr_code_conc
AND sorccon_curr_rule = sobcurr_curr_rule
AND sobcurr_program = smrprle_program
AND govsdav_table_name LIKE '%STVMAJR%'
AND govsdav_attr_name = 'TIPO_CAMPO_ESTUDIO'
AND govsdav_value_as_char = 1
AND smrprle_program = VE_PROGRAM;
END SP_BUSCAR_AL;
I eliminated all the unused parameters, and the local variables which also weren't used.
Now, when using this procedure you should first call the procedure, and the loop over the cursor to fetch the results and then use them:
DECLARE
CSR SYS_REFCURSOR;
stvMajr_code STVMAJR%STVMAJR_CODE%TYPE;
stvMajr_desc STVMAJR%STVMAJR_DESC%TYPE;
BEGIN
SP_BUSCAR_AL(VE_PROGRAM => 'some value',
c => CSR);
LOOP
FETCH CSR
INTO stvMajr_code,
stvMajr_desc;
EXIT WHEN CSR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('CODE=''' || stvMajr_code ||
''' DESC=''' || stvMajr_desc || '''');
END LOOP;
END;
Share and enjoy;
I have faced this question during an interview very recently. Please hep me on this. Let us say there are two functions in our schema the prototypes of which are as follows,
display(a varchar2, b number)
display(c varchar2, d varchar2, e number)
and I issue the following statement
drop function display;
which function will be dropped?
overloading means use of same subprograms to call different subprograms. this is an example
declare
x number;
y number;
function findenqno (fname1 varchar2) return number is --–function 1
enqno1 number (10);
begin
select enquiryno
into enqno1
from enquiry
where fname = fname1;
return(enqno1);
end;
function findenqno (refcode1 number) return number is --–function 2
enqno1 number (10);
begin
select enquiryno
into enqno1
from enquiry
where refcode = refcode1;
return (enqno1);
end;
begin
-- You call the function as:
X := findenqno ('ANIL');
dbms_output.put_line('using name '||x);
Y := findenqno (1002);
dbms_output.put_line('using refcode '||y);
end;
/
this is not a standlone subprogram so there is no point droping a overloaded function .
as it is not written in the db.