Chapter 11 · PL/SQL Fundamentals: Blocks, Types, Procedures, Functions, and Packages

Procedures and Functions, Parameter Modes, Overloading, Determinism, and SQL Integration

Design stored procedures and functions with explicit parameter contracts, safe SQL integration, disciplined overloading, and truthful DETERMINISTIC assertions rather than hidden side effects.

Intermediate → Advanced115–135 minutesProcedure/function + SQL-callability labDETERMINISTIC is an assertion, not engine verificationFree-compatible · no management pack requiredLast reviewed: August 2026

Learning outcomes

ServiceHub has copied the same validation block into several jobs. A developer turns it into a function, marks it DETERMINISTIC, and then adds an audit-table insert inside the function. Another developer calls that function from a query over many rows and assumes Oracle invokes it exactly once per row. Reusability alone is not enough: procedures and functions need explicit parameter contracts, SQL-callability rules, and truthful side-effect semantics.

01

Choose procedure versus function from the caller contract and return semantics.

02

Use IN, OUT, and IN OUT parameter modes deliberately, with defaults where they improve API clarity.

03

Overload subprograms only when parameter profiles are unambiguous and semantically related.

04

Treat DETERMINISTIC as a developer assertion that Oracle does not verify.

05

Explain SQL-callable function restrictions, side effects, and row-by-row SQL-to-PL/SQL invocation hazards.

Version, scope, privileges, tooling, and licensing baseline

Mandatory examples target a disposable ServiceHub schema in Oracle AI Database Free 26ai and were reviewed against RU 23.26.3, SQL Developer 26.2, and SQLcl 26.2.1. Free is limited to 2 foreground CPU cores, 2 GB combined SGA/PGA memory, and 12 GB user data and receives no Oracle patches or Support service requests. The chapter requires no Diagnostics Pack, Tuning Pack, RAC, Data Guard, Exadata, GoldenGate, OCI service, or COMPATIBLE change. Stored program creation in the course owner requires CREATE PROCEDURE; cross-schema execution requires explicit EXECUTE grants. Dynamic performance views used for optional session/PGA evidence should be read through a DBA observer or narrowly granted V_$ views in the disposable PDB.

1. Procedures perform an action; functions return a value

A procedure can expose zero or more OUT/IN OUT results and is called as a statement. A function has a return type and every normal execution path must return a value. Use a function when “compute a value” is the natural contract; use a procedure for an operation with action-oriented outputs or orchestration.

sql · procedure with explicit parameter modes
CREATE OR REPLACE PROCEDURE servicehub_adjust_amount (  p_case_id      IN     NUMBER,  p_multiplier   IN     NUMBER DEFAULT 1,  p_new_amount      OUT NUMBER) AUTHID DEFINERISBEGIN  UPDATE servicehub_subprogram_case  SET amount = amount * p_multiplier  WHERE case_id = p_case_id  RETURNING amount INTO p_new_amount;  IF SQL%ROWCOUNT = 0 THEN    RAISE_APPLICATION_ERROR(-20001,'Unknown case_id');  END IF;END;/

IN is the default mode. OUT returns a value through a parameter. IN OUT lets the subprogram read and then replace/modify the caller's value; use it sparingly because it increases coupling.

2. Overloading is one API name with distinguishable parameter profiles

Package subprograms can be overloaded when PL/SQL can distinguish calls by formal parameter profiles. Overloads should represent the same conceptual operation, not unrelated behaviors hidden behind one name.

sql · related overloads
CREATE OR REPLACE PACKAGE servicehub_format_api AS  FUNCTION format_key(p_case_id NUMBER) RETURN VARCHAR2;  FUNCTION format_key(p_external_ref VARCHAR2) RETURN VARCHAR2;END servicehub_format_api;/CREATE OR REPLACE PACKAGE BODY servicehub_format_api AS  FUNCTION format_key(p_case_id NUMBER) RETURN VARCHAR2 IS  BEGIN    RETURN 'CASE-' || TO_CHAR(p_case_id);  END;  FUNCTION format_key(p_external_ref VARCHAR2) RETURN VARCHAR2 IS  BEGIN    RETURN UPPER(TRIM(p_external_ref));  END;END servicehub_format_api;/

Avoid overloads whose types are easily confused through implicit conversion. Stable API design is more valuable than clever dispatch.

3. SQL-callable functions have a stricter contract

A stored function referenced from a SQL expression must have only IN formal parameters and must obey restrictions intended to control side effects. A query-invoked function cannot perform ordinary DML in the same logical SQL context. A function called by DML also cannot read or modify the table being modified by that invoking statement.

sql · deliberately wrong: function writes while invoked from a query
CREATE OR REPLACE FUNCTION servicehub_bad_touch (  p_case_id IN NUMBER) RETURN NUMBERAUTHID DEFINERISBEGIN  UPDATE servicehub_subprogram_case  SET touched_at = SYSTIMESTAMP  WHERE case_id = p_case_id;  RETURN p_case_id;END;/SELECT servicehub_bad_touch(case_id)FROM servicehub_subprogram_case;-- ORA-14551: cannot perform a DML operation inside a query

