Hi everyone so I'm making an authentification scheme that has 2 functions.
A function that authenticates the user. All the data for the user is stored in a table called DJELATNIK which has attributes KORISNICKO_IME (username) and LOZINKA (password) and some more.
So this function just returns true if the username and password match in that table.
create or replace FUNCTION
prijava_custom(p_username IN VARCHAR2, p_password IN VARCHAR2)
RETURN BOOLEAN
AS
v_korisnicko varchar2(100);
v_lozinka varchar2(100);
BEGIN
SELECT KORISNICKO_IME, LOZINKA
INTO v_korisnicko, v_lozinka
FROM DJELATNIK
WHERE UPPER(KORISNICKO_IME) = UPPER(p_username)
AND LOZINKA = enkripcija_MD5(p_password);
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN FALSE;
END;
The other function is the encryption mentioned in the last function.
create or replace Function enkripcija_MD5 (pstring IN VARCHAR2) Return VARCHAR2 IS
hash_lozinka VARCHAR2(32) := '' ;
BEGIN
hash_lozinka := DBMS_OBFUSCATION_TOOLKIT.md5(input => UTL_I18N.STRING_TO_RAW (pstring, 'AL32UTF8' ));
RETURN hash_lozinka;
END enkripcija_MD5;
The thing that escapes my mind at the moment is how I save the encrypted password in the table instead of the plain text password?
I tried making an "After submit" process on the FORM edit page but that didn't work. Tried making a dynamic action that sets the password value right away to the hashed value, but that didnt work either. I know it's like a really banal thing and I should know it but I really cant think of it so I'm looking for ideas.
One option would be a database trigger.
Here's an example.
Simplified table:
SQL> CREATE TABLE djelatnik
2 (
3 korisnicko_ime VARCHAR2 (20),
4 lozinka VARCHAR2 (32)
5 );
Table created.
Function:
SQL> CREATE OR REPLACE FUNCTION enkripcija_MD5 (pstring IN VARCHAR2)
2 RETURN VARCHAR2
3 IS
4 hash_lozinka VARCHAR2 (32) := '';
5 BEGIN
6 hash_lozinka :=
7 DBMS_OBFUSCATION_TOOLKIT.md5 (
8 input => UTL_I18N.STRING_TO_RAW (pstring, 'AL32UTF8'));
9 RETURN hash_lozinka;
10 END enkripcija_MD5;
11 /
Function created.
Trigger:
SQL> CREATE OR REPLACE TRIGGER trg_biu_djel
2 BEFORE INSERT OR UPDATE
3 ON djelatnik
4 FOR EACH ROW
5 BEGIN
6 :new.lozinka := enkripcija_md5 (:new.lozinka);
7 END;
8 /
Trigger created.
Let's test it:
SQL> INSERT INTO djelatnik (korisnicko_ime, lozinka)
2 VALUES ('little', 'foot');
1 row created.
Table contents:
SQL> SELECT * FROM djelatnik;
KORISNICKO_IME LOZINKA
-------------------- --------------------------------
little D8735F7489C94F42F508D7EB1C249584
Query from your prijava_custom function:
SQL> SELECT *
2 FROM djelatnik
3 WHERE UPPER (korisnicko_ime) = 'LITTLE'
4 AND lozinka = enkripcija_md5 ('foot');
KORISNICKO_IME LOZINKA
-------------------- --------------------------------
little D8735F7489C94F42F508D7EB1C249584
SQL>
Testing your function:
SQL> set serveroutput on
SQL> CREATE OR REPLACE FUNCTION prijava_custom (p_username IN VARCHAR2,
2 p_password IN VARCHAR2)
3 RETURN BOOLEAN
4 AS
5 v_korisnicko VARCHAR2 (100);
6 v_lozinka VARCHAR2 (100);
7 BEGIN
8 SELECT KORISNICKO_IME, LOZINKA
9 INTO v_korisnicko, v_lozinka
10 FROM DJELATNIK
11 WHERE UPPER (KORISNICKO_IME) = UPPER (p_username)
12 AND LOZINKA = enkripcija_MD5 (p_password);
13
14 RETURN TRUE;
15 EXCEPTION
16 WHEN NO_DATA_FOUND
17 THEN
18 RETURN FALSE;
19 END;
20 /
Function created.
SQL> begin
2 if prijava_custom('little', 'foot') then
3 dbms_output.put_line('True');
4 else
5 dbms_output.put_line('False');
6 end if;
7 end;
8 /
True
PL/SQL procedure successfully completed.
SQL>
Everything looks OK to me.
Related
Sample Data
create table Employees (emp_id number, emp_name varchar2(50), salary number, department_id number) ;
insert into Employees values(1,'ALex',10000,10);
insert into Employees values(2,'Duplex',20000,20);
insert into Employees values(3,'Charles',30000,30);
insert into Employees values(4,'Demon',40000,40);
Code :
create or replace function validate_emp(empno in number)
return boolean
is lv_count number
begin
select count(employee_id) into lv_count from hr.employees where employee_id = empno;
if lv_count >1 then
return true;
else
return false;
end;
I want to Create a function named VALIDATE_EMP which accepts empno as a parameter, Returns TRUE if the specified employee exists in the table name “Employeee” else FALSE.
missing semi-colon as terminator of the local variable declaration
if user you're connected to isn't hr, remove it (otherwise, leave it as is)
column name is emp_id, not employee_id
missing end if
When fixed, code compiles:
SQL> CREATE OR REPLACE FUNCTION validate_emp (empno IN NUMBER)
2 RETURN BOOLEAN
3 IS
4 lv_count NUMBER;
5 BEGIN
6 SELECT COUNT (emp_id)
7 INTO lv_count
8 FROM employees
9 WHERE emp_id = empno;
10
11 IF lv_count > 1
12 THEN
13 RETURN TRUE;
14 ELSE
15 RETURN FALSE;
16 END IF;
17 END;
18 /
Function created.
SQL>
How to call it? Via PL/SQL as Oracle's SQL doesn't have the Boolean datatype.
SQL> set serveroutput on
SQL> declare
2 result boolean;
3 begin
4 result := validate_emp(1);
5
6 dbms_output.put_line(case when result then 'employee exists'
7 else 'employee does not exist'
8 end);
9 end;
10 /
employee does not exist
PL/SQL procedure successfully completed.
SQL>
Maybe you'd rather return VARCHAR2; then you'd mimic Boolean, but you'd be able to use it in plain SQL:
SQL> CREATE OR REPLACE FUNCTION validate_emp (empno IN NUMBER)
2 RETURN VARCHAR2
3 IS
4 lv_count NUMBER;
5 BEGIN
6 SELECT COUNT (emp_id)
7 INTO lv_count
8 FROM employees
9 WHERE emp_id = empno;
10
11 IF lv_count > 1
12 THEN
13 RETURN 'TRUE';
14 ELSE
15 RETURN 'FALSE';
16 END IF;
17 END;
18 /
Function created.
SQL> select validate_emp(1) from dual;
VALIDATE_EMP(1)
-------------------------------------------------------------------
FALSE
SQL>
In the desired structure, the function will take 2 string parameters.
If 2nd String is found in 1st String; The 1.string in the 2.string will be removed and added to the end of the 2.string.
If it is not found, the error 'NOT FOUND' will be given.
The desired structure should be as follows.
Here's one option:
SQL> create or replace function f_test (par_1 in varchar2, par_2 in varchar2)
2 return varchar2
3 is
4 retval varchar2(20);
5 begin
6 if instr(par_1, par_2) > 0 then
7 retval := replace(par_1, par_2) || par_2;
8 else
9 retval := 'Not found';
10 end if;
11
12 return retval;
13 end;
14 /
Function created.
SQL>
SQL> select f_test('topualiat', 'ali' ) result_1,
2 f_test('little' , 'foot') result_2
3 from dual;
RESULT_1 RESULT_2
--------------- ---------------
topuatali Not found
SQL>
I am executing the below procedure from SQL DEVELPER, I get an option to insert the input values for z_id & i_type however i_data is greyed out.
can a procedure with input param as collection cannot be executed from SQL
DEVELOPER tool ?
What am I missing here ? The code gets compiled but unable to execute it through SQL Developer
below is what I have done but this gives compilation error on Oracle 19c
create or replace type my_type AS OBJECT (
p_id number,
p_text varchar2 (100),
p_details clob);
/
create or replace type tab1 is table of my_type;
/
create or replace procedure vehicle_det (z_id in varchar2, i_type in varchar2, i_data in tab1)
IS
BEGIN
for i in 1..i_data.count
LOOP
if (i_type ='BMW')
THEN
UPDATE STOCK_DATA
set stock_id=i_data(i).p_id, stock_des=i_data(i).p_text, clearance=i_data(i).p_details where s_id=z_id ;
end if;
end loop;
end vehicle_det;
Below is the error, please provide your wisdom::::
**ERROR --ORA-06531 Reference to uninitialized collection **
Here's code that actually works. See how it is done.
Types and sample table:
SQL> create or replace type my_type AS OBJECT (
2 p_id number,
3 p_text varchar2 (100),
4 p_details clob);
5 /
Type created.
SQL> create or replace type tab1 is table of my_type;
2 /
Type created.
SQL> create table stock_data
2 (s_id number,
3 stock_id number,
4 stock_des varchar2(20),
5 clearance clob);
Table created.
SQL> insert into stock_data
2 select 1 s_id, 1 stock_id, 'Description' stock_Des, null clearance
3 from dual;
1 row created.
SQL>
Procedure:
SQL> create or replace procedure vehicle_det
2 (z_id in varchar2, i_type in varchar2, i_data in tab1)
3 IS
4 BEGIN
5 for i in 1..i_data.count LOOP
6 if i_type = 'BMW' THEN
7 UPDATE STOCK_DATA
8 set stock_id = i_data(i).p_id,
9 stock_des = i_data(i).p_text,
10 clearance = i_data(i).p_details
11 where s_id = z_id ;
12 end if;
13 end loop;
14 end vehicle_det;
15 /
Procedure created.
Testing: current table contents / run the procedure / see the result:
SQL> select * from stock_data;
S_ID STOCK_ID STOCK_DES CLEARANCE
---------- ---------- -------------------- ------------------------------
1 1 Description
SQL> declare
2 l_data tab1 := tab1();
3 begin
4 l_data.extend;
5 l_data(1) := my_type(1, 'This is BMW', 'Oh yes, this IS a BMW!');
6
7 vehicle_det(1, 'BMW', l_data);
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select * from stock_data;
S_ID STOCK_ID STOCK_DES CLEARANCE
---------- ---------- -------------------- ------------------------------
1 1 This is BMW Oh yes, this IS a BMW!
SQL>
i am using below function to change the password ,
it give me compilation error once i compile
CREATE or replace FUNCTION updatePassword(CurrentP VARCHAR2,NewPwd VARCHAR2,StudentId VARCHAR2) RETURN VARCHAR2
is
getCount integer :=0;
BEGIN
Select count(*) into getCount from users where student_id=StudentId and Password=md5(CurrentP);
if getCount == 1
then
update users set Password=md5(NewPwd) where student_id=StudentId and Password=md5(CurrentP);
else
getCount = 0
RETURN getCount;
END;
/
i want to return getCount value on successfully update password else it return 0
below is error mention
UPDATEPASSWORD Compiled (with errors)
You have some PL/SQL syntax issues
CREATE or replace FUNCTION updatePassword(CurrentP VARCHAR2,NewPwd VARCHAR2,StudentId VARCHAR2) RETURN VARCHAR2
is
getCount integer :=0;
BEGIN
Select count(*) into getCount from users where student_id=StudentId and Password=md5(CurrentP);
if getCount = 1
then
update users set Password=md5(NewPwd) where student_id=StudentId and Password=md5(CurrentP);
else
getCount := 0;
end if;
RETURN getCount;
END;
/
You have a little syntax error. The code should look likes this:
CREATE or replace FUNCTION updatePassword(
CurrentP in VARCHAR2,
NewPwd in VARCHAR2,
StudentId in number) RETURN number
is
getCount number:=0;
BEGIN
Select count(*) into getCount from users where student_id=StudentId and Password=md5(CurrentP);
if getCount = 1
then
update users set Password=md5(NewPwd) where student_id=StudentId and Password=md5(CurrentP);
end if;
RETURN getCount;
END;
UPDATE:
After a closer look, you have a lot of syntax problems^^ Modified the code.
Suggestions:
Avoid stand alone functions/procedures. Use the Oracle advantage - packages. Helps to avoid invalidated objects situation;
When you use PL/SQL - try to stick with the coding standards in PL/SQL.
Set the correct types of variables.
Here's an example which shows how to do that.
First, test case. The MD5 function doesn't do anything; it just returns the IN parameter's value.
SQL> CREATE TABLE users
2 (
3 student_id VARCHAR2 (10),
4 password VARCHAR2 (20)
5 );
Table created.
SQL> INSERT INTO users (student_id, password)
2 VALUES ('100', 'Stack');
1 row created.
SQL> CREATE OR REPLACE FUNCTION md5 (par_password IN VARCHAR2)
2 RETURN VARCHAR2
3 IS
4 BEGIN
5 RETURN par_password;
6 END;
7 /
Function created.
SQL>
You should use a procedure to modify a password, not a function as you can't perform DML in a function (OK, you can, but you shouldn't. I'll show you show to do that later).
The procedure returns number of updated rows; if you want, you can return getcount (which is number of selected rows).
SQL> CREATE OR REPLACE PROCEDURE updatepassword (p_currentp IN VARCHAR2,
2 p_newpwd IN VARCHAR2,
3 p_studentid IN VARCHAR2,
4 retval OUT NUMBER)
5 IS
6 getcount INTEGER := 0;
7 BEGIN
8 SELECT COUNT (*)
9 INTO getcount
10 FROM users
11 WHERE student_id = p_studentid
12 AND password = md5 (p_currentp);
13
14 IF getcount = 1
15 THEN
16 UPDATE users
17 SET password = md5 (p_newpwd)
18 WHERE student_id = p_studentid
19 AND password = md5 (p_currentp);
20
21 retval := SQL%ROWCOUNT;
22 END IF;
23 END;
24 /
Procedure created.
SQL>
Testing: change password from "Stack" to "Overflow":
SQL> SET SERVEROUTPUT ON;
SQL>
SQL> DECLARE
2 l_retval NUMBER;
3 BEGIN
4 updatepassword ('Stack',
5 'Overflow',
6 '100',
7 l_retval);
8 DBMS_OUTPUT.put_line ('retval = ' || l_retval);
9 END;
10 /
retval = 1
PL/SQL procedure successfully completed.
SQL> SELECT * FROM users;
STUDENT_ID PASSWORD
---------- --------------------
100 Overflow
SQL>
Seems to be OK.
And here's why you can't use a function:
SQL> DROP PROCEDURE updatepassword;
Procedure dropped.
SQL> CREATE OR REPLACE FUNCTION updatepassword (p_currentp IN VARCHAR2,
2 p_newpwd IN VARCHAR2,
3 p_studentid IN VARCHAR2)
4 RETURN NUMBER
5 IS
6 getcount INTEGER := 0;
7 BEGIN
8 SELECT COUNT (*)
9 INTO getcount
10 FROM users
11 WHERE student_id = p_studentid
12 AND password = md5 (p_currentp);
13
14 IF getcount = 1
15 THEN
16 UPDATE users
17 SET password = md5 (p_newpwd)
18 WHERE student_id = p_studentid
19 AND password = md5 (p_currentp);
20 END IF;
21
22 RETURN getcount;
23 END;
24 /
Function created.
SQL> SELECT updatepassword ('Overflow', 'Littlefoot', '100') FROM DUAL;
SELECT updatepassword ('Overflow', 'Littlefoot', '100') FROM DUAL
*
ERROR at line 1:
ORA-14551: cannot perform a DML operation inside a query
ORA-06512: at "SCOTT.UPDATEPASSWORD", line 16
SQL>
Finally, a function which shows that you can do DML (but you really don't want to do that) - use pragma autonomous_transaction which instructs Oracle to execute code within that function separately from an outside transaction. It requires you to commit (or rollback).
SQL> CREATE OR REPLACE FUNCTION updatepassword (p_currentp IN VARCHAR2,
2 p_newpwd IN VARCHAR2,
3 p_studentid IN VARCHAR2)
4 RETURN NUMBER
5 IS
6 PRAGMA AUTONOMOUS_TRANSACTION;
7 getcount INTEGER := 0;
8 BEGIN
9 SELECT COUNT (*)
10 INTO getcount
11 FROM users
12 WHERE student_id = p_studentid
13 AND password = md5 (p_currentp);
14
15 IF getcount = 1
16 THEN
17 UPDATE users
18 SET password = md5 (p_newpwd)
19 WHERE student_id = p_studentid
20 AND password = md5 (p_currentp);
21 END IF;
22
23 COMMIT;
24
25 RETURN getcount;
26 END;
27 /
Function created.
SQL> SELECT updatepassword ('Overflow', 'Littlefoot', '100') FROM DUAL;
UPDATEPASSWORD('OVERFLOW','LITTLEFOOT','100')
---------------------------------------------
1
SQL> select * from users;
STUDENT_ID PASSWORD
---------- --------------------
100 Littlefoot
SQL>
So I have a function that accepts a student id and checks to see if the user exists. I created the function without error and I'm trying to store the return variable in a Boolean like this and print the result
SQL> DECLARE
2 tf BOOLEAN;
3 BEGIN
4 EXECUTE tf := valid_stud(5)
5 DBMS_OUTPUT.PUT_LINE(tf);
6 END;
7 /
But this is getting me an error.
ERROR at line 4:
ORA-06550: line 4, column 9:
PLS-00103: Encountered the symbol "TF" when expecting one of the following:
:= . ( # % ; immediate
The symbol "." was substituted for "TF" to continue.
My function is this
CREATE OR REPLACE FUNCTION valid_stud(v_student_id NUMBER) RETURN BOOLEAN
IS
v_id NUMBER;
BEGIN
SELECT student_id
INTO v_id
FROM STUDENT
WHERE student_id = v_student_id;
IF SQL%FOUND THEN
RETURN TRUE;
END IF;
EXCEPTION
WHEN no_data_found THEN RETURN FALSE;
END valid_stud;
/
Here's a demonstration which shows how to do that.
Sample table:
SQL> create table student (
2 student_id number
3 );
Table created.
Function: I removed unnecessary check whether SELECT returned a value; if it did, fine. If not, it'll raise an exception.
SQL> create or replace function valid_stud (
2 v_student_id number
3 ) return boolean is
4 v_id number;
5 begin
6 select student_id into
7 v_id
8 from student
9 where student_id = v_student_id;
10
11 return true;
12 exception
13 when no_data_found then
14 return false;
15 end valid_stud;
16 /
Function created.
Testing:
SQL> set serveroutput on
SQL> declare
2 tf boolean;
3 begin
4 tf := valid_stud(5);
5 if tf then
6 dbms_output.put_line('Student exists');
7 else
8 dbms_output.put_line('Student does not exist');
9 end if;
10 end;
11 /
Student does not exist
PL/SQL procedure successfully completed.
SQL>