Best Practice

Simple Demonstration of Halo Database Package Functionality

D
DBA Team
October 26, 2023

In Oracle databases, Package is a very important feature. The Package function consists of two parts: the package header (package) and the package body. The package header declares data types, constants, variables, cursors, functions, stored procedures, and exception handling within the package; these elements are the public elements of the package. The package body is the specific implementation of the package header, responsible for providing implementations for the sub-programs declared in the header. Private elements of the package can also be declared within the package body. Starting from Halo version 13, the Halo database has fully adapted the Oracle Package functionality. This article will briefly demonstrate some functions of Halo-Package using the current mainstream Halo 14 version.

1. Package Related Syntax

1.1 Package Creation Syntax

sql
CREATE [ OR REPLACE ] PACKAGE package_name
  [ { AUTHID DEFINER } | { AUTHID CURRENT_USER } ]  -- Related permission settings
  { IS | AS }
  [ declaration; ] ... -- Custom types, constants, variables, cursors, etc. can be declared here 
   [                  
     {                 -- Procedure declaration 
       PROCEDURE proc_name
       ([ argname [ IN | IN OUT | OUT ] argtype [ DEFAULT value ] ... ]) ; 
     } 
     |
     {                 -- Function declaration  
        FUNCTION func_name ([ argname [ IN | IN OUT | OUT ] argtype [ DEFAULT value ] ... ]) 
         RETURN rettype ; 
      } 
   ] ...
 END [ package_name ] ;
sql
CREATE [ OR REPLACE ] PACKAGE BODY package_name
  { IS | AS }
  [ private_declaration; ] ...     -- Private constants, variables, cursors, functions, procedures, etc. can be defined here... not exposed externally for internal Package use only   
  [ 
    {
       PROCEDURE proc_name[ {argname [ IN | IN OUT | OUT ] argtype [ DEFAULT value ] ... }] 
        { IS | AS }
       [ declaration; ] [, ...]
        BEGIN
         statement; [...]
        [ EXCEPTION
           { WHEN exception [OR exception] [...]] THEN statement; }
           [...]
        ]
       END [ proc_name ] ;
    }
    |
    {
      FUNCTION func_name [ argument_list ]
        RETURN rettype [DETERMINISTIC]
        { IS | AS }
       [ declaration; ] [, ...]
        BEGIN
         statement; [...]
        [ EXCEPTION
          { WHEN exception [ OR exception ] [...] THEN statement; }
          [...]
        ]
       END [ func_name ] ;
    }  
    ] ...
 END [ package_name ] ;

1.2 Package Removal Syntax

sql
DROP PACKAGE package_name;  -- Remove the entire package
DROP PACKAGE BODY package_name; -- Remove the current package body

2. Package Functionality Demonstration

2.1 Constants

sql
CREATE OR REPLACE PACKAGE PKG_CONSTANT AS
    C_CODE_SUCCESS  CONSTANT VARCHAR2(10) := 'SUCCESS'; -- Declare constant and assign value
    PROCEDURE PRO_TEST;
END PKG_CONSTANT;                                     
/
CREATE OR REPLACE PACKAGE BODY PKG_CONSTANT AS
PROCEDURE PRO_TEST AS
BEGIN
DBMS_OUTPUT.PUT_LINE('PKG_CONSTANT.C_CODE_SUCCESS: '||PKG_CONSTANT.C_CODE_SUCCESS);
END PRO_TEST;
END PKG_CONSTANT;
/
-- Execution
EXEC PKG_CONSTANT.PRO_TEST; 
-- Constants are not allowed to be modified; attempting to modify will result in an error
BEGIN
PKG_CONSTANT.C_CODE_SUCCESS := 'ERROR';
DBMS_OUTPUT.PUT_LINE('PKG_CONSTANT.C_CODE_SUCCESS: '||PKG_CONSTANT.C_CODE_SUCCESS);
END;
/

2.2 Variables

sql
CREATE OR REPLACE PACKAGE PKG_VAR AS
    VAR_A   VARCHAR2;   -- Declare variable
    PROCEDURE PRO_TEST;
END PKG_VAR;
/
CREATE OR REPLACE PACKAGE BODY PKG_VAR AS
PROCEDURE PRO_TEST AS
BEGIN
-- Initial assignment
PKG_VAR.VAR_A := 'VAR_TEST';
DBMS_OUTPUT.PUT_LINE('PKG_VAR.VAR_A: '||PKG_VAR.VAR_A);
-- Change variable value again
PKG_VAR.VAR_A := 'VAR_A';
DBMS_OUTPUT.PUT_LINE('PKG_VAR.VAR_A: '||PKG_VAR.VAR_A);
END PRO_TEST;
END PKG_VAR;
/
-- Execution
EXEC PKG_VAR.PRO_TEST;

2.3 Cursors

sql
CREATE TABLE example(manager_id INT, employee_id INT, employee VARCHAR2(30));
INSERT INTO example VALUES(5, 1, 'Nick');
INSERT INTO example VALUES(1, 2, 'Josh');
INSERT INTO example VALUES(2, 3, 'Ali');
INSERT INTO example VALUES(6, 4, 'Joe');
INSERT INTO example VALUES(4, 5, 'Kyle');
CREATE OR REPLACE PACKAGE PKG_CURSOR
AS
TYPE PKG_TYPE_CURSOR IS REF CURSOR;
PROCEDURE PRO_TEST;
END PKG_CURSOR;
/
CREATE OR REPLACE PACKAGE BODY PKG_CURSOR
AS
PROCEDURE PRO_TEST
IS
  cur_cursor PKG_TYPE_CURSOR;
  cur_val example%ROWTYPE;
BEGIN
  OPEN cur_cursor FOR SELECT * FROM example;
  LOOP 
  FETCH cur_cursor INTO cur_val; 
  EXIT WHEN NOT FOUND; 
  DBMS_OUTPUT.PUT_LINE('manager_id: '||cur_val.manager_id||' employee_id: '||cur_val.employee_id||' employee: '||cur_val.employee);
  END LOOP;
  CLOSE cur_cursor;
END PRO_TEST;
END PKG_CURSOR;
/
-- Execution
EXEC PKG_CURSOR.PRO_TEST

2.4 Functions and Stored Procedures

sql
CREATE OR REPLACE PACKAGE PKG_TEST AS
  FUNCTION F_TEST( f_a INTEGER , f_b INTEGER ) RETURN INTEGER;
  PROCEDURE PRO_TEST;
END PKG_TEST;  
/
CREATE OR REPLACE PACKAGE BODY PKG_TEST AS
FUNCTION F_TEST( f_a IN INTEGER , f_b IN INTEGER )
RETURN INTEGER
AS
  f_c INTEGER;
BEGIN 
  f_c := f_a + f_b;
  RETURN f_c;
END F_TEST;
PROCEDURE PRO_TEST
AS 
  var_a INTEGER;
BEGIN  
  var_a := PKG_TEST.F_TEST(12,13);
  DBMS_OUTPUT.PUT_line('PKG_TEST.F_TEST(12,13) = '|| var_a); 
END PRO_TEST; 
END PKG_TEST;
/

2.5 Custom Types

sql
CREATE OR REPLACE PACKAGE PKG_RECODE_TEST AS
  TYPE RECODE_TYPE IS RECORD(
    DS NUMBER(10, 3),
    DA VARCHAR(2)
    );
  PROCEDURE PRO_TEST;
END PKG_RECODE_TEST;  
/
CREATE OR REPLACE PACKAGE BODY PKG_RECODE_TEST AS
PROCEDURE PRO_TEST
AS 
  recode_a RECODE_TYPE;
BEGIN  
  SELECT 1,'x' INTO recode_a FROM dual;
  DBMS_OUTPUT.PUT_line(recode_a.ds||' '||recode_a.da); 
END PRO_TEST; 
END PKG_RECODE_TEST;
/
-- Execution
EXEC PKG_RECODE_TEST.PRO_TEST;

2.6 Exceptions

sql
CREATE OR REPLACE PACKAGE ERRLOG
IS
   no_such_table EXCEPTION;
      PRAGMA EXCEPTION_INIT (no_such_table, -942);
   invalid_table_name EXCEPTION;
      PRAGMA EXCEPTION_INIT (invalid_table_name, -903);
   PROCEDURE PRO_TEST;
END;
/
CREATE OR REPLACE PACKAGE BODY ERRLOG AS
PROCEDURE PRO_TEST
AS 
BEGIN
  RAISE ERRLOG.no_such_table;
  DBMS_OUTPUT.PUT_LINE('ERROR');
EXCEPTION
  WHEN no_such_table THEN
  DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE||' SQLERRM: '||SQLERRM); 
END PRO_TEST; 
END ERRLOG;
/
-- Execution
EXEC ERRLOG.PRO_TEST;

3. Precautions

3.1 Unable to end normally, entering $ state

Check whether the database is connected via psql or hsql. If connected via psql, there are two handling methods: one is to use \q to exit the connection and then connect to the database via hsql; the other method is to check if the parameter ENABLE_PL_BLOCK is on. If it is not on, use the command below. Generally, if there is no need to use PG's SQL syntax, it is recommended to connect and manage the database using hsql.

sql
\set                         -- View ENABLE_PL_BLOCK parameter
 \set ENABLE_PL_BLOCK on      -- Enable ENABLE_PL_BLOCK

Latest Articles

Security Announcement
April 11, 2025

Xihe (Halo) Database Critical Patch Update Announcement - April 2025

Security Announcement
June 20, 2024

Xihe (Halo) Database Critical Patch Update Announcement - June 2024

Security Announcement
December 18, 2023

Xihe (Halo) Database Critical Patch Update Announcement - December 2023