Skip to content

[BUG] Oracle: eager full-owner getSchema() on connect freezes the UI on large schemas (no lazy/paged introspection) #765

Description

@ket000

Description

On Oracle connections, LibreDB Studio eagerly introspects the entire schema owned by the connecting user in a single getSchema() call the moment the connection opens. There is no lazy/paged (two-phase) loading, so when the connecting user owns a very large catalog (e.g. a PeopleSoft SYSADM schema with tens of thousands of tables/columns/indexes/constraints), the UI freezes/becomes unresponsive for an extended period while the scan runs. It eventually completes, but the app is unusable during the scan, and the default container heap (--max-old-space-size=384) makes it worse.

Steps to Reproduce

Deploy the container: wslc run --rm -it -p 3000:3000 … libredb-studio:latest (Docker-equivalent).
Add an Oracle connection whose user owns a very large schema (e.g. PeopleSoft SYSADM, ~tens of thousands of tables).
Open/select that connection — it begins "scanning schema".
Observe the UI (browser tab) hang and become unresponsive; it recovers only after a long delay.

Expected Behavior

Schema browsing should be lazy/two-phase: load the table list first, then fetch columns/PKs/FKs/indexes per table on expand (or in bounded batches), and/or provide an option to limit/defer introspection (name filter, max objects, allowlist). Opening a connection to a large owner schema should not block the UI.

Actual Behavior

getSchema() runs 5 bulk ALL_* queries filtered by OWNER = (tables, columns, primary keys, foreign keys, indexes), grouped in memory, for the whole owner at once, on connect. Per the Oracle provider doc (§3.3 / §7 and "Known limitations"): "No two-phase schema loading — /api/db/schema/list falls back to the full getSchema()." For a large owner the result set is huge, exhausts the Node heap (only mitigated by raising --max-old-space-size far above the 384 MB image default), and blocks rendering. It is also re-triggered on any DDL matching schemaRefreshPattern (CREATE|DROP|ALTER|TRUNCATE).

Screenshots

N/A (UI is frozen during the scan; can add a screen recording of the hang on request).

Environment

Please provide the following information:

LibreDB Studio Version: 0.15.0 (image ghcr.io/libredb/libredb-studio:latest, digest sha256:2c9a48047f85…)
Browser: Chrome (latest)
OS: Windows 11 host; container base Debian GNU/Linux 13 (trixie), glibc 2.41
Node.js/Bun Version: Node.js 26.8.1 (image runtime; NODE_OPTIONS=--max-old-space-size=384 by default)
Database Type: Oracle (PeopleSoft), oracledb driver in Thick mode (Instant Client 23.5; required because the server enforces Native Network Encryption — ORACLE_CLIENT_LIB_DIR + LD_LIBRARY_PATH set)
Database Version: Oracle Database 19c (PDB)

Additional Context

The scan cost is proportional to how many objects the connecting user owns (OWNER = USER). Connecting as a small-owner account is fast; connecting as SYSADM (owns the whole PeopleSoft catalog) triggers the freeze.
Common for enterprise Oracle schemas (PeopleSoft, EBS, etc.).
The 384 MB default heap compounds the problem; users must discover and override NODE_OPTIONS.
Workarounds: (1) raise NODE_OPTIONS=--max-old-space-size=4096 (container had ~15 GB free; 384 MB is far too low); (2) connect as a low-object user and reference big schemas by qualified name (SELECT * FROM SYSADM.PS_JOB …) instead of expanding the tree — avoids the mass scan but loses object-browser visibility.
Possibly-related (may warrant separate issues): NUMBER returned as JS double loses precision (NUMBER(38,0) → 1.23…e+37), significant for PeopleSoft ID/sequence columns; and there is no server-side query timeout.

Possible Solution

Implement two-phase/lazy schema loading for Oracle: fetch the table list first (ALL_TABLES WHERE OWNER = :u), then columns/PKs/FKs/indexes per table on expand or in bounded batches.
Add an optional introspection limit/filter (name prefix, max object count, or schema/table allowlist).
Raise the image's default heap and/or prominently document the large-schema NODE_OPTIONS requirement in the Oracle provider doc.
Wire connection.callTimeout (already noted as future work) so a slow introspection can be bounded rather than hanging.

Logs

[INFO ] {route=seed/config-loader, connectionCount=1} Seed config loaded
[DB] Creating sqlite provider for "Sample (Employees)"
… extended unresponsive period here while Oracle getSchema() runs 5 ALL_* queries over a large OWNER (e.g. SYSADM) …

Paste logs here

Measured on the affected DB, the connecting owner (SYSADM, PeopleSoft) holds ~43.5K tables, ~910K columns, ~49.8K indexes, and ~633K constraints. On connect, getSchema() pulls all of these in five bulk ALL_* queries in one pass and groups them in memory — roughly 1.6M+ rows materialized and serialized before the UI can render, which is what causes the multi-second-to-minutes freeze. A lazy/two-phase load (table list first, per-table detail on expand) would avoid materializing ~910K column rows up front.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcore-capabilitiesloop:needs-moderator-actionFlagged by the maintainer loop: suspicious content or a decision only a human can makesecuritySupply-chain, auth, or hardening work

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions