CURRENT_ROLE() behaviour in procedure vs function - user-defined-functions

I'd like to validate my observation of getting different result from CURRENT_ROLE() when called from a procedure vs UDF..
For Example, from the UI, I create below procedure and function as role_A:
create or replace procedure tst_exec_owner_proc()
returns VARCHAR
language javascript
as
$$
// Set the second session variable
var stmt = snowflake.createStatement(
{sqlText: "select CURRENT_ROLE();"}
);
var rs = stmt.execute();
rs.next();
return rs.getColumnValue(1);
$$
;
create or replace function tst_exec_owner_func()
returns VARCHAR
as
$$
select current_role()
$$;
Now, invoking the procedure, and function returns "role_A";
But once I switch to role_B, call tst_exec_owner_proc() returns "role_A" whereas select tst_exec_owner_func() returns "role_B". Is this expected behaviour (assuming role_A and role_B have necessary USAGE grants)?

A stored procedure can execute with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE ... EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE ... EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. By default (if neither OWNER nor CALLER is specified explicitly at the time the procedure is created), the procedure runs as an owner’s rights stored procedure.
Try include EXECUTE AS CALLER in your code.

Related

To pass collection to Stored procedure call as input without using the variable

I have a requirement where we have to call a oracle Stored Procedure which has collection type as input parameter.
So my stored procedure is like:
Create or replace package test
As
Type t is table of varchar(400) index by binary_integer.
Procedure testprc(p_client_id in number,t_no in number,t1 in t,t2 in t);
End;
Create or replace package body test
As
Procedure testprc(p_client_id in number,t_no in number,t1 in t, t2 in t)
is
Begin
for i in 1 ..tno loop
Insert into client
(Client_id,Client_phone,client_email) values (p_client_id,t1(i),t2(i));
End loop;
End;
End;
Now in the call to this stored procedure testprc.test I don't want to create a variable of type t and pass it to the stored procedure instead I want to directly pass the list of values to the SP.
Something like this
Exec testprc(13,1,{1=>'22737371'},{1=>'test#abc.com'}).
Is there any way I can achieve this.
If you are on 18c or higher, you can use a qualified expression to avoid having to create a temporary variable to hold associative arrays. For example:
SQL> exec test.testprc(13,1,test.t(1=>'22737371'),test.t(1=>'test#abc.com'))
PL/SQL procedure successfully completed.

What is the result for stored procedure with in ,out parameters and IS keyword parameters before procedure body

Procedure with in , out parameters and having IS keyword with parameters list before BEGIN. In this case which result we will get after executing procedure.
PROCEDURE sample_proc (id in VARCHAR2, name in VARCHAR2, Course out varchar2)
IS error EXCEPTION, error_code VARCHAR2(100), courseID NUMBER, price NUMBER
BEGIN
select * from student where ID =id and name=name;
END executePROC;
Which fields we will get as result after executing via mybatis.
The stored procedure having parameters with data type before BEGIN keyword. In this case the parameters after IS and Before BEGIN keyword how it will work. Please explain
Which fields we will get as result after executing via mybatis.
None, the code has syntax errors and will not compile in Oracle.
You have:
A statement starting with PROCEDURE and not CREATE PROCEDURE (assuming that it is not part of a package as you do not include a preceding CREATE PACKAGE statement).
, following the variable declarations and not ;
A SELECT statement in the PL/SQL scope that does not have an INTO clause.
WHERE id = id AND name=name is (almost) the same as doing WHERE 1=1 AND 1=1 as the id and name values on both sides of the equality comparison will be from the local scope of the SQL statement and will not reference the procedure's arguments.
Variables that you are not using.
The procedure's identifier does not match the identifier after the final END statement.
To fix it you want something like:
CREATE PROCEDURE sample_proc (
i_id in STUDENT.ID%TYPE,
i_name in STUDENT.NAME%TYPE,
o_Course out STUDENT.COURSEID%TYPE
)
IS
BEGIN
SELECT courseid
INTO o_course
FROM student
WHERE id = i_id
AND name = i_name;
END sample_proc;
/
db<>fiddle here
IS keyword with parameters list before BEGIN.
They are not parameters, they are local variables.
As MTO has explained, the example you gave is not valid for a number of reasons.
But for the sake of argument, if you did actually have something like:
... PROCEDURE sample_proc (...)
IS
error EXCEPTION;
error_code VARCHAR2(100);
courseID NUMBER;
price NUMBER;
BEGIN
...
then the bit between IS and BEGIN is the optional declaration part, as described in the documention:
Declarative part (optional)
This part declares and defines local types, cursors, constants, variables, exceptions, and nested subprograms. These items cease to exist when the subprogram completes execution.
This part can also specify pragmas.
Note: The declarative part of a subprogram does not begin with the keyword DECLARE, as the declarative part of an anonymous block does.
The bit that is particularly relevant to your question (as I understand it anyway) is "These items cease to exist when the subprogram completes execution." They are local variables for use within the procedure, and not visible to or accessible by whatever calls the procedure.
The only data made visible to the caller is whatever it put into the OUT parameters.

