Tuesday 5 December 2023

How to convert number to words in oracle

Method 1:
A common method for converting a number to words is to use the TO_DATE function and 'j' format to convert the number to a julian date (the number of days since January 1, 4712 B.C.), then use the TO_CHAR function and 'jsp' format to spell the julian date.

I am using below query to convert for this number(1235487) to word.

SELECT TO_CHAR (TO_DATE (1235487, 'j'), 'Jsp') FROM DUAL;

                                                                    OR

SELECT AP_AMOUNT_UTILITIES_PKG.ap_convert_number(1235487) FROM DUAL;

It's return for : One Million Two Hundred Thirty-Five Thousand Four Hundred Eighty-Seven

But i want result like :

Twelve Lakh Thirty Five Thousand Four Hundred Eighty Seven Only

And also it has range from 1 to 5373484 is we put value after 5373484, like 5373485

SELECT TO_CHAR (TO_DATE (5373485, 'j'), 'Jsp') FROM DUAL;

then it will throw you an error

"ORA-01854: julian date must be between 1 and 5373484"

How to achieve this?

Solution:
If you wish to spell numbers greater than the maximum julian date allowed (5373484) or if you wish to include decimal places, or if you wish to have the output in another format or language, then you will need a more complex function that works for larger numbers and include decimal places, other formats, and other languages.

======================Function for Indian Format========================
create or replace function amt_to_word( p_number in number )
return varchar2
as
type myArray is table of varchar2(255);
l_str myArray := myArray(' Thousand ', ' Lakh ',' Crore ', ' Arav ',' Kharav ',' Neel ',' Padma ', ' Shankh ');
l_num varchar2(50) default trunc( p_number );
l_return varchar2(4000);
begin
if (substr( l_num, length(l_num)-2,3 )<>0)
then
l_return := REPLACE (to_char(to_date(substr(l_num, length(l_num)-2, 3),'J'),'Jsp'),'-',' ');
end if;
l_num:=substr( l_num, 1,length(l_num)-3);
for i in 1 .. l_str.count
loop
exit when l_num is null;
if (substr( l_num, length(l_num)-1,2 )<>0)
then
l_return := REPLACE (to_char(to_date(substr(l_num, length(l_num)-1, 2),'J' ),'Jsp'),'-',' ')|| l_str(i) || l_return;
end if;
l_num:=substr( l_num, 1,length(l_num)-2);
end loop;
if to_char( p_number ) like '%.%'
then
l_num := substr(round(p_number,2),instr(p_number,'.')+1);
if (length(substr(round(p_number,2),instr(p_number,'.')+1 )))=1
then
l_num := to_number(to_char(l_num) ||'0');
end if;
if l_num>0
then
l_return :=l_return ||' And' || REPLACE (to_char(to_date(l_num,'J'),' Jsp'),'-',' ')||' Paise';
end if;
end if;
--return(l_return);
return(l_return||' Only');
end amt_to_word;

======================Query=================================
SQL>select amt_to_word(5373485) from dual;

It's return for: Fifty Three Lakh Seventy Three Thousand Four Hundred Eighty Five Only

======================Function for International Format==================
CREATE OR REPLACE FUNCTION APPS.num_to_word (p_number IN NUMBER)
RETURN VARCHAR2
AS
TYPE myArray IS TABLE OF VARCHAR2 (255);
l_str myArray:= myArray ('',' thousand ',' million ',' billion ',' trillion ',' quadrillion ',' quintillion ',
' sextillion ',' septillion ',' octillion ',' nonillion ',' decillion ',' undecillion ',' duodecillion ');
l_num VARCHAR2 (50) DEFAULT TRUNC (abs(p_number));
l_return VARCHAR2 (4000);
V_POS NUMBER;
V_FRACTION VARCHAR2(1000);
BEGIN
FOR i IN 1 .. l_str.COUNT
LOOP
EXIT WHEN l_num IS NULL;
IF (SUBSTR (l_num, LENGTH (l_num) - 2, 3) <> 0)
THEN
l_return :=TO_CHAR (TO_DATE (SUBSTR (l_num, LENGTH (l_num) - 2, 3), 'J'),'Jsp')|| l_str (i)|| l_return;
END IF;
l_num := SUBSTR (l_num, 1, LENGTH (l_num) - 3);
END LOOP;
------------------FOR FRACTION VALUE------------------------
V_POS := INSTR(TO_CHAR(P_NUMBER),'.');
IF V_POS > 0 THEN
SELECT INITCAP(TO_CHAR(TO_DATE(SUBSTR(P_NUMBER,V_POS+1,LENGTH(P_NUMBER)), 'J'), 'JSP')) INTO V_FRACTION FROM DUAL;
l_return := l_return||'Point '||V_FRACTION;
END IF;
RETURN l_return;
END;
/

======================Query=================================
SQL>select num_to_word(5373485) from dual

It's return for: Five million Three Hundred Seventy-Three thousand Four Hundred Eighty-Five

Method 2: 
Number to Word conversion in RTF

xdofx vs xdoxslt

<?xdofx:expression?> for extended SQL functions
<?xdoxslt:expression?> for extended XSL functions.

You cannot mix xdofx statements with XSL expressions in the same context

This function enables the conversion of numbers to words for RTF template output. This is a common requirement for check printing.

The new function is “to_check_number”. The syntax of this function is

<?xdofx:to_check_number(amount, precisionOrCurrency, caseType, decimalStyle)?>

RTF Template Entry
<?xdofx:to_check_number(12345.67, 2)?>

Returned Output
Twelve thousand three hundred forty-five and 67/100

Alternative

<?xdoxslt:toWordsAmt(TEST_AMOUNT)?>

Then it will display amount in words in Indian currency means Rupees not millions but it's showing some wrong spelling of particular number like Fourty.

Example:

<?xdoxslt: toWordsAmt(1244454.88)?>

Then it will display as

Twelve Lakh Fourty Four Thousand Four Hundred Fifty Four and paise Eighty Eight

Alternative

Use the following function in rdf level

IBY_AMOUNT_IN_WORDS.Get_Amount_In_Words(TEST_AMOUNT)

Tuesday 10 October 2023

How to mask data in HRMS or Any Other Data?

What is Oracle Data Redaction with Examples (Mask your sensitive Data)

There are many cases when data needs to be masked to hide some or all of the data for users working with data.

Oracle Data Redaction is one of the new features introduced in Oracle Database Oracle 12c and back-ported to 11.2.0.4 via patch set(Some examples of implementing Data Redaction using DBMS_REDACT (Doc ID 1588270.1)). This new feature is part of the Advanced Security option and enables the protection of data shown to the user in real-time, without requiring changes to the application.Oracle Data Redaction enables you to mask (redact) data that is returned from queries issued by applications.

Data masking (also known as data scrambling and data anonymization) is the process of replacing sensitive information copied from production databases to test non-production databases with realistic, but scrubbed, data based on masking rules. Data masking is ideal for virtually any situation when confidential or regulated data needs to be shared with non-production users. 

This can be done using Data Redaction in Oracle.Let's see we will look at how these can be used to hide data or mask data.Oracle allow you to mask sensitive data and display only a portion or completely randomize the result. In Oracle, Data Redaction allows you to control every aspect of query execution, so it can be based on user, role, weekday, time, IP, etc. 

Oracle Data Redaction provides the ability to masking data, typically sensitive data in real-time like credit card, Aadhar card details etc. before displaying with application. For example, in a call center, the agent able to view sensitive data in application because of the data they getting from PROD. Those Exposition may lead to privacy regulation and the corresponding user into risk.

Oracle Advanced Security Data Redaction is on-the-fly redaction, i.e., masking of sensitive data in query results prior to display by applications, as shown in the following illustration. It enables consistent redaction of database columns across application modules accessing the same data.

You can redact column data by using one of the following methods:

Full redaction. You redact all of the contents of the column data. The redacted value returned to the querying application user depends on the data type of the column. For example, columns of the NUMBER data type are redacted with a zero (0), and character data types are redacted with a single space.

Partial redaction. You redact a portion of the column data. For example, you can redact a Social Security number with asterisks (*), except for the last 4 digits.

Regular expressions. You can use regular expressions to look for patterns of data to redact. For example, you can use regular expressions to redact email addresses, which can have varying character lengths. It is designed for use with character data only.

Random redaction. The redacted data presented to the querying application user appears as randomly generated values each time it is displayed, depending on the data type of the column.

No redaction. The None redaction type option enables you to test the internal operation of your redaction policies, with no effect on the results of queries against tables with policies defined on them. You can use this option to test the redaction policy definitions before applying them to a production environment.

Oracle Database applies the redaction at runtime when users access the data (that is, at query-execution time). This solution works well in a production system. During the time that the data is being redacted, all of the data processing is performed normally, and the back-end referential integrity constraints are preserved.

Masking Data in Oracle with Data Redaction:
To mask data, use the function below to create a data redaction policy.

DBMS_REDACT.ADD_POLICY ( 
 object_schema               IN VARCHAR2 := NULL, 
 object_name                  IN VARCHAR2 := NULL, 
 policy_name                  IN VARCHAR2, 
 policy_description         IN VARCHAR2 := NULL, 
 column_name                IN VARCHAR2 := NULL, 
 column_description       IN VARCHAR2 := NULL, 
 function_type                 IN BINARY_INTEGER := DBMS_REDACT.FULL, 
 function_parameters      IN VARCHAR2 := NULL, 
 expression                      IN VARCHAR2, 
 enable                             IN BOOLEAN := TRUE, 
 regexp_pattern                IN VARCHAR2 := NULL, 
 regexp_replace_string    IN VARCHAR2 := NULL, 
 regexp_position              IN BINARY_INTEGER :=1, 
 regexp_occurrence         IN BINARY_INTEGER :=0, 
 regexp_match_parameter      IN VARCHAR2 := NULL); 

Important Procedures related to DBMS_REDACT

ProcedureDescription
DBMS_REDACT.ADD_POLICYAdds a Data Redaction policy to a table or view
DBMS_REDACT.ALTER_POLICYModifies a Data Redaction policy
DBMS_REDACT.APPLY_POLICY_EXPR_TO_COLApplies a Data Redaction policy expression to a table or view column
DBMS_REDACT.CREATE_POLICY_EXPRESSIONCreates a Data Redaction policy expression
DBMS_REDACT.DISABLE_POLICYDisables a Data Redaction policy
DBMS_REDACT.DROP_POLICYDrops a Data Redaction policy
DBMS_REDACT.DROP_POLICY_EXPRESSIONDrops a Data Redaction policy expression
DBMS_REDACT.ENABLE_POLICYEnables a Data Redaction policy
DBMS_REDACT.UPDATE_FULL_REDACTION_VALUESGlobally updates the full redaction value for a given data type. You must restart the database instance before the updated values can be used.
DBMS_REDACT.UPDATE_POLICY_EXPRESSIONUpdates a Data Redaction policy expression

It supports the following column data types:

NUMBER, BINARY_FLOAT, BINARY_DOUBLE, CHAR, VARCHAR2, NCHAR, NCLOB, NVARCHAR2, DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, BLOB and CLOB.

How to check Redaction policies OR View Existing Data Redaction Policies:
To view existing policies, you can use the code below:

select * from redaction_policies;

SELECT * FROM REDACTION_COLUMNS;

We need to make sure the respective user like apps (in my case redact user) has access to the DBMS_REDACT package.

GRANT EXECUTE ON sys.dbms_redact TO apps/redact;

Example: Let's create a user

$sqlplus / as sysdba

SQL>CREATE USER REDACT IDENTIFIED BY MyPwd;
SQL>GRANT CREATE SESSION TO REDACT;
SQL>ALTER USER REDACT quota unlimited on SYSTEM;
SQL>GRANT CREATE ANY TABLE TO REDACT;
SQL>grant execute on sys.dbms_redact to redact;

SQL>conn redact/MyPwd

Let's create a table
SQL>CREATE TABLE REDACTT
(cust_id     NUMBER NOT NULL
,name        varchar2(20)
,credit_card NUMBER(16)
,exp_date    DATE
,credit_limit NUMBER(6,2)
,email_adr    varchar2(20)
);
 
SQL>INSERT INTO REDACTT
VALUES (8714,'John Smith'    ,6283723982745971,'01-FEB-2017',49.50,'john.smith@gmail.com');
SQL>INSERT INTO REDACTT
VALUES (8743,'Paul McCartney',8995984092832971,'01-APR-2017',150.00,'paul@oracle.com');
SQL>INSERT INTO REDACTT
VALUES (8345,'George Lennon' ,9345945634845567,'01-FEB-2017',19.99,'glennon@qualogy.com');
SQL>INSERT INTO REDACTT
VALUES (9019,'Ricky Star'    ,2383834982340341,'01-JUN-2017',100.00,'star@aol.com');

SQL>set pagesize 200;
SQL>set linesize 300;
SQL>COLUMN credit_card format 0000000000000000
SQL>COLUMN EMAILADR    format a20
SQL>select * from redact.redactt;
 
CUST_ID  NAME      CREDIT_CARD   EXP_DATE  CREDIT_LIMIT  EMAIL_ADR
----------  --------------     -----------------             -----------       ---------------  --------------------
8714     John Smith    6283723982745971   01-FEB-2017    49.5   john.smith@gmail.com
8743     Paul McCar   8995984092832971   01-APR-2017   150     paul@oracle.com
8345     George Le     9345945634845567   01-FEB-2017    19.99  glennon@qualogy.com
9019     Ricky Star     2383834982340341   01-JUN-2017    100     star@aol.com

FULL REDACTION: Add a new policy
SQL>begin
DBMS_REDACT.ADD_POLICY ( 
 object_schema              =>'REDACT', 
 object_name                 =>'REDACTT', 
 policy_name                 =>'REDACT_CARD_POLICY',
 column_name               =>'CUST_ID', 
 function_type               =>DBMS_REDACT.FULL, 
 expression                    =>'1=1'); 
end;
/

Note: Expression of "1=1" means the redaction will always take place.

Check again data mask or not
select * from redact.redactt;

Alter an Existing Policy: Full unmask the data
We can also amend the policy so it does not affect the schema owner. The following example uses the SYS_CONTEXT function in the EXPRESSION parameter to determine the current user, making the application of the redaction policy conditional.

SQL>begin
DBMS_REDACT.ALTER_POLICY ( 
 object_schema              =>'REDACT', 
 object_name                 =>'REDACTT', 
 policy_name                 =>'REDACT_CARD_POLICY',
 column_name               =>'CUST_ID',
 action                            =>DBMS_REDACT.modify_expression,
 expression                     =>'sys_context(''userenv'',''session_user'') != ''REDACT''');
end;
/

Check data unmask or not---
SQL>select * from redact.redactt;

Drop a Data Redaction Policy:
To drop the policy, you can use the code below:
SQL>begin
DBMS_REDACT.DROP_POLICY ( 
 object_schema               =>'REDACT', 
 object_name                  =>'REDACTT', 
 policy_name                  =>'REDACT_CARD_POLICY');
end;
/

PARTIAL REDACTION: Partial Redaction on number values 
In Partial Redaction, the first 12 digits of the credit card numbers are masked with 0. We can mention the function_parameters to achieve this results.

Example 1:
BEGIN
 DBMS_REDACT.ADD_POLICY (
   object_schema       => 'REDACT',
   object_name          => 'REDACTT',
   column_name        => 'CREDIT_CARD',
   policy_name          => 'REDACT_CARD_POLICY',
   function_type        => DBMS_REDACT.PARTIAL,
   function_parameters => '0,1,12',
   expression             => '1=1'
 );
END;
/

Example 2:
Partial redaction can also be done on a date. Here we keep the year, but hide the rest of the date:

BEGIN
 DBMS_REDACT.ADD_POLICY (
   object_schema             => 'REDACT',
   object_name                => 'REDACTT',
   column_name              => 'EXP_DATE',
   policy_name                => 'REDACT_CARD_POLICY',
   function_type               => DBMS_REDACT.PARTIAL,
   function_parameters    => 'm1d1Y',
   expression                    => '1=1' );
END;
/

RANDOM REDACTION:
In Random Redaction the card numbers are transformed to entirely different card numbers as random number.

BEGIN
 DBMS_REDACT.ADD_POLICY (
   object_schema       => 'REDACT',
   object_name          => 'REDACTT',
   column_name        => 'CREDIT_CARD',
   policy_name          => 'REDACT_CARD_POLICY',
   function_type        => DBMS_REDACT.RANDOM,
   expression             => '1=1'
 );
END;
/

OR 

BEGIN
   DBMS_REDACT.ALTER_POLICY(
     object_schema       => 'REDACT',
     object_name          => 'REDACTT',
     column_name        => 'CREDIT_CARD',
     policy_name          => 'REDACT_CARD_POLICY',
     action                     => DBMS_REDACT.modify_column,
     function_type        => DBMS_REDACT.random);
END;
/

REGULAR EXPRESSION:
In this example the customer email address is getting transformed to xxxxxx@domain.com using the regular expression redaction.

BEGIN
    DBMS_REDACT.ADD_POLICY (
           object_schema         => 'REDACT',
           object_name            => 'REDACTT',
           policy_name            => 'REDACT_CARD_POLICY',
           column_name          => 'EMAIL_ADR',
           function_type          => DBMS_REDACT.REGEXP,
           expression               => '1=1',
           enable                      => TRUE,
           regexp_pattern        => '(.){2,}\@([[:alnum:]])',
           regexp_replace_string  => 'xxxxxxx@\2',
           regexp_position            => '1',
           regexp_occurrence       => '0',
           regexp_match_parameter  => 'i'
   );
END;
/

OR

BEGIN
 DBMS_REDACT.ADD_POLICY (
   object_schema           => 'REDACT',
   object_name              => 'REDACTT',
   column_name            => 'EMAIL_ADR',
   policy_name              => 'REDACT_CARD_POLICY',
   function_type            => DBMS_REDACT.REGEXP,
   regexp_pattern          => DBMS_REDACT.RE_PATTERN_EMAIL_ADDRESS,
   regexp_replace_string   => DBMS_REDACT.RE_REDACT_EMAIL_NAME,
   regexp_position             => DBMS_REDACT.RE_BEGINNING,
   regexp_occurrence         => DBMS_REDACT.RE_ALL,
   expression                      => '1=1'
 );
END;
/

Exceptions:
If you have the EXEMPT REDACTION POLICY system privilege, data is never redacted.Redaction is also never used in the following situations:

connections as SYS
database replication
backup and restore
export and import

SYS and DBA privileged schema over DBMS_REDACT
The sys and dba privileged schemas can view the details of columns masked using DBMS_REDACT.

$sqlplus / as sysdba
SQL>set pagesize 200;
SQL>set linesize 300;
SQL>select * from redact.redactt;

Thursday 5 October 2023

Create an APPS READONLY user:

There are 2 ways to achieve this:

1) Create a user and grant select option to that user.
This will have to be done individually for all users that you want to have as read only.

2) Create a readonly role and assign users this role.
This will have to be done once and then assign this role to the users.

1. Create a user and grant select option to that user.
Step 1: Connect as sysdba and create the database user to be used for apps read only schema.

$sqlplus / as sysdba
SQL> create user appsro identified by appsro default tablespace APPS_TS_TX_DATA;
User created.
SQL> grant connect to appsro;
Grant succeeded.
SQL> grant select any table to appsro;
Grant succeeded.

Step 2: Connect with the appsro user and run the SQL commands:
SQL> conn appsro
Enter password:
Connected.
SQL> show user
USER is "APPSRO"

Step 3: Try to access an apps schema table
SQL> select count(*) from apps.po_headers_all;
COUNT(*)
----------
132206

Step 4: Try to update an apps schema table
SQL> update apps.po_headers_all set attribute1 = '1' where po_header_id = 126;
update apps.po_headers_all set attribute1 = '1' where po_header_id = 126
*
ERROR at line 1:
ORA-01031: insufficient privileges

2. Create a read only role and assign to users this role.
Step 1: Connect as sysdba and create the database user to be used for apps read only schema.

SQL> create user appsro identified by appsro default tablespace APPS_TS_TX_DATA;
User created.
SQL> grant connect to appsro;
Grant succeeded.
SQL> create role role_readonly;
Role created.
SQL> grant select any table to role_readonly;
Grant succeeded.
SQL> grant role_readonly to appsro;
Grant succeeded.

Step 2: Connect with the appsro user and run the SQL commands:
SQL> conn appsro
Enter password:
Connected.
SQL> show user
USER is "APPSRO"

Step 3: Try to access an apps schema table
SQL> select count(*) from apps.po_headers_all;
COUNT(*)
----------
132206

Step 4: Try to update an apps schema table
SQL> update apps.po_headers_all set attribute1 = '1' where po_header_id = 126;
update apps.po_headers_all set attribute1 = '1' where po_header_id = 126
*
ERROR at line 1:
ORA-01031: insufficient privileges

Example: Grant another user the 'read only' role
SQL> create user apps_readonly identified by apps_readonly;
User created.
SQL> grant connect to apps_readonly;
Grant succeeded.
SQL> grant role_readonly to apps_readonly;
Grant succeeded.
SQL> conn apps_readonly
Enter password:
Connected.
SQL> show user
USER is "APPS_READONLY"
SQL> select count(*) from apps.fnd_concurrent_requests;
COUNT(*)
----------
75724
SQL> select count(*) from apps.po_headers_all;
COUNT(*)
----------
132206
SQL> update apps.po_headers_all set attribute1 = '1' where po_header_id = 126;
update apps.po_headers_all set attribute1 = '1' where po_header_id = 126
*
ERROR at line 1:
ORA-01031: insufficient privileges

SQL> exit;

You are done. Now your users can use “appsro” schema to have the read only access to Apps Data.

Wednesday 4 October 2023

Prevent users from login into a database within defined period.

Description:

It shows how to set up the database security so that users cannot log into the database outside defined time-window. Here we are using Event Triggers.

Steps to be followed :

Step 1 : Create a user (or existing user) and check, whether is able to connect.

SQL> connect username/*****
Connected.

Now we able to connect, afterthat login as sys user and create a trigger .

Step 2 : Create an event trigger that allow the user to login the database only on Monday to Friday included 9 AM to 6 PM.

Except DBA Privilege user, remaining users connection occurs only within the time frame.

SQL> create or replace trigger prevent_logon_database_trigger after logon on database
begin
if (to_char(sysdate,'D') not between '2' and '6') ------(2 for monday and 6 for friday)
or (to_char(sysdate, 'HH24')  between '09' and '18') 
-----or (to_char(sysdate, 'HH24') not between '09' and '18') 
then RAISE_APPLICATION_ERROR(-20001, 'Please login on your given date');
end if;
end;
/

Trigger created.

OR

SQL>create or replace trigger prevent_logon_database_trigger after logon on database 
declare
current_hour pls_integer;
restricted_user boolean;
restricted_time boolean;
begin
restricted_user := user = 'USERNAME';
current_hour    := extract(hour from systimestamp);
restricted_time := (current_hour < 18 or current_hour >= 9);
if restricted_user and restricted_time 
then raise_application_error(-20001, 'You can''t come in!');
end if;
end ;
/

Trigger created.

Step 3 : Now check whether you are able to connect to the database.

Example : It’s Saturday normal user cannot be able to log into the database. We have created trigger for all the users to login into the database on Monday and Friday included 9AM to 6PM. So the error throws .

SQL> connect username/*****

ERROR:

ORA-00604: error occurred at recursive SQL level 1
ORA-20001: You are not allowed to log into database now.
ORA-06512: at line 3
Warning: You are no longer connected to ORACLE.

Step 4 : Disable trigger.

SQL>Drop trigger prevent_logon_database_trigger;

Trigger dropped.

Wednesday 27 September 2023

Create User and Add Responsibility from backend

Adding new user in Oracle Apps (EBS) from back end

Application users in Oracle Apps (EBS) can be created from the front end as well as back end. The back end method for user creation can be used when you don’t have sysadmin access to the applciation or also it can be used to speed up the process when there are many userids to be created.

You will require apps access to connect to database  to run the package fnd_user_pkg.
fnd_user_pkg is the seeded generic API provided by Oracle.

Sample code to create a user (FND_USER) from backend and add responsibility.
DECLARE
v_user_name VARCHAR2 (100) := upper('&Enter_User_Name');
v_description VARCHAR2 (100) := 'Put Any description as like New User, etc..';
 v_app_short_name VARCHAR2 (100);
 v_resp_key VARCHAR2 (100);
 CURSOR user_cur IS
 select a.application_short_name, r.responsibility_key
 from fnd_responsibility_vl r, fnd_application_vl a where
 r.application_id =a.application_id
 and R.responsibility_ID IN (SELECT RESPONSIBILITY_ID FROM fnd_user_resp_groups WHERE USER_ID=&from_userid AND END_dATE IS NULL and a.application_short_name not in ('SQLAP','SQLGL','JTF','FND'));
user_rec user_cur%ROWTYPE;
BEGIN
 fnd_user_pkg.createuser
(x_user_name => v_user_name,
 x_owner => NULL,
 x_unencrypted_password => '&input_password',
 x_session_number => 0,
 x_start_date => SYSDATE,
 x_end_date => NULL,
 x_last_logon_date => NULL,
 x_description => v_description,
 x_password_date => NULL,
 x_password_accesses_left => NULL,
 x_password_lifespan_accesses => NULL,
 x_password_lifespan_days => NULL,
 x_employee_id => NULL,
 x_email_address => NULL,
 x_fax => NULL,
 x_customer_id => NULL,
 x_supplier_id => NULL,
 x_user_guid => NULL,
 x_change_source => NULL
 );
 COMMIT;
 OPEN user_cur;
 LOOP
 FETCH user_cur INTO user_rec;
 EXIT WHEN user_cur%NOTFOUND;
 fnd_user_pkg.addresp(username => v_user_name
 ,resp_app => user_rec.application_short_name
 ,resp_key => user_rec.responsibility_key
 ,security_group => 'STANDARD'
 ,description => NULL
 ,start_date => SYSDATE
 ,end_date => null);
 END LOOP;
 CLOSE user_cur;
commit;
END;
/

Wednesday 20 September 2023

How to increase oacore/jvm processes in R12.1.3

Below are the steps to increase oacore process:

STEP1: Take a backup of context file and opmn.xml file. 
a. $INST_TOP/ora/10.1.3/opmn/conf/opmn.xml
b. $CONTEXT_FILE

STEP2: Modify $CONTEXT_FILE as follows
From
<oacore_nprocs oa_var="s_oacore_nprocs">1</oacore_nprocs>
To
<oacore_nprocs oa_var="s_oacore_nprocs">2</oacore_nprocs>

STEP3: Modify $INST_TOP/ora/10.1.3/opmn/conf/opmn.xml as follows
$INST_TOP/ora/10.1.3/opmn/conf/opmn.xml file under oacore section as follows:
<process-type id="oacore" module-id="OC4J" status="enabled" working-dir="$ORACLE_HOME/j2ee/home">
From
<process-set id="default_group" numprocs="1"/>
To
<process-set id="default_group" numprocs="2"/>

STEP4:
Bounce Apache services, no need of autoconfig.  If your application services are already running, just reload the ocaore processes using adopmnctl.sh reaload command.
                                                        OR 
Bounce the Application services for safe side.

Identify versions of components in EBS

Useful commands to find the versions of various components used in Oracle E-Business Suite

Log in to the Application server and source the environment fine and execute the below command.

Find Apache Version in R12

$IAS_ORACLE_HOME/Apache/Apache/bin/httpd -v

Find Perl Version in EBS

$IAS_ORACLE_HOME/perl/bin/perl -v|grep built

Find Java Version/JDK Version

cd $ADMIN_SCRIPTS_HOME/
sh java.sh -version

Find JRE Version

cat $FORMS_WEB_CONFIG_FILE|grep sun_plugin_version

Find Weblogic Version

cat $FMW_HOME/wlserver_10.3/.product.properties | grep WLS_PRODUCT_VERSION

Find Opatch Version

$ORACLE_HOME/OPatch/opatch lsinventory

Oracle EBS version from the backend then connect to the database as user apps,

Find Oracle EBS Version

SQL>select release_name from apps.fnd_product_groups;

Find AD & TXK version in R12

SQL>select ABBREVIATION, NAME, codelevel FROM apps.AD_TRACKABLE_ENTITIES where abbreviation in ('txk','ad');

Find Workflow Version in R12

SQL>select text ,name from wf_resources where name like '%WF_VERSION%';

Oracle has provisioned bulit in scripts to collect versions of technology stack components. Reference – 601736.1

For Application Tier

perl $FND_TOP/patch/115/bin/TXKScript.pl 
-script=$FND_TOP/patch/115/bin/txkInventory.pl 
-txktop=$APPLTMP -contextfile=$CONTEXT_FILE 
-appspass=<apps password> 
-outfile=<File_Directory>/<output_file_name>

For Database Tier

$ADPERLPRG $ORACLE_HOME/appsutil/bin/TXKScript.pl
-script=$ORACLE_HOME/appsutil/bin/txkInventory.pl 
-txktop=$ORACLE_HOME/appsutil/temp
-contextfile=$CONTEXT_FILE
-appspass=<apps password>
-outfile=<File_Directory>/<output_file_name>

Wednesday 2 August 2023

How to assign multiple responsibility to multiple user in oracle apps from backend

Adding Mutiple Responsibilty to Mutiple User from Back End in Oracle Apps

With the following we can add multiple user name and multiple responsibilities through backend.

This script can be used to assign multiple responsibilities to multiple  user in Oracle Apps

Declare 
  cursor get_user 
   is 
     select USER_NAME 
from fnd_user 
where END_DATE is null 
and LAST_UPDATED_BY not in (1,0) 
and USER_ID not in (0,1110,1120,1606,1826,2126,2608,2869,3030)
--and user_id =3030--ERP_SUPPORT
ORDER BY 1; 
   cursor create_responsibilities 
   is 
     select resp.responsibility_key 
           ,resp.responsibility_name 
           ,app.application_short_name       
     from  fnd_responsibility_vl resp, 
           fnd_application       app 
     where resp.application_id = app.application_id  
     and   resp.responsibility_name in ( 'XX ERP Issue Register','System Administrator' ) ; 
 begin 
   for c_user in get_user loop 
   for get_resp in create_responsibilities  
   loop 
     fnd_user_pkg.addresp (
                username        => c_user.user_name 
               ,resp_app        => get_resp.application_short_name 
               ,resp_key        => get_resp.responsibility_key 
               ,security_group  => 'STANDARD' 
               ,description     => null 
               ,start_date      => sysdate 
               ,end_date        => null); 
     dbms_output.put_line('Responsibility '||get_resp.responsibility_name||' added !!!!!!');   
   end loop; 
end loop;
   commit; 
 exception 
   when others then 
   dbms_output.put_line ('Exception : '||SUBSTR(SQLERRM, 1, 500)); 
   rollback; 
 end;

Monday 26 June 2023

Concurrent request Error: The executable file for this concurrent program cannot be executed.

Issue: Concurrent request completed with below Error.

This request finished with an error and produced the following completion message: The executable file /$CUSTOM_TOP/bin/MAIL_SCRIPT for this concurrent program cannot be executed.

ERROR:
The executable file /$CUSTOM_TOP/bin/MAIL_SCRIPT for this concurrent program cannot be executed.Contact your system administrator or support representative.

Cause:Verify that the execution path to the executable file

Run the below command
$cd /$CUSTOM_TOP/bin
$ls -ll 
OR
$ls -lrt /$CUSTOM_TOP/bin/MAIL_SCRIPT
Output of the above command shows executable is pointing to a wrong symbolic link or not showing link.
Solution:
1.Create a soft link with the program name as below:
$cd /$CUSTOM_TOP/bin
$ln -s -f $FND_TOP/bin/fndcpesr MAIL_SCRIPT
2. Re-run the concurrent program and test the issue.

How To Register Shell Script as Concurrent Program in Oracle Apps

INTRODUCTION:
To run a UNIX shell script as a concurrent program, we need to register the shell script as a Host Concurrent Program. Also we need to ensure that there is execute permission for executable.

High Level Stepts:
Step to regist shell script as a host program or concurrent program in Oracle Applications.
1. Create a shell script ( say xyz) and move it to the appropriate BIN directory in Oracle Application.
2. The parameters in the shell scripts should start with $5 , $6 Onwards.
3. Rename the shell script to *.prog ( xyz.prog).
4. Change Permissions to 755 for the *.prog file.
5. Create Link to the shell Script ( ln -s $FND_TOP/bin/fndcpesr/xyz.prog) to create xyz file.
6. Now Register this executable in the application as a host executable (Using System Administrator Responsibility).

While registering the shell script as a concurrent program make sure that the first parameter in the concurrent program is passed as the Fifth parameter in the shell scripts because the first four parameters are allocated to userid,request_id,resp_id,resp_appl_id.

Step 1: mailx syntax
mailx [-s subject] [-a attachment ] [-c cc-addr] [-b bcc-addr] [-r from-addr] [-h hops] [-A account] [-S variable[=value]] to-addr

Options:
-s – subject of an email. Mention it in double-quotes if it contains space
-a – attach the given filename to message
-b – send blind carbon copies to list of users
-c – send carbon copies to list of users
-r – set the from address.
-v – Verbose mode. This displays details of delivery on the user’s terminal

Note:- All parameters to this command are optional.

Shell Script: MAIL_SCRIPT.sh
#!/bin/bash
# |Description      : Check mail Sending throgh CP                           |
# |Change Record:                                                                             |
# |===============                                                                     |
# |Version           Date                     Author           Remarks               |
# |=======   ==========  =============    ===========  |
# |Draft            23-06-2023      XXXXXXXXXX     Initial Version  |
# +=============================================+
#Parameters from 1 to 4 i.e $1 $2 $3 $4 are standard parameters
# $1 : username/password of the database
# $2 : userid
# $3 : USERNAME
# $4 : Concurrent Request ID
ToAddress=$5
CcAddress=$6
BccAddress=$7
Subject=$8
echo ------------------
echo -Parameters received from concurrent program ..-
echo - Time : -`date`
echo ------------------
echo - Arguments  : -
echo - Apps       : -$1
echo - ToAddress  : -${ToAddress}
echo - CcAddress  : -${CcAddress}
echo - BccAddress : -${BccAddress}
echo - Subject    : -${Subject}
echo -------------------
echo - PPDDEBUGNEXTCODE 10
IP=XX.XX.XXX.41
MAIL_SUB="Invalid Object alert @ $ORACLE_SID Production Application server($IP)"
MAILING_LIST_S=erpteam@xxx.in
#mailx syntax
#echo -e "MSG Body" | mailx [-s subject] [-a attachment ] [-c cc-addr] [-b bcc-addr] [-r from-addr] [-h hops] [-A account] [-S variable[=value]] to-addr
echo -e " Dear Team,\n\nWe have found some Invalid Object in Production, please check.\n\nThanks & Regard\nERPTEAM" | mailx -s "$MAIL_SUB" -a $attachment -c cc-addr -b bcc-addr -r from-addr $MAILING_LIST_S
if [ $? -ne 0 ]
then
echo -Entered Exception at mail sending, contact Administrator-
else
echo -Email utility completed successfully-
fi
echo -****************************************************************

Step 2: Rename the shell script to *.prog
Save the shell script to $CUSTOM_TOP/bin as MAIL_SCRIPT.prog
Change Permissions to 755 for the *.prog file.

Step 3: Create Softlink as follows
cd /$CUSTOM_TOP/bin
ln -s $FND_TOP/bin/fndcpesr MAIL_SCRIPT

Step 4: Create Executable

Step 5: Register as Concurrent Program (Using System Administrator Responsibility)

Step 6: Define User Parameters

Step 7: Run Request

Log file



Wednesday 19 April 2023

How to Resolve Gaps in Data Guard Apply Using Incremental RMAN Backup

Suppose in between primary & standby database have many archives difference like 1000 archives, so we have need to recover it using incremental backup.

Action ON STANDBY:
Step-1. Check the current SCN number on standby using the following command but before it just cancels the recovery.

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
SQL> SELECT CURRENT_SCN FROM V$DATABASE; 
      CURRENT_SCN
----------------------
       512520
SQL> SHU IMMEDIATE;

Manually resolve archive log gap

Step-2. After that, we need to take incremental backup on the primary server using the above SCN number, follow me.

Action ON PRIMARY

RMAN > BACKUP AS COMPRESSED BACKUPSET INCREMENTAL FROM SCN 512520 DATABASE;

Step-3. After taking incremental backup need to create a new standby control file using the following commands.

SQL> ALTER DATABASE CREATE STANDBY CONTROLFILE AS '/u01/standby_contrlfile.ctl';

Then copy both (backup & controlfile) backup on standby.

Action ON STANDBY

Step-4. Start standby database up to nomount status.

SQL> STARTUP NOMOUNT;

Step-5. Now replace all existing controlfiles with the backup of controlfile be careful then start standby up to mount status.

SQL> ALTER DATABASE MOUNT;

Step-6. connect with RMAN and start recovery, using the following command.

$rman target sys/Oracle12c@ocpdr

RMAN> catalog start with '/u01/';

RMAN> recover database noredo;

Step-7. After successfully recover of your standby database, start the redo apply process using the following command.

SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

How to check MRP process

Check MRP process is running or not.

SQL> SELECT SEQUENCE#,PROCESS,STATUS FROM V$MANAGED_STANDBY;

Congratulations now you have successfully recovered your standby. 

Another Error related this ORA-00257: Archiver error. Connect AS SYSDBA only until resolved Error

Our 11.2.0.4 physical standby database was down for about 6 days and after starting it back up it and after a few hours I checked the status. Everything appears to be caught up with redo applying and all archive redo logs transferred to the physical standby database. The following query shows a status of RESOLVABLE GAP (query is run on primary database):

select switchover_status from v$database;

There are no errors and no gaps anywhere except from the switchover status.

There are various reason which cause this error-

1. One of the common issue here is archive destination of your database is 100% full.
2. The mount point/disk group assigned to archive destination or FRA is dismounted due to OS issue/Storage issue.
3. If db_recovery_file_dest_size is set to small value.
4. Human Error – Sometimes location doesn’t have permission or we set to location which doesn’t exists.

What are Different Ways to Understand if there is ORA-00257: Archiver error. Connect AS SYSDBA only until resolved Error

There are different ways to understand what is there issue. Usually end user doesn’t understand the ORA- code and they will rush to you with a Problem statement as -> DB is running slow or I am not able to login to the database.

Check the Alert Log First –
Always check alert log of the database to understand what is the problem here –

I have set the log_archive_dest_1 to a location which doesn’t exists to reproduce ORA-00257: Archiver error. Connect AS SYSDBA only until resolved Error. So alert log clearly suggest that

ORA-19504: failed to create file %s
ORA-27040: file create error, unable to create file
Linux-x86-64 Error: 13: Permission denied.

Check Space availability –
Once you rule out that there is no human error, and the archive log location exists Now you should check if mount point/ disk group has enough free space available, if it is available for writing and you can access it.

If your database is on ASM, then you can use following query – Check for free_mb/usable file mb and state column against your diskgroup name.

SQL> select name,state,free_mb,usable_file_mb,total_mb from v$asm_diskgroup;
If your database is on filesystem, then you can use following OS command –

For linux, sun solaris -
$df -kh 
For AIX -
$df -gt   
If case you have FRA been used for archive destination then we have additional query to identify space available and how much is allocated to it.
What Happens when ORA-00257: Archiver error. Connect AS SYSDBA only until resolved Error occurs

Lets us understand what end user see and understand there pain as well. So when a normal user try to connect to the database which is already in archiver error (ORA-00257: Archiver error. Connect AS SYSDBA only until resolved ) state then they directory receive the error –

ORA-00257: Archiver error. Connect AS SYSDBA only until resolved on the screen.

How to Resolve ORA-00257: Archiver error. Connect AS SYSDBA only until resolved error

It’s always better to know the environment before firing any command. Archive deletion can be destructive for DR setup or Goldengate Setup.

Solution 1:
Check if you have DR database and it’s in sync based on that take a call of clearing the archive until sequence. You can use following command on RMAN prompt.

delete archivelog until sequence <sequence> thread <thread no>;

Solution 2:
You can change destination to a location which has enough space.
SQL>archive log list
SQL>show parameter log_archive_dest_1 
(or whichever you are using it, usually we use dest_1)
Say your diskgroup  +ARCH is full and +DATA has lot of space then you can fire
SQL> alter system set log_archive_dest_1='location=+DATA reopen';

You might be wondering why reopen. So since your archive location was full. There are chances if you clear the space on OS level and archiver process still remain stuck. Hence we gave reopen option here.

Solution 3:
Other reason could be your db_recovery_file_dest_size is set to lower size. Sometimes we have FRA enabled for archivelog. And we have enough space available on the diskgroup/ filesystem level.
SQL>archive log list;
SQL>show parameter db_recovery_file_dest_size
SQL>alter system set db_recovery_file_dest_size=<greater size then current value please make note of filesystem/diskgroup freespace as well>

example -
Initially it was 20G
alter system set db_recovery_file_dest_size=100G sid='*';

Tuesday 21 March 2023

Performance Monitoring Tool for All Unix/Linux Distrubitions (Oracle,Red Hat,AIX,Centos,Debian,Ubuntu,SLES,openSUSE)

Linux | Nmon

Nmon is a fully interactive performance monitoring command-line utility tool for Linux. It is a benchmark tool that displays performance about the CPU, MEMORY, NETWORK, DISKS, FILE SYSTEM, NFS, TOP PROCESSES, RESOURCES, AND POWER MICRO-PARTITION.

INSTALLATION

On Ubuntu/Debian :
$ sudo apt-get install nmon

On Fedora:
# yum install nmon

CentOS/RHEL:
# yum install epel-release
# yum install nmon

Once the installation of Nmon has been finished and you launch it from the terminal by typing the ‘nmon‘ command you will be presented with the following output.

$ nmon


Check CPU by processor
In order to get the CPU performance, you should hit the ‘c‘ key on the keyboard of the system you are using.

Top Process Details
In order to get the top processes that are running currently, you should hit the ‘t‘ key on the keyboard of the system you are using.

Check Network Statistics
In order to check network statistics, you should hit the ‘n‘ key on the keyboard of the system you are using.

Disk I/O Graphs
In order to get informations of disks, you should hit the ‘d‘ key on the keyboard of the system you are using.

Check Kernel Information
In order to check kernel information, you should hit the ‘k‘ key on the keyboard of the system you are using.

Get System Information
In order to get system information on different resources such as operating system version, Linux Version, Machine architecture, you should hit the ‘r‘ key on the keyboard of the system you are using.

Check File System Statistics
In order to check File System Statistics, you should hit the ‘j‘ key on the keyboard of the system you are using. You can get information on the size of the file system, used space, free space, type of the file system and the mount point.

Virtual Memory Statistics
In order to check Virtual Memory Statistics, you should hit the ‘V‘ key on the keyboard of the system you are using.

CPU Long Term
In order to check CPU Long Term Statistics, you should hit the ‘l‘ key on the keyboard of the system you are using.

Note: If you want use this facility in all operating systems without installation then follow the below steps:

1-Download rpm/tar.gz or etc.

You can download all versions of the tool with command below. Please download from here “http://nmon.sourceforge.net/pmwiki.php?n=Site.Download”
OR
wget https://netcologne.dl.sourceforge.net/project/nmon/nmon16m_helpsystems.tar.gz

2-Untar the file

[root@erptstdb01 nmon]#mkdir nmon

[root@erptstdb01 nmon]#mv nmon16m_helpsystems.tar.gz nmon

[root@erptstdb01 nmon]#cd nmon/

[root@erptstdb01 nmon]#tar -xvf nmon16m_helpsystems.tar.gz

[root@erptstdb01 nmon]# chmod 777 *

3-You can run nmon for your Linux Distrubition here without installation.

Press key you want to monitor.

For example press d for Disk and then . to see only working disks. Same for all other resources.

Example: Press m ( Memory ) + n (Network) + d (Disks ) + . ( dot)