Pass varray variables into stored procedure - basic - oracle

Hello I am a php developer, trying to get going with Oracle. So I need to pass a collection of variables into an Oracle stored procedure. So as a basic try, I am trying to access a procedure which would accept three parameters, out of which two would be varrays, but when I pass the declared varrays, I am getting an error. I am pretty sure, it is something to do with a little syntax, but i am not able to figure out that thing.
Below is my table schema and stored procedure:
create table emails (
user_id varchar2(10),
friend_name varchar2(20),
email_address varchar2(20));
create or replace type email_array as varray(100) of varchar2(20);
/
show errors
create or replace type friend_array as varray(100) of varchar2(20);
/
show errors
create or replace procedure update_address_book(
p_user_id in varchar2,
p_friend_name friend_array,
p_email_addresses email_array)
is
begin
delete from emails where user_id = p_user_id;
forall i in indices of p_email_addresses
insert into emails (user_id, friend_name, email_address)
values (p_user_id, p_friend_name(i), p_email_addresses(i));
end update_address_book;
Now, below pasted is my the way I am trying to access this procedure from an anonymous block.
declare
type email_list is varray(100) of varchar2(20);
type friend_list is varray(100) of varchar2(20);
emails email_list;
friends friend_list;
begin
emails :=email_list('khwaja#gmail.com','sayya#gmail.com','mayya#gmail.com');
friends := friend_list('kwaja','sayya','mayya');
execute update_address_book('1',emails,friends);
end;
The error I am getting is near the execute, I think I am not supposed to execute a procedure inside a declare block, but I am unable to understand how would I work around.

You don't need the keyword EXECUTE to call the procedure from within a PL/SQL block. Just remove that word.
But it would be helpful if you showed the actual error(s) you're getting as there could be something else wrong. For example, you also have the parameters to the update_address_book() call in the wrong order, and you're recreating new types inside your block instead of using the ones declared earlier.
This will run:
declare
emails email_array;
friends friend_array;
begin
emails := email_array('khwaja#gmail.com','sayya#gmail.com','mayya#gmail.com');
friends := friend_array('kwaja','sayya','mayya');
update_address_book('1',friends,emails);
end;
/

Related

How to transfer pop up window functionality into code in Oracle SQL for variable declaration?