Using DECODE in PL/SQL procedure call

I have a stored PL/SQL procedure (say X) that inserts records into a table. I am calling that procedure from another procedure (say Y). I have some parameters in procedure Y like para1,para2,para3 which can have two values either zero or one, for zero and one values I have one id stored in a TBL_SETUP, and when I call procedure X I want to check that if para1 is null then return null, if it is not null then check if it is one then return YES_ID and if it is no then return NO_ID.
I have tried something like this. I wrote a SELECT statement for getting YES_ID,NO_ID before calling the procedure and it is working fine, but when I write procedure call as below, it is giving me error "PLS-00204: Function or pseudo-column may be used inside a SQL statement only". How to use DECODE in a procedure call?
PROC_X(DECODE(para1,NULL,NULL,DECODE(para1,'1',YES_ID,NO_ID)),para2,NULL,NULL,DECODE(para2,'1',YES_ID,NO_ID)),para3,NULL,NULL,DECODE(para3,'1',YES_ID,NO_ID)),)
You could use SELECT INTO:
DECLARE
DECODE_RESULT VARCHAR2(100); -- or any suitable data type
BEGIN
SELECT DECODE(...) INTO DECODE_RESULT FROM dual;
PROC_X(DECODE_RESULT);
END;

Calling a Procedure in Select Statement

I have a package consists of function and procedures
CREATE OR REPLACE PACKAGE BODY schema.pkg_product as
function xxxxx()
procedure product_get(p_product_id IN Number,
P_direct_balance Out Number,
P_indirect_balance Out Number) IS
v_request CLOB :=<soapenv:Envelope xmnlns:----->
v request_end varchar(100) := <can:----->
BEGIN
Selct statement
END
My question is can we can Call the procedure in the select statement and how can I get the P_direct_balance , P_indirect_balance. if so in the select query coz I want to retrieve that data from the procedure.
It's not possible. You could write a function but you cannot use functions with out parameters in SQL. So you'll have to rewrite your code. For instance create two functions that return p_direct_balance and p_indirect_balance.
If rewriting the procedure to be a function with an out parameter is not possible, I would suggest altering the procedure to write the relevant values to a temporary table and commit. Then use your select statement to retrieve the values from the temp table.

Receive a db link name as a variable in Oracle PLSQL

I have the following function in PLSQL which connects remotely to different Database Links to change passwords:
FUNCTION fun_change_password(DB_LINK_VARIABLE varchar2)
RETURN binary_integer IS
jobid binary_integer;
BEGIN
dbms_job.submit#DB_LINK_VARIABLE (jobid,'begin execute immediate ''alter user MYUSER identified by mypassw''; end;');
COMMIT;
RETURN jobid;
END;
My goal is to specify which DB Link to use sending its name in a varchar2 variable called *DB_LINK_VARIABLE*. But when I compile this into a package, the parser sends me an error:
PLS-00352: Unable to access another database 'DB_LINK_VARIABLE'
Obviously, I pre-configured and tested all my datalinks and works perfectly.
How can I use variable 'DB_LINK_VARIABLE' into this code?
You can do this with dynamic SQL by executing an anonymous PL/SQL block.
Below is a simple example where I execute dbms_utility.get_time function over a database link.
$ cat so35.sql
declare
function remote_time(p_dblink in varchar2) return number is
v_time number;
begin
execute immediate
'begin :time := dbms_utility.get_time#' || p_dblink || '; end;'
using out v_time;
return v_time;
end;
begin
dbms_output.put_line('time = ' || remote_time('foo'));
end;
/
SQL> select dbms_utility.get_time as local, dbms_utility.get_time#foo as remote from dual;
LOCAL REMOTE
---------- ----------
77936814 1546395927
SQL> #so35.sql
time = 1546396850
PL/SQL procedure successfully completed.
SQL>
PLS-00352: Unable to access another database 'DB_LINK_VARIABLE'
Error message shows, oracle is looking for a db link called DB_LINK_VARIABLE instead of the value associated to it.
You may need to do a check on variable, and make the hardcoding of the db link , instead of using a bind variable for it.!
Functions are compiled code in DB, so I guess oracle would do a semantic check on this during compilation itself, rather than doing it in runtime.
If it was just a SQL call to remote db, EXECUTE IMMEDIATE would have been used. Since it is PL/SQL there is no way for it, but for having multiple IF conditions, to validate the variable name, and making the full name in your PL/SQL block.

Resources