Wrong number of arguments in call of a SP PL-SQL [duplicate] - oracle

Just calling this directly from the editor (Toad). No idea why getting the above error having checked the function definition and variable types repeatedly. All of the information available online seems to be for stored procedures - which I don't believe are used here
DECLARE
TYPE attrs_type is VARRAY(10) of STRING(10);
l_ldap_host VARCHAR(255) := 'SERVERNAME';
l_ldap_port INT := 389;
l_ldap_user VARCHAR(255) := 'USERNAME';
l_ldap_passwd VARCHAR(255) := 'PASSWORD';
l_ldap_base VARCHAR(255) := 'l=something,dc=something';
l_session DBMS_LDAP.session;
l_retval NUMBER;
l_entry VARCHAR(255);
l_attrs attrs_type;
l_message VARCHAR(255) := null;
l_filter VARCHAR(255) := 'objectclass=*';
BEGIN
l_session := DBMS_LDAP.init(hostname => l_ldap_host,
portnum => l_ldap_port);
l_retval := DBMS_LDAP.simple_bind_s(ld => l_session,
dn => l_ldap_user,
passwd => l_ldap_passwd);
l_attrs(1) := '*'; -- retrieve all attributes
l_retval := DBMS_LDAP.search_s(
ld => l_session,
base => l_ldap_base,
scope => DBMS_LDAP.SCOPE_SUBTREE,
filter => l_filter,
attrs => l_attrs,
attronly => 0,
res => l_message);
DBMS_OUTPUT.put_line(l_message);
-- code to do stuff
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.put_line (SQLERRM);
END

You have to define l_attrs as dbms_ldap.string_collection, not your own type. Even if your type is defined in the same way, it will not be interchangeable with another apparently-similar type. To Oracle, your attrs_type is not the same as string_collection. Hence the error you're getting - you are indeed using the wrong type for that argument.
From the documentation:
A collection type defined in a package specification is incompatible with an identically defined local or standalone collection type.

Related

create list with value from ldap oracle apex

i would like to create a list with data from ldap directory.
I want to be able to display this list and go through this list to select a user from the list.
I have already read about pipeline functions that can return a list (can I as well retrieve data from ldap with such a function?). Another function can then be used to start a search through the list.
I haven't had much to do with ldap so far and would be grateful for any hints and yes in our system we use ldap for authentication.
create object type:
create or replace type ldap_user_ot as object
(email varchar2(30),
username varchar2(30),
firstname varchar2(256),
lastname varchar2(256),
uuid number);
create nested table type:
create or replace type ldap_user_nt as table of ldap_user_ot;
create table function
create or replace function get_user_from_ldap (
p_container IN VARCHAR2 DEFAULT ',ou=users,dc=my-company,dc=en')---what to enter here???
return ldap_user_nt
PIPELINED
IS
l_retval PLS_INTEGER;
l_session dbms_ldap.SESSION;
l_attrs dbms_ldap.string_collection;
l_message dbms_ldap.message;
l_entry dbms_ldap.message;
l_attr_name VARCHAR2(256);
l_ber_element dbms_ldap.ber_element;
l_vals dbms_ldap.string_collection;
l_user ldap_user_ot:=ldap_user_ot(NULL,NULL,NULL,NULL,NULL);
begin
--IF p_ad_group IS NOT NULL THEN lv_retval := -1; ----what to enter here? do I need if statement since I want to return all users
-- Choose to raise exceptions.
dbms_ldap.use_exception := TRUE;
-- Connect to the LDAP server.
l_session := dbms_ldap.Init(hostname => l_ldap_host,
portnum => l_ldap_port)
;
l_retval := dbms_ldap.Simple_bind_s(ld => l_session, dn => v_un,
passwd => p_password);
-- Get all attributes
l_attrs(1) := '*';
l_retval := dbms_ldap.Search_s(ld => l_session, base => l_ldap_base, scope
=>
dbms_ldap.scope_subtree,
filter => '(&(objectclass=posixAccount)(uid='
||p_user_name
||'))', attrs => l_attrs, attronly => 0, res => l_message);
IF dbms_ldap.Count_entries(ld => l_session, msg => l_message) > 0 THEN
v_tableresult := 1;
-- Get all the entries returned by our search.
l_entry := dbms_ldap.First_entry(ld => l_session, msg => l_message);
<< entry_loop >>
WHILE l_entry IS NOT NULL LOOP
-- Get all the attributes for this entry.
dbms_output.Put_line('---------------------------------------');
l_attr_name := dbms_ldap.First_attribute(ld => l_session,
ldapentry => l_entry,
ber_elem => l_ber_element);
<< attributes_loop >>
WHILE l_attr_name IS NOT NULL LOOP
-- Get all the values for this attribute.
l_vals := dbms_ldap.Get_values (ld => l_session,
ldapentry => l_entry,
attr
=>
l_attr_name
);
<< values_loop >>
FOR i IN l_vals.first .. l_vals.last LOOP
CASE l_attr_name
WHEN 'mail' THEN
v_email := Substr(L_vals(i), 1, 200);
WHEN 'givenName' THEN
v_firstname := Substr(L_vals(i), 1, 200);
WHEN 'uid' THEN
v_username := Substr(L_vals(i), 1, 200);
WHEN 'sn' THEN
v_lastname := Substr(L_vals(i), 1, 200);
ELSE
dbms_output.Put_line('ATTIBUTE_NAME: '
|| l_attr_name
|| ' = '
|| Substr(L_vals(i), 1, 200));
END CASE;
END LOOP values_loop;
l_attr_name := dbms_ldap.Next_attribute(ld => l_session,
ldapentry => l_entry,
ber_elem => l_ber_element);
END LOOP attibutes_loop;
l_entry := dbms_ldap.Next_entry(ld => l_session, msg => l_entry);
PIPE ROW(l_user);
END LOOP entry_loop;
END IF;
l_retval := dbms_ldap.Unbind_s(ld => l_session);
end if;
return;
EXCEPTION WHEN no_data_needed THEN
-- unbind from the directory
l_retval := dbms_ldap.Unbind_s(ld => l_session);
return;
WHEN others THEN
IF l_session IS NOT NULL THEN
l_retval := dbms_ldap.Unbind_s(ld => l_session);
END IF;
RAISE;
END get_user_from_ldap;

