Oracle Apex error handling - oracle

I have a textbox (tb_pcode) that user must enter the personnel code. This is a part of my code :
declare
n varchar2(20);
begin
select name into n
from pers e
where e.pcode = :tb_pcode;
exception
when no_data_found then
apex_error.add_error (
p_message => 'No person found!',
p_display_location => apex_error.c_inline_in_notification );
end;
but this lines ignore at all and no message display.
apex_error.add_error (
p_message => 'No person found!',
p_display_location => apex_error.c_inline_in_notification );
Why?!

I've just tried it on Apex 5.1.1, works just fine.
Where did you put that code? I created a validation on the TB_PCODE text item; validation type is "PL/SQL Function (returning Error Text)".
On the other hand, one reason might be that you, actually, entered a valid code and query returned something (i.e. SELECT didn't raise no-data-found).

Related

How can i get current username in PL/SQL?

i have some code
create or replace function policy_test (p_schema varchar2, p_object varchar2)
return varchar2 is
v VARCHAR2(30);
begin
v := USER;
return 'name = ' || v;
end;
Begin
DBMS_RLS.add_policy (
object_schema => 'system',
object_name => 'WORKMAN',
policy_name => 'WORKMAN_policy_test2',
function_schema => 'system',
policy_function => 'policy_test',
statement_types => 'select',
update_check => true
);
End;
and i'd like to ruturn 'name=system' or 'name=Jack' from function policy_test, but i get some error :
[28113] ORA-28113 policy predicate has error
How can i get current user name in policy_test and return sting like 'name=Jack' ?
Your particular VPD policy will append the return value to an implicit WHERE clause. The problem lies in your desired behavior. You stated, "and i'd like to return 'name=system' or 'name=Jack' from function policy_test"
If you were to write out an SQL statement like this: SELECT * FROM mytable WHERE name=system or SELECT * FROM mytable WHERE name=Jack, what would happen? The query will fail every time. When doing string comparison in a WHERE clause, you must enclose the string literal with single tick marks. Change it to WHERE name = 'Jack' and you have valid SQL.
Back to your function. Your function is returning a string, name=Jack and so WHERE name=Jack is what Oracle is generating. You haven't quoted the string literal so the SQL fails. The nature of VPD hides the exception raised (very frustrating) but Oracle does log it in the trace file.

Column Validation not firing in Interactive Grid Oracle APEX

I'm developing a simple application in Oracle APEX and one of the requirements is to create an error message if a duplicate column (which is also the UK of the table) is saved to the Interactive Grid. I've created a support package and then a column validation in APEX that calls the function in the support package.
When I first implemented the code and the call, everything was working and the correct error message was displayed. However, I think I unknowingly modified a property setting or something because now I cannot get the validation to fire -- if the user enters a duplicate column value and presses save, they get the generic "constraint violation" error message that Oracle raises. The only IG Process in this app is the Automatic Row Processing - Save button.
Does anyone have know why the column validation is being ignored? I have gone through the error stack of the "constraint violation" and all I am seeing is the Save process and Oracles generic error messages.
Support Package Function:
`FUNCTION Prod_Family_Exists (
i_id IN NUMBER
,i_prod_family IN VARCHAR2
) RETURN BOOLEAN IS
v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM adm_prod_families
WHERE prod_family = i_prod_family
AND id <> i_id
;
IF v_cnt = 0 THEN
RETURN(FALSE);
ELSE
RETURN(TRUE);
END IF;
EXCEPTION
WHEN OTHERS THEN
RETURN(FALSE);
END Prod_Family_Exists;
END Z_TEST;`
Validation Call in APEX - PL/SQL Function (Returning Boolean):
BEGIN
IF z_test.prod_family_exists( i_id => :id
,i_prod_family => :prod_family)
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END;
Based on the image below and the code I've provided, my custom error message would only be raised if the result from the validation returned FALSE right? Is the code bad?
I figured this out. The code for the validation call to the support package function needed to be modified. New code:
BEGIN
IF z_test.prod_family_exists( i_id => NVL(:id,0)
,i_prod_family => :prod_family)
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END;

How to add a new user in a PL/SQL table using a function?

I am fairly new to PL/SQL and one of the doubts I have is to create and declare functions.
Specifically this one:
Create a function that creates a new user:
Use a sequence togive the new User a new ID
Pass the name, address, etc... as IN arguments
Return as OUT arguments the ID created and a O_ERROR_MESSAGE
Function returns TRUE if the user is added, otherwise returns FALSE
Handle exceptions
Create a PL/SQL block and test the created function
This is my code so far:
CREATE OR REPLACE FUNCTION DSB_ADD_NEW_USERS (I_NAME IN VARCHAR2,
I_ADDRESS IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2)
RETURN NUMBER IS
O_ERROR_MESSAGE EXCEPTION;
CURRENT_USER NUMBER;
BEGIN
DSB_NB_SEQ_USER_ID.NEXTVAL;
SELECT COUNT(USER_ID) INTO CURRENT_USER
FROM DSB_NB_USERS;
WHILE CURRENT_USER != 0
LOOP
DSB_NB_SEQ_USER_ID.NEXTVAL;
SELECT COUNT(USER_ID) INTO CURRENT_USER
FROM DSB_NB_USERS;
END LOOP;
INSERT INTO DSB_NB_USERS (USER_ID, NAME, ADDRESS, BIRTHDATE, COUNTRY_ID_FK) VALUES (CURRENT_USER, I_NAME, I_ADDRESS, TO_DATE('I_BIRTHDATE', 'DD/MM/YYYY'), I_COUNTRY);
RETURN CURRET_USER;
EXCEPTION
WHEN O_ERROR_MESSAGE THEN
RETURN NULL;
WHEN OTHERS THEN
RETURN NULL;
END;
DECLARE
I_NEW_USER NUMBER;
BEGIN
I_NEW_USER := DSB_ADD_NEW_USERS(I_NAME => 'Arnaldo Amaral',
I_ADDRESS => 'Rua da Agra',
I_BIRTHDATE => '03/05/1959',
I_COUNTRY => 'PT');
END;
Am i too far from the truth?
I know there's still a lot to add.
Thank you for the help!!!
It seems to me you are asking for a lifeline, that needs more than just a code response. First off look at the answer by
#Tejash. His solution is a far cry from what you have, and is correct for your function definition (although that is itself incorrect given your listed requirements.) Also, #EdStevens is correct that is is a very poor use of a function. However a function is your assignment's requirement.
So lets dissect your code and see how it satisfies each of your requirements. (I cannot stand all caps, so I'm lower casing it.)
Fails. While you have a sequence it is used improperly. You can not
just code a standalone name. It must be used in either a SQL
statement or an assignment statement.
Passes.
Fails. Your function passes the IN parameters correctly. However
there are no OUT parameters.
Your function returns Number not the required True/False which
requires either Boolean or varchar2 for literal.
Code section for requirements 3,4.
create or replace function dsb_add_new_users (i_name in varchar2,
i_address in varchar2,
i_birthdate in date,
i_country in varchar2) <<< where are the 2 required out parameters
return number is <<< Should be True or False so either Boolean or varchar2
o_error_message exception; <<< Should be an Out parameter not an exception
Yes you have the Exception Section, which is required for handling
exceptions. However you do not handle exceptions so much as suppress
them, indicating to Oracle, and to the calling routine, that they didn't actually happen.
exception
when o_error_message then <<< as coded this is a developer defined exception, yet is not raised so it cannot happen.
return null; <<< even if it were raised you have thrown it away, the calling routine will never it happened
when others then <<< One of the worst pieces of code that can be written. I tend to remember seeing a discussion in
return null; <<< Oracle that would make this a compile time error. To bad the supporters lost the argument.
Passed, mostly. Correct for posted code, but insufficient per requirements.
So all-in-all not highly successful when viewed against the requirements.
A couple other items not specific the requirements, but disaster to successful implementation.
While technically you might get away with the following it is very bad practice. Current_User is an Oracle reserved word.
current_user number; <<< NO, NO bad verifiable name.
The following completely decimates your function. It creates a never ending loop. Well not quite -- it runs 1 time, but never afterward.
I believe you intended for the current_user variable to contain the ID assigned to the user. But it actually contains the number of rows in the table. Further what would the number of rows (count) have to do with Inserting a row? SO what does the code actually Do?
dsb_nb_seq_user_id.nextval; <<< systax error.
select count(user_id) into current_user <<< count the number of rows in the table
from dsb_nb_users;
while current_user != 0 <<< if there are any rows in the table
loop
dsb_nb_seq_user_id.nextval; <<< syntax error
select count(user_id) into current_user <<< try counting then again until there are none.
from dsb_nb_users;
end loop;
So correcting for the above what do we wind up with. I hesitate here in fear you will just copy the below and submit it. Please don't do that but study and understand what it's doing, then rewrite you routine. But after tearing you initial effort up, I guess I owe a corrected solution.
create or replace function dsb_add_new_users
( i_name in varchar2
, i_address in varchar2
, i_birthdate in date
, i_country in varchar2
, o_new_user_id out number
, o_error_message out varchar2
return boolean
is
country_id_l number;
begin
-- initialize out variables
o_new_user_id := null;
o_error_message := null;
-- get country id from input parameter
select country_id
into country_id_l
from country
where name = i_country;
-- create user and get the assigned user_id
insert into dsb_nb_users (user_id, name, address, birthdate, country_id_fk)
values dsb_nb_seq_user_id.nextval
, i_name
, i_address
, i_birthdate
, country_id_l
)
returning user_id
into o_new_user_id;
return true;
exception
when no_date_found then
o_output_message = 'ERROR: Specified country name ''' || country_id_l || ''' Not Found.';
return false;
when others then
o_output_message := 'ERROR: ' || sqlerrm;
return false
end dsb_add_new_users ;
--------------- Test Driver ----------------
declare
i_new_user number;
new_user_created boolean;
error_message varchar2(255);
begin
new_user_created := dsb_add_new_users( i_name => 'Arnaldo Amaral',
, i_address => 'Rua da Agra'
, i_birthdate => to_date('03/05/1959','mm/dd/yyyy') -- or is it 'dd/mm/yyyy'
, i_country => 'PT'
, o_new_user_id => i_new_user
, o_error_message => error_message);
if not new_user_created
then
dbms_output.put_line (error_messag);
end if ;
end;
Disclaimer: As you did not post table DDL nor test data the routine has not been tested nor even compiled. Any syntax error(s) is for you to resolve. Further, I follow Tejash in the assumption you actually have a countries table and there is a FK to it. That may be an erroneous assumption.
Why don't you directly use the sequence value to insert new user as follows:
CREATE OR REPLACE FUNCTION DSB_ADD_NEW_USERS (
I_NAME IN VARCHAR2,
I_ADDRESS IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2
) RETURN NUMBER IS
CURRENT_USER_ID NUMBER;
BEGIN
CURRENT_USER_ID := DSB_NB_SEQ_USER_ID.NEXTVAL; -- returns new and unique number
INSERT INTO DSB_NB_USERS (
USER_ID,
NAME,
ADDRESS,
BIRTHDATE,
COUNTRY_ID_FK
) VALUES (
CURRENT_USER_ID,
I_NAME,
I_ADDRESS,
I_BIRTHDATE,
(
SELECT
COUNTRY_ID
FROM
COUNTRIES
WHERE
NAME = I_COUNTRY
) -- it is FK so need to use SELECT sub-query to find COUNTRY_ID
);
RETURN CURRENT_USER_ID; -- returning the new user ID
EXCEPTION
WHEN OTHERS THEN
RETURN -1; -- returning -1 in case there is any error
END;
-1 will be returned when there is an error while adding the new user.
Came up with this much simpler answer after asking to a few people for help.
create or replace FUNCTION DSB_ADD_NEW_USERS (I_NAME IN VARCHAR2,
I_ADDRESS IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2)
RETURN NUMBER IS
CURRENT_USER NUMBER;
BEGIN
CURRENT_USER := DSB_NB_SEQ_USER_ID.NEXTVAL;
DBMS_OUTPUT.PUT_LINE('Hello World');
INSERT INTO DSB_NB_USERS (USER_ID, NAME, ADDRESS, BIRTHDATE, COUNTRY_ID_FK) VALUES (CURRENT_USER, I_NAME, I_ADDRESS, TO_DATE(I_BIRTHDATE, 'DD/MM/YYYY'), I_COUNTRY);
RETURN CURRENT_USER;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END;
SET SERVEROUT ON
DECLARE
I_NEW_USER NUMBER;
BEGIN
I_NEW_USER := DSB_ADD_NEW_USERS(I_NAME => 'Arnaldo Amaral',
I_ADDRESS => 'Rua da Agra',
I_BIRTHDATE => '03/MAY/1959',
I_COUNTRY => 'PT');
commit;
END;
/
Thank you all!!!

Sending email based on field name UTL_MAIL.send

How can I send an email based on what is entered into a apex Text field. eg If I enter me#test.com in :p6_supervisor, I would like the email to be sent to that person.
At present I have a preset UTL_MAIL.send which is working.
begin
UTL_MAIL.send(sender => 'test#test.com',
recipients => 'test1#test.com',
subject => 'Test,
message => 'Please Note this is a test' );
end;
But of course its for another purpose, which is sending email to one recipient from a trigger.
Below is the Cursor example
create or replace function "email"
( name_in IN varchar2 )
RETURN number
IS
supervisoremail varchar2(30);
CURSOR c1
IS
select
supervisoremail
from
EMPLOYEE,supervisors
where TO_DATE(contract_start_period,'DD-MM-YYYY') < TO_DATE (SYSDATE,'DD-MM-YYYY') - 275
and (supervisors.supervisorname = employee.supervisorname1
or supervisors.supervisorname = employee.supervisorname2)
and employee_name ='test'
;
BEGIN
OPEN c1;
FETCH c1 INTO supervisoremail;
CLOSE c1;
RETURN supervisoremail;
END;
It'll work, no problem. A simple way is to
create a text item (P6_SUPERVISOR)
create a button which submits the page; you need it so that P6_SUPERVISOR's value is set into the session state
create a process which calls UTL_MAIL; P6_SUPERVISOR item's contents is used as a source for the RECIPIENTS parameter. For example:
UTL_MAIL.send (sender => 'test#test.com',
recipients => :P6_SUPERVISOR,
subject => 'Test message - subject',
MESSAGE => 'Test message - message body');
[EDIT: how to send mails in a loop?]
I'm not sure what you meant by creating a function; it returns just one e-mail address that, probably, belongs to name passed through the NAME_IN parameter (but you used the 'test' name in cursor query).
However, you specified that the function returns a NUMBER, while variable you're selecting the result into is a VARCHAR2. So, which one of these is true?
If you insist on a function, don't enclose its name into double quotes as you'll always have to reference it that way (double quotes, correct upper/lower/mixed case).
Furthermore, what is contract_start_period column's datatype? If it is DATE, don't TO_DATE it. The same goes for SYSDATE - it is a function that returns DATE datatype anyway, so it is wrong to convert it to date once again.
Here's an example which uses a cursor FOR loop (as it is easier to maintain) and sends mail to all supervisoremail addresses returned by that SELECT statement.
begin
for cur_r in (select supervisoremail
from employee e join supervisors s on s.supervisorname = e.supervisorname1
or s.supervisorname = e.supervisorname2
where contract_start_period < sysdate - 275
and e.employee_name = 'test'
)
loop
utl_mail.send(sender => 'test#test.com',
recipients => cur_r.supervisoremail,
subject => 'Test message - subject',
message => 'Test message - message body');
end loop;
end;

ora-01422 error in SELECT INTO statements

I have one row in my Company_Person_all view named by 'YENER UZUN' in EMPLOYEE_NAME column (I already want only one result). When I send parameter to this function (fname, instead of using 'YENER UZUN') I encounter
ORA-01422:exact fetch returns more than requested number of rows ...
What should I do to prevent this error? Also when I write the code below ('YENER UZUN', instead of fname) it's ok it doesn't give me an error.
FUNCTION Get_Calistigi_Santiye_By_Fname(fname IN varchar2)
RETURN varchar2
IS
temp_ varchar2(100);
BEGIN
select free_field6
into temp_
from company_person_all
where employee_name = 'YENER UZUN';
DBMS_OUTPUT.put_line(temp_);
RETURN temp_;
END;
I solved it by changing 'fname' parameter name to 'xyz'. 'fname' was being used a RECORD instance name by other procedures and functions in the package.
So that when i changed parameter name the error instantly fixed.
Mostly, Using a cursor instead of select .. into is a shortcut to avoid ORA-01422 with a proper order by(asc [default] / desc) clause due to which of the records prefer for your business logic(last or first record ) as in the following :
FUNCTION Get_Calistigi_Santiye_By_Fname( fname company_person_all.employee_name%type )
RETURN company_person_all.free_field6%type
IS
temp_ company_person_all.free_field6%type;
BEGIN
for c in
(
select free_field6 ff6
from company_person_all
where employee_name = fname --> 'YENER UZUN'
order by work_date_time
)
loop
temp_ := c.ff6;
end loop;
dbms_output.put_line(temp_);
RETURN temp_;
END;

Resources