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) …
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.
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) …
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.