Thursday, June 25, 2020

Show custom error message against database constraint in oracle apex

In oracle apex application, when an end user face an error on constraint (such as primary key, foreign key, unique key, check etc.) of database then user see the error message that defined on database. Most of the time that messages are not clear to end user. Sometimes error raises like it.
 

On this point, oracle apex has a great error handling feature to show our customize message to end user. For generating customized message, follow the following steps. It's very simple.

Firstly, you have to create a table. Here is the table script for you help.
CREATE TABLE  CONSTRAINT_LOOKUP 
   (CONSTRAINT_NAME VARCHAR2(30), 
	MESSAGE VARCHAR2(4000) NOT NULL ENABLE, 
	 PRIMARY KEY (CONSTRAINT_NAME) ENABLE
   );
Then create a function on your schema. You can just copy and paste function code from here.
CREATE OR REPLACE FUNCTION apex_error_handling_example (
   p_error IN apex_error.t_error)
   RETURN apex_error.t_error_result
IS
   l_result            apex_error.t_error_result;
   l_reference_id      NUMBER;
   l_constraint_name   VARCHAR2 (255);
BEGIN
   l_result := apex_error.init_error_result (p_error => p_error);

   IF p_error.is_internal_error
   THEN
      IF NOT p_error.is_common_runtime_error
      THEN
         -- Change the message to the generic error message which doesn't expose
         -- any sensitive information.
         l_result.MESSAGE :=
               'An unexpected internal application error has occurred. '
            || 'Please get in contact with XXX and provide '
            || 'reference# '
            || TO_CHAR (l_reference_id, '999G999G999G990')
            || ' for further investigation.';
         l_result.additional_info := NULL;
      END IF;
   ELSE
      l_result.display_location :=
         CASE
            WHEN l_result.display_location = apex_error.c_on_error_page
            THEN
               apex_error.c_inline_in_notification
            ELSE
               l_result.display_location
         END;

      IF p_error.ora_sqlcode IN (-1, -2091, -2290, -2291, -2292)
      THEN
         l_constraint_name :=
            apex_error.extract_constraint_name (p_error => p_error);

         BEGIN
            SELECT MESSAGE
              INTO l_result.MESSAGE
              FROM constraint_lookup
             WHERE constraint_name = l_constraint_name;
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN
               NULL;  
         END;
      END IF;

      IF     p_error.ora_sqlcode IS NOT NULL
         AND l_result.MESSAGE = p_error.MESSAGE
      THEN
         l_result.MESSAGE :=
            apex_error.get_first_ora_error_text (p_error => p_error);
      END IF;

      IF l_result.page_item_name IS NULL AND l_result.column_alias IS NULL
      THEN
         apex_error.auto_set_associated_item (p_error          => p_error,
                                              p_error_result   => l_result);
      END IF;
   END IF;

   RETURN l_result;
END apex_error_handling_example;
After then go to Shared Component / Application Definition Attributes / Error Handling section and place your function name at Error Handling Function field.

 
Finally, insert your message against constraint of database on CONSTRAINT_LOOKUP table.
NB: Here OID and SIDPK is the constraint name of database.

Now go to application and face the constraint error again see your customized message. For enhancing your error handling follow APEX_ERROR API.

Think it helps you. As always I am here to help you. Enjoy!

Sunday, May 10, 2020

How to expand navigation menu on hover in oracle apex

Oracle Apex application navigation menu has two types of position one is Top and another is Side. If your settings are like this image then after login at your application, navigation menu would be collapsed with icon because Collapse Mode is Icon(Default). It will expand after clicking the navigation icon from navigation menu.

How to expand navigation menu on hover
How to expand navigation menu on hover
If you want to expand your navigation menu on hover (when you mouse pointer will come) then follow the simple steps of this video.


Click the Download link to get the code that are used in this video.


Think it helps you. Good luck.

Friday, May 8, 2020

What happened on 20.1 API references in oracle apex

Slit your string with APEX_STRING_UTL