I am preparing Oracle SQL program for my team to use. This can eventually used by other teams as well by changing few where conditions. We all are using Toad for Oracle to run the query. So I added variables in the query. See the example code below.
DECLARE v_lob VARCHAR(2);BEGIN v_lob := 't' ;END;
select :v_lob as Test from dual
My issue is when Toad has a pop-up window option to bind the variable. Since my team is using v_lob := 't' any way, I prefer them not to have enter it each time when they query. How can I remove the pop-up window option and use the value 't' for the variable as in the code?
You might want to use a CONTEXT for holding a large number of session variables. This solution should work with any IDE.
One user, one time, must create the context and create a package for setting the context values (based on this oracle-base article):
--Create a package on a shared schema.
create or replace package context_api is
procedure set_parameter(p_name varchar2, p_value varchar2);
end;
/
create or replace package body context_api is
procedure set_parameter(p_name varchar2, p_value varchar2) is
begin
dbms_session.set_context('my_context', p_name, p_value);
end;
end;
/
--Create a context on a shared database.
--(Note that contexts are global objects and don't belong to a specific schema.)
create or replace context my_context using context_api;
Each user then needs code like this in their worksheets:
--At the top of the worksheet, set the variables like this:
begin
context_api.set_parameter('v_lob', 'asdf');
end;
/
--Call the variables with SYS_CONTEXT:
select sys_context('my_context', 'v_lob') as test from dual;
TEST
----
asdf

ERROR: Remote Operations Not Permitted on Object Tables or User-Defined Type Columns

Whenever I am trying to fetch data from remote table using db link and put inside the collection variable, I am getting ORA-22804 Error.
I don't have access to the remote database.
I tried recreating the type using oid, but still facing the same issue.
create or replace type type_demo as table of varchar2(32767);
CREATE OR REPLACE PROCEDURE PROC_TEST(EMP_ID IN TYPE_DEMO,E_NAME OUT TYPE_DEMO)
AS
BEGIN
SELECT EMP_NAME BULK COLLECT INTO E_NAME FROM EMP_TABLE#CDM_LINK WHERE EMPLOYEE_ID MEMBER OF EMP_ID;
END;
/
Whenever I am trying to test the above procedure I am getting ORA-22804 Error:
DECLARE
A TYPE_DEMO:=TYPE_DEMO('1001');
B TYPE_DEMO:=TYPE_DEMO();
BEGIN
PROC_TEST(A,B);
FOR I IN 1..B.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(B(i));
END LOOP;
END;
The error message says it all:
ORA-22804 remote operations not permitted on object tables or user-defined type columns
You're trying to do exactly that - remote operation on a user defined type type_demo, over a database link CDM_LINK.
Cheers

stored procedure for select query not giving output

I am using sqlplus and have a table named users from which I wish to retrieve all values with the help of a stored procedure in oracle. Here is what I am trying to do -
create or replace procedure getall(prc out sys_refcursor)
is
begin
open prc for select * from users
end;
/
When I hit return after this, I get the following error -
Warning: Procedure created with compilation errors.
Why does this happen? And how do I get the desired output? Help much appreciated!
To see the compilation errors use the show errors‌​ SQL*Plus command (which also works in SQL Developer), or query the user_errors view which works with any client. You can also query all_errors to see problems with objects that are not in your schema.
But you are just missing a semicolon after the select:
create or replace procedure getall(prc out sys_refcursor)
is
begin
open prc for select * from users;
end;
/
You'll need a bind variable to be able to see the output in SQL*Plus, e.g.:
variable rc refcursor;
exec getall(:rc);
print rc
Notice the colon before the rc in the procedure call, which shows it's a bind variable reference. And exec is a shorthand anonymous block.
You might find it simpler to have a function that returns a ref cursor, or a pipelined function; or just query the table directly of course.

Log In procedure not working in oracle 11g

My table contain only two row. When i am giving empid and password of another row stil login is done. This is my procedure
CREATE OR REPLACE PROCEDURE prco_LoginCheck(Emp_Id IN number,
Cpassword In varchar2,
cur_out out Types.cursor_type) AS
BEGIN
open cur_out for
select count(*) from TBL_REGISTRATION a
where a.confirm_password= Cpassword and a.emp_id=Emp_Id;
END prco_LoginCheck;
Aside from the fact that storing a password in a table is a horribly insecure design (you should only be storing a hash of the password plus some random salt), and the fact that it doesn't make a lot of sense to define your own weak ref cursor type rather than using the built-in sys_refcursor (unless you really need to work with ancient versions of Oracle), and that returning a cursor from a procedure seems like a really odd way to do a login rather than writing a function that returns a boolean or some indicator, the problem is one of naming conventions.
When you write the SQL statement
select count(*)
from TBL_REGISTRATION a
where a.confirm_password= Cpassword
and a.emp_id=Emp_Id;
I assume that your intention is to compare the emp_id column in tbl_registration to the emp_id parameter. That is not actually what is happening, however. Your unqualified emp_id is resolved as a column in the table not the parameter. Normally, people use a naming convention to ensure that parameter names don't match column names. I, for example, generally use a p_ prefix for parameters and l_ for local variables. That would look something like
CREATE OR REPLACE PROCEDURE prco_LoginCheck(p_Emp_Id IN number,
p_password In varchar2,
p_cur_out out Types.cursor_type) AS
BEGIN
open p_cur_out for
select count(*)
from TBL_REGISTRATION a
where a.confirm_password= p_password
and a.emp_id=p_Emp_Id;
END prco_LoginCheck;
It is also possible to use your existing parameter names and just fully qualify the emp_id to force it to resolve to the parameter name
CREATE OR REPLACE PROCEDURE prco_LoginCheck(Emp_Id IN number,
Cpassword In varchar2,
cur_out out Types.cursor_type) AS
BEGIN
open cur_out for
select count(*)
from TBL_REGISTRATION a
where a.confirm_password= Cpassword
and a.emp_id=prco_LoginCheck.Emp_Id;
END prco_LoginCheck;

Oracle Add a new member function/procedure to an object type

I am trying to do the following; let's say I have created an object type in Oracle
create type test as object(
name varchar2(12),
member procedure print1);
/
create type body test is
member procedure print1 is
begin
dbms_output.put_line('Test');
end print1;
end;
/
Now I want to add a new member procedure print2 - again, I can do that by typing:
alter type test
add member procedure print2 cascade;
Now, my question is: how do I just define the body and add print2 without repeating other definitions? I know I can do a create or replace body test and list implementations for both procedures, but this is not practical as I have to maintain code for object types that others wrote and I have no idea how they implemented the code, just that these procedures and functions exist.
I have been through the documentation and the web, but could not find an answer and it seems silly to me that Oracle would expect the developer to type all the definitions again.
Regards,
George
How about creating a procedure that dynamically adds a definition to a type:
create or replace procedure add_procedure(p_new_procedure_definition varchar2)
authid current_user
is
v_object_type_body varchar2(32767) := 'create or replace ';
begin
--Build string with current definitions
for source_code in
(
select text
from user_source
where name = 'TEST'
and type = 'TYPE BODY'
order by line
) loop
--Don't include the last "END;" yet.
--(Huge assumption that the package ends with "END;")
if replace(upper(trim(source_code.text)),chr(10)) <> 'END;' then
v_object_type_body := v_object_type_body||source_code.text;
end if;
end loop;
--Add new definition
v_object_type_body := v_object_type_body||chr(10)||
p_new_procedure_definition||chr(10)||'end;';
--For debugging
--dbms_output.put_line(v_object_type_body);
--Compile the type
execute immediate v_object_type_body;
end;
/
Then run it like this:
begin
add_procedure(
'
member procedure print2 is
begin
dbms_output.put_line(''Test2'');
end print2;
'
);
end;
/
Although you need to make some pretty big assumptions about how the package will end. To make this a truly generic solution you'd need to build a PL/SQL parser, which is basically impossible. And the procedure will only work with 32K, if the types are very large you'll probably need to use CLOBs.
Use Oracle SQL Developer to change the type body.
Or use any text editor to change the source file and run it in your favorite SQL prompt.
Object types are the most advanced programming concept in Oracle. Maybe you'd be better off with standalone functions?
However, I understand your point. AFAIK the type body cannot contain functions that are not listed in the specification. The order of the methods shouldn't matter either, so there seems to be no reason not to have this option.

Resources