DBMS_RANDOM package design
1. Goals and scope
DBMS_RANDOM provides Oracle-style random number and string interfaces in the ivorysql_ora extension: INITIALIZE, SEED, TERMINATE, NORMAL, RANDOM, STRING, and VALUE. The implementation aims to preserve the package interface and common behavior while allowing seeded sequences to be replayed within IvorySQL. Because the underlying generator differs from Oracle’s, the sequences are not guaranteed to match across databases.
2. Code organization
| File | Responsibility |
|---|---|
|
Seed handling, value generation, and state reset |
|
C function registration in |
|
Regression tests and expected output |
|
Build and installation registration |
|
Integration of package state reset with extension hooks |
These paths are relative to contrib/ivorysql_ora/.
3. Call path
The SQL registration file creates sys.ora_dbms_random_* C functions and declares the Oracle-style interface with CREATE OR REPLACE PACKAGE dbms_random AUTHID CURRENT_USER. The package body calls the corresponding sys functions. GRANT EXECUTE ON PACKAGE dbms_random TO PUBLIC allows ordinary users to invoke the package.
dbms_random.value(10, 20)
→ PL/iSQL package body
→ sys.ora_dbms_random_value_range(NUMBER, NUMBER)
→ C implementation and session generator state
All registered C functions are marked VOLATILE. The numeric and text seed entry points are marked STRICT, so NULL seeds never reach the C conversion functions. STRING and the two-argument VALUE are not marked STRICT; their C implementations handle NULL arguments.
4. Generator state and seeding
The C module stores a static pg_prng_state and a state_seeded flag, isolating the sequence within each backend session. On first use, ensure_seeded() combines the current timestamp and backend process ID to form a seed. Calling INITIALIZE or SEED explicitly replaces the current state.
Numeric seeds are converted through numeric_int8 to 64-bit integers and passed to pg_prng_seed(); INITIALIZE and numeric SEED share this logic. Text seeds are hashed to 64 bits with hash_any_extended() and passed to pg_prng_seed(). The same seed and call order replay a sequence within IvorySQL. The implementation does not promise a bit-for-bit match with Oracle’s proprietary generator.
TERMINATE is a no-op retained for compatibility with legacy calls. The extension hooks for DISCARD ALL and DISCARD PACKAGES call ora_dbms_random_reset() to clear the seeded flag. The next random call seeds the generator automatically again.
5. Subprogram implementation
| Subprogram | Implementation |
|---|---|
|
Obtains a value from |
|
Uses |
|
Uses |
|
Keeps the bounds as |
|
Selects a character set, generates an index for each character, and joins the characters |
When the two VALUE bounds are equal, the function returns the bound without consuming a random value. Reversed bounds produce a result in (high, low]. A NULL bound returns NULL. Regression tests cover these cases.
STRING supports U (uppercase letters), L (lowercase letters), A (mixed-case letters), X (uppercase letters and digits), and P (printable characters), case-insensitively. NULL, empty, and unknown single-character options fall back to U; a multi-character option raises an error. The length is truncated to an integer: zero or less returns NULL, values above 4000 are capped at 4000, and a NULL length raises an error.
6. Regression coverage
sql/dbms_random.sql covers numeric and text seeds, replayed sequences, the RANDOM range, NORMAL, STRING character classes and lengths, forward/reversed/equal VALUE bounds, large numeric bounds, TERMINATE, and state after DISCARD ALL. Seeded tests assert exact results; auto-seeded tests check only range or availability.