Think you have a large text phrase and now you have to separate web addresses or email addresses or links or specific phrases from here. What you will do now?

Don't worry! In new release 20.1 of Apex API reference introduce APEX_STRING_UTL as extension of APEX_STRING to do such complex task easily. APEX_STRING_UTL has the following functions:
  1. REPLACE_WHITESPACE Function
  2. FIND_FILE_EXTENSION Function
  3. FIND_PHRASE Function
  4. FIND_PHRASES Function
  5. FIND_EMAIL_ADDRESSES Function
  6. FIND_EMAIL_FROM Function
  7. FIND_EMAIL_SUBJECT Function
  8. FIND_TAGS Function
  9. FIND_LINKS Function
  10. GET_DOMAIN Function
  11. FIND_IDENTIFIERS Function
  12. TO_DISPLAY_FILESIZE Function
  13. TO_SLUG Function
Example 1:
select APEX_STRING_UTIL.TO_DISPLAY_FILESIZE(13312312) from dual;
-> 12.7MB
Example 2:
select APEX_STRING_UTIL.FIND_FILE_EXTENSION('foo.xlsx') from dual
-> xlsx
There are very effective functions in APEX_STRING_UTL are waiting for you.

Manage Interactive Grid with APEX_IG

This is also brand new API reference for Oracle Apex developers just like APEX_IR. By this package you will be able to add filter, delete saved report as well as clear or reset the IG report. APEX_IG has the following procedures and functions:
  1. ADD_FILTER Procedure Signature 1
  2. ADD_FILTER Procedure Signature 2
  3. CHANGE_REPORT_OWNER Procedure
  4. CLEAR_REPORT Procedure Signature 1
  5. CLEAR_REPORT Procedure Signature 2
  6. DELETE_REPORT Procedure
  7. GET_LAST_VIEWED_REPORT_ID Function
  8. RESET_REPORT Procedure Signature 1
  9. RESET_REPORT Procedure Signature 2
Others update at 20.1

APEX_AUTHENTICATION is updated in this release with new PERSISTENT_COOKIES_ENABLED function and update of SEND_LOGIN_USERNAME_COOKIE.

APEX_JSON has added new function GET_CLOB_OUTPUT for returning temporary CLOB.

APEX_INSTANCE_ADMIN add some parameters to get and set more control on workspace, instance, password and admin password. Here is the following parameters.
  1. WORKSPACE_NAME_USER_COOKIE
  2. PASSWORD_NOT_LIKE_USERNAME
  3. PASSWORD_NOT_LIKE_WORDS
  4. PASSWORD_NOT_LIKE_WS_NAME
  5. PASSWORD_ONE_ALPHA
  6. PASSWORD_ONE_LOWER_CASE
  7. PASSWORD_ONE_NUMERIC
  8. PASSWORD_ONE_PUNCTUATION
  9. PASSWORD_ONE_UPPER_CASE
  10. SERVICE_ADMIN_PASSWORD_MIN_LENGTH
  11. SERVICE_ADMIN_PASSWORD_NEW_DIFFERS_BY
  12. SERVICE_ADMIN_PASSWORD_ONE_ALPHA
  13. SERVICE_ADMIN_PASSWORD_ONE_NUMERIC
  14. SERVICE_ADMIN_PASSWORD_ONE_PUNCTUATION
  15. SERVICE_ADMIN_PASSWORD_ONE_UPPER_CASE
  16. SERVICE_ADMIN_PASSWORD_ONE_LOWER_CASE
  17. SERVICE_ADMIN_PASSWORD_NOT_LIKE_USERNAME
  18. SERVICE_ADMIN_PASSWORD_NOT_LIKE_WS_NAME
  19. SERVICE_ADMIN_PASSWORD_NOT_LIKE_WORDS
Deprecated and desupported at 20.1

You have to use OAUTH_AUTHENTICATE_CREDENTIAL intead of OAUTH_AUTHENTICATE Procedure Signature 2. Because OAUTH_AUTHENTICATE Procedure Signature 2 is deprecated from 20.1.

