Oracle Sql Function Compiled (with errors) - oracle

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>

Related

I want to fetch column values from column name rollnoofstud of tableA using PL/SQL

DECLARE
TYPE norollno IS TABLE OF VARCHAR2(100);
rollno norollno;
BEGIN
BEGIN
SELECT token
BULK COLLECT INTO rollno
FROM tableA
WHERE columname='rollnoofstud';
EXCEPTION
WHEN NO_DATA_FOUND THEN
rollno := norollno();
END ;
IF rollno >0 THEN
FOR i IN rollno.FIRST..norollno.LAST
LOOP
<doSomeThing>
END LOOP;
END IF;
END;
I am trying this but I am not getting output. I doubt if my select statement is correct.
I don't have your table so I created one:
SQL> CREATE TABLE tablea
2 AS
3 SELECT ename AS token, 'rollnoofstud' AS columname
4 FROM emp
5 WHERE deptno = 10;
Table created.
Code you posted isn't that wrong; requires a little bit of fixing (see line #17, the way you check whether collection contains something (count it!); typo in FOR loop):
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 TYPE norollno IS TABLE OF VARCHAR2 (100);
3
4 rollno norollno;
5 BEGIN
6 BEGIN
7 SELECT token
8 BULK COLLECT INTO rollno
9 FROM tableA
10 WHERE columname = 'rollnoofstud';
11 EXCEPTION
12 WHEN NO_DATA_FOUND
13 THEN
14 rollno := norollno ();
15 END;
16
17 IF rollno.COUNT > 0
18 THEN
19 FOR i IN rollno.FIRST .. rollno.LAST
20 LOOP
21 DBMS_OUTPUT.put_line (rollno (i));
22 END LOOP;
23 END IF;
24 END;
25 /
CLARK --> here's the result
KING
MILLER
PL/SQL procedure successfully completed.
SQL>
[EDIT: with your sample table and data:]
(note that there's no text datatype in Oracle!)
SQL> CREATE TABLE students
2 (
3 rollnostud INTEGER PRIMARY KEY,
4 name VARCHAR2 (10) NOT NULL,
5 gender VARCHAR2 (1) NOT NULL
6 );
Table created.
SQL> INSERT INTO students
2 VALUES (1, 'Ryan', 'M');
1 row created.
SQL> INSERT INTO students
2 VALUES (2, 'Joanna', 'F');
1 row created.
SQL> INSERT INTO students
2 VALUES (3, 'John', 'M');
1 row created.
Procedure:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 TYPE norollno IS TABLE OF VARCHAR2 (100);
3
4 rollno norollno;
5 BEGIN
6 BEGIN
7 SELECT name
8 BULK COLLECT INTO rollno
9 FROM students;
10 EXCEPTION
11 WHEN NO_DATA_FOUND
12 THEN
13 rollno := norollno ();
14 END;
15
16 IF rollno.COUNT > 0
17 THEN
18 FOR i IN rollno.FIRST .. rollno.LAST
19 LOOP
20 DBMS_OUTPUT.put_line (rollno (i));
21 END LOOP;
22 END IF;
23 END;
24 /
Ryan
Joanna
John
PL/SQL procedure successfully completed.
SQL>

How to insert encrypted value in table Oracle apex

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.

PL/SQL simple task

I want to create a procedure whith two arguments. It should check if the arguments are values of family table and if both are not the same value.
I planned this code but I noted it doesn't work
create or replace procedure Compare(first_value values.value%type, second_value values.value%type)
as
begin
if second_value not exists(select values from family) then
dbms.output.put_line('The second values doesn't exist');
else if first_value = second_value then
dbms.output.put_line('Both values are the same');
else
dbms.output.put_line('Great Job');
end if;
end;
/
I'll appreciate any help.
Here's one option.
SQL> set serveroutput on
Sample data:
SQL> select * from family;
C_VALUES
--------
Little
Foot
Procedure:
SQL> create or replace procedure p_compare
2 (par_value_1 in family.c_values%type,
3 par_value_2 in family.c_values%type
4 )
5 as
6 l_cnt_1 number;
7 l_cnt_2 number;
8 begin
9 select count(*)
10 into l_cnt_1
11 from family
12 where c_values = par_value_1;
13
14 select count(*)
15 into l_cnt_2
16 from family
17 where c_values = par_value_2;
18
19 if l_cnt_1 = 0 then
20 dbms_output.put_line('The first value does not exist');
21 elsif l_cnt_2 = 0 then
22 dbms_output.put_line('The second value does not exist');
23 elsif par_value_1 = par_value_2 then
24 dbms_output.put_line('Both values are the same');
25 else
26 dbms_output.put_line('Great job');
27 end if;
28 end;
29 /
Procedure created.
Testing:
SQL> exec p_compare('Little', 'Foot');
Great job
PL/SQL procedure successfully completed.
SQL> exec p_compare('Little', 'Little');
Both values are the same
PL/SQL procedure successfully completed.
SQL> exec p_compare('Big', 'Foot');
The first value does not exist
PL/SQL procedure successfully completed.
SQL>
Here is a not so well written, but somehow alternative take on the task:
CREATE OR REPLACE PROCEDURE COMPARE(FIRST_VALUE VALUES.VALUE%TYPE,
SECOND_VALUE VALUES.VALUE%TYPE)
AS
l_message VARCHAR2(40);
BEGIN
SELECT CASE WHEN test_val < 2 THEN 'The first value does not exist'
WHEN test_val < 3 THEN 'The second value does not exist'
WHEN first_value = second_value THEN 'Both values are the same'
ELSE 'Great job'
END
INTO l_message
FROM (SELECT NVL(SUM(val),0) AS test_val
FROM (SELECT 2 AS val
FROM family
WHERE val = first_value
AND ROWNUM = 1
UNION ALL
SELECT 1 AS val
FROM family
WHERE val = second_value
AND ROWNUM = 1));
DBMS_OUTPUT.PUT_LINE(l_message);
END;
/

I want to Create a function named VALIDATE_EMP which accepts employeeNumber as a parameter, Returns TRUE or FALSE depending on existence

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>

Need to find the number of times PLSQL function gets executed

There is a requirement from client side that after function get executed more than 2 times then its output should be concatinated with some string and this function is inside a package .
for example...
function get called 7 times from package (its a backend job which executed automatically) and returns 'abc' but when the job runs for the 3rd time i want output 'abcde'.
One option is to create a separate log table and insert a row for each of function calls; then - within a function - check how many times it was invoked and return appropriate output. Something like this:
Log table:
SQL> CREATE TABLE flog
2 (
3 cuser VARCHAR2 (30),
4 sid NUMBER
5 );
Table created.
Package:
SQL> CREATE OR REPLACE PACKAGE pkg_test
2 IS
3 FUNCTION f_test
4 RETURN VARCHAR2;
5
6 PROCEDURE p_test;
7 END;
8 /
Package created.
Package body:
SQL> CREATE OR REPLACE PACKAGE BODY pkg_test
2 IS
3 FUNCTION f_test
4 RETURN VARCHAR2
5 IS
6 l_cnt NUMBER;
7 retval VARCHAR2 (10);
8 BEGIN
9 SELECT COUNT (*)
10 INTO l_cnt
11 FROM flog
12 WHERE cuser = USER
13 AND sid = SYS_CONTEXT ('USERENV', 'SID');
14
15 retval := CASE WHEN l_cnt <= 2 THEN 'abc' ELSE 'abc' || 'de' END;
16 RETURN retval;
17 END;
18
19 PROCEDURE p_test
20 IS
21 BEGIN
22 FOR i IN 1 .. 3
23 LOOP
24 INSERT INTO flog (cuser, sid)
25 VALUES (USER, SYS_CONTEXT ('USERENV', 'SID'));
26
27 DBMS_OUTPUT.put_line ('Execution #' || i || ', result = ' || f_test);
28 END LOOP;
29 END;
30 END pkg_test;
31 /
Package body created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL> EXEC pkg_test.p_test;
Execution #1, result = abc
Execution #2, result = abc
Execution #3, result = abcde
PL/SQL procedure successfully completed.
SQL>

Resources