Pass the attachment correctly to UTL_MAIL.SEND_ATTACH_RAW

Say i have two files with the same filename sample.xlsx
in two separate directories u1\data\out1\ and u2\data\out2\
both of these directories already have entried in DBA_DIRECTORIES as EXT_OUT1 and EXT_OUT2, respectively.
I would like to send sample.xlsx from EXT_OUT1 using UTL_MAIL.SEND_ATTACH_RAW,
how can i pass it correctly to the attachment parameter?
Sample Anonymous Block (Note the comments):
DECLARE
vInHandle utl_file.file_type;
l_sender varchar2(100) := 'SO#SO.com';
l_recipients varchar2(100) := 'migs.isip.23#gmail.com';
l_subject varchar2(100) := 'Employee Roster Report';
l_message varchar2(100) := 'Hello';
l_attachment raw;
l_directory varchar2(100) := 'EXT_OUT1';
fname varchar2(100) := 'sample.xlsx';
BEGIN
/* how put RAW data into l_attachment here? */
--vInHandle := utl_file.fopen(l_directory, fname, 'R'); -- If i'm not mistaken, this reads the File from the specified directory
--utl_file.get_raw(); -- not sure what parameters i should pass
--utl_file.fclose(vInHandle); -- ?
UTL_MAIL.SEND_ATTACH_RAW
(
sender => l_sender
, recipients => l_recipients
, subject => l_subject
, message => l_message
, attachment => l_attachment
, att_filename => 'clouds.jpg'
);
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'The following error has occured: ' || sqlerrm);
END;
The attachment content is the value you are supplying as the attachment parameter. The filename is simply a label. It doesn't read the file, so you'd have to do that yourself and then assign that as the attachment.

Encrypt/Decrypt Password in Oracle Function

Due to previously poorly designed structure, the current database that I have to work with stores users' password as text.
Now, I am building a front end part that has to use those passwords and I certainly don't want to be sending passwords unencrypted.
My idea is to write an Oracle function to encrypt and decrypt text password and use those functions in the stored procedures that will return encrypted data.
What would be the best approach in Oracle to do so?
If you want to write your own functions to encrypt and decrypt data, you would simply want to call the DBMS_CRYPTO encrypt and decrypt methods with appropriate parameters (i.e. pick your encryption algorithm, your key, etc.).
Of course, if you write your own routines, assuming that you store the key in the database or somewhere the database has access to, you're not doing much for security. It's bad to send passwords unencrypted over the network but it is generally much worse to store unencrypted passwords in the database (or encrypted passwords if there is a decrypt method in the database that has access to the key to decrypt the data). It's generally a lot easier to steal data from a database than it is to sniff data getting sent over the network in order to find a password.
The right answer, of course, would be to rearchitect the system so that you don't store the passwords at all. You should be storing password hashes (which you can also generate using the DBMS_CRYPTO package) which are non-reversible.
Take a look at DBMS_CRYPTO
It has methods to encrypt and decrypt data built in. Better than writing your own.
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_crypto.htm
Or you could use the password hashing algorithm pbkdf2 like this http://mikepargeter.wordpress.com/2012/11/26/pbkdf2-in-oracle/
I verified the outcome with the rfc https://www.ietf.org/rfc/rfc6070.txt and it works fine.
Check this link for minimal iterations and key_size: PBKDF2 recommended key size?
Note that the result is double the length, because it is hex-encoded.
we store these columns in the db
PASSWORD_HASH VARCHAR2(512 BYTE),
PASSWORD_SALT VARCHAR2(256 BYTE),
PASSWORD_ITERATIONS NUMBER(10),
PASSWORD_HASH_METHOD VARCHAR2(30 BYTE),
PASSWORD_CHANGED_DT DATE
the hash, salt and iterations are to feed the pbkdf2 algorithm
the hash_method is for migration purposes
and the changed_dt is to expire passwords
Here's a packaged function (successful implementation) for encrypting passwords using (DBMS_CRYPTO)-
CREATE OR REPLACE
PACKAGE BODY encrypt_paswd
AS
G_CHARACTER_SET VARCHAR2(10) := 'AL32UTF8';
G_STRING VARCHAR2(32) := '12345678901234567890123456789012';
G_KEY RAW(250) := utl_i18n.string_to_raw
( data => G_STRING,
dst_charset => G_CHARACTER_SET );
G_ENCRYPTION_TYPE PLS_INTEGER := dbms_crypto.encrypt_aes256
+ dbms_crypto.chain_cbc
+ dbms_crypto.pad_pkcs5;
------------------------------------------------------------------------
--Encrypt a password
--Salt the password
------------------------------------------------------------------------
FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN RAW
IS
l_val RAW(32) := UTL_I18N.STRING_TO_RAW( p_val, G_CHARACTER_SET );
l_encrypted RAW(32);
BEGIN
l_val := utl_i18n.string_to_raw
( data => p_val,
dst_charset => G_CHARACTER_SET );
l_encrypted := dbms_crypto.encrypt
( src => l_val,
typ => G_ENCRYPTION_TYPE,
key => G_KEY );
RETURN l_encrypted;
END encrypt_val;
END encrypt_paswd;
This uses encrypt_aes256 -"Advanced Encryption Standard. Block cipher. Uses 256-bit key size." , chain_cbc- "Cipher Block Chaining. Plaintext is XORed with the previous ciphertext block before it is encrypted." and pad_pkcs5 - "Provides padding which complies with the PKCS #5: Password-Based Cryptography Standard".
In addition to this You can create a similar function to decrypt. like -
FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2
IS
l_decrypted RAW(32);
l_decrypted_string VARCHAR2(32);
l_user VARCHAR2(32);
BEGIN
SELECT user
INTO l_user
FROM dual;
if l_user = 'ADMIN' -- you can restrict usage of decrypt to certain db users only.
then
l_decrypted := dbms_crypto.decrypt
( src => p_val,
typ => G_ENCRYPTION_TYPE,
key => G_KEY );
l_decrypted_string := utl_i18n.raw_to_char
( data => l_decrypted,
src_charset => G_CHARACTER_SET );
RETURN l_decrypted_string;
else
RAISE_APPLICATION_ERROR(-20101, 'You are not authorized to use this function - decrypt_val()');
end if;
RETURN 'Unknown';
END decrypt_val;
You may also consider wrapping the package before compiling it in the database using wrap iname=package_name.pkb and then compiling the resulting plb.
user this code definitely work
create or replace PACKAGE "PKG_LOGI_PWD_REG"
AS
function ENCRYPT_VAL( P_VAL in varchar2 ) return varchar2;
function DECRYPT_VAL( P_VAL in raw ) return varchar2;
end;
/
create or replace PACKAGE BODY "PKG_LOGI_PWD_REG"
as
FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2
IS
l_decrypted RAW(32);
l_decrypted_string VARCHAR2(32);
L_USER varchar2(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY raw(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
BEGIN
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
l_decrypted := dbms_crypto.decrypt
( SRC => P_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
l_decrypted_string := utl_i18n.raw_to_char
( data => l_decrypted ,
src_charset => 'AL32UTF8' );
RETURN l_decrypted_string;
end DECRYPT_VAL;
FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN VARCHAR2
is
L_VAL RAW(32);
L_ENCRYPTED raw(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY RAW(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
begin
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
L_VAL := utl_i18n.string_to_raw
( data => p_val,
dst_charset => 'AL32UTF8' );
L_ENCRYPTED := dbms_crypto.encrypt
( SRC => L_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
return L_ENCRYPTED;
EXCEPTION when OTHERS then
RETURN SQLCODE||'-'||SQLERRM;
end ENCRYPT_VAL;
end PKG_LOGI_PWD_REG;
/

How to determine payload type for DBMS_AQ.DEQUEUE_ARRAY

I am attempting to use the function DBMS_AQ.DEQUEUE_ARRAY in Oracle 10.2.0.4.0. to browse the contents of a queue. Is there a way to determine the type to use for the message array? Is there some "generic" type I could be using? What I'm attempting is as follows:
CREATE or REPLACE TYPE I_NEED_THIS_TYPE AS ????
/
CREATE or REPLACE myFunction
return pls_integer
IS
dequeue_options DBMS_AQ.dequeue_options_t;
message_properties DBMS_AQ.message_properties_t;
msgPropArray DBMS_AQ.message_properties_array_t;
msgIdArray DBMS_AQ.msgid_array_t;
msgArray I_NEED_THIS_TYPE;
cMsgs pls_integer;
BEGIN
msgPropArray := DBMS_AQ.message_properties_array_t();
msgIdArray := dbms_aq.msgid_array_t();
msgArray := I_NEED_THIS_TYPE();
--where SOME_NAME and SOME_QUEUE_TABLE I get from
--select owner,name from user_queues;
dequeue_options.CONSUMER_NAME := 'SOME_NAME.SOME_QUEUE_TABLE';
dequeue_options.DEQUEUE_MODE := DBMS_AQ.BROWSE;
dequeue_options.NAVIGATION := DBMS_AQ.FIRST_MESSAGE;
dequeue_options.VISIBILITY := DBMS_AQ.IMMEDIATE;
dequeue_options.WAIT := DBMS_AQ.NO_WAIT;
dequeue_options.MSGID := null;
cMsgs := DBMS_AQ.DEQUEUE_ARRAY(
queue_name => 'MY_QUEUE_NAME',
dequeue_options => dequeue_options,
array_size => 30,
message_properties => msgPropArray,
payload_array => msgArray,
msgid_array => msgIdArray);
return cMsgs;
END;
/
I have tried numerous combinations of
CREATE or REPLACE TYPE I_NEED_THIS_TYPE AS VARRAY(100) of CLOB;
CREATE or REPLACE TYPE I_NEED_THIS_TYPE AS VARRAY(100) of SYS.xmltype;
CREATE or REPLACE TYPE I_NEED_THIS_TYPE AS VARRAY(100) of xmltype;
CREATE or REPLACE TYPE I_NEED_THIS_TYPE AS OBJECT(
id NUMBER,
xmlData CLOB
)
DECLARE
TYPE assoc_array is TABLE OF CLOB index by pls_integer;
myData assoc_array;
I AM able to use the DBMS_AQ.DEQUEUE function as expected, the message parameter for that is SYS.xmltype.
I am unable to use the administrator account, but do have privilieges to create types and functions. If there is no way to determine this information, what type of query should I ask the administrator to run so that I can determine this information?
Thanks!
It's probable your queue was created with a payload type when CREATE_QUEUE_TABLE was run. You can therefore find out the type for the queue by performing this query:
select OBJECT_TYPE
from DBA_QUEUE_TABLES
where OWNER = 'SOME_NAME' and QUEUE_TABLE = 'SOME_QUEUE_TABLE';
Then your function can use this:
type I_NEED_THIS_TYPE is varray(100) of <OBJECT_TYPE>;

How to run this stored procedure

I have to check this procedure
im giving following values as parameters
34220, 2815,'7/20/2011', 32760, 100, 'PMNT_CHECK', 1, null, "", false, null, null
DECLARE
P_APP_ID NUMBER;
P_USER_ID NUMBER;
P_DATE DATE;
P_INV_IDS WB_PROD.WB_PCK_TYPES.T_IDS;
P_AMNTS WB_PROD.WB_PCK_TYPES.T_NUMBERS;
P_PMNT_METHOD VARCHAR2(15);
P_BANK_AC_FROM NUMBER;
P_CHECK_NUMBERS WB_PROD.WB_PCK_TYPES.T_NUMBERS;
P_MEMO VARCHAR2(1000);
P_PAY_MULTIPLE NUMBER;
P_CRD_IDS WB_PROD.WB_PCK_TYPES.T_IDS;
P_CRD_AMOUNTS WB_PROD.WB_PCK_TYPES.T_PRICES;
O_PY_ID NUMBER;
BEGIN
P_APP_ID := 34220;
P_USER_ID := 2815;
P_DATE := '7/20/2011';
-- Modify the code to initialize the variable
P_INV_IDS := 32760;
-- Modify the code to initialize the variable
P_AMNTS := 100;
P_PMNT_METHOD := 'PMNT_CHECK';
P_BANK_AC_FROM := 1;
-- Modify the code to initialize the variable
--P_CHECK_NUMBERS := NULL;
P_MEMO := '';
P_PAY_MULTIPLE := false;
-- Modify the code to initialize the variable
-- P_CRD_IDS := NULL;
-- Modify the code to initialize the variable
-- P_CRD_AMOUNTS := NULL;
WB_PCK_BILL_PAYMENTS.PAY_BILLS(
P_APP_ID => P_APP_ID,
P_USER_ID => P_USER_ID,
P_DATE => P_DATE,
P_INV_IDS => P_INV_IDS,
P_AMNTS => P_AMNTS,
P_PMNT_METHOD => P_PMNT_METHOD,
P_BANK_AC_FROM => P_BANK_AC_FROM,
P_CHECK_NUMBERS => P_CHECK_NUMBERS,
P_MEMO => P_MEMO,
P_PAY_MULTIPLE => P_PAY_MULTIPLE,
P_CRD_IDS => P_CRD_IDS,
P_CRD_AMOUNTS => P_CRD_AMOUNTS,
O_PY_ID => O_PY_ID
);
DBMS_OUTPUT.PUT_LINE('O_PY_ID = ' || O_PY_ID);
END;
Im getting error at this line
P_INV_IDS := 32760;
i checked type of
P_INV_IDS WB_PROD.WB_PCK_TYPES.T_IDS;
which is in Declare statement, which is like this
type t_ids is table of t_id
index by binary_integer;
I donot understand how to give parameter to this type. Please let me know how to give this parameter.
Thank you
P_INV_IDS is an associative array as per your type declaration.
you can not assign this way
P_INV_IDS := 32760;
you need to specify the index in P_INV_IDS to which you are assigning value
something like
P_INV_IDS(0) := 32760;
P_INV_IDS(1) := 32761;
http://www.java2s.com/Tutorial/Oracle/0520__Collections/AssignvaluetoPLSQLtable.htm
How is the TYPE t_id defined? That will dictate how you initialize this array. If it were a number, then you will want to initialize your value this way:
P_INV_IDS(1) := 32760;
If, however, t_id is defined as, say a RECORD:
TYPE t_id IS RECORD (
ID INTEGER;
DESCRIPTION VARCHAR2(32);
);
Then you might want to initialize thusly:
P_INV_IDS(1).id := 32760;
P_INV_IDS(1).description := 'Description for 32760';

Resources