NB: You need minimum 20.1 version of Oracle Apex to run these API references. For more you can visit API documentation.

Think its help you. Good Luck.

Tuesday, May 5, 2020

Importance of PREPARE_URL for redirecting in oracle apex

An application which developed by Oracle Apex, is a web application with bunch of pages for presenting data and for communicating with oracle database server. Within this application an end-user travels one page to another page.

When an end-user redirects one page to another, we must have to make it secure as we prevent unwanted DML request. PREPARE_URL function of APEX_UTIL package helps to make secure redirecting when we pass value from page item of one page to page item of another page.

Firstly we have to understand how oracle apex URL construct. See the example before 20.1
f?p=App:Page:Session:Request:Debug:ClearCache:itemNames:itemValues:PrinterFriendly
After launching friendly URL from 20.1, URL looks like.
https://apex.oracle.com/pls/apex/zigzag/r/apex-recipe/home?session=714253588663910
The construction of URL is still same, it just changes appearance.

If we want to communicate with database server from any page of our application then we have to set page access protection "Arguments Must Have Checksum" from page properties.

What checksum does?
Checksum make our actual redirecting value to &cs=<large hex value>. to restrict user from changing actual value of URL. 

Have a look at the messages about page access protection from oracle apex.

Unrestricted

The page may be requested using a URL, with or without session state arguments, and without having to have a checksum.
Arguments Must Have Checksum
If Request, Clear Cache, or Name/Value Pair arguments appear in the URL, a checksum must also be provided.
The checksum type must be compatible with the most stringent Session State Protection attribute of all the items passed as arguments.
No Arguments Supported
A URL may be used to request the page, but the URL can not contain Request, Clear Cache, or Name/Value Pair arguments.
No URL Access
The page may not be accessed using a URL.
However, the page may be the target of a Branch to Page branch type, as this does not perform a URL redirect.

Let's hear a good news. All the default redirecting scopes from oracle apex provide checksum redirecting. So, LINK or branching or redirecting from attributes are safe to use. But when we make a URL manually to redirect we must have to be cautious.

In the end, use APEX_UTL.PREPARE_URL to redirect with valid 'SESSION' level arguments.
DECLARE
    l_url varchar2(2000);
    l_app number := v('APP_ID');
    l_session number := v('APP_SESSION');
BEGIN
    l_url := APEX_UTIL.PREPARE_URL(
        p_url => 'f?p=' || l_app || ':10:'||l_session||'::NO::P10_ITEM:ABC',
        p_checksum_type => 'SESSION');
END;
You can use APEX_UTL.PREPARE_URL within anchor tag (<a> tag) like,
<a href="'|| APEX_UTIL.PREPARE_URL(
   p_url => 'f?p=' || V('APP_ID') || ':27:'|| V('APP_SESSION') ||'::NO::P27_GUEST_ID:'|| ID ||'',
   p_checksum_type => 'SESSION')||'">
Link Text</a>
And if your user is public user and page is public page then use this code.
APEX_UTIL.PREPARE_URL(p_url => 'f?p=' || :APP_ID || ':10:'|| :APP_SESSION
||'::NO::P10_ITEM:ABC');

Think it helps you. Good luck.

Sunday, May 3, 2020

Complete guide to change or reset internal admin password of oracle apex

There is an authentication mechanism of Oracle Apex for confirming security of its content. For securing, Oracle Apex has one main workspace named INTERNAL with username ADMIN and it's password.

If you forget the password of ADMIN's username for INTERNAL workspace, then you are in a big trouble.

Don't worry! here are two ways to change or reset internal admin password:
  1. By executing apxchpwd.sql script.
  2. By executing some manual script
Follow these steps to execute apxchpwd.sql script.
1. Open command prompt (cmd) or terminal.
2. Go to your apex (cd e:\oraclexe\apex) directory.
3. Login to database as sysdba.
4. Type @apxchpwd.sql and press enter. Then follow the steps that comes.

Follow these steps to execute some manual script.
1. Open command prompt (cmd) or terminal.
2. Login to database as sysdba.
3. Change schema to your apex schema. Script to help you,
ALTER SESSION SET CURRENT_SCHEMA = APEX_190200;
NB: Here, "APEX_190200" is your apex schema.

4. Then run this query to get userid of admin username.
SELECT RTRIM (MIN (user_id)) user_id
  FROM wwv_flow_fnd_user
 WHERE security_group_id = 10 AND user_name = UPPER ('ADMIN');
5. To change or reset password of ADMIN username,
UPDATE wwv_flow_fnd_user
   SET web_password = 'Apexpassword1#'
 WHERE user_name = 'ADMIN' AND user_id = '1820122815444026';
NB: Here, "1820122815444026" is the userid that you get from previous query.

6. To unlock the ADMIN username execute the script below.
BEGIN
   WWV_FLOW_SECURITY.g_security_group_id := 10;
   WWV_FLOW_FND_USER_API.unlock_account ('ADMIN');
   COMMIT;
END;
If you use Toad or SQL Developer then you can start from step 4 by direct login your apex schema. 

Tested on 5.0, 5.1, 18.1, 18.2, 19.1 and 19.2 version of Oracle Apex.

Think it helps you. Good Luck.

How to import data from excel's csv file into oracle database

If you want to import data from external file like excel's .csv or .xlsx and when you have to consider more then 50 columns, then collection or apex_collection don't help you to do it.

At this point, UTL_FILE package will help you to do it very easily. Let's see how this amazing package works.

Firstly, you have to create a directory at your server. Here are scripts to help you.
CREATE OR REPLACE DIRECTORY CSV_DIR AS 'c:\oracle\csv_files';
GRANT READ, WRITE ON DIRECTORY CSV_DIR TO HR;
Then, write a procedure at HR schema to place the .csv blob file to the CSV_DIR directory.
CREATE OR REPLACE PROCEDURE pro_save_csv_to_dir (
   p_csv_blob   IN OUT NOCOPY BLOB,
   p_dir          IN            VARCHAR2,
   p_filename     IN            VARCHAR2)
AS
   v_file       UTL_FILE.file_type;
   v_buffer     RAW (32767);
   v_amount     BINARY_INTEGER := 32767;
   v_pos        INTEGER := 1;
   v_blob_len   INTEGER;
BEGIN
   v_blob_len := DBMS_LOB.getlength (p_csv_blob);

   v_file :=
      UTL_FILE.fopen (p_dir,
                      p_filename,
                      'wb',
                      32767);

   WHILE v_pos <= v_blob_len
   LOOP
      DBMS_LOB.read (p_csv_blob,
                     v_amount,
                     v_pos,
                     v_buffer);
      UTL_FILE.put_raw (v_file, v_buffer, TRUE);
      v_pos := v_pos + v_amount;
   END LOOP;

   UTL_FILE.fclose (v_file);
EXCEPTION
   WHEN OTHERS
   THEN
      UTL_FILE.fclose (v_file);
      RAISE;
END;
NB: Here, "p_csv_blob" is your .csv blob file, "p_dir" is your created directory name.

After successfully placing your .csv blob file to the directory, write another procedure to insert data from file into a database table.
CREATE OR REPLACE PROCEDURE pro_insert_from_dir (
   p_dir          IN     VARCHAR2,
   p_file_name    IN     VARCHAR2,
   p_table_name   IN     VARCHAR2,
   p_out_msg         OUT VARCHAR2)
AS
   v_values        VARCHAR2 (20000);
   v_values2       VARCHAR2 (20000);
   sqlstmt         VARCHAR2 (20000);

   acc_open_file   UTL_FILE.file_type;
