I want to write a custom login and for that I want to use a procedure/function to create and login the user (to hash the password)
My current database setup looks like this (From this site: https://oracle-base.com/articles/9i/storing-passwords-in-the-database-9i):
CREATE TABLE app_users (
id NUMBER(10) NOT NULL,
username VARCHAR2(30) NOT NULL,
password VARCHAR2(40) NOT NULL
)
/
ALTER TABLE app_users ADD (
CONSTRAINT app_users_pk PRIMARY KEY (id)
)
/
ALTER TABLE app_users ADD (
CONSTRAINT app_users_uk UNIQUE (username)
)
/
CREATE SEQUENCE app_users_seq
/
My current PLSQL Package definition looks like this:
CREATE OR REPLACE PACKAGE app_user_security AS
FUNCTION get_hash (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN VARCHAR2;
PROCEDURE add_user (p_username IN VARCHAR2,
p_password IN VARCHAR2);
PROCEDURE change_password (p_username IN VARCHAR2,
p_old_password IN VARCHAR2,
p_new_password IN VARCHAR2);
PROCEDURE valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2);
FUNCTION valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN;
END;
/
And the package itself looks like this:
CREATE OR REPLACE PACKAGE BODY app_user_security AS
FUNCTION get_hash (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN VARCHAR2 AS
l_salt VARCHAR2(30) := 'PutYourSaltHere';
BEGIN
-- Pre Oracle 10g
RETURN DBMS_OBFUSCATION_TOOLKIT.MD5(
input_string => UPPER(p_username) || l_salt || UPPER(p_password));
-- Oracle 10g+ : Requires EXECUTE on DBMS_CRYPTO
--RETURN DBMS_CRYPTO.HASH(UTL_RAW.CAST_TO_RAW(UPPER(p_username) || l_salt || UPPER(p_password)),DBMS_CRYPTO.HASH_SH1);
END;
PROCEDURE add_user (p_username IN VARCHAR2,
p_password IN VARCHAR2) AS
BEGIN
INSERT INTO app_users (
id,
username,
password
)
VALUES (
app_users_seq.NEXTVAL,
UPPER(p_username),
get_hash(p_username, p_password)
);
COMMIT;
END;
PROCEDURE change_password (p_username IN VARCHAR2,
p_old_password IN VARCHAR2,
p_new_password IN VARCHAR2) AS
v_rowid ROWID;
BEGIN
SELECT rowid
INTO v_rowid
FROM app_users
WHERE username = UPPER(p_username)
AND password = get_hash(p_username, p_old_password)
FOR UPDATE;
UPDATE app_users
SET password = get_hash(p_username, p_new_password)
WHERE rowid = v_rowid;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid username/password.');
END;
PROCEDURE valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2) AS
v_dummy VARCHAR2(1);
BEGIN
SELECT '1'
INTO v_dummy
FROM app_users
WHERE username = UPPER(p_username)
AND password = get_hash(p_username, p_password);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid username/password.');
END;
FUNCTION valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN AS
BEGIN
valid_user(p_username, p_password);
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END;
END;
/
I can call it like this in the CMD:
exec app_user_security.add_user('admin','admin');
But if I want to create a user in APEX > SQL Workshop > SQL Commands, it just tells me
ORA-00900: invalid SQL statement
Why is that so and how can I fix this? I want to use this login later on a application with a custom login scheme so it would be nice if there were some users in there.
Please try to run below code under APEX > SQL Workshop > SQL Commands
BEGIN
app_user_security.add_user('admin','admin');
END;
To know more about sql command under Sql workshop please check below link
https://docs.oracle.com/cd/E37097_01/doc.42/e35128/GUID-AF7DD819-A3E4-4027-84B7-4AEAD16314B7.htm#AEUTL219
Hope this will help you!
Related
After upgrading APEX version I wanted to start using APEX_IG package for IG manipulation instead of using javascript.
I looked over the documentation for adding a filter and it requires to know the numeric ID for the IG which I do not have. My IG has a static ID but it is a string. How do i go about finding the region ID?
APEX_IG.ADD_FILTER(
p_page_id IN NUMBER,
p_region_id IN NUMBER,
p_filter_value IN VARCHAR2,
p_column_name IN VARCHAR2 DEFAULT NULL,
p_operator_abbr IN VARCHAR2 DEFAULT NULL,
p_is_case_sensitive IN BOOLEAN DEFAULT FALSE,
p_report_name IN VARCHAR2 DEFAULT NULL );
Use the below code to get the region id
select region_id
from apex_application_page_regions
where page_id = YOUR_PAGE_NUMBER
and static_id = 'YOUR_REGION_STATIC_ID';
Im trying to write a procedure that updates the domain of an email (example: converting Email123#gmail.com into Email123#hotmail.com when i pass 2 strings gmail.com and hotmail.com) while having a cursor in my procedure
create of replace procedure pr_update_email
(Old_Email Varchar2, New_Email Varchar2)
As
V_OldDomain Varchar2(50);
Cursor C_Domains IS Select Email_Address
From Customer
where Email_Address Like '%#'||Old_Email;
Begin
Open C_Domains;
Fetch C_Domains INTO V_OldDomain;
While C_Domains %Found loop
Update Customer
Set Email_Address = regexp_replace(Email_Address, '^(.*#.*)'||Old_Email||'\1'||New_Email)
WHERE Email_Address LIKE V_OldDomain;
Fetch C_Domains into New_Email;
End Loop;
Close C_Domains;
End pr_update_email;
/
Show Errors;
getting errors:
19/11 PL/SQL: SQL Statement ignored
19/32 PLS-00403: expression'NEW_EMAIL' cannot be used as an INTO-target of a
SELECT/FETCH statement
You can directly update without creating a Stored Procedure but by using Regexp_Replace() and Instr() Functions :
SQL> Update Customer
Set Email_Address = Regexp_Replace(Email_Address,'(.*)#[gmail]+.(.*)','\1#hotmail.\2')
Where Instr(Email_Address,'#gmail.') > 0;
SQL> Commit;
If you want to create a generic structure in order to be able to use for such other cases also, then transfer the above Update statement as :
SQL> Create Or Replace Procedure pr_update_email(Old_Email Varchar2, New_Email Varchar2) As
Begin
Update Customer
Set Email_Address = Regexp_Replace(Email_Address,'(.*)#['||Old_Email||']+.(.*)','\1#'||New_Email||'.\2')
Where Instr(Email_Address,'#'||Old_Email||'.')>0 ;
End;
/
SQL> Begin
pr_update_email('gmail','hotmail');
End;
/
SQL> Commit;
Why you are using the cursor? It can be handled using simple update statement.
Your procedure should look like this:
create procedure pr_update_email (p_oldemail in varchar2,
p_newemail in varchar2)
As
Begin
UPDATE BROKER
SET
EMAIL_ADDRESS = REPLACE(EMAIL_ADDRESS, p_oldemail, p_newemail)
WHERE
REGEXP_LIKE ( EMAIL_ADDRESS,'.*#'|| p_oldemail|| '$' );
Commit;
End;
/
Or if you really want to use the loop then
create of replace procedure pr_update_email
(Old_Email Varchar2, New_Email Varchar2)
As
Begin
For i in (Select Email_Address
From Customer
where Email_Address Like '%#'||Old_Email) loop
Update Customer
Set Email_Address = Replace(Email_Address, old_email, new_email)
WHERE Email_Address = i.Email_Address;
End Loop;
Commit;
End pr_update_email;
/
To call this procedure, you need to pass both the domain as following:
Begin
pr_update_email('gmail.com', 'hotmail.com');
End;
/
And Yes, Issue in your code is following line:
Fetch C_Domains into New_Email;
New_Email is an input parameter and you can not assign any value to the input parameter.
Cheers!!
I have PL/SQL anonymous block to work with finding an employees based on their department_id. I wrote a procedure for that.
Code
CREATE OR REPLACE PROCEDURE find_employees (
p_dept_no IN NUMBER,
p_error_message OUT VARCHAR2)
AS
v_dept_no NUMBER;
dept_chk EXCEPTION;
CURSOR find_emp
IS
SELECT employee_id,
first_name,
last_name,
salary,
hire_date
FROM employees
WHERE department_id = p_dept_no;
BEGIN
-- Check if the department_id in departments table
IF Condition
THEN --Need to check the condition here
RAISE dept_chk;
END IF;
FOR i IN find_emp
LOOP
DBMS_OUTPUT.put_line (i.employee_id);
DBMS_OUTPUT.put_line (i.first_name);
DBMS_OUTPUT.put_line (i.last_name);
DBMS_OUTPUT.put_line (i.salary);
DBMS_OUTPUT.put_line (i.hire_date);
END LOOP;
EXCEPTION
WHEN dept_chk
THEN
p_error_message := 'Please enter valid department number';
END find_employees;
How to check if the department_id in departments table
Note:
On that procedure there is one input parameter p_dept_no as INPUT
and p_error_message is the output parameter.
I need to check the if the department_id is in in the departments table then automatically the records will show other wise it's showing an exception so there i need to check the condition how it's possible let me know Thanks in advance.
Given that you already scan the table, you can simply set a variable in within the loop and check its value outside.
For example:
CREATE OR REPLACE PROCEDURE find_employees(p_dept_no IN
NUMBER,p_error_message OUT VARCHAR2)
AS
v_dept_no NUMBER;
dept_chk EXCEPTION;
vEmployeeFound boolean := false; -- a boolean variable
CURSOR find_emp
IS
SELECT
employee_id, first_name, last_name, salary, hire_date
FROM
employees
WHERE
department_id = p_dept_no;
BEGIN
FOR i in find_emp
LOOP
dbms_output.put_line(i.employee_id);
dbms_output.put_line(i.first_name);
dbms_output.put_line(i.last_name);
dbms_output.put_line(i.salary);
dbms_output.put_line(i.hire_date);
vEmployeeFound := true; -- set the variable
END LOOP;
-- Check if the department_id in departments table
IF NOT vEmployeeFound THEN -- check the variable value
RAISE dept_chk;
END IF;
EXCEPTION
WHEN dept_chk THEN
p_error_message:='Please enter valid department number';
END find_employees;
At opencart2.0, I want to create a ocmod extension, In install.sql, I need to modify the database field. When I modify the database field, I need to decide if the field exists. Ive tried multiple variations of this, but none of them seem to work. Any ideas? Thanks in advance.
this is my install.sql,but is error
DROP PROCEDURE IF EXISTS add_col_need_credit;
DELIMITER $$ CREATE PROCEDURE add_col_need_credit() BEGIN IF NOT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='oc_customer_group_description' AND column_name='need_credit' ) THEN ALTER TABLE `oc_customer_group_description` ADD `need_credit` numeric(10,4) NOT NULL default 0; END IF;END$$ DELIMITER ;
CALL add_col_need_credit();
this is not error,you can in mysql console use it
DROP PROCEDURE IF EXISTS add_col_need_credit;
DELIMITER $$ CREATE PROCEDURE add_col_need_credit() BEGIN IF NOT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='oc_customer_group_description' AND column_name='need_credit' ) THEN ALTER TABLE `oc_customer_group_description` ADD `need_credit` numeric(10,4) NOT NULL default 0; END IF;END$$ DELIMITER ;
CALL add_col_need_credit();
DROP PROCEDURE IF EXISTS add_col_need_credit;
DELIMITER $$ CREATE PROCEDURE add_col_need_credit() BEGIN IF NOT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='oc_customer_group_description' AND column_name='need_credit' ) THEN ALTER TABLE `oc_customer_group_description` ADD `need_credit` numeric(10,4) NOT NULL default 0; END IF;END$$ DELIMITER ;
CALL add_col_need_credit();
Because of my C++ OCI wrapper only supports to bind Int/Double/String/Clob type of data. So I was wondering if it's possible to have my stored procedure returning a clob, which save the result set that's from a SELECT statement.
Like:
FUNCTION sp(
in_param VARCHAR2,
) RETURN CLOB
IS
my_clob CLOB;
BEGIN
my_clob := SELECT col1, col2, col3 FROM s WHERE s.param = in_param;
RETURN my_clob;
END sp;
I have a table with a CLOB and and a VARCHAR column and this works:
create or replace
FUNCTION F_LOB_TEST(in_char VARCHAR2 ) RETURN CLOB
IS
my_clob CLOB;
BEGIN
SELECT FIELD_CLOB
INTO my_clob
FROM LOB_TEST
WHERE FIELD_CHAR=in_char;
RETURN my_clob;
END;
To make sure the function returns what you're expecting in PL/SQL
you can call the above function like this:
select F_LOB_TEST('A') FROM DUAL;