Oracle APEX: Error Message in field raises Error Message - oracle-apex

I have the following code:
DECLARE
i NUMBER;
BEGIN
SELECT COUNT(*) INTO i FROM apex_collections where collection_name = 'COLLECTION';
if i = 0 then
apex_error.add_error(
p_message => 'Invalid Excel file!'
, p_display_location => apex_error.c_inline_with_field
, p_page_item_name => 'P3_BROWSE_EXCEL'
);
end if;
END;
All it does is check if a collection exists. If not, it should raise an error.
I am calling this from a Process, so an Alert or something similar is no alternative.
Instead of showing the correct error message next to the P3_BROWSE_EXCEL - item, it shows this error on top of the page:
1 error has occurred
Error: Not found
I am 100% sure P3_BROWSE_EXCEL exists on that page, so why?

Why don't you use simple SQL validation? Validation Type - Rows returned, the query
SELECT 1 FROM apex_collections where collection_name = 'COLLECTION';
Display location - Inline with field, Associated Item - you can choose an item from a list with 100% guarantee that it exists.

Related

How to use page item value inside a trigger query in oracle?

I want the following trigger to be run correctly but it rise an error which is: bad bind variable 'P23_ID'.
The trigger query is:
Create or replace trigger "newTRG"
Before
Insert on "my_table"
For each row
Begin
If :new."ID" is null then
Insert into my_table (ID) values (:P23_ID);
end if;
End;
Use the v() syntax:
create or replace trigger "newTRG" before
insert on "my_table"
for each row
begin
if :new."ID" is null then
insert into my_table ( id ) values (v('P23_ID'));
end if;
end;
On a side note, if this is a primary key value it is a lot easier to use identity columns (the new way) or a sequence (the old way) to populate your column. Doing this from a page item is error prone.

How to handle error in ibm_db python package while calling stored procedure?

I'm trying call stored procedure using following code
conn = ibm_db.connect("database","username","password")
sql = "CALL DB2INST1.KPI_VALIDATE()"
stmt = ibm_db.exec_immediate(conn, sql)
But this procedure does not return any rows & It will only return code. Now I need to handle error whether procedure run successfully or not. Could anyone help me how to handle this?
Thanks
For test purposes, I've created a table:
db2 "create table so(c1 int not null primary key)"
and my procedure will simply insert a row into this table - this will allow me to easily force an error with a duplicate key:
db2 "create or replace procedure so_proc(in insert_val int)
language sql
insert into so values(insert_val)"
db2 "call so_proc(1)"
Return Status = 0
db2 "call so_proc(1)"
SQL0803N One or more values in the INSERT statement, UPDATE statement, or
foreign key update caused by a DELETE statement are not valid because the
primary key, unique constraint or unique index identified by "1" constrains
table "DB2V115.SO" from having duplicate values for the index key.
SQLSTATE=23505
now with Python:
conn = ibm_db.connect("DATABASE=SAMPLE;HOSTNAME=localhost;PORT=61115;UID=db2v115;PWD=xxxxx;","","")
stmt = ibm_db.exec_immediate(conn, "CALL SO_PROC(2)")
stmt = ibm_db.exec_immediate(conn, "CALL SO_PROC(2)")
Exception Traceback (most recent call last)
<ipython-input-8-c1f4b252e70a> in <module>
----> 1 stmt = ibm_db.exec_immediate(conn, "CALL SO_PROC(2)")
Exception: [IBM][CLI Driver][DB2/LINUXX8664] SQL0803N One or more values in the INSERT statement, UPDATE statement, or foreign key update caused by a DELETE statement are not valid because the primary key, unique constraint or unique index identified by "1" constrains table "DB2V115.SO" from having duplicate values for the index key. SQLSTATE=23505 SQLCODE=-803
so if a procedure hits an exception then you'll get it, you just need to handle exception Try/Except block:
try:
stmt = ibm_db.exec_immediate(conn, "CALL SO_PROC(2)")
except Exception:
print("Procedure failed with sqlstate {}".format(ibm_db.stmt_error()))
print("Error {}".format(ibm_db.stmt_errormsg()))
Procedure failed with sqlstate 23505
Error [IBM][CLI Driver][DB2/LINUXX8664] SQL0803N One or more values in the INSERT statement, UPDATE statement, or foreign key update caused by a DELETE statement are not valid because the primary key, unique constraint or unique index identified by "1" constrains table "DB2V115.SO" from having duplicate values for the index key. SQLSTATE=23505 SQLCODE=-803
Or you are actually interested with CALL return code/status? E.g.:
create or replace procedure so_proc_v2(in insert_val int)
language sql
if not exists (select 1 from so where c1 = insert_val)
then
insert into so values(insert_val);
return 0;
else
return -1;
end if#
test:
db2 "call so_proc_v2(10)"
Return Status = 0
db2 "call so_proc_v2(10)"
Return Status = -1
then this is a bit tricky. With CLI trace enabled (I have ibm_db installed in my local path so it fetched CLI package there too):
export LD_LIBRARY_PATH=$HOME/.local/lib/python3.7/site-packages/clidriver/lib/
$HOME/.local/lib/python3.7/site-packages/clidriver/bin/db2trc on -cli -f /tmp/cli/trc
<run_code>
$HOME/.local/lib/python3.7/site-packages/clidriver/bin/db2trc off
$HOME/.local/lib/python3.7/site-packages/clidriver/bin/db2trc fmt -cli /tmp/cli.trc /tmp/cli.fmt
trace does show the returns status:
SQLExecute( hStmt=1:8 )
---> Time elapsed - -7.762688E+006 seconds
( Row=1, iPar=1, fCType=SQL_C_LONG, rgbValue=10 )
( return=-1 )
( COMMIT REQUESTED=1 )
( COMMIT REPLY RECEIVED=1 )
but I don't see anywhere in python-ibmdb API a way to fetch it... (e.g. ibm_dbcallproc doesn't have such option). Which means, that unless I'm missing something, you would have to raise an issue on Github to extent the API

How to show alert if user tries to save values, that are already present my table for my Oracle Apex Form based application

I have a form in my Oracle APEX based application, I want to have validation on submit button, so that the combination of two specific entries, if they already are present in the SQL table/View, I want to show an alert, like "The entry for this combination of values of A and B already exists, please enter correct values."
If those two specific entries are represented by two form items (e.g. :P1_ONE and :P2_TWO), then the validation procedure might be a function that returns error text, such as
declare
l_cnt number;
retval varchar2(200);
begin
select count(*)
into l_cnt
from your_table t
where t.column_one = :P1_ONE
and t.column_two = :P1_TWO;
if l_cnt > 0 then
retval := 'The entry for this combination already exists';
end if;
end;
The query itself might need to be modified, depending on what exactly you meant by describing the problem; that's the way I understood it.
Then you should have a unique constraint on the table, and let that validate incoming data.
Any violation of this constraint will have exception raised, which can be transformed within the APEX error handling procedure.

How to show other vaues in a selectlist in APEX

I am using Oracle APEX to build a interactive report. There is a field in my database called method which should contain either A or B. In the edit page, I want to show a list containing A and B so that users can choose from those two.
I set the type of the item to SelectList and since I need to add the other value to the list, in the List of Values area, I set the type to PL/SQL Function Body returning SQL Query and the code is as follows:
Begin
select TEST_METHOD into method from table_test
where ROWID = :P2_ROWID;
IF ('Live' = method) THEN
return select 'Screenshots' from dual;
END IF;
return select 'Live' from dual;
End;
However, I got the following error:
ORA-06550: line 5, column 10: PLS-00103: Encountered the symbol "SELECT" when expecting one of the following: ( - + ; case mod new not null continue avg count current exists max min prior sql stddev sum variance execute forall merge time timestamp interval date pipe
I am new to plsql and APEX, I know the code looks wired but I don't know what's wrong. I am also wondering if there is any other way to achieve my goal? Thanks!

Validation to detect text in numeric field

I'm trying to prevent users crashing the create new product apex page. On the create page i have a text field:product_name and a numeric field: product_quantity.
Currently when they enter text in the product_quantity field and click 'Save' they get the following error:
Error processing validation.
ORA-01722: invalid number
I have investigated the error however i thought in Apex, if you selected a numeric field, it would detect whether the user entered text or numeric characters?
Is there a method to display a validation message if the user has entered text, it shouts, otherwise it enables the user to save the new entry?
UPDATE
I know why its happening but dont know how to solve it.
I recreated my page and it worked. I then added two pieces of validation in my page processing and when i then try it i get the error in my intial post. If i disable them it works again. The validation use NOT EXISTS to find whether the entered value already exists in the table before they add it.
If only the validation kicks in after looking whether a numerical value has been entered. I stopped the validation looking at an associated item, and turned off the 'when button pressed' but still no joy.
select 1 from MY_TABLE where column_name = :P6_TEXT_FIELD
Is there a way to run the text box validation (checking whether its text entered) before the validation i have created in the page processing?
That's the thing with validations: they all get executed and do not short-circuit. You can actually clearly see this happening when you debug the page.
In the case of a number field, you'd see it does not pass the number validation. But this does not stop validation. So your second validation will be run which uses the submitted value, but would obviously fail when you entered text for instance.
There are some work-arounds for that.
For example, you could change your NOT-EXISTS validation to a PLSQL function returning an error message and execute something like this (example):
DECLARE
v_test_nbr NUMBER;
v_check_exists NUMBER;
BEGIN
BEGIN
v_test_nbr := to_number(:P6_TEXT_FIELD);
EXCEPTION
WHEN OTHERS THEN
-- or catch 1722 (invalid number) and 6502 (char to number conversion error)
v_test_nbr := NULL;
END;
IF v_test_nbr IS NOT NULL
THEN
-- if v_test_nbr is not null then the field should be numerically valid
-- if it isn't then this code would be skipped and this validation
-- will not throw an error.
-- However, the previous validation will still fail when text is entered,
-- so this shouldn't matter.
BEGIN
SELECT 1
INTO v_check_exists
FROM my_table
WHERE column_name = :P6_TEXT_FIELD;
EXCEPTION
WHEN no_data_found THEN
v_check_exists := 0;
END;
IF v_check_exists = 1
THEN
RETURN 'A record with this key already exists';
END IF;
END IF;
RETURN NULL;
END;
HOWEVER - in this case, where you want to check for duplicate entries a better option may exist if you are at least on version 4.1. If your table has the correct constraints defined, then you would have a unique key defined on the field you are performing the not-exists on. This means that if you would not have this validation on the field, you would get an ora-00001 DUP_VAL_ON_INDEX error.
You could then use the error processing provided by apex to catch this error, and produce a user-friendly message.
You can find an example of how to use and implement this on the blog of Patrick Wolf of the apex development team:
apex-4-1-error-handling-improvements-part-1/
apex-4-1-error-handling-improvements-part-2/