BEGIN
   acc_open_file :=
      UTL_FILE.fopen ('' || p_dir || '', '' || p_file_name || '', 'R');

   LOOP
      BEGIN
         UTL_FILE.get_line (acc_open_file, v_values);
         DBMS_OUTPUT.put_line (v_values);

         SELECT REPLACE (v_values, ',', ''',
                         ''')
           INTO v_values2
           FROM DUAL;

         sqlstmt :=
               'insert into '
            || p_table_name
            || ' (col1, col2, col3) values('''
            || v_values2
            || ''')';

         EXECUTE IMMEDIATE sqlstmt;

         DBMS_OUTPUT.put_line (sqlstmt);
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            EXIT;
      END;
   END LOOP;

   UTL_FILE.fclose (acc_open_file);
END;

NB: Here "col1, col2, col3" is the column from table to maintain the sequence of .csv file's column.

You must have to remember,
  1. In this procedure, comma (,) is used as separator. So, no other comma (,) is allowed at your .csv file.
  2. Each and every row of .csv file would consider as a record. So, cut the heading column from .csv file before uploading.
If you don't want to consider above terms, then you should upload and import .xlsx file.

You may also like:

Saturday, May 2, 2020

How to import data from excel's xlsx file into oracle database

Think, if we can consider a row of an excel file as a record or row of table and a column as a table column. Is it possible at all? Yeap, Now it's possible. Anton Scheffer's as_read_xlsx package helps me to make it possible.

You will be able to direct query from excel's xlsx file in oracle database by using as_read_xlsx package. And then, manipulate your data as you want. Download this package from the following link.


After downloading, there are two ways to use this xlsx file.
  1. Read xlsx from a directory.
  2. Read xlsx from a blob column of database.
Follow these steps to read xlsx from a directory:
1. Execute the script to create package in oracle database.
2. To contain the xlsx file, create a directory object. Here are scripts to help you.
CREATE OR REPLACE DIRECTORY XLSX_DIR AS 'c:\oracle\xlsx_files';
GRANT READ, WRITE ON DIRECTORY XLSX_DIR TO HR;
3. Place xlsx file to this directory.
4. You can write a query like this,
SELECT * 
FROM TABLE(as_read_xlsx.read(as_read_xlsx.file2blob('XLSX_DIR', 'file.xlsx')));
The result would be viewed as like as a query from a table. Now you can use this query in PL/SQL procedure as a cursor and insert data into database table.

Follow these steps to read xlsx from a blob column of database:
1. Execute the script to create package in oracle database.
2. Upload xlsx file into a blob column in table.
3. You can write query like this,
      WITH xlsx
           AS (SELECT ROW_NR,
                      COL_NR,
                      CASE CELL_TYPE
                         WHEN 'S' THEN STRING_VAL
                         WHEN 'N' THEN TO_CHAR (NUMBER_VAL)
                         WHEN 'D' THEN TO_CHAR (DATE_VAL, 'MM/DD/YYYY')
                         ELSE FORMULA
                      END
                         CELL_VAL
                 FROM (SELECT *
                         FROM TABLE (as_read_xlsx.read (
                                        (SELECT blob_column
                                           FROM xlsx_files
                                          WHERE xlsx_id = 1),
                                        'Sheet1'))))
      SELECT xl.ID,
             xl.FIRST_NAME,
             xl.LAST_NAME,
             xl.FATHER_NAME
        FROM xlsx PIVOT (MAX (CELL_VAL)
                  FOR COL_NR
                  IN  (1 AS ID,
                      2 AS FIRST_NAME,
                      3 AS LAST_NAME,
                      4 AS FATHER_NAME)) xl
       WHERE row_nr > 1;
NB: Here, "xlsx_files" is database table, "blob_column" is blob column of table, "xlsx_id" is unique key of table, "Sheet1" is the sheet name of excel's xlsx file and  "row_nr > 1" is used to cut the row from header of excel's xlsx file.

Again, the result would be viewed as like as a query from a table. Now you can use this query in PL/SQL procedure as a cursor and insert data into database table.

Remember,
  • If you have lot of data at your .xlsx file then it will take some time. But if you can upload and import file from .csv then it would more faster and easier.

Think it helps you. Good luck.

You may also like: