Oracle PL/SQL Packages: Quick Overview

Rajesh Vinayagam
6 min readJan 21, 2024

Oracle PL/SQL packages are a cornerstone of Oracle database programming, offering an efficient way to encapsulate related procedures, functions, and data types. This article provides an in-depth look at Oracle packages, their advantages, usage examples, and integration with Java applications.

What is a Package?

A package in Oracle PL/SQL is essentially a schema object that encapsulates related PL/SQL types, variables, constants, procedures, functions, and cursors. It is composed of two parts:

  1. Package Specification: This is the interface to the package. It declares the types, variables, constants, exceptions, cursors, procedures, and functions that can be referenced and invoked from outside the package. This part of the package does not contain any code for the procedures or functions; it only contains their declarations.
  2. Package Body: This contains the implementation of the package. It includes the code for the procedures and functions declared in the package specification. Additionally, it can contain private declarations that are not visible outside the package.

Key Features of Packages

  1. Encapsulation: Packages encapsulate related procedures, functions, and other PL/SQL constructs, making them easier to understand, manage, and modify.
  2. Modularity: By grouping related functionality, packages promote modularity in application development. This makes complex systems more manageable and easier to navigate.
  3. Performance Improvement: Oracle stores packages in a compiled state, which means that the PL/SQL code within packages runs faster than standalone procedures and functions. Additionally, packages are loaded into memory once and shared among users, reducing memory usage and enhancing performance.
  4. Maintainability: Packages allow for separating the interface (specification) from the implementation (body). This means that changes to the package body do not affect the clients as long as the specification remains unchanged.
  5. Reusability: Functions and procedures in a package can be reused in multiple applications, reducing code duplication.
  6. Private and Public Components: Packages can have both private (declared only in the package body) and public components (declared in the package specification), allowing for better control over data and implementation details.

Advantages of Using Packages

  • Encapsulation and Organization: Packages encapsulate logically related database logic, making the database more organized and manageable.
  • Performance Improvement: Since packages are loaded into memory once, they can improve performance by reducing disk I/O.
  • Maintainability: Packages allow separating the interface from the implementation, making maintenance easier.
  • Reusability and Sharing: Commonly used code can be placed in packages and reused across multiple applications.

Example: Employee Management Package

Package Specification

CREATE OR REPLACE PACKAGE emp_mgmt AS
PROCEDURE add_employee(p_name VARCHAR2, p_department_id NUMBER);
FUNCTION get_department(p_emp_id NUMBER) RETURN VARCHAR2;
END emp_mgmt;
/

Package Body

CREATE OR REPLACE PACKAGE BODY emp_mgmt AS

PROCEDURE add_employee(p_name VARCHAR2, p_department_id NUMBER) IS
BEGIN
INSERT INTO employees (name, department_id) VALUES (p_name, p_department_id);
END add_employee;

FUNCTION get_department(p_emp_id NUMBER) RETURN VARCHAR2 IS
v_department_name VARCHAR2(100);
BEGIN
SELECT department_name INTO v_department_name FROM departments WHERE department_id = p_emp_id;
RETURN v_department_name;
END get_department;

END emp_mgmt;
/

In this example, theemp_mgmt package includes a procedure to add an employee and a function to retrieve the department name.

Calling PL/SQL Package from Java

Java applications can interact with Oracle databases using JDBC (Java Database Connectivity).

Setting Up JDBC

Add JDBC Library

To enable JDBC connectivity, the Oracle JDBC Driver (ojdbc) must be included in your project’s dependencies. This driver enables Java applications to connect to Oracle databases.

Establish a connection

import java.sql.*;

public class OracleConnection {
public static Connection getConnection() throws SQLException {
String url = "jdbc:oracle:thin:@hostname:port:sid";
String username = "your_username";
String password = "your_password";
return DriverManager.getConnection(url, username, password);
}
}
  • TheOracleConnection class provides a static method getConnection which establishes a connection to the Oracle database.
  • URL: The JDBC URLjdbc:oracle:thin:@hostname:port:sid specifies the protocol (jdbc:oracle:thin), the database server's hostname, port, and the Oracle System Identifier (SID) or service name.

Executing Package Subprograms

Calling a Procedure

import java.sql.*;

public class EmployeeManager {
public static void addEmployee(String name, int departmentId) {
try (Connection conn = OracleConnection.getConnection()) {
CallableStatement cstmt = conn.prepareCall("{call emp_mgmt.add_employee(?, ?)}");
cstmt.setString(1, name);
cstmt.setInt(2, departmentId);
cstmt.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

In EmployeeManager.addEmployee, a stored procedure add_employee from the emp_mgmt package is invoked.

  • CallableStatement: ACallableStatement is prepared using the connection object. The SQL statement {call emp_mgmt.add_employee(?, ?)} is used to call the procedure with placeholders (?) for parameters.
  • Setting Parameters: The setString and setInt methods bind values to the input parameters of the stored procedure.
  • Execution: The execute method runs the stored procedure.

Calling a Function

import java.sql.*;

public class EmployeeManager {
public static void addEmployee(String name, int departmentId) {
try (Connection conn = OracleConnection.getConnection()) {
CallableStatement cstmt = conn.prepareCall("{call emp_mgmt.add_employee(?, ?)}");
cstmt.setString(1, name);
cstmt.setInt(2, departmentId);
cstmt.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

In EmployeeManager.getDepartment, a stored function get_department from the emp_mgmt package is called.

  • CallableStatement for Function: The call {? = call emp_mgmt.get_department(?)} is used, where ? = indicates that the function returns a value.
  • Registering and Setting Parameters: The first parameter is registered as an output parameter to hold the function’s return value. The second parameter is the input parameter.
  • Retrieving the Result: After execution, the function’s return value is retrieved with getString.

Usage in Java Application

public class Main {
public static void main(String[] args) {
EmployeeManager.addEmployee("John Doe", 101);

String department = EmployeeManager.getDepartment(5);
System.out.println("Department: " + department);
}
}

The Main class demonstrates how to use the EmployeeManager class.

  • Adding an Employee: EmployeeManager.addEmployee is called with an employee name and department ID.
  • Retrieving Department Name: EmployeeManager.getDepartment fetches the department name for a given employee ID.

Other Examples

Creating Oracle PL/SQL packages involves defining stored procedures, functions, and variables that can be public (accessible from outside the package) or private (only accessible within the package). Additionally, you can reference external procedures or functions from other packages. Let’s look at examples covering these aspects:

Example 1: Package with Stored Procedure and Function

In this example, employee_pkg contains both a procedure (add_employee) and a function (get_department_name).

Package Specification

CREATE OR REPLACE PACKAGE employee_pkg AS
-- Public procedure and function
PROCEDURE add_employee(p_name VARCHAR2, p_dept_id NUMBER);
FUNCTION get_employee_count(p_dept_id NUMBER) RETURN NUMBER;
END employee_pkg;
/

Package Body

CREATE OR REPLACE PACKAGE BODY employee_pkg AS

-- Implementation of add_employee procedure
PROCEDURE add_employee(p_name VARCHAR2, p_dept_id NUMBER) IS
BEGIN
INSERT INTO employees (name, department_id) VALUES (p_name, p_dept_id);
END add_employee;

-- Implementation of get_employee_count function
FUNCTION get_employee_count(p_dept_id NUMBER) RETURN NUMBER IS
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM employees WHERE department_id = p_dept_id;
RETURN v_count;
END get_employee_count;

END employee_pkg;
/

Example 2: Package Referencing External Procedures/Functions

Suppose we have an existing package hr_utils_pkg with a function is_department_active.

The below example shows how to reference external functions from another package (hr_utils_pkg) within a new package (hr_extended_pkg).

External Package Specification

CREATE OR REPLACE PACKAGE hr_utils_pkg AS
FUNCTION is_department_active(p_dept_id NUMBER) RETURN BOOLEAN;
END hr_utils_pkg;
/

Using External Function in a New Package

CREATE OR REPLACE PACKAGE hr_extended_pkg AS
FUNCTION check_department_status(p_dept_id NUMBER) RETURN VARCHAR2;
END hr_extended_pkg;
/

CREATE OR REPLACE PACKAGE BODY hr_extended_pkg AS
FUNCTION check_department_status(p_dept_id NUMBER) RETURN VARCHAR2 IS
BEGIN
IF hr_utils_pkg.is_department_active(p_dept_id) THEN
RETURN 'Active';
ELSE
RETURN 'Inactive';
END IF;
END check_department_status;
END hr_extended_pkg;
/

Example 3: Using Public, Private, and Global Variables

Below example provides the usage of variable

  • Public Variable: g_tax_rate in finance_pkg can be accessed and modified by other PL/SQL blocks or packages.
  • Private Variable: v_default_rate is private to finance_pkg and cannot be accessed outside its package body.
  • Global Variable: While PL/SQL doesn’t have global variables in the traditional sense, public package variables like g_tax_rate act similarly, maintaining their values across different sessions and calls.

Package Specification with Public Variable

CREATE OR REPLACE PACKAGE finance_pkg AS
-- Public variable
g_tax_rate NUMBER;

FUNCTION calculate_tax(p_amount NUMBER) RETURN NUMBER;
END finance_pkg;
/

Package Body with Private and Global Variables

CREATE OR REPLACE PACKAGE BODY finance_pkg AS

-- Private variable
v_default_rate NUMBER := 0.05;

-- Implementation of calculate_tax function
FUNCTION calculate_tax(p_amount NUMBER) RETURN NUMBER IS
BEGIN
IF g_tax_rate IS NULL THEN
RETURN p_amount * v_default_rate; -- Using private variable
ELSE
RETURN p_amount * g_tax_rate; -- Using public variable
END IF;
END calculate_tax;

END finance_pkg;
/

Conclusion

As we end, it is clear that Oracle PL/SQL packages have long been the foundation of effective database programming, providing unparalleled benefits in organising, securing, and simplifying complicated database operations. These packages have greatly influenced traditional database management approaches, simplifying maintenance and boosting performance.

However, the fast expansion of technology necessitates the modernization of these traditional systems to conform with contemporary technology stacks and techniques. In the following post, we will look at ways for deconstructing PL/SQL packages using AI, aligning database functionality with microservices, and assuring seamless integration with cloud platforms.

--

--