Skip to content

Add PLiSQL per-package and reset-all API#1375

Open
db-nikhil wants to merge 1 commit into
IvorySQL:masterfrom
db-nikhil:db-nikhil/reset_pkg
Open

Add PLiSQL per-package and reset-all API#1375
db-nikhil wants to merge 1 commit into
IvorySQL:masterfrom
db-nikhil:db-nikhil/reset_pkg

Conversation

@db-nikhil

@db-nikhil db-nikhil commented Jun 30, 2026

Copy link
Copy Markdown

Implements #1376 (Fixes #1376)

Reset a single PL/iSQL package by OID (Oracle DBMS_SESSION.RESET_PACKAGE semantics): close refcursors, free variable memory, reset mutable globals, and mark the package as uninitialized (PLISQL_PACKAGE_NO_INIT) so that the full init sequence — default expressions re-evaluated and init block re-executed — runs lazily on next access.

This lazy re-init is spec-compliant: dynamic defaults (SYSDATE, seq.NEXTVAL, cross-package function calls) are re-evaluated at re-init time, not frozen at reset time. A snapshot/restore approach would have captured stale values; NO_INIT delegates everything to the existing lazy-init path in plisql_check_package_status.

ResetAllPackagesContext uses a two-phase approach (collect via PackageCacheListItems, then reset each) to avoid hash iterator corruption during modification.

Both APIs are exposed via the rendezvous mechanism (plisql_internal_funcs.package_reset_context) so the PL/iSQL layer does not need to access the PackageCache hash directly. Invalid OIDs trigger ERROR; NULL OIDs are short-circuited by the STRICT function attribute.

ResetPackageContext returns bool: true if package was reset, false if nothing to do (status too low).

ResetAllPackagesContext returns int: count of packages actually reset, or -1 if PL/iSQL is unavailable (rendezvous function pointer is NULL).

Test extension test_package_reset provides:

  • reset_package_by_oid(oid) -> bool
  • reset_all_packages() -> int4

Five test scenarios:

  • test_package_reset: extension loads; reset_all returns -1 when PL/iSQL unavailable; reset_package_by_oid(0) throws ERROR
  • test_reset_one_oid: reset each of 3 packages by OID individually, siblings untouched; loop reset each individually; NULL OID short- circuits to NULL with no side effects
  • test_reset_all: reset all -> init one -> get all -> reset all ->
    get all -> init all -> get all -> reset all -> get all
  • test_reset_defaults: package with default 42, no-default, and text default; verify mutation then reset restores defaults (lazy re-init)

Rendezvous field: bool (*)(Oid) in PLiSQL_funcs_call and PLiSQL_plugin. PackageCacheListItems is static (no external callers).

Spec reference: Oracle 21c DBMS_SESSION.RESET_PACKAGE — session-only effect, does not affect other sessions. Defaults are re-evaluated (§2.1: 'Default values for package variables are re-initialized'), init block re-executed (§2.3: 'The INITIALIZATION section runs once per session; RESET_PACKAGE forces re-execution'), re-instantiation is lazy (§4.2: 'Re-instantiation occurs when next referenced').

Authored-by: Cedric Villemain cedric.villemain@data-bene.io
Co-authored-by: Nikhil nikhil@data-bene.io

Summary by CodeRabbit

Summary

  • New Features

    • Added SQL-callable package reset APIs to clear PL/iSQL package runtime state: reset a single package by OID (returns true/false) or reset all packages (returns a reset count).
    • Added dbms_session.reset_package() to trigger the same behavior.
  • Bug Fixes

    • Resets now reliably clear package in-memory state, including declared defaults (including arrays), without affecting non-package session application context.
  • Tests

    • Added and expanded an Oracle-focused regression test suite covering single reset, full reset, default restoration, invalid OID handling, and STRICT NULL semantics.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds package reset support in PL/iSQL, exposes it through DBMS_SESSION and a test extension, and adds regression coverage for single-package, bulk, NULL, and default-restoration behavior.

Changes

Package reset implementation and tests

Layer / File(s) Summary
PL/iSQL reset logic
src/include/funcapi.h, src/pl/plisql/src/pl_package.h, src/pl/plisql/src/pl_package.c, src/pl/plisql/src/pl_subproc_function.c
Adds the internal package reset callback, implements per-package datum cleanup and state reset, and registers the callback in the PL/iSQL function table.
Package cache reset API
src/include/utils/packagecache.h, src/backend/utils/cache/packagecache.c
Declares and implements single-package and bulk package reset entry points, including cache enumeration and return handling when PL/iSQL is unavailable.
DBMS_SESSION reset_package wiring
contrib/ivorysql_ora/src/builtin_packages/dbms_session/dbms_session--1.0.sql, contrib/ivorysql_ora/src/builtin_packages/dbms_session/dbms_session.c, contrib/ivorysql_ora/sql/dbms_session.sql, contrib/ivorysql_ora/expected/dbms_session.out
Adds the SQL-visible dbms_session.reset_package procedure, connects it to bulk package reset, and covers package-state preservation behavior.
Test extension module
src/oracle_test/modules/test_package_reset/Makefile, src/oracle_test/modules/test_package_reset/meson.build, src/oracle_test/modules/test_package_reset/test_package_reset.control, src/oracle_test/modules/test_package_reset/test_package_reset.c, src/oracle_test/modules/test_package_reset/.gitignore, src/oracle_test/modules/test_package_reset/README, src/oracle_test/modules/Makefile, src/oracle_test/modules/meson.build
Adds the test module build, SQL wrappers, extension metadata, generated-file ignores, and module documentation.
Regression tests and expected output
src/oracle_test/modules/test_package_reset/sql/*, src/oracle_test/modules/test_package_reset/expected/*
Adds smoke, selective reset, bulk reset, NULL/STRICT, and default-restoration coverage with matching expected outputs.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant test_package_reset.reset_package_by_oid as SQL
  participant ResetPackageContext as Cache API
  participant plisql_internal_funcs as PL/iSQL dispatch
  participant plisql_package_reset_context as Reset implementation

  SQL->>Cache API: ResetPackageContext(pkg_oid)
  Cache API->>PL/iSQL dispatch: package_reset_context(pkg_oid)
  PL/iSQL dispatch->>Reset implementation: dispatch
  Reset implementation->>Reset implementation: clear package datums
  Reset implementation-->>PL/iSQL dispatch: bool result
  PL/iSQL dispatch-->>Cache API: bool result
  Cache API-->>SQL: bool result
Loading

Suggested labels: feature

Suggested reviewers: OreoYang, NotHimmel, jiaoshuntian

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: new PL/iSQL APIs for single-package and reset-all package state.
Linked Issues check ✅ Passed Issue #1376 is addressed: package reset clears package state, closes cursors, preserves application context, and adds coverage for lazy re-init.
Out of Scope Changes check ✅ Passed The added test module files, build wiring, README, and .gitignore all support the new reset API and its coverage.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out (1)

84-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a dynamic-default or init-block assertion here.

This expected output only proves that literal defaults and NULL come back after reset. It would still pass if the implementation restored a saved snapshot instead of re-running default expressions / the init block, which is the behavior this PR is explicitly trying to preserve. Adding a value derived from a changing expression or an init-block side effect would close that gap. As per path instructions, "**/expected/*.out: These are expected test outputs from pg_regress. Review for: ... Edge case coverage ... Consistency with corresponding .sql test files`."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out`
around lines 84 - 108, Add an assertion in the pkg_defaults_test reset
expectations that exercises a dynamic default or init block, not just literal
defaults and NULL, so the pg_regress output verifies re-execution after reset.
Update the corresponding expected output for test_reset_defaults to include a
value from a changing expression or init-block side effect, using the existing
test_package_reset.reset_all_packages and pkg_defaults_test getters as anchors
to keep coverage aligned with the .sql test.

Source: Path instructions

src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql (1)

5-15: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a dynamic-default / init-block assertion here.

This only proves literal defaults are restored. The PR contract also says reset must re-evaluate dynamic defaults and rerun the package init block lazily, but neither behavior is exercised here, so a cached-default or skipped-init regression would still pass. As per path instructions, **/sql/*.sql should ensure comprehensive coverage of features.

Also applies to: 61-67

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql`
around lines 5 - 15, Add coverage in the pkg_defaults_test setup to assert both
a dynamic default and the package init block are re-evaluated after reset, not
just literal defaults. Update the SQL test around pkg_defaults_test by
introducing a dynamic-default-backed symbol and an initialization side effect,
then verify via the existing reset flow that the dynamic value changes and the
init block runs lazily again on first access after reset. Use the
pkg_defaults_test package and its reset-defaults test case to locate the
assertions and extend them rather than creating a separate test.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/backend/utils/cache/packagecache.c`:
- Around line 310-312: The package cache entrypoint is checking
plisql_internal_funcs.isload before the rendezvous table has been initialized,
which can leave it reading stale zero-initialized state in a fresh backend.
Update the package-cache path that performs this early return so it first calls
plisql_internel_funcs_init() before accessing plisql_internal_funcs.isload,
mirroring the initialization order used by ResetPackageContext(). Keep the
existing count behavior, but ensure the load-state check only happens after the
rendezvous lookup is ready.
- Around line 265-269: Guard the callback invocation in ResetPackageContext by
checking whether plisql_internal_funcs.package_reset_context is set before
calling it, since PL/iSQL may not be loaded in the same way
ResetAllPackagesContext already handles. If the callback is NULL, return the
“not loaded” path instead of dereferencing it; otherwise, call the existing
package_reset_context handler after plisql_internel_funcs_init().

In `@src/oracle_test/modules/test_package_reset/expected/test_reset_all.out`:
- Around line 58-63: Update the expected output for the first bulk reset in the
test scenario so it matches the actual behavior of ResetAllPackagesContext after
the CREATE PACKAGE and CREATE PACKAGE BODY statements have loaded PL/iSQL. The
reset_all_packages result should be 0 instead of -1, since the “PL/iSQL not
loaded” path is no longer applicable here; adjust the test_package_reset
expected .out fixture accordingly and keep the surrounding SQL output unchanged.

In `@src/oracle_test/modules/test_package_reset/README`:
- Around line 15-18: The documented no-op behavior for reset_package_by_oid is
inconsistent across the package-reset docs: this README says it returns true
when nothing needed resetting, while test_package_reset--1.0.sql and the
bulk-reset wording imply a false/no-op or “actually reset” contract. Update the
README and the related SQL docs for
reset_package_by_oid/reset_package_by_oid_bulk to agree on one return-value
convention, and keep the wording consistent around the status-already-initial
case and what counts toward bulk reset totals.

In `@src/oracle_test/modules/test_package_reset/test_package_reset--1.0.sql`:
- Around line 18-19: The SQL comment for test_package_reset.reset_all_packages()
describes the wrong failure sentinel; update it to match the behavior in
ResetAllPackagesContext(), which returns -1 only when PL/iSQL is not loaded,
while an empty package cache should return 0. Keep the comment aligned with the
function’s actual contract by revising the “-1” wording so it no longer refers
to an uninitialized cache.

---

Nitpick comments:
In `@src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out`:
- Around line 84-108: Add an assertion in the pkg_defaults_test reset
expectations that exercises a dynamic default or init block, not just literal
defaults and NULL, so the pg_regress output verifies re-execution after reset.
Update the corresponding expected output for test_reset_defaults to include a
value from a changing expression or init-block side effect, using the existing
test_package_reset.reset_all_packages and pkg_defaults_test getters as anchors
to keep coverage aligned with the .sql test.

In `@src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql`:
- Around line 5-15: Add coverage in the pkg_defaults_test setup to assert both a
dynamic default and the package init block are re-evaluated after reset, not
just literal defaults. Update the SQL test around pkg_defaults_test by
introducing a dynamic-default-backed symbol and an initialization side effect,
then verify via the existing reset flow that the dynamic value changes and the
init block runs lazily again on first access after reset. Use the
pkg_defaults_test package and its reset-defaults test case to locate the
assertions and extend them rather than creating a separate test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e209aae6-3ef9-4ae2-9ff4-0e3633e0e0c2

📥 Commits

Reviewing files that changed from the base of the PR and between bf9871e and 1169798.

📒 Files selected for processing (20)
  • src/backend/utils/cache/packagecache.c
  • src/include/funcapi.h
  • src/include/utils/packagecache.h
  • src/oracle_test/modules/test_package_reset/.gitignore
  • src/oracle_test/modules/test_package_reset/Makefile
  • src/oracle_test/modules/test_package_reset/README
  • src/oracle_test/modules/test_package_reset/expected/test_package_reset.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_all.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_one_oid.out
  • src/oracle_test/modules/test_package_reset/sql/test_package_reset.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_all.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_one_oid.sql
  • src/oracle_test/modules/test_package_reset/test_package_reset--1.0.sql
  • src/oracle_test/modules/test_package_reset/test_package_reset.c
  • src/oracle_test/modules/test_package_reset/test_package_reset.control
  • src/pl/plisql/src/pl_package.c
  • src/pl/plisql/src/pl_package.h
  • src/pl/plisql/src/pl_subproc_function.c

Comment thread src/backend/utils/cache/packagecache.c
Comment thread src/backend/utils/cache/packagecache.c
Comment thread src/oracle_test/modules/test_package_reset/README Outdated
Comment thread src/oracle_test/modules/test_package_reset/test_package_reset--1.0.sql Outdated
@jiaoshuntian

Copy link
Copy Markdown
Collaborator

@hs-liuxh will follow up on this.

@db-nikhil db-nikhil force-pushed the db-nikhil/reset_pkg branch from 1169798 to 76b93b2 Compare June 30, 2026 16:14
@db-nikhil

Copy link
Copy Markdown
Author

Implements #1376

@sixhui

sixhui commented Jul 1, 2026

Copy link
Copy Markdown

Hi @db-nikhil, thanks for this work — the backend de-instantiation logic is a solid foundation. I'll review the code as soon as possible. For now, I have two initial suggestions:

  1. The Oracle DBMS_SESSION groundwork from Compatible with Oracle DBMS_SESSION #1369 is now in master, under contrib/ivorysql_ora/src/builtin_packages/dbms_session/ . Please complete the user-facing DBMS_SESSION.RESET_PACKAGE there.

  2. I noticed you added a test_package_reset module to exercise the new functionality. Have you considered registering it into CI(src/oracle_test/modules/Makefile & meson.build), or is it meant to be a temporary test?

@db-nikhil

Copy link
Copy Markdown
Author

Hi @sixhui

  1. The Oracle DBMS_SESSION groundwork from Compatible with Oracle DBMS_SESSION #1369 is now in master, under contrib/ivorysql_ora/src/builtin_packages/dbms_session/ . Please complete the user-facing DBMS_SESSION.RESET_PACKAGE there.

Yeah, that was the intention anyways :-), I have added this implementation in this PR now.

  1. I noticed you added a test_package_reset module to exercise the new functionality. Have you considered registering it into CI(src/oracle_test/modules/Makefile & meson.build), or is it meant to be a temporary test?

Good idea, I have registered it via meson.build changes in this PR as well now.

@db-nikhil db-nikhil force-pushed the db-nikhil/reset_pkg branch from 76b93b2 to afc9414 Compare July 3, 2026 08:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
contrib/ivorysql_ora/sql/dbms_session.sql (1)

118-153: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add coverage that RESET_PACKAGE leaves other session state untouched.

This section validates package-state reset, but doesn't verify dbms_session.reset_package() is scoped to packages only. Per PR objectives, the reset must not "impact other sessions or non-package session state." Consider setting a DBMS_SESSION application-context value before calling reset_package() and asserting it's still readable afterward.

💡 Suggested addition
+-- Verify RESET_PACKAGE does not disturb unrelated session state (application context)
+call dbms_session.set_context('rp_isolation', 'k', 'v');
+call dbms_session.reset_package();
+select sys_context('rp_isolation', 'k') as context_survives_reset;
+
 DROP PACKAGE rp_pkg;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contrib/ivorysql_ora/sql/dbms_session.sql` around lines 118 - 153, The
RESET_PACKAGE smoke test in dbms_session.sql only verifies package state, but it
should also prove non-package session state is preserved. Extend the existing
reset_package scenario by using dbms_session to set a
session/application-context value before the call and asserting it remains
readable afterward, while keeping the current rp_pkg package-state checks
intact.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@contrib/ivorysql_ora/sql/dbms_session.sql`:
- Around line 118-153: The RESET_PACKAGE smoke test in dbms_session.sql only
verifies package state, but it should also prove non-package session state is
preserved. Extend the existing reset_package scenario by using dbms_session to
set a session/application-context value before the call and asserting it remains
readable afterward, while keeping the current rp_pkg package-state checks
intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 00ebefd0-471b-4d9f-a7a5-09a9175c1dad

📥 Commits

Reviewing files that changed from the base of the PR and between 76b93b2 and afc9414.

📒 Files selected for processing (27)
  • contrib/ivorysql_ora/expected/dbms_session.out
  • contrib/ivorysql_ora/sql/dbms_session.sql
  • contrib/ivorysql_ora/src/builtin_packages/dbms_session/dbms_session--1.0.sql
  • contrib/ivorysql_ora/src/builtin_packages/dbms_session/dbms_session.c
  • src/backend/utils/cache/packagecache.c
  • src/include/funcapi.h
  • src/include/utils/packagecache.h
  • src/oracle_test/modules/Makefile
  • src/oracle_test/modules/meson.build
  • src/oracle_test/modules/test_package_reset/.gitignore
  • src/oracle_test/modules/test_package_reset/Makefile
  • src/oracle_test/modules/test_package_reset/README
  • src/oracle_test/modules/test_package_reset/expected/test_package_reset.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_all.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_one_oid.out
  • src/oracle_test/modules/test_package_reset/meson.build
  • src/oracle_test/modules/test_package_reset/sql/test_package_reset.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_all.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_one_oid.sql
  • src/oracle_test/modules/test_package_reset/test_package_reset--1.0.sql
  • src/oracle_test/modules/test_package_reset/test_package_reset.c
  • src/oracle_test/modules/test_package_reset/test_package_reset.control
  • src/pl/plisql/src/pl_package.c
  • src/pl/plisql/src/pl_package.h
  • src/pl/plisql/src/pl_subproc_function.c
✅ Files skipped from review due to trivial changes (6)
  • src/oracle_test/modules/test_package_reset/.gitignore
  • src/oracle_test/modules/Makefile
  • src/oracle_test/modules/test_package_reset/test_package_reset.control
  • src/oracle_test/modules/test_package_reset/README
  • src/include/utils/packagecache.h
  • src/oracle_test/modules/test_package_reset/expected/test_reset_all.out
🚧 Files skipped from review as they are similar to previous changes (15)
  • src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out
  • src/oracle_test/modules/test_package_reset/expected/test_reset_one_oid.out
  • src/oracle_test/modules/test_package_reset/expected/test_package_reset.out
  • src/include/funcapi.h
  • src/oracle_test/modules/test_package_reset/test_package_reset--1.0.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_one_oid.sql
  • src/oracle_test/modules/test_package_reset/sql/test_reset_all.sql
  • src/oracle_test/modules/test_package_reset/sql/test_package_reset.sql
  • src/pl/plisql/src/pl_package.h
  • src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql
  • src/oracle_test/modules/test_package_reset/test_package_reset.c
  • src/backend/utils/cache/packagecache.c
  • src/oracle_test/modules/test_package_reset/Makefile
  • src/pl/plisql/src/pl_subproc_function.c
  • src/pl/plisql/src/pl_package.c

@db-nikhil db-nikhil force-pushed the db-nikhil/reset_pkg branch from afc9414 to 63378be Compare July 6, 2026 09:59
@db-nikhil

Copy link
Copy Markdown
Author

Handled the nitpick comment from coderabbit as well.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql (1)

104-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

set_elem mutation is never independently verified.

set_elem(2, 99) at line 104 is immediately overwritten by set_arr(ARRAY[10, 20, 30, 40]) at line 105 with no intermediate SELECT. If set_elem were a no-op, the test would still pass, leaving the element-update code path untested.

Add a SELECT between the two CALL statements to verify the element mutation took effect, and update the expected output accordingly.

♻️ Proposed fix
 CALL pkg_arr_defaults.set_elem(2, 99);
+SELECT pkg_arr_defaults.get_arr_len AS len, pkg_arr_defaults.get_arr_first AS first;
 CALL pkg_arr_defaults.set_arr(ARRAY[10, 20, 30, 40]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql`
around lines 104 - 105, The pkg_arr_defaults.set_elem mutation is overwritten by
pkg_arr_defaults.set_arr before it is verified, so the element-update path is
not actually tested. Insert a SELECT of the package array state between the
set_elem and set_arr calls in test_reset_defaults.sql, using the existing
pkg_arr_defaults symbols so the mutation is asserted independently, and update
the expected output for that added verification before continuing with the array
reset.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql`:
- Around line 104-105: The pkg_arr_defaults.set_elem mutation is overwritten by
pkg_arr_defaults.set_arr before it is verified, so the element-update path is
not actually tested. Insert a SELECT of the package array state between the
set_elem and set_arr calls in test_reset_defaults.sql, using the existing
pkg_arr_defaults symbols so the mutation is asserted independently, and update
the expected output for that added verification before continuing with the array
reset.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3f6b3e22-4589-466c-95b4-974c1c6763ab

📥 Commits

Reviewing files that changed from the base of the PR and between 63378be and f3f937e.

📒 Files selected for processing (2)
  • src/oracle_test/modules/test_package_reset/expected/test_reset_defaults.out
  • src/oracle_test/modules/test_package_reset/sql/test_reset_defaults.sql

@hs-liuxh

hs-liuxh commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Hi @db-nikhil, I've found a memory deallocation bug in the package-reset path (src/pl/plisql/src/pl_package.c, the PLISQL_DTYPE_VAR branch, ~line 3745).

Array-typed package globals fall into the PLISQL_DTYPE_VAR case and are freed using pfree. However, since Array-typed package globals become expanded objects once assigned, they should be released via DeleteExpandedObject. The adjacent PLISQL_DTYPE_REC branch already does exactly this (DeleteExpandedObject), so the VAR branch just needs the same treatment.

I've also pushed a test case to verify this. Compiling with the --enable-cassert flag during ./configure is highly recommended for this new test case.

Could you please fix this issue?

Note that I pushed a commit adding a regression test — please git pull before amending so it isn't overwritten.

Reset a single PL/iSQL package by OID (Oracle DBMS_SESSION.RESET_PACKAGE
semantics): close refcursors, free variable memory, reset mutable globals,
and mark the package as uninitialized (PLISQL_PACKAGE_NO_INIT) so that
the full init sequence — default expressions re-evaluated and init block
re-executed — runs lazily on next access.

This lazy re-init is spec-compliant: dynamic defaults (SYSDATE,
seq.NEXTVAL, cross-package function calls) are re-evaluated at
re-init time, not frozen at reset time.  A snapshot/restore approach
would have captured stale values; NO_INIT delegates everything to the
existing lazy-init path in plisql_check_package_status.

ResetAllPackagesContext uses a two-phase approach (collect via
PackageCacheListItems, then reset each) to avoid hash iterator corruption
during modification.

Both APIs are exposed via the rendezvous mechanism
(plisql_internal_funcs.package_reset_context) so the PL/iSQL layer does
not need to access the PackageCache hash directly.  Invalid OIDs trigger
ERROR; NULL OIDs are short-circuited by the STRICT function attribute.

ResetPackageContext returns bool: true if package was reset, false if
nothing to do (status too low).

ResetAllPackagesContext returns int: count of packages actually reset,
or -1 if PL/iSQL is unavailable (rendezvous function pointer is NULL).

Also add DBMS_SESSION.RESET_PACKAGE and register test_package_reset in CI

Test extension test_package_reset provides:
  - reset_package_by_oid(oid) -> bool
  - reset_all_packages() -> int4

Five test scenarios:
  - test_package_reset: extension loads; reset_all returns -1 when PL/iSQL
    unavailable; reset_package_by_oid(0) throws ERROR
  - test_reset_one_oid: reset each of 3 packages by OID individually,
    siblings untouched; loop reset each individually; NULL OID short-
    circuits to NULL with no side effects
  - test_reset_all: reset all -> init one -> get all -> reset all ->
    get all -> init all -> get all -> reset all -> get all
  - test_reset_defaults: package with default 42, no-default, and text
    default; verify mutation then reset restores defaults (lazy re-init)

Rendezvous field: bool (*)(Oid) in PLiSQL_funcs_call and PLiSQL_plugin.
PackageCacheListItems is static (no external callers).

Spec reference: Oracle 21c DBMS_SESSION.RESET_PACKAGE — session-only
effect, does not affect other sessions.  Defaults are re-evaluated
(§2.1: 'Default values for package variables are re-initialized'),
init block re-executed (§2.3: 'The INITIALIZATION section runs once
per session; RESET_PACKAGE forces re-execution'), re-instantiation
is lazy (§4.2: 'Re-instantiation occurs when next referenced').

Authored-by: Cedric Villemain <cedric.villemain@data-bene.io>
Co-authored-by: Nikhil <nikhil@data-bene.io>
@db-nikhil db-nikhil force-pushed the db-nikhil/reset_pkg branch from f3f937e to 2bd694f Compare July 8, 2026 09:47
@db-nikhil

Copy link
Copy Markdown
Author

Hi @hs-liuxh

Hi @db-nikhil, I've found a memory deallocation bug in the package-reset path (src/pl/plisql/src/pl_package.c, the PLISQL_DTYPE_VAR branch, ~line 3745).

Array-typed package globals fall into the PLISQL_DTYPE_VAR case and are freed using pfree. However, since Array-typed package globals become expanded objects once assigned, they should be released via DeleteExpandedObject. The adjacent PLISQL_DTYPE_REC branch already does exactly this (DeleteExpandedObject), so the VAR branch just needs the same treatment.

I've also pushed a test case to verify this. Compiling with the --enable-cassert flag during ./configure is highly recommended for this new test case.

Could you please fix this issue?

Thanks for the report! I missed using the same logic for VAR. And yes, I always configure with --enable-cassert in my compiles :-)

Note that I pushed a commit adding a regression test — please git pull before amending so it isn't overwritten.

Ok, thanks for the test. I have amended my commit to include your test changes along with the relevant fixes.

@hs-liuxh hs-liuxh self-assigned this Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement RESET_PACKAGE semantics

4 participants