Oracle's ORA-14551 message notes that an autonomous transaction can make DML independent of the invoking query, but that is not a general recommendation for row-by-row logging. It creates independent commits and side effects whose execution count/order can be surprising in declarative SQL.

4. DETERMINISTIC is a promise you make—not a proof Oracle performs

DETERMINISTIC asserts that the same inputs always return the same result and that the function obeys required semantics. Oracle documentation explicitly warns that the database does not verify the assertion. A false declaration can silently produce wrong results, especially with function-based indexes, virtual columns, materialized views, or optimizer reuse.

sql · truthful pure computation
CREATE OR REPLACE FUNCTION servicehub_net_amount (  p_gross IN NUMBER,  p_discount_pct IN NUMBER) RETURN NUMBERDETERMINISTICAUTHID DEFINERISBEGIN  RETURN p_gross * (1 - NVL(p_discount_pct,0)/100);END;/
Do not mark session/time/data-dependent functions deterministic

A function that reads SYSTIMESTAMP, mutable package/session state, a mutable table, a sequence, or another nondeterministic source does not satisfy the same-input/same-output contract merely because DETERMINISTIC makes the DDL compile.

5. A PL/SQL function inside SQL can be invoked an unspecified number of times

SQL is declarative. Oracle can transform, reorder, eliminate, or repeat expression evaluation while preserving SQL semantics. Do not rely on a SQL-invoked PL/SQL function being called exactly once for every returned row. If invocation count itself is a business requirement, orchestrate explicitly outside the declarative SQL expression.

Even a pure function can add SQL-to-PL/SQL call overhead when evaluated for many rows. Before wrapping a built-in SQL expression, compare a direct set-based expression, virtual column, SQL macro where appropriate, or another design that keeps optimization visible to SQL.

6. Reproducible lab

sql · setup
BEGIN  EXECUTE IMMEDIATE 'DROP TABLE servicehub_subprogram_case PURGE';EXCEPTION WHEN OTHERS THEN  IF SQLCODE != -942 THEN RAISE; END IF;END;/CREATE TABLE servicehub_subprogram_case (  case_id      NUMBER PRIMARY KEY,  amount       NUMBER(10,2) NOT NULL,  discount_pct NUMBER(5,2) NOT NULL,  touched_at   TIMESTAMP);INSERT INTO servicehub_subprogram_case VALUES (1,100,10,NULL);INSERT INTO servicehub_subprogram_case VALUES (2,200,5,NULL);COMMIT;
sql · pure function in SQL
CREATE OR REPLACE FUNCTION servicehub_net_amount (  p_gross IN NUMBER,  p_discount_pct IN NUMBER) RETURN NUMBERDETERMINISTICAUTHID DEFINERISBEGIN  RETURN p_gross * (1 - NVL(p_discount_pct,0)/100);END;/SELECT  case_id,  amount,  discount_pct,  servicehub_net_amount(amount,discount_pct) AS net_amountFROM servicehub_subprogram_caseORDER BY case_id;
sql · verify object status
SELECT object_name, object_type, statusFROM user_objectsWHERE object_name IN (  'SERVICEHUB_NET_AMOUNT',  'SERVICEHUB_BAD_TOUCH',  'SERVICEHUB_ADJUST_AMOUNT')ORDER BY object_name;
sql · cleanup
BEGIN EXECUTE IMMEDIATE 'DROP FUNCTION servicehub_bad_touch'; EXCEPTION WHEN OTHERS THEN NULL; END;/BEGIN EXECUTE IMMEDIATE 'DROP FUNCTION servicehub_net_amount'; EXCEPTION WHEN OTHERS THEN NULL; END;/BEGIN EXECUTE IMMEDIATE 'DROP PROCEDURE servicehub_adjust_amount'; EXCEPTION WHEN OTHERS THEN NULL; END;/BEGIN EXECUTE IMMEDIATE 'DROP PACKAGE servicehub_format_api'; EXCEPTION WHEN OTHERS THEN NULL; END;/DROP TABLE servicehub_subprogram_case PURGE;

7. Production judgment

Stored subprograms are schema APIs. Keep parameter types and side effects explicit, choose definer/invoker rights deliberately, grant EXECUTE narrowly, and avoid hidden commits. Mark a function DETERMINISTIC only when you can prove its semantic promise across sessions and time. Do not use row-by-row function calls from SQL merely to make code look modular.

No special edition, pack, restart, or COMPATIBLE change is required. Lesson 3 packages these subprograms into stable public specifications and hidden bodies, then makes package session state and invalidation behavior visible.

Check your understanding

  1. What parameter mode is the default?
  2. What parameter-mode restriction applies to a function invoked from SQL?
  3. Does Oracle verify that a DETERMINISTIC function is truly deterministic?
  4. Why can a DML-performing function raise ORA-14551 when called from a query?
  5. Can a SQL caller rely on a user-defined function being invoked exactly once per returned row?
Review the answers

IN.

SQL-callable functions must use IN parameters rather than OUT or IN OUT parameters.

No. DETERMINISTIC is a developer assertion; false declarations can silently produce incorrect behavior.

A function invoked from a query cannot perform ordinary DML in that logical query context because Oracle restricts side effects.

No. SQL is declarative, so Oracle may transform expression evaluation while preserving results.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.