+
+creating_a_subprocedure creating_a_subfunction block_relationships invoking_subprograms using_forward_declarations overloading_subprograms accessing_subprogram_variables
+
+
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/08_compilation_errors_in_procedures_and_functions.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/08_compilation_errors_in_procedures_and_functions.mdx
new file mode 100644
index 00000000000..7264839644d
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/08_compilation_errors_in_procedures_and_functions.mdx
@@ -0,0 +1,74 @@
+---
+title: "Compilation errors in procedures and functions"
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.055.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.149.html"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/08_compilation_errors_in_procedures_and_functions/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+```
+
+Where `number_of_errors` specifies the number of SPL errors that can occur before the server stops compiling. For example:
+
+```sql
+SET spl.max_error_count = 6
+```
+## Example
+
+The example instructs the server to continue past the first five SPL errors it encounters. When the server encounters the sixth error, it stops validating and prints six detailed error messages and one error summary.
+
+To save time when developing new code or when importing code from another source, you might want to set the `spl.max_error_count` configuration parameter to a relatively high number of errors.
+
+If you instruct the server to continue parsing in spite of errors in the SPL code in a program body, and the parser encounters an error in a segment of SQL code, there can be more errors in any SPL or SQL code that follows the incorrect SQL code. For example, the following function results in two errors:
+
+```sql
+CREATE FUNCTION computeBonus(baseSalary number) RETURN number AS
+BEGIN
+
+ bonus := baseSalary * 1.10;
+ total := bonus + 100;
+
+ RETURN bonus;
+END;
+
+ERROR: "bonus" is not a known variable
+LINE 4: bonus := baseSalary * 1.10;
+ ^
+ERROR: "total" is not a known variable
+LINE 5: total := bonus + 100;
+ ^
+ERROR: compilation of SPL function/procedure "computebonus" failed due to 2 errors
+```
+
+This example adds a `SELECT` statement to the example. The error in the `SELECT` statement masks the other errors that follow.
+
+```sql
+CREATE FUNCTION computeBonus(employeeName number) RETURN number AS
+BEGIN
+ SELECT salary INTO baseSalary FROM emp
+ WHERE ename = employeeName;
+
+ bonus := baseSalary * 1.10;
+ total := bonus + 100;
+
+ RETURN bonus;
+
+END;
+
+ERROR: "basesalary" is not a known variable
+LINE 3: SELECT salary INTO baseSalary FROM emp WHERE ename = emp...
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/01_execute_privilege.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/01_execute_privilege.mdx
new file mode 100644
index 00000000000..0a39e05f954
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/01_execute_privilege.mdx
@@ -0,0 +1,41 @@
+---
+title: "EXECUTE privilege"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/09_program_security/01_execute_privilege/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+An SPL program (function, procedure, or package) can begin execution only if any of the following are true:
+
+- The current user is a superuser.
+- The current user was granted `EXECUTE` privilege on the SPL program.
+- The current user inherits `EXECUTE` privilege on the SPL program by virtue of being a member of a group that has this privilege.
+- `EXECUTE` privilege was granted to the `PUBLIC` group.
+
+Whenever an SPL program is created in EDB Postgres Advanced Server, `EXECUTE` privilege is granted to the `PUBLIC` group by default. Therefore, any user can immediately execute the program.
+
+You can remove this default privilege by using the `REVOKE EXECUTE` command. For example:
+
+```sql
+REVOKE EXECUTE ON PROCEDURE list_emp FROM PUBLIC;
+```
+
+You can then grant explicit `EXECUTE` privilege on the program to individual users or groups.
+
+```sql
+GRANT EXECUTE ON PROCEDURE list_emp TO john;
+```
+
+Now, user `john` can execute the `list_emp` program. Other users who don't meet any of the required conditions can't.
+
+Once a program begins to execute, the next aspect of security is the privilege checks that occur if the program attempts to perform an action on any database object including:
+
+- Reading or modifying table or view data
+- Creating, modifying, or deleting a database object such as a table, view, index, or sequence
+- Obtaining the current or next value from a sequence
+- Calling another program (function, procedure, or package)
+
+Each such action can be protected by privileges on the database object either allowed or disallowed for the user.
+
+It's possible for a database to have more than one object of the same type with the same name, but each such object belongs to a different schema in the database. If this is the case, which object is being referenced by an SPL program? For more information, see [Database object name resolution](02_database_object_name_resolution).
\ No newline at end of file
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/02_database_object_name_resolution.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/02_database_object_name_resolution.mdx
new file mode 100644
index 00000000000..b705bb8e5e9
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/02_database_object_name_resolution.mdx
@@ -0,0 +1,27 @@
+---
+title: "Database object name resolution"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/09_program_security/02_database_object_name_resolution/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+You can reference a database object inside an SPL program either by its qualified name or by an unqualified name. A qualified name is in the form of `schema.name`, where `schema` is the name of the schema under which the database object with identifier `name` exists. An unqualified name doesn't have the `schema.` portion. When a reference is made to a qualified name, there is no ambiguity as to which database object is intended. It either does or doesn't exist in the specified schema.
+
+Locating an object with an unqualified name, however, requires the use of the current user’s search path. When a user becomes the current user of a session, a default search path is always associated with that user. The search path consists of a list of schemas that are searched in left-to-right order for locating an unqualified database object reference. The object is considered nonexistent if it can’t be found in any of the schemas in the search path. You can display the default search path in PSQL using the `SHOW search_path` command:
+
+```sql
+edb=# SHOW search_path;
+__OUTPUT__
+ search_path
+-----------------
+ "$user", public
+(1 row)
+```
+
+`$user` in the search path is a generic placeholder that refers to the current user. So if the current user of this session is `enterprisedb`, an unqualified database object is searched for in the following schemas in this order: first in `enterprisedb`, and then in `public`.
+
+Once an unqualified name is resolved in the search path, you can determine if the current user has the appropriate privilege to perform the desired action on that specific object.
+
+!!! Note
+ The concept of the search path isn't compatible with Oracle databases. For an unqualified reference, Oracle looks in the schema of the current user for the named database object. Also, in Oracle, a user and their schema is the same entity. In EDB Postgres Advanced Server, a user and a schema are two distinct objects.
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/03_database_object_privileges.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/03_database_object_privileges.mdx
new file mode 100644
index 00000000000..683e24c2f78
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/03_database_object_privileges.mdx
@@ -0,0 +1,9 @@
+---
+title: "Database object privileges"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/09_program_security/03_database_object_privileges/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Once an SPL program begins execution, any attempt to access a database object from the program results in a check. This check ensures that the current user is authorized to perform the intended action against the referenced object. Privileges on database objects are added and removed using the `GRANT` and `REVOKE` commands. If the current user attempts unauthorized access on a database object, then the program throws an exception. See [Exception handling](/epas/latest/reference/application_programmer_reference/stored_procedural_language_reference/05_control_structures/07_exception_handling/#exception_handling).
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/04_definers_vs_invokers_rights.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/04_definers_vs_invokers_rights.mdx
new file mode 100644
index 00000000000..3f93904ddb3
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/04_definers_vs_invokers_rights.mdx
@@ -0,0 +1,23 @@
+---
+title: "About definer and invoker rights"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/09_program_security/04_definers_vs_invokers_rights/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+When an SPL program is about to begin executing, a determination is made as to the user to associate with this process. This user is referred to as the *current user*. The current user’s database object privileges are used to determine whether access to database objects referenced in the program is permitted. The current prevailing search path in effect when the program is invoked is used to resolve any unqualified object references.
+
+The selection of the current user is influenced by whether the SPL program was created with definer’s right or invoker’s rights. The `AUTHID` clause determines that selection. Appearance of the clause `AUTHID DEFINER` gives the program definer’s rights. This is also the default if the `AUTHID` clause is omitted. Use of the clause `AUTHID CURRENT_USER` gives the program invoker’s rights. The difference between the two is summarized as follows:
+
+- If a program has *definer’s rights*, then the owner of the program becomes the current user when program execution begins. The program owner’s database object privileges are used to determine if access to a referenced object is permitted. In a definer’s rights program, the user who actually invoked the program is irrelevant.
+- If a program has *invoker’s rights*, then the current user at the time the program is called remains the current user while the program (but not necessarily the subprogram) is executing. When an invoker’s rights program is invoked, the current user is typically the user that started the session (made the database connection). You can change the current user after the session started using the `SET ROLE` command. In an invoker’s rights program, who actually owns the program is irrelevant.
+
+From the previous definitions, the following observations can be made:
+
+- If a definer’s rights program calls a definer’s rights program, the current user changes from the owner of the calling program to the owner of the called program while the called program executes.
+- If a definer’s rights program calls an invoker’s rights program, the owner of the calling program remains the current user whiile both the calling and called programs execute.
+- If an invoker’s rights program calls an invoker’s rights program, the current user of the calling program remains the current user while the called program executes.
+- If an invoker’s rights program calls a definer’s rights program, the current user switches to the owner of the definer’s rights program while the called program executes.
+
+The same principles apply if the called program in turn calls another program in these cases.
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/05_security_example.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/05_security_example.mdx
new file mode 100644
index 00000000000..76813b775d8
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/05_security_example.mdx
@@ -0,0 +1,281 @@
+---
+title: "Security example"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/09_program_security/05_security_example/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+
+In this example, a new database is created along with two users:
+- `– hr_mgr`, who owns a copy of the entire sample application in schema `hr_mgr`
+- `sales_mgr`, who owns a schema named `sales_mgr` that has a copy of only the `emp` table containing only the employees who work in sales
+
+The procedure `list_emp`, function `hire_clerk`, and package `emp_admin` are used in this example. All of the default privileges that are granted upon installation of the sample application are removed and then explicitly regranted so as to present a more secure environment.
+
+Programs `list_emp` and `hire_clerk` are changed from the default of definer’s rights to invoker’s rights. Then, when `sales_mgr` runs these programs, they act on the `emp` table in the `sales_mgr` schema since the `sales_mgr` search path and privileges are used for name resolution and authorization checking.
+
+Programs `get_dept_name` and `hire_emp` in the `emp_admin` package are then executed by `sales_mgr`. In this case, the `dept` table and `emp` table in the `hr_mgr` schema are accessed as `hr_mgr` is the owner of the `emp_admin` package which is using definer’s rights. Since the default search path is in effect with the `$user` placeholder, the schema matching the user (in this case, `hr_mgr`) is used to find the tables.
+
+## Step 1: Create database and users
+
+As user `enterprisedb`, create the `hr` database:
+
+```sql
+CREATE DATABASE hr;
+```
+
+Switch to the hr database and create the users:
+
+```sql
+\c hr enterprisedb
+CREATE USER hr_mgr IDENTIFIED BY password;
+CREATE USER sales_mgr IDENTIFIED BY password;
+```
+
+## Step 2: Create the sample application
+
+Create the entire sample application, owned by `hr_mgr`, in the `hr_mgr` schema.
+
+```sql
+\c - hr_mgr
+\i /usr/edb/as14/share/edb-sample.sql
+
+BEGIN
+CREATE TABLE
+CREATE TABLE
+CREATE TABLE
+CREATE VIEW
+CREATE SEQUENCE
+ .
+ .
+ .
+CREATE PACKAGE
+CREATE PACKAGE BODY
+COMMIT
+```
+
+## Step 3: Create the emp table in schema sales_mgr
+
+Create a subset of the `emp` table owned by `sales_mgr` in the `sales_mgr` schema.
+
+```sql
+\c – hr_mgr
+GRANT USAGE ON SCHEMA hr_mgr TO sales_mgr;
+\c – sales_mgr
+CREATE TABLE emp AS SELECT * FROM hr_mgr.emp WHERE job = 'SALESMAN';
+```
+
+The `GRANT USAGE ON SCHEMA` command allows `sales_mgr` access into the `hr_mgr`’s schema to make a copy of the `hr_mgr` `emp` table. This step is required in EDB Postgres Advanced Server and isn't compatible with Oracle databases. Oracle doesn't have the concept of a schema that's distinct from its user.
+
+## Step 4: Remove default privileges
+
+Remove all privileges to later illustrate the minimum required privileges needed.
+
+```sql
+\c – hr_mgr
+REVOKE USAGE ON SCHEMA hr_mgr FROM sales_mgr;
+REVOKE ALL ON dept FROM PUBLIC;
+REVOKE ALL ON emp FROM PUBLIC;
+REVOKE ALL ON next_empno FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION new_empno() FROM PUBLIC;
+REVOKE EXECUTE ON PROCEDURE list_emp FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION hire_clerk(VARCHAR2,NUMBER) FROM PUBLIC;
+REVOKE EXECUTE ON PACKAGE emp_admin FROM PUBLIC;
+```
+
+## Step 5: Change list_emp to invoker’s rights
+
+While connected as user `hr_mgr`, add the `AUTHID CURRENT_USER` clause to the `list_emp` program and resave it in EDB Postgres Advanced Server. When performing this step, be sure you're logged in as `hr_mgr`. Otherwise the modified program might end up in the `public` schema instead of in the `hr_mgr` schema.
+
+```sql
+CREATE OR REPLACE PROCEDURE list_emp
+AUTHID CURRENT_USER
+IS
+ v_empno NUMBER(4);
+ v_ename VARCHAR2(10);
+ CURSOR emp_cur IS
+ SELECT empno, ename FROM emp ORDER BY empno;
+BEGIN
+ OPEN emp_cur;
+ DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
+ DBMS_OUTPUT.PUT_LINE('----- -------');
+ LOOP
+ FETCH emp_cur INTO v_empno, v_ename;
+ EXIT WHEN emp_cur%NOTFOUND;
+ DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
+ END LOOP;
+ CLOSE emp_cur;
+END;
+```
+
+## Step 6: Change hire_clerk to invoker’s rights and qualify call to new_empno
+
+While connected as user `hr_mgr`, add the `AUTHID CURRENT_USER` clause to the `hire_clerk` program.
+
+Also, after the `BEGIN` statement, fully qualify the reference `new_empno` to `hr_mgr.new_empno` to ensure the `hire_clerk` function call to the `new_empno` function resolves to the `hr_mgr` schema.
+
+When resaving the program, be sure you're logged in as `hr_mgr`. Otherwise the modified program might end up in the `public` schema instead of in the `hr_mgr` schema.
+
+```sql
+CREATE OR REPLACE FUNCTION hire_clerk (
+ p_ename VARCHAR2,
+ p_deptno NUMBER
+) RETURN NUMBER
+AUTHID CURRENT_USER
+IS
+ v_empno NUMBER(4);
+ v_ename VARCHAR2(10);
+ v_job VARCHAR2(9);
+ v_mgr NUMBER(4);
+ v_hiredate DATE;
+ v_sal NUMBER(7,2);
+ v_comm NUMBER(7,2);
+ v_deptno NUMBER(2);
+BEGIN
+ v_empno := hr_mgr.new_empno;
+ INSERT INTO emp VALUES (v_empno, p_ename, 'CLERK', 7782,
+ TRUNC(SYSDATE), 950.00, NULL, p_deptno);
+ SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno INTO
+ v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno
+ FROM emp WHERE empno = v_empno;
+ DBMS_OUTPUT.PUT_LINE('Department : ' || v_deptno);
+ DBMS_OUTPUT.PUT_LINE('Employee No: ' || v_empno);
+ DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
+ DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
+ DBMS_OUTPUT.PUT_LINE('Manager : ' || v_mgr);
+ DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
+ DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
+ DBMS_OUTPUT.PUT_LINE('Commission : ' || v_comm);
+ RETURN v_empno;
+EXCEPTION
+ WHEN OTHERS THEN
+ DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:');
+ DBMS_OUTPUT.PUT_LINE(SQLERRM);
+ DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
+ DBMS_OUTPUT.PUT_LINE(SQLCODE);
+ RETURN -1;
+END;
+```
+
+## Step 7: Grant required privileges
+
+While connected as user `hr_mgr`, grant the privileges needed so `sales_mgr` can execute the `list_emp` procedure, `hire_clerk` function, and `emp_admin` package. The only data object `sales_mgr` has access to is the `emp` table in the `sales_mgr` schema. `sales_mgr` has no privileges on any table in the `hr_mgr` schema.
+
+```sql
+GRANT USAGE ON SCHEMA hr_mgr TO sales_mgr;
+GRANT EXECUTE ON PROCEDURE list_emp TO sales_mgr;
+GRANT EXECUTE ON FUNCTION hire_clerk(VARCHAR2,NUMBER) TO sales_mgr;
+GRANT EXECUTE ON FUNCTION new_empno() TO sales_mgr;
+GRANT EXECUTE ON PACKAGE emp_admin TO sales_mgr;
+```
+
+## Step 8: Run programs list_emp and hire_clerk
+
+Connect as user `sales_mgr`, and run the following anonymous block:
+
+```sql
+\c – sales_mgr
+DECLARE
+ v_empno NUMBER(4);
+BEGIN
+ hr_mgr.list_emp;
+ DBMS_OUTPUT.PUT_LINE('*** Adding new employee ***');
+ v_empno := hr_mgr.hire_clerk('JONES',40);
+ DBMS_OUTPUT.PUT_LINE('*** After new employee added ***');
+ hr_mgr.list_emp;
+END;
+
+EMPNO ENAME
+----- -------
+7499 ALLEN
+7521 WARD
+7654 MARTIN
+7844 TURNER
+*** Adding new employee ***
+Department : 40
+Employee No: 8000
+Name : JONES
+Job : CLERK
+Manager : 7782
+Hire Date : 08-NOV-07 00:00:00
+Salary : 950.00
+*** After new employee added ***
+EMPNO ENAME
+----- -------
+7499 ALLEN
+7521 WARD
+7654 MARTIN
+7844 TURNER
+8000 JONES
+```
+
+The table and sequence accessed by the programs of the anonymous block are shown in the following diagram. The gray ovals represent the schemas of `sales_mgr` and `hr_mgr`. The current user during each program execution is shown in parenthesis in bold red font.
+
+![Invokers Rights Programs](../../images/invokers_rights_programs.png)
+
+ Fig. 1: Invokers Rights Programs
+
+Selecting from the `sales_mgr` `emp` table shows that the update was made in this table.
+
+```sql
+SELECT empno, ename, hiredate, sal, deptno,
+hr_mgr.emp_admin.get_dept_name(deptno) FROM sales_mgr.emp;
+__OUTPUT__
+ empno | ename | hiredate | sal | deptno | get_dept_name
+-------+--------+--------------------+---------+--------+---------------
+ 7499 | ALLEN | 20-FEB-81 00:00:00 | 1600.00 | 30 | SALES
+ 7521 | WARD | 22-FEB-81 00:00:00 | 1250.00 | 30 | SALES
+ 7654 | MARTIN | 28-SEP-81 00:00:00 | 1250.00 | 30 | SALES
+ 7844 | TURNER | 08-SEP-81 00:00:00 | 1500.00 | 30 | SALES
+ 8000 | JONES | 08-NOV-07 00:00:00 | 950.00 | 40 | OPERATIONS
+(5 rows)
+```
+
+The following diagram shows that the `SELECT` command references the `emp` table in the `sales_mgr` schema. However, the `dept` table referenced by the `get_dept_name` function in the `emp_admin` package is from the `hr_mgr` schema since the `emp_admin` package has definer’s rights and is owned by `hr_mgr`. The default search path setting with the `$user` placeholder resolves the access by user `hr_mgr` to the `dept` table in the `hr_mgr` schema.
+
+![Definer's Rights Package](../../images/definers_rights_package.png)
+
+ Fig. 2: Definer's Rights Package
+
+## Step 9: Run program hire_emp in the emp_admin package
+
+While connected as user `sales_mgr`, run the `hire_emp` procedure in the `emp_admin` package.
+
+```sql
+EXEC hr_mgr.emp_admin.hire_emp(9001,
+'ALICE','SALESMAN',8000,TRUNC(SYSDATE),1000,7369,40);
+```
+
+This diagram shows that the `hire_emp` procedure in the `emp_admin` definer’s rights package updates the `emp` table belonging to `hr_mgr`. The object privileges of `hr_mgr` are used and the default search path setting with the `$user` placeholder resolves to the schema of `hr_mgr`.
+
+![Definer's Rights Package](../../images/definer's_rights_package.png)
+
+ Fig. 3: Definer's Rights Package
+
+Now connect as user `hr_mgr`. The following `SELECT` command verifies that the new employee was added to the `hr_mgr` `emp` table since the `emp_admin` package has definer’s rights and `hr_mgr` is the `emp_admin` owner.
+
+```sql
+\c – hr_mgr
+SELECT empno, ename, hiredate, sal, deptno,
+hr_mgr.emp_admin.get_dept_name(deptno) FROM hr_mgr.emp;
+__OUTPUT__
+empno | ename | hiredate | sal | deptno | get_dept_name
+-------+--------+--------------------+---------+--------+---------------
+ 7369 | SMITH | 17-DEC-80 00:00:00 | 800.00 | 20 | RESEARCH
+ 7499 | ALLEN | 20-FEB-81 00:00:00 | 1600.00 | 30 | SALES
+ 7521 | WARD | 22-FEB-81 00:00:00 | 1250.00 | 30 | SALES
+ 7566 | JONES | 02-APR-81 00:00:00 | 2975.00 | 20 | RESEARCH
+ 7654 | MARTIN | 28-SEP-81 00:00:00 | 1250.00 | 30 | SALES
+ 7698 | BLAKE | 01-MAY-81 00:00:00 | 2850.00 | 30 | SALES
+ 7782 | CLARK | 09-JUN-81 00:00:00 | 2450.00 | 10 | ACCOUNTING
+ 7788 | SCOTT | 19-APR-87 00:00:00 | 3000.00 | 20 | RESEARCH
+ 7839 | KING | 17-NOV-81 00:00:00 | 5000.00 | 10 | ACCOUNTING
+ 7844 | TURNER | 08-SEP-81 00:00:00 | 1500.00 | 30 | SALES
+ 7876 | ADAMS | 23-MAY-87 00:00:00 | 1100.00 | 20 | RESEARCH
+ 7900 | JAMES | 03-DEC-81 00:00:00 | 950.00 | 30 | SALES
+ 7902 | FORD | 03-DEC-81 00:00:00 | 3000.00 | 20 | RESEARCH
+ 7934 | MILLER | 23-JAN-82 00:00:00 | 1300.00 | 10 | ACCOUNTING
+ 9001 | ALICE | 08-NOV-07 00:00:00 | 8000.00 | 40 | OPERATIONS
+(15 rows)
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/index.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/index.mdx
new file mode 100644
index 00000000000..337591d753c
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/09_program_security/index.mdx
@@ -0,0 +1,24 @@
+---
+title: "Program security"
+indexCards: simple
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.056.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.150.html"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/09_program_security/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+You can control the security over whether a user can execute an SPL program. You can also control the database objects an SPL program can access for any given user executing the program. These are controlled by the following:
+
+- Privilege to execute a program
+- Privileges granted on the database objects (including other SPL programs) that a program attempts to access
+- Whether the program is defined with definer’s rights or invoker’s rights
+
+
+
+execute_privilege database_object_name_resolution database_object_privileges definers_vs_invokers_rights security_example
+
+
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/index.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/index.mdx
new file mode 100644
index 00000000000..dc41bbca5ff
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/02_spl_programs/index.mdx
@@ -0,0 +1,22 @@
+---
+title: "Types of SPL programs"
+indexCards: simple
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.049.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.143.html"
+redirects:
+ - /epas/latest/epas_compat_spl/02_spl_programs/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+SPL is a procedural, block-structured language. You can create four different types of programs using SPL: *procedures*, *functions*, *triggers*, and *packages*.
+
+In addition, you can use SPL to create subprograms. A *subprogram* refers to a *subprocedure* or a *subfunction*. These are nearly identical in appearance to procedures and functions. They differ in that procedures and functions are *standalone programs*. They are stored individually in the database, and you can invoke them from other SPL programs or from PSQL. You can invoke subprograms only from the standalone program where they were created.
+
+
+
+basic_spl_elements spl_block_structure anonymous_blocks procedures_overview functions_overview procedure_and_function_parameters subprograms_subprocedures_and_subfunctions compilation_errors_in_procedures_and_functions program_security
+
+
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/01_declaring_a_variable.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/01_declaring_a_variable.mdx
new file mode 100644
index 00000000000..a5c1a3686fc
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/01_declaring_a_variable.mdx
@@ -0,0 +1,55 @@
+---
+title: "Declaring a variable"
+redirects:
+ - /epas/latest/epas_compat_spl/03_variable_declarations/01_declaring_a_variable/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Generally, you must declare all variables used in a block in the declaration section of the block. A variable declaration consists of a name that's assigned to the variable and its data type. Optionally, you can initialize the variable to a default value in the variable declaration.
+
+## Syntax
+
+The general syntax of a variable declaration is:
+
+```sql
+ [ { := | DEFAULT } { | NULL } ];
+```
+
+`name` is an identifier assigned to the variable.
+
+`type` is the data type assigned to the variable.
+
+`[ := expression ]`, if given, specifies the initial value assigned to the variable when the block is entered. If the clause isn't given then the variable is initialized to the SQL `NULL` value.
+
+The default value is evaluated every time the block is entered. So, for example, assigning `SYSDATE` to a variable of type `DATE` causes the variable to have the time of the current invocation, not the time when the procedure or function was precompiled.
+
+## Example: Variable declarations that use defaults
+
+This procedure shows some variable declarations that use defaults consisting of string and numeric expressions:
+
+```sql
+CREATE OR REPLACE PROCEDURE dept_salary_rpt (
+ p_deptno NUMBER
+)
+IS
+ todays_date DATE := SYSDATE;
+ rpt_title VARCHAR2(60) := 'Report For Department # ' || p_deptno
+ || ' on ' || todays_date;
+ base_sal INTEGER := 35525;
+ base_comm_rate NUMBER := 1.33333;
+ base_annual NUMBER := ROUND(base_sal * base_comm_rate, 2);
+BEGIN
+ DBMS_OUTPUT.PUT_LINE(rpt_title);
+ DBMS_OUTPUT.PUT_LINE('Base Annual Salary: ' || base_annual);
+END;
+```
+
+The following output of the procedure shows that default values in the variable declarations are assigned to the variables:
+
+```sql
+EXEC dept_salary_rpt(20);
+__OUTPUT__
+Report For Department # 20 on 10-JUL-07 16:44:45
+Base Annual Salary: 47366.55
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/02_using__type_in_variable_declarations.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/02_using__type_in_variable_declarations.mdx
new file mode 100644
index 00000000000..f319d7a4748
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/02_using__type_in_variable_declarations.mdx
@@ -0,0 +1,128 @@
+---
+title: "Using %TYPE in variable declarations"
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.058.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.152.html"
+redirects:
+ - /epas/latest/epas_compat_spl/03_variable_declarations/02_using__type_in_variable_declarations/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Often, variables are declared in SPL programs that are used to hold values from tables in the database. To ensure compatibility between the table columns and the SPL variables, make sure their data types are the same.
+
+However, often a change is made to the table definition. If the data type of the column is changed, you might need to make the corresponding change to the variable in the SPL program.
+
+Instead of coding the specific column data type into the variable declaration, you can use the column attribute `%TYPE`. Specify a qualified column name in dot notation or the name of a previously declared variable as a prefix to `%TYPE`. The data type of the column or variable prefixed to `%TYPE` is assigned to the variable being declared. If the data type of the given column or variable changes, the new data type is associated with the variable, and you don't need to modify the declaration code.
+
+!!! Note
+ You can use the `%TYPE` attribute with formal parameter declarations as well.
+
+## Syntax
+
+```sql
+ { { | }. | }%TYPE;
+```
+
+- `name` is the identifier assigned to the variable or formal parameter that's being declared.
+- `column` is the name of a column in `table` or `view`.
+- `variable` is the name of a variable that was declared prior to the variable identified by `name`.
+
+!!! Note
+ The variable doesn't inherit any of the column’s other attributes that you specify on the column with the `NOT NULL` clause or the `DEFAULT` clause.
+
+## Example: Defining parameters using %TYPE
+
+In this example, a procedure:
+
+- Queries the `emp` table using an employee number
+- Displays the employee’s data
+- Finds the average salary of all employees in the department to which the employee belongs
+- Compares the chosen employee’s salary with the department average
+
+```sql
+CREATE OR REPLACE PROCEDURE emp_sal_query (
+ p_empno IN NUMBER
+)
+IS
+ v_ename VARCHAR2(10);
+ v_job VARCHAR2(9);
+ v_hiredate DATE;
+ v_sal NUMBER(7,2);
+ v_deptno NUMBER(2);
+ v_avgsal NUMBER(7,2);
+BEGIN
+ SELECT ename, job, hiredate, sal, deptno
+ INTO v_ename, v_job, v_hiredate, v_sal, v_deptno
+ FROM emp WHERE empno = p_empno;
+ DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
+ DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
+ DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
+ DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
+ DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
+ DBMS_OUTPUT.PUT_LINE('Dept # : ' || v_deptno);
+
+ SELECT AVG(sal) INTO v_avgsal
+ FROM emp WHERE deptno = v_deptno;
+ IF v_sal > v_avgsal THEN
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
+ || 'department average of ' || v_avgsal);
+ ELSE
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
+ || 'department average of ' || v_avgsal);
+ END IF;
+END;
+```
+
+Alternatively, you can write the procedure without explicitly coding the `emp` table data types into the declaration section of the procedure:
+
+```sql
+CREATE OR REPLACE PROCEDURE emp_sal_query (
+ p_empno IN emp.empno%TYPE
+)
+IS
+ v_ename emp.ename%TYPE;
+ v_job emp.job%TYPE;
+ v_hiredate emp.hiredate%TYPE;
+ v_sal emp.sal%TYPE;
+ v_deptno emp.deptno%TYPE;
+ v_avgsal v_sal%TYPE;
+BEGIN
+ SELECT ename, job, hiredate, sal, deptno
+ INTO v_ename, v_job, v_hiredate, v_sal, v_deptno
+ FROM emp WHERE empno = p_empno;
+ DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
+ DBMS_OUTPUT.PUT_LINE('Name : ' || v_ename);
+ DBMS_OUTPUT.PUT_LINE('Job : ' || v_job);
+ DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_hiredate);
+ DBMS_OUTPUT.PUT_LINE('Salary : ' || v_sal);
+ DBMS_OUTPUT.PUT_LINE('Dept # : ' || v_deptno);
+
+ SELECT AVG(sal) INTO v_avgsal
+ FROM emp WHERE deptno = v_deptno;
+ IF v_sal > v_avgsal THEN
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
+ || 'department average of ' || v_avgsal);
+ ELSE
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
+ || 'department average of ' || v_avgsal);
+ END IF;
+END;
+```
+
+`p_empno` shows an example of a formal parameter defined using `%TYPE`. `v_avgsal` shows the use of `%TYPE` referring to another variable instead of a table column.
+
+The following is sample output from executing this procedure:
+
+```sql
+EXEC emp_sal_query(7698);
+__OUTPUT__
+Employee # : 7698
+Name : BLAKE
+Job : MANAGER
+Hire Date : 01-MAY-81 00:00:00
+Salary : 2850.00
+Dept # : 30
+Employee's salary is more than the department average of 1566.67
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/03_using__row_type_in_record_declarations.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/03_using__row_type_in_record_declarations.mdx
new file mode 100644
index 00000000000..3133ce5a563
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/03_using__row_type_in_record_declarations.mdx
@@ -0,0 +1,59 @@
+---
+title: "Using %ROWTYPE in record declarations"
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.059.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.153.html"
+redirects:
+ - /epas/latest/epas_compat_spl/03_variable_declarations/03_using__row_type_in_record_declarations/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+The `%TYPE` attribute provides an easy way to create a variable that depends on a column's data type. Using the `%ROWTYPE` attribute, you can define a record that contains fields that correspond to all columns of a given table. Each field takes on the data type of its corresponding column. The fields in the record don't inherit any of the columns' other attributes like those specified with the `NOT NULL` clause or the `DEFAULT` clause.
+
+A *record* is a named, ordered collection of fields. A *field* is similar to a variable. It has an identifier and data type but has the additional property of belonging to a record. You must refereence it using dot notation with the record name as its qualifier.
+
+## Syntax
+
+You can use the `%ROWTYPE` attribute to declare a record. The `%ROWTYPE` attribute is prefixed by a table name. Each column in the named table defines an identically named field in the record with the same data type as the column.
+
+```text
+ %ROWTYPE;
+```
+
+- `record` is an identifier assigned to the record.
+- `table` is the name of a table or view whose columns define the fields in the record.
+
+## Example
+
+This example shows how you can modify the `emp_sal_query` procedure from [Using %TYPE in variable declarations](02_using__type_in_variable_declarations) to use `emp%ROWTYPE` to create a record named `r_emp` instead of declaring individual variables for the columns in `emp`:
+
+```sql
+CREATE OR REPLACE PROCEDURE emp_sal_query (
+ p_empno IN emp.empno%TYPE
+)
+IS
+ r_emp emp%ROWTYPE;
+ v_avgsal emp.sal%TYPE;
+BEGIN
+ SELECT ename, job, hiredate, sal, deptno
+ INTO r_emp.ename, r_emp.job, r_emp.hiredate, r_emp.sal, r_emp.deptno
+ FROM emp WHERE empno = p_empno;
+ DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
+ DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
+ DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
+ DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
+ DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
+ DBMS_OUTPUT.PUT_LINE('Dept # : ' || r_emp.deptno);
+ SELECT AVG(sal) INTO v_avgsal
+ FROM emp WHERE deptno = r_emp.deptno;
+ IF r_emp.sal > v_avgsal THEN
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
+ || 'department average of ' || v_avgsal);
+ ELSE
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
+ || 'department average of ' || v_avgsal);
+ END IF;
+END;
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/04_user_defined_record_types_and_record_variables.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/04_user_defined_record_types_and_record_variables.mdx
new file mode 100644
index 00000000000..55669da0581
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/04_user_defined_record_types_and_record_variables.mdx
@@ -0,0 +1,111 @@
+---
+title: "User-defined record types and record variables"
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.060.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.154.html"
+redirects:
+ - /epas/latest/epas_compat_spl/03_variable_declarations/04_user_defined_record_types_and_record_variables/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+You can declare records based on a table definition using the `%ROWTYPE` attribute, as shown in [Using %ROWTYPE in record declarations](03_using__row_type_in_record_declarations). You can also define a new record structure that isn't tied to a particular table definition.
+
+You use the `TYPE IS RECORD` statement to create the definition of a record type. A *record type* is a definition of a record made up of one or more identifiers and their corresponding data types. You can't use a record type by itself to manipulate data.
+
+## Syntax
+
+The syntax for a `TYPE IS RECORD` statement is:
+
+```sql
+TYPE IS RECORD ( )
+```
+
+Where `fields` is a comma-separated list of one or more field definitions of the following form:
+
+```sql
+ [NOT NULL][{:= | DEFAULT} ]
+```
+
+Where:
+
+- `rec_type` is an identifier assigned to the record type.
+- `field_name` is the identifier assigned to the field of the record type.
+- `data_type` specifies the data type of `field_name`.
+- The `DEFAULT` clause assigns a default data value for the corresponding field. The data type of the default expression must match the data type of the column. If you don't specify a default, then the default is `NULL`.
+
+A *record variable* or *record* is an instance of a record type. A record is declared from a record type. The properties of the record such as its field names and types are inherited from the record type.
+
+The following is the syntax for a record declaration:
+
+```text
+
+```
+
+`record` is an identifier assigned to the record variable. `rectype` is the identifier of a previously defined record type. Once declared, you can't then use a record to hold data.
+
+Use dot notation to reference the fields in the record:
+
+```text
+.
+```
+
+`record` is a previously declared record variable and `field` is the identifier of a field belonging to the record type from which `record` is defined.
+
+## Example
+
+This `emp_sal_query` procedure uses a user-defined record type and record variable:
+
+```sql
+CREATE OR REPLACE PROCEDURE emp_sal_query (
+ p_empno IN emp.empno%TYPE
+)
+IS
+ TYPE emp_typ IS RECORD (
+ ename emp.ename%TYPE,
+ job emp.job%TYPE,
+ hiredate emp.hiredate%TYPE,
+ sal emp.sal%TYPE,
+ deptno emp.deptno%TYPE
+ );
+ r_emp emp_typ;
+ v_avgsal emp.sal%TYPE;
+BEGIN
+ SELECT ename, job, hiredate, sal, deptno
+ INTO r_emp.ename, r_emp.job, r_emp.hiredate, r_emp.sal, r_emp.deptno
+ FROM emp WHERE empno = p_empno;
+ DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
+ DBMS_OUTPUT.PUT_LINE('Name : ' || r_emp.ename);
+ DBMS_OUTPUT.PUT_LINE('Job : ' || r_emp.job);
+ DBMS_OUTPUT.PUT_LINE('Hire Date : ' || r_emp.hiredate);
+ DBMS_OUTPUT.PUT_LINE('Salary : ' || r_emp.sal);
+ DBMS_OUTPUT.PUT_LINE('Dept # : ' || r_emp.deptno);
+
+ SELECT AVG(sal) INTO v_avgsal
+ FROM emp WHERE deptno = r_emp.deptno;
+ IF r_emp.sal > v_avgsal THEN
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary is more than the '
+ || 'department average of ' || v_avgsal);
+ ELSE
+ DBMS_OUTPUT.PUT_LINE('Employee''s salary does not exceed the '
+ || 'department average of ' || v_avgsal);
+ END IF;
+END;
+```
+
+Instead of specifying data type names, you can use the `%TYPE` attribute for the field data types in the record type definition.
+
+The following is the output from executing this stored procedure:
+
+```sql
+EXEC emp_sal_query(7698);
+__OUTPUT__
+Employee # : 7698
+Name : BLAKE
+Job : MANAGER
+Hire Date : 01-MAY-81 00:00:00
+Salary : 2850.00
+Dept # : 30
+Employee's salary is more than the department average of 1566.67
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/index.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/index.mdx
new file mode 100644
index 00000000000..4005c2a5b6f
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/03_variable_declarations/index.mdx
@@ -0,0 +1,20 @@
+---
+title: "Using variable declarations"
+indexCards: simple
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.057.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.151.html"
+redirects:
+ - /epas/latest/epas_compat_spl/03_variable_declarations/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+SPL is a block-structured language. The first section that can appear in a block is the declaration. The declaration contains the definition of variables, cursors, and other types that you can use in SPL statements contained in the block.
+
+
+
+declaring_a_variable using\_%\_type_in_variable_declarations using\_%\_row_type_in_record_declarations user_defined_record_types_and_record_variables
+
+
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/01_commit.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/01_commit.mdx
new file mode 100644
index 00000000000..c9a78de11d4
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/01_commit.mdx
@@ -0,0 +1,66 @@
+---
+title: "COMMIT"
+redirects:
+ - /epas/latest/epas_compat_spl/06_transaction_control/01_commit/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+The `COMMIT` command makes all database updates from the current transaction permanent and ends the current transaction.
+
+```sql
+COMMIT [ WORK ];
+```
+
+You can use the `COMMIT` command in anonymous blocks, stored procedures, or functions. In an SPL program, it can appear in the executable section and the exception section.
+
+In this example, the third `INSERT` command in the anonymous block results in an error. The effect of the first two `INSERT` commands is retained as shown by the first `SELECT` command. Even after issuing a `ROLLBACK` command, the two rows remain in the table, as shown by the second `SELECT` command verifying that they were indeed committed.
+
+!!! Note
+ You can set the `edb_stmt_level_tx` configuration parameter shown in the example for the entire database using the `ALTER DATABASE` command. Alternatively, you can set it for the entire database server by changing it in the `postgresql.conf` file.
+
+```sql
+\set AUTOCOMMIT off
+SET edb_stmt_level_tx TO on;
+
+BEGIN
+ INSERT INTO dept VALUES (50, 'FINANCE', 'DALLAS');
+ INSERT INTO dept VALUES (60, 'MARKETING', 'CHICAGO');
+ COMMIT;
+ INSERT INTO dept VALUES (70, 'HUMAN RESOURCES', 'CHICAGO');
+EXCEPTION
+ WHEN OTHERS THEN
+ DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
+ DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
+END;
+
+SQLERRM: value too long for type character varying(14)
+SQLCODE: 22001
+
+SELECT * FROM dept;
+__OUTPUT__
+deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 50 | FINANCE | DALLAS
+ 60 | MARKETING | CHICAGO
+(6 rows)
+```
+```sql
+ROLLBACK;
+
+SELECT * FROM dept;
+__OUTPUT__
+deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 50 | FINANCE | DALLAS
+ 60 | MARKETING | CHICAGO
+(6 rows)
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/02_rollback.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/02_rollback.mdx
new file mode 100644
index 00000000000..75dd37430c5
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/02_rollback.mdx
@@ -0,0 +1,183 @@
+---
+title: "ROLLBACK"
+redirects:
+ - /epas/latest/epas_compat_spl/06_transaction_control/02_rollback/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+The `ROLLBACK` command undoes all database updates made during the current transaction and ends the current transaction.
+
+```sql
+ROLLBACK [ WORK ];
+```
+
+You can use the `ROLLBACK` command in anonymous blocks, stored procedures, or functions. In an SPL program, it can appear in the executable section and the exception section.
+
+In this example, the exception section contains a `ROLLBACK` command. Even though the first two `INSERT` commands execute successfully, the third causes an exception that results in the rollback of all the `INSERT` commands in the anonymous block.
+
+```sql
+\set AUTOCOMMIT off
+SET edb_stmt_level_tx TO on;
+
+BEGIN
+ INSERT INTO dept VALUES (50, 'FINANCE', 'DALLAS');
+ INSERT INTO dept VALUES (60, 'MARKETING', 'CHICAGO');
+ INSERT INTO dept VALUES (70, 'HUMAN RESOURCES', 'CHICAGO');
+EXCEPTION
+ WHEN OTHERS THEN
+ ROLLBACK;
+ DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
+ DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
+END;
+
+SQLERRM: value too long for type character varying(14)
+SQLCODE: 22001
+
+SELECT * FROM dept;
+__OUTPUT__
+deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+(4 rows)
+```
+
+This example uses both `COMMIT` and `ROLLBACK`. First, the following stored procedure is created. It inserts a new employee.
+
+```sql
+\set AUTOCOMMIT off
+SET edb_stmt_level_tx TO on;
+
+CREATE OR REPLACE PROCEDURE emp_insert (
+ p_empno IN emp.empno%TYPE,
+ p_ename IN emp.ename%TYPE,
+ p_job IN emp.job%TYPE,
+ p_mgr IN emp.mgr%TYPE,
+ p_hiredate IN emp.hiredate%TYPE,
+ p_sal IN emp.sal%TYPE,
+ p_comm IN emp.comm%TYPE,
+ p_deptno IN emp.deptno%TYPE
+)
+IS
+BEGIN
+ INSERT INTO emp VALUES (
+ p_empno,
+ p_ename,
+ p_job,
+ p_mgr,
+ p_hiredate,
+ p_sal,
+ p_comm,
+ p_deptno);
+
+ DBMS_OUTPUT.PUT_LINE('Added employee...');
+ DBMS_OUTPUT.PUT_LINE('Employee # : ' || p_empno);
+ DBMS_OUTPUT.PUT_LINE('Name : ' || p_ename);
+ DBMS_OUTPUT.PUT_LINE('Job : ' || p_job);
+ DBMS_OUTPUT.PUT_LINE('Manager : ' || p_mgr);
+ DBMS_OUTPUT.PUT_LINE('Hire Date : ' || p_hiredate);
+ DBMS_OUTPUT.PUT_LINE('Salary : ' || p_sal);
+ DBMS_OUTPUT.PUT_LINE('Commission : ' || p_comm);
+ DBMS_OUTPUT.PUT_LINE('Dept # : ' || p_deptno);
+ DBMS_OUTPUT.PUT_LINE('----------------------');
+END;
+```
+
+This procedure has no exception section. Any errors are propagated up to the calling program.
+
+Then the following anonymous block runs. The `COMMIT` command is used after all calls to the `emp_insert` procedure and the `ROLLBACK` command in the exception section.
+
+```sql
+BEGIN
+ emp_insert(9601,'FARRELL','ANALYST',7902,'03-MAR-08',5000,NULL,40);
+ emp_insert(9602,'TYLER','ANALYST',7900,'25-JAN-08',4800,NULL,40);
+ COMMIT;
+EXCEPTION
+ WHEN OTHERS THEN
+ DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
+ DBMS_OUTPUT.PUT_LINE('An error occurred - roll back inserts');
+ ROLLBACK;
+END;
+__OUTPUT__
+Added employee...
+Employee # : 9601
+Name : FARRELL
+Job : ANALYST
+Manager : 7902
+Hire Date : 03-MAR-08 00:00:00
+Salary : 5000
+Commission :
+Dept # : 40
+----------------------
+Added employee...
+Employee # : 9602
+Name : TYLER
+Job : ANALYST
+Manager : 7900
+Hire Date : 25-JAN-08 00:00:00
+Salary : 4800
+Commission :
+Dept # : 40
+----------------------
+```
+
+The following `SELECT` command shows that employees Farrell and Tyler were successfully added:
+
+```sql
+SELECT * FROM emp WHERE empno > 9600;
+__OUTPUT__
+empno | ename | job | mgr | hiredate | sal | comm | deptno
+------+--------+--------+-----+--------------------+---------+------+--------
+ 9601| FARRELL| ANALYST|7902 | 03-MAR-08 00:00:00 | 5000.00 | | 40
+ 9602| TYLER | ANALYST|7900 | 25-JAN-08 00:00:00 | 4800.00 | | 40
+(2 rows)
+```
+
+Next, execute the following anonymous block:
+
+```sql
+BEGIN
+ emp_insert(9603,'HARRISON','SALESMAN',7902,'13-DEC-07',5000,3000,20);
+ emp_insert(9604,'JARVIS','SALESMAN',7902,'05-MAY-08',4800,4100,11);
+ COMMIT;
+EXCEPTION
+ WHEN OTHERS THEN
+ DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
+ DBMS_OUTPUT.PUT_LINE('An error occurred - roll back inserts');
+ ROLLBACK;
+END;
+__OUTPUT__
+Added employee...
+Employee # : 9603
+Name : HARRISON
+Job : SALESMAN
+Manager : 7902
+Hire Date : 13-DEC-07 00:00:00
+Salary : 5000
+Commission : 3000
+Dept # : 20
+----------------------
+SQLERRM: insert or update on table "emp" violates foreign key constraint
+"emp_ref_dept_fk"
+An error occurred - roll back inserts
+```
+
+A `SELECT` command run against the table produces the following:
+
+```sql
+SELECT * FROM emp WHERE empno > 9600;
+__OUTPUT__
+empno | ename | job | mgr | hiredate | sal | comm | deptno
+------+--------+--------+-----+--------------------+---------+------+--------
+ 9601| FARRELL| ANALYST|7902 | 03-MAR-08 00:00:00 | 5000.00 | | 40
+ 9602| TYLER | ANALYST|7900 | 25-JAN-08 00:00:00 | 4800.00 | | 40
+(2 rows)
+```
+
+The `ROLLBACK` command in the exception section successfully undoes the insert of employee Harrison. Employees Farrell and Tyler are still in the table as their inserts were made permanent by the `COMMIT` command in the first anonymous block.
+
+!!! Note
+ Executing a `COMMIT` or `ROLLBACK` in a plpgsql procedure throws an error if an Oracle-style SPL procedure is on the runtime stack.
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/03_pragma_autonomous_transaction.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/03_pragma_autonomous_transaction.mdx
new file mode 100644
index 00000000000..e26d2edddf1
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/03_pragma_autonomous_transaction.mdx
@@ -0,0 +1,419 @@
+---
+title: "PRAGMA AUTONOMOUS_TRANSACTION"
+redirects:
+ - /epas/latest/epas_compat_spl/06_transaction_control/03_pragma_autonomous_transaction/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+A stored procedural language (SPL) program can be declared as an *autonomous transaction* by specifying the following directive in the declaration section of the SPL block. An autonomous transaction is an independent transaction started by a calling program.
+
+```sql
+PRAGMA AUTONOMOUS_TRANSACTION;
+```
+
+A commit or rollback of SQL commands in the autonomous transaction has no effect on the commit or rollback in any transaction of the calling program. A commit or rollback in the calling program has no effect on the commit or rollback of SQL commands in the autonomous transaction.
+
+## Requirements and restrictions
+
+The following SPL programs can include `PRAGMA AUTONOMOUS_TRANSACTION`:
+
+- Standalone procedures and functions
+- Anonymous blocks
+- Procedures and functions declared as subprograms in packages and other calling procedures, functions, and anonymous blocks
+- Triggers
+- Object type methods
+
+The following are issues and restrictions related to autonomous transactions:
+
+- Each autonomous transaction consumes a connection slot for as long as it's in progress. In some cases, this might mean that you need to raise the `max_connections` parameter in the `postgresql.conf` file.
+- In most respects, an autonomous transaction behaves as if it were a completely separate session, but GUCs (settings established with `SET`) are a deliberate exception. Autonomous transactions absorb the surrounding values and can propagate values they commit to the outer transaction.
+- Autonomous transactions can be nested, but there is a limit of 16 levels of autonomous transactions in a single session.
+- Parallel query isn't supported in autonomous transactions.
+- The EDB Postgres Advanced Server implementation of autonomous transactions isn't entirely compatible with Oracle databases. The EDB Postgres Advanced Server autonomous transaction doesn't produce an error if there's an uncommitted transaction at the end of an SPL block.
+
+## About the examples
+
+The following set of examples use autonomous transactions. This first set of scenarios shows the default behavior when there are no autonomous transactions.
+
+Before each scenario, the `dept` table is reset to the following initial values:
+
+```sql
+SELECT * FROM dept;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+(4 rows)
+```
+
+## Scenario 1a: No autonomous transactions with only a final COMMIT
+
+This first set of scenarios shows the insertion of three rows:
+
+- Starting just after the initial `BEGIN` command of the transaction
+- From an anonymous block in the starting transactions
+- From a stored procedure executed from the anonymous block
+
+The stored procedure is the following:
+
+```sql
+CREATE OR REPLACE PROCEDURE insert_dept_70 IS
+BEGIN
+ INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
+END;
+```
+
+The PSQL session is the following:
+
+```sql
+BEGIN;
+INSERT INTO dept VALUES (50,'HR','DENVER');
+BEGIN
+ INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
+ insert_dept_70;
+END;
+COMMIT;
+```
+
+After the final commit, all three rows are inserted:
+
+```sql
+SELECT * FROM dept ORDER BY 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+-------------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 50 | HR | DENVER
+ 60 | FINANCE | CHICAGO
+ 70 | MARKETING | LOS ANGELES
+(7 rows)
+```
+
+## Scenario 1b: No autonomous transactions but a final ROLLBACK
+
+The next scenario shows that a final `ROLLBACK` command after all inserts results in the rollback of all three insertions:
+
+```sql
+BEGIN;
+INSERT INTO dept VALUES (50,'HR','DENVER');
+BEGIN
+ INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
+ insert_dept_70;
+END;
+ROLLBACK;
+
+SELECT * FROM dept ORDER BY 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+(4 rows)
+```
+
+## Scenario 1c: No autonomous transactions, but anonymous block ROLLBACK
+
+A `ROLLBACK` command given at the end of the anonymous block also eliminates all three prior insertions:
+
+```sql
+BEGIN;
+INSERT INTO dept VALUES (50,'HR','DENVER');
+BEGIN
+ INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
+ insert_dept_70;
+ ROLLBACK;
+END;
+COMMIT;
+
+SELECT * FROM dept ORDER BY 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+(4 rows)
+```
+
+The next set of scenarios shows the effect of using autonomous transactions with `PRAGMA AUTONOMOUS_TRANSACTION` in various locations.
+
+## Scenario 2a: Autonomous transaction of anonymous block with COMMIT
+
+The procedure remains as initially created:
+
+```sql
+CREATE OR REPLACE PROCEDURE insert_dept_70 IS
+BEGIN
+ INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
+END;
+```
+
+The `PRAGMA AUTONOMOUS_TRANSACTION` is given with the anonymous block along with the `COMMIT` command at the end of the anonymous block:
+
+```sql
+BEGIN;
+INSERT INTO dept VALUES (50,'HR','DENVER');
+DECLARE
+ PRAGMA AUTONOMOUS_TRANSACTION;
+BEGIN
+ INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
+ insert_dept_70;
+ COMMIT;
+END;
+ROLLBACK;
+```
+
+After the `ROLLBACK` at the end of the transaction, only the first row insertion at the beginning of the transaction is discarded. The other two row insertions in the anonymous block with `PRAGMA AUTONOMOUS_TRANSACTION` were independently committed.
+
+```sql
+SELECT * FROM dept ORDER BY 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+-------------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 60 | FINANCE | CHICAGO
+ 70 | MARKETING | LOS ANGELES
+(6 rows)
+```
+
+## Scenario 2b: Autonomous transaction anonymous block with COMMIT, including procedure with ROLLBACK but not an autonomous transaction procedure
+
+This procedure has the `ROLLBACK` command at the end. However, the `PRAGMA ANONYMOUS_TRANSACTION` isn't included in this procedure.
+
+```sql
+CREATE OR REPLACE PROCEDURE insert_dept_70 IS
+BEGIN
+ INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
+ ROLLBACK;
+END;
+```
+
+The rollback in the procedure removes the two rows inserted in the anonymous block (`deptno` 60 and 70) before the final `COMMIT` command in the anonymous block:
+
+```sql
+BEGIN;
+INSERT INTO dept VALUES (50,'HR','DENVER');
+DECLARE
+ PRAGMA AUTONOMOUS_TRANSACTION;
+BEGIN
+ INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
+ insert_dept_70;
+ COMMIT;
+END;
+COMMIT;
+```
+
+After the final commit at the end of the transaction, the only row inserted is the first one from the beginning of the transaction. Since the anonymous block is an autonomous transaction, the rollback in the enclosed procedure has no effect on the insertion that occurs before the anonymous block is executed.
+
+```sql
+SELECT * FROM dept ORDER by 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 50 | HR | DENVER
+(5 rows)
+```
+
+## Scenario 2c: Autonomous transaction anonymous block with COMMIT, including procedure with ROLLBACK that is also an autonomous transaction procedure
+
+The procedure with the `ROLLBACK` command at the end also has `PRAGMA ANONYMOUS_TRANSACTION` included. This isolates the effect of the `ROLLBACK` command in the procedure.
+
+```sql
+CREATE OR REPLACE PROCEDURE insert_dept_70 IS
+ PRAGMA AUTONOMOUS_TRANSACTION;
+BEGIN
+ INSERT INTO dept VALUES (70,'MARKETING','LOS ANGELES');
+ ROLLBACK;
+END;
+```
+
+The rollback in the procedure removes the row inserted by the procedure but not the other row inserted in the anonymous block.
+
+```sql
+BEGIN;
+INSERT INTO dept VALUES (50,'HR','DENVER');
+DECLARE
+ PRAGMA AUTONOMOUS_TRANSACTION;
+BEGIN
+ INSERT INTO dept VALUES (60,'FINANCE','CHICAGO');
+ insert_dept_70;
+ COMMIT;
+END;
+COMMIT;
+```
+
+After the final commit at the end of the transaction, the row inserted is the first one from the beginning of the transaction as well as the row inserted at the beginning of the anonymous block. The only insertion rolled back is the one in the procedure.
+
+```sql
+SELECT * FROM dept ORDER by 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 50 | HR | DENVER
+ 60 | FINANCE | CHICAGO
+(6 rows)
+```
+
+The following examples show `PRAGMA AUTONOMOUS_TRANSACTION` in a couple of other SPL program types.
+
+## Autonomous transaction trigger
+
+This example shows the effect of declaring a trigger with `PRAGMA AUTONOMOUS_TRANSACTION`.
+
+The following table is created to log changes to the `emp` table:
+
+```sql
+CREATE TABLE empauditlog (
+ audit_date DATE,
+ audit_user VARCHAR2(20),
+ audit_desc VARCHAR2(20)
+);
+```
+
+The trigger attached to the `emp` table that inserts these changes into the `empauditlog` table is the following. `PRAGMA AUTONOMOUS_TRANSACTION` is included in the declaration section.
+
+```sql
+CREATE OR REPLACE TRIGGER emp_audit_trig
+ AFTER INSERT OR UPDATE OR DELETE ON emp
+DECLARE
+ PRAGMA AUTONOMOUS_TRANSACTION;
+ v_action VARCHAR2(20);
+BEGIN
+ IF INSERTING THEN
+ v_action := 'Added employee(s)';
+ ELSIF UPDATING THEN
+ v_action := 'Updated employee(s)';
+ ELSIF DELETING THEN
+ v_action := 'Deleted employee(s)';
+ END IF;
+ INSERT INTO empauditlog VALUES (SYSDATE, USER,
+ v_action);
+END;
+```
+
+The following two inserts are made into the `emp` table in a transaction started by the `BEGIN` command:
+
+```sql
+BEGIN;
+INSERT INTO emp VALUES (9001,'SMITH','ANALYST',7782,SYSDATE,NULL,NULL,10);
+INSERT INTO emp VALUES (9002,'JONES','CLERK',7782,SYSDATE,NULL,NULL,10);
+```
+
+The following shows the two new rows in the `emp` table as well as the two entries in the `empauditlog` table:
+
+```sql
+SELECT * FROM emp WHERE empno > 9000;
+__OUTPUT__
+ empno | ename | job | mgr | hiredate | sal | comm | deptno
+-------+-------+---------+------+--------------------+-----+------+--------
+ 9001 | SMITH | ANALYST | 7782 | 23-AUG-18 07:12:27 | | | 10
+ 9002 | JONES | CLERK | 7782 | 23-AUG-18 07:12:27 | | | 10
+(2 rows)
+```
+```sql
+SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "audit date",
+ audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;
+__OUTPUT__
+ audit date | audit_user | audit_desc
+--------------------+--------------+-------------------
+ 23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
+ 23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
+(2 rows)
+```
+
+But then the `ROLLBACK` command is given during this session. The `emp` table no longer contains the two rows, but the `empauditlog` table still contains its two entries. The trigger implicitly performed a commit, and `PRAGMA AUTONOMOUS_TRANSACTION` commits those changes independent from the rollback given in the calling transaction.
+
+```sql
+ROLLBACK;
+
+SELECT * FROM emp WHERE empno > 9000;
+__OUTPUT__
+ empno | ename | job | mgr | hiredate | sal | comm | deptno
+-------+-------+-----+-----+----------+-----+------+--------
+(0 rows)
+```
+```sql
+SELECT TO_CHAR(AUDIT_DATE,'DD-MON-YY HH24:MI:SS') AS "audit date",
+ audit_user, audit_desc FROM empauditlog ORDER BY 1 ASC;
+__OUTPUT__
+ audit date | audit_user | audit_desc
+--------------------+--------------+-------------------
+ 23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
+ 23-AUG-18 07:12:27 | enterprisedb | Added employee(s)
+(2 rows)
+```
+
+## Autonomous transaction object type method
+
+This example shows the effect of declaring an object method with `PRAGMA AUTONOMOUS_TRANSACTION`.
+
+The following object type and object type body are created. The member procedure in the object type body contains the `PRAGMA AUTONOMOUS_TRANSACTION` in the declaration section along with `COMMIT` at the end of the procedure.
+
+```sql
+CREATE OR REPLACE TYPE insert_dept_typ AS OBJECT (
+ deptno NUMBER(2),
+ dname VARCHAR2(14),
+ loc VARCHAR2(13),
+ MEMBER PROCEDURE insert_dept
+);
+
+CREATE OR REPLACE TYPE BODY insert_dept_typ AS
+ MEMBER PROCEDURE insert_dept
+ IS
+ PRAGMA AUTONOMOUS_TRANSACTION;
+ BEGIN
+ INSERT INTO dept VALUES (SELF.deptno,SELF.dname,SELF.loc);
+ COMMIT;
+ END;
+END;
+```
+
+In the following anonymous block, an insert is performed into the `dept` table, followed by invoking the `insert_dept` method of the object and ending with a `ROLLBACK` command in the anonymous block.
+
+```sql
+BEGIN;
+DECLARE
+ v_dept INSERT_DEPT_TYP :=
+ insert_dept_typ(60,'FINANCE','CHICAGO');
+BEGIN
+ INSERT INTO dept VALUES (50,'HR','DENVER');
+ v_dept.insert_dept;
+ ROLLBACK;
+END;
+```
+
+Since `insert_dept` was declared as an autonomous transaction, its insert of department number 60 remains in the table, but the rollback removes the insertion of department 50:
+
+```sql
+SELECT * FROM dept ORDER BY 1;
+__OUTPUT__
+ deptno | dname | loc
+--------+------------+----------
+ 10 | ACCOUNTING | NEW YORK
+ 20 | RESEARCH | DALLAS
+ 30 | SALES | CHICAGO
+ 40 | OPERATIONS | BOSTON
+ 60 | FINANCE | CHICAGO
+(5 rows)
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/about_transactions.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/about_transactions.mdx
new file mode 100644
index 00000000000..2469034108f
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/about_transactions.mdx
@@ -0,0 +1,17 @@
+---
+title: "About transactions"
+---
+
+A transaction begins when the first SQL command is encountered in the SPL program. All subsequent SQL commands are included as part of that transaction.
+
+The transaction ends when one of the following occurs:
+
+- An unhandled exception occurs. In this case, the effects of all database updates made during the transaction are rolled back, and the transaction is aborted.
+- A `COMMIT` command is encountered. In this case, the effect of all database updates made during the transaction become permanent.
+- A `ROLLBACK` command is encountered. In this case, the effects of all database updates made during the transaction are rolled back, and the transaction is aborted. If a new SQL command is encountered, a new transaction begins.
+- Control returns to the calling application, such as Java or PSQL. In this case, the action of the application determines whether the transaction is committed or rolled back. The exception is when the transaction is in a block in which `PRAGMA AUTONOMOUS_TRANSACTION` was declared. In this case, the commitment or rollback of the transaction occurs independently of the calling program.
+
+!!! Note
+ Unlike Oracle, DDL commands such as `CREATE TABLE` don't implicitly occur in their own transaction. Therefore, DDL commands don't cause an immediate database commit as in Oracle, and you can roll back DDL commands just like DML commands.
+
+A transaction can span one or more `BEGIN/END` blocks, or a single `BEGIN/END` block can contain one or more transactions.
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/index.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/index.mdx
new file mode 100644
index 00000000000..404c31aa24d
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/06_transaction_control/index.mdx
@@ -0,0 +1,34 @@
+---
+title: "Working with transactions"
+indexCards: simple
+navigation:
+ - about_transactions
+ - 01_commit
+ - 02_rollback
+ - 03_pragma_autonomous_transaction
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.072.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.166.html"
+redirects:
+ - /epas/latest/epas_compat_spl/06_transaction_control/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+There might be times when you want all updates to a database to occur successfully or for none to occur in case of any error. A set of database updates that occur successfully as a single unit or not at all is called a *transaction*.
+
+A common example in banking is a funds transfer between two accounts. The two parts of the transaction are the withdrawal of funds from one account and the deposit of the funds in another account. Both parts of this transaction must occur for the bank’s books to balance. The deposit and withdrawal are one transaction.
+
+You can create an SPL application that uses a style of transaction control compatible with Oracle databases if the following conditions are met:
+
+- The `edb_stmt_level_tx` parameter is set to `TRUE`. This prevents the action of unconditionally rolling back all database updates in the `BEGIN/END` block if any exception occurs.
+- The application isn't running in autocommit mode. If autocommit mode is on, each successful database update is immediately committed and can't be undone. The manner in which autocommit mode is turned on or off depends on the application.
+
+The three main transaction commands are COMMIT, ROLLBACK, and PRAGM_AUTONOMOUS_TRANSACTION.
+
+
+
+commit rollback pragma_autonomous_transaction
+
+
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/07_dynamic_sql.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/07_dynamic_sql.mdx
new file mode 100644
index 00000000000..07f98567f0a
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/07_dynamic_sql.mdx
@@ -0,0 +1,122 @@
+---
+title: "Using dynamic SQL"
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.073.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.167.html"
+redirects:
+ - /epas/latest/epas_compat_spl/07_dynamic_sql/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+*Dynamic SQL* is a technique that lets you execute SQL commands that aren't known until the commands are about to be executed. In static SQL commands, the full command (with the exception of variables) must be known and coded into the program before the program can begin to execute. Using dynamic SQL, the executed SQL can change during program runtime.
+
+In addition, dynamic SQL is the only method by which data definition commands, such as `CREATE TABLE`, can be executed from an SPL program.
+
+However, the runtime performance of dynamic SQL is slower than static SQL.
+
+## Syntax
+
+The `EXECUTE IMMEDIATE` command is used to run SQL commands dynamically:
+
+```sql
+EXECUTE IMMEDIATE ';'
+ [ INTO { [, ...] | } ]
+ [ USING {[] } [, ...]} ];
+```
+
+Where:
+
+- `sql_expression` is a string expression containing the SQL command to dynamically execute
+- `variable` receives the output of the result set, typically from a `SELECT` command, created as a result of executing the SQL command in `sql_expression`. The number, order, and type of variables must match the number and order and be type-compatible with the fields of the result set.
+
+When using the `USING` clause, the value of `expression` is passed to a *placeholder*. Placeholders appear embedded in the SQL command in `sql_expression` where you can use variables. Placeholders are denoted by an identifier with a colon (:) prefix, for example, `:name`. The number and order of the evaluated expressions must match the number, order of the placeholders in `sql_expression`. The resulting data types must also be compatible with the placeholders. You don't declare placeholders in the SPL program. They appear only in `sql_expression`.
+
+Currently `bind_type` is ignored, and `bind_argument` is treated as `IN OUT`.
+
+Alternatively, a `record` can be specified as long as the record’s fields match the number and order and are type-compatible with the result set.
+
+When using the `INTO` clause, exactly one row must be returned in the result set. Otherwise an exception occurs. When using the `USING` clause, the value of `expression` is passed to a *placeholder*. Placeholders appear embedded in the SQL command in `sql_expression` where variables can be used. Placeholders are denoted by an identifier with a colon (:) prefix, such as `:name`. The number, order, and resultant data types of the evaluated expressions must match the number and order and be type-compatible with the placeholders in `sql_expression`.
+
+Placeholders aren't declared anywhere in the SPL program. They appear only in `sql_expression`.
+
+Currently all options for `bind_type` are ignored and `bind_argument` is treated as `IN OUT`.
+
+## Example: SQL commands as string literals
+
+This example shows basic dynamic SQL commands as string literals:
+
+```sql
+DECLARE
+ v_sql VARCHAR2(50);
+BEGIN
+ EXECUTE IMMEDIATE 'CREATE TABLE job (jobno NUMBER(3),' ||
+ ' jname VARCHAR2(9))';
+ v_sql := 'INSERT INTO job VALUES (100, ''ANALYST'')';
+ EXECUTE IMMEDIATE v_sql;
+ v_sql := 'INSERT INTO job VALUES (200, ''CLERK'')';
+ EXECUTE IMMEDIATE v_sql;
+END;
+```
+
+This example uses the `USING` clause to pass values to placeholders in the SQL string:
+
+```sql
+DECLARE
+ v_sql VARCHAR2(50) := 'INSERT INTO job VALUES ' ||
+ '(:p_jobno, :p_jname)';
+ v_jobno job.jobno%TYPE;
+ v_jname job.jname%TYPE;
+BEGIN
+ v_jobno := 300;
+ v_jname := 'MANAGER';
+ EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
+ v_jobno := 400;
+ v_jname := 'SALESMAN';
+ EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
+ v_jobno := 500;
+ v_jname := 'PRESIDENT';
+ EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
+END;
+```
+
+This example shows both the `INTO` and `USING` clauses. The last execution of the `SELECT` command returns the results into a record instead of individual variables.
+
+```sql
+DECLARE
+ v_sql VARCHAR2(60);
+ v_jobno job.jobno%TYPE;
+ v_jname job.jname%TYPE;
+ r_job job%ROWTYPE;
+BEGIN
+ DBMS_OUTPUT.PUT_LINE('JOBNO JNAME');
+ DBMS_OUTPUT.PUT_LINE('----- -------');
+ v_sql := 'SELECT jobno, jname FROM job WHERE jobno = :p_jobno';
+ EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 100;
+ DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
+ EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 200;
+ DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
+ EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 300;
+ DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
+ EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 400;
+ DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
+ EXECUTE IMMEDIATE v_sql INTO r_job USING 500;
+ DBMS_OUTPUT.PUT_LINE(r_job.jobno || ' ' || r_job.jname);
+END;
+```
+
+The following is the output from this anonymous block:
+
+```sql
+__OUTPUT__
+JOBNO JNAME
+----- -------
+100 ANALYST
+200 CLERK
+300 MANAGER
+400 SALESMAN
+500 PRESIDENT
+```
+
+You can use the `BULK COLLECT` clause to assemble the result set from an `EXECUTE IMMEDIATE` statement into a named collection. See [Using the BULK COLLECT clause](12_working_with_collections/04_using_the_bulk_collect_clause/#using_the_bulk_collect_clause), `EXECUTE IMMEDIATE BULK COLLECT` for more information.
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/01_declaring_a_cursor.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/01_declaring_a_cursor.mdx
new file mode 100644
index 00000000000..53901cbeeea
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/01_declaring_a_cursor.mdx
@@ -0,0 +1,35 @@
+---
+title: "Declaring a cursor"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/01_declaring_a_cursor/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Before you can use a cursor, you must first declare it in the declaration section of the SPL program. A cursor declaration appears as follows:
+
+```sql
+CURSOR IS ;
+```
+
+Where:
+
+- `name` is an identifier used to reference the cursor and its result set later in the program.
+- `query` is a SQL `SELECT` command that determines the result set retrievable by the cursor.
+
+!!! Note
+ An extension of this syntax allows the use of parameters. For details, see [Parameterized cursors](08_parameterized_cursors/#parameterized_cursors).
+
+This example shows some cursor declarations:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ CURSOR emp_cur_1 IS SELECT * FROM emp;
+ CURSOR emp_cur_2 IS SELECT empno, ename FROM emp;
+ CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
+ ORDER BY empno;
+BEGIN
+ ...
+END;
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/02_opening_a_cursor.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/02_opening_a_cursor.mdx
new file mode 100644
index 00000000000..d32f5673458
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/02_opening_a_cursor.mdx
@@ -0,0 +1,28 @@
+---
+title: "Opening a cursor"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/02_opening_a_cursor/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Before you can use a cursor to retrieve rows, you must open it using the `OPEN` statement.
+
+```sql
+OPEN ;
+```
+
+`name` is the identifier of a cursor that was previously declared in the declaration section of the SPL program. Don't execute the `OPEN` statement on a cursor that is already open.
+
+This example shows an `OPEN` statement with its corresponding cursor declaration:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
+ ORDER BY empno;
+BEGIN
+ OPEN emp_cur_3;
+ ...
+END;
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/03_fetching_rows_from_a_cursor.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/03_fetching_rows_from_a_cursor.mdx
new file mode 100644
index 00000000000..8771c3886f0
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/03_fetching_rows_from_a_cursor.mdx
@@ -0,0 +1,75 @@
+---
+title: "Fetching rows from a cursor"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/03_fetching_rows_from_a_cursor/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Once a cursor is open, you can retrieve rows from the cursor’s result set by using the `FETCH` statement.
+
+## Syntax
+
+```sql
+FETCH INTO { | [, ]... };
+```
+
+Where:
+
+- `name` is the identifier of a previously opened cursor.
+- `record` is the identifier of a previously defined record (for example, using `table%ROWTYPE`).
+
+`variable, variable_2...` are SPL variables that receive the field data from the fetched row. The fields in `record` or `variable, variable_2...` must match in number and order the fields returned in the `SELECT` list of the query given in the cursor declaration. The data types of the fields in the `SELECT` list must match or be implicitly convertible to the data types of the fields in `record` or the data types of `variable, variable_2...`
+
+!!! Note
+ A variation of `FETCH INTO` using the `BULK COLLECT` clause can return multiple rows at a time into a collection. See [Using the BULK COLLECT clause](../12_working_with_collections/04_using_the_bulk_collect_clause/#using_the_bulk_collect_clause) for more information on using the `BULK COLLECT` clause with the `FETCH INTO` statement.
+
+## Example
+
+The following shows the `FETCH` statement:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ v_empno NUMBER(4);
+ v_ename VARCHAR2(10);
+ CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
+ ORDER BY empno;
+BEGIN
+ OPEN emp_cur_3;
+ FETCH emp_cur_3 INTO v_empno, v_ename;
+ ...
+END;
+```
+
+Instead of explicitly declaring the data type of a target variable, you can use `%TYPE` instead. In this way, if the data type of the database column changes, the target variable declaration in the SPL program doesn't have to change. `%TYPE` picks up the new data type of the specified column.
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ v_empno emp.empno%TYPE;
+ v_ename emp.ename%TYPE;
+ CURSOR emp_cur_3 IS SELECT empno, ename FROM emp WHERE deptno = 10
+ ORDER BY empno;
+BEGIN
+ OPEN emp_cur_3;
+ FETCH emp_cur_3 INTO v_empno, v_ename;
+ ...
+END;
+```
+
+If all the columns in a table are retrieved in the order defined in the table, you can use `%ROWTYPE` to define a record into which the `FETCH` statement places the retrieved data. You can then access each field in the record using dot notation:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ v_emp_rec emp%ROWTYPE;
+ CURSOR emp_cur_1 IS SELECT * FROM emp;
+BEGIN
+ OPEN emp_cur_1;
+ FETCH emp_cur_1 INTO v_emp_rec;
+ DBMS_OUTPUT.PUT_LINE('Employee Number: ' || v_emp_rec.empno);
+ DBMS_OUTPUT.PUT_LINE('Employee Name : ' || v_emp_rec.ename);
+ ...
+END;
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/04_closing_a_cursor.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/04_closing_a_cursor.mdx
new file mode 100644
index 00000000000..0be146a08ca
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/04_closing_a_cursor.mdx
@@ -0,0 +1,42 @@
+---
+title: "Closing a cursor"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/04_closing_a_cursor/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Once all the desired rows are retrieved from the cursor result set, close the cursor. After you close the cursor, you can no longer access the result set.
+
+The `CLOSE` statement appears as follows:
+
+```sql
+CLOSE ;
+```
+
+`name` is the identifier of a cursor that's currently open. After you close a cursor, don't close it again. However, after you close the cursor, you can use the `OPEN` statement again on the closed cursor and rebuild the query result set. After that, the `FETCH` statement can then retrieve the rows of the new result set.
+
+This example uses the `CLOSE` statement:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ v_emp_rec emp%ROWTYPE;
+ CURSOR emp_cur_1 IS SELECT * FROM emp;
+BEGIN
+ OPEN emp_cur_1;
+ FETCH emp_cur_1 INTO v_emp_rec;
+ DBMS_OUTPUT.PUT_LINE('Employee Number: ' || v_emp_rec.empno);
+ DBMS_OUTPUT.PUT_LINE('Employee Name : ' || v_emp_rec.ename);
+ CLOSE emp_cur_1;
+END;
+```
+
+This procedure produces the following output. Employee number `7369, SMITH` is the first row of the result set.
+
+```sql
+EXEC cursor_example;
+__OUTPUT__
+Employee Number: 7369
+Employee Name : SMITH
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/05_using__rowtype_with_cursors.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/05_using__rowtype_with_cursors.mdx
new file mode 100644
index 00000000000..6022162be01
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/05_using__rowtype_with_cursors.mdx
@@ -0,0 +1,59 @@
+---
+title: "Using %ROWTYPE with cursors"
+legacyRedirectsGenerated:
+ # This list is generated by a script. If you need add entries, use the `legacyRedirects` key.
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.6/Database_Compatibility_for_Oracle_Developers_Guide_v9.6.1.075.html"
+ - "/edb-docs/d/edb-postgres-advanced-server/user-guides/database-compatibility-for-oracle-developers-guide/9.5/Database_Compatibility_for_Oracle_Developers_Guide.1.169.html"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/05_using__rowtype_with_cursors/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Using the `%ROWTYPE` attribute, you can define a record that contains fields corresponding to all columns fetched from a cursor or cursor variable. Each field takes on the data type of its corresponding column. The `%ROWTYPE` attribute is prefixed by a cursor name or cursor variable name.
+
+```text
+ %ROWTYPE;
+```
+
+`record` is an identifier assigned to the record. `cursor` is an explicitly declared cursor in the current scope.
+
+This example shows how you can use a cursor with `%ROWTYPE` to get information about which employee works in which department:
+
+```sql
+CREATE OR REPLACE PROCEDURE emp_info
+IS
+ CURSOR empcur IS SELECT ename, deptno FROM emp;
+ myvar empcur%ROWTYPE;
+BEGIN
+ OPEN empcur;
+ LOOP
+ FETCH empcur INTO myvar;
+ EXIT WHEN empcur%NOTFOUND;
+ DBMS_OUTPUT.PUT_LINE( myvar.ename || ' works in department '
+ || myvar.deptno );
+ END LOOP;
+ CLOSE empcur;
+END;
+```
+
+The following is the output from this procedure:
+
+```sql
+EXEC emp_info;
+__OUTPUT__
+SMITH works in department 20
+ALLEN works in department 30
+WARD works in department 30
+JONES works in department 20
+MARTIN works in department 30
+BLAKE works in department 30
+CLARK works in department 10
+SCOTT works in department 20
+KING works in department 10
+TURNER works in department 30
+ADAMS works in department 20
+JAMES works in department 30
+FORD works in department 20
+MILLER works in department 10
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/01_isopen.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/01_isopen.mdx
new file mode 100644
index 00000000000..bb53f7f94fd
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/01_isopen.mdx
@@ -0,0 +1,35 @@
+---
+title: "%ISOPEN"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/06_cursor_attributes/01_isopen/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+Use the `%ISOPEN` attribute to test whether a cursor is open.
+
+```text
+%ISOPEN
+```
+
+`cursor_name` is the name of the cursor for which a `BOOLEAN` data type of `TRUE` is returned if the cursor is open, `FALSE` otherwise.
+
+This example uses `%ISOPEN`:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ ...
+ CURSOR emp_cur_1 IS SELECT * FROM emp;
+ ...
+BEGIN
+ ...
+ IF emp_cur_1%ISOPEN THEN
+ NULL;
+ ELSE
+ OPEN emp_cur_1;
+ END IF;
+ FETCH emp_cur_1 INTO ...
+ ...
+END;
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/02_found.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/02_found.mdx
new file mode 100644
index 00000000000..87ede01dbe6
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/02_found.mdx
@@ -0,0 +1,64 @@
+---
+title: "%FOUND"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/06_cursor_attributes/02_found/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+
+
+The `%FOUND` attribute tests whether a row is retrieved from the result set of the specified cursor after a `FETCH` on the cursor.
+
+```text
+%FOUND
+```
+
+`cursor_name` is the name of the cursor for which a `BOOLEAN` data type of `TRUE` is returned if a row is retrieved from the result set of the cursor after a `FETCH`.
+
+After the last row of the result set is fetched, the next `FETCH` results in `%FOUND` returning `FALSE`. `FALSE` is also returned after the first `FETCH` if the result set has no rows to begin with.
+
+Referencing `%FOUND` on a cursor before it's opened or after it's closed results in an `INVALID_CURSOR` exception.
+
+`%FOUND` returns `null` if it's referenced when the cursor is open but before the first `FETCH`.
+
+This example uses `%FOUND`:
+
+```sql
+CREATE OR REPLACE PROCEDURE cursor_example
+IS
+ v_emp_rec emp%ROWTYPE;
+ CURSOR emp_cur_1 IS SELECT * FROM emp;
+BEGIN
+ OPEN emp_cur_1;
+ DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
+ DBMS_OUTPUT.PUT_LINE('----- -------');
+ FETCH emp_cur_1 INTO v_emp_rec;
+ WHILE emp_cur_1%FOUND LOOP
+ DBMS_OUTPUT.PUT_LINE(v_emp_rec.empno || ' ' || v_emp_rec.ename);
+ FETCH emp_cur_1 INTO v_emp_rec;
+ END LOOP;
+ CLOSE emp_cur_1;
+END;
+```
+
+The following is the output from this example:
+
+```sql
+EXEC cursor_example;
+__OUTPUT__
+EMPNO ENAME
+----- ------
+7369 SMITH
+7499 ALLEN
+7521 WARD
+7566 JONES
+7654 MARTIN
+7698 BLAKE
+7782 CLARK
+7788 SCOTT
+7839 KING
+7844 TURNER
+7876 ADAMS
+7900 JAMES
+7902 FORD
+7934 MILLER
+```
diff --git a/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/03_notfound.mdx b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/03_notfound.mdx
new file mode 100644
index 00000000000..315886b85dc
--- /dev/null
+++ b/product_docs/docs/epas/16/application_programming/epas_compat_spl/08_static_cursors/06_cursor_attributes/03_notfound.mdx
@@ -0,0 +1,64 @@
+---
+title: "%NOTFOUND"
+redirects:
+ - /epas/latest/epas_compat_spl/08_static_cursors/06_cursor_attributes/03_notfound/ #generated for docs/epas/reorg-role-use-case-mode
+---
+
+