Skip to content

Fatal error on EDB Postgres (EPAS): has_schema_privilege crashes due to client-side schema filtering in InspectStage2 #765

@bartfaizoli76

Description

@bartfaizoli76

Describe the bug
When running ldap2pg (v6.5.1) against EnterpriseDB Postgres Advanced Server (EPAS versions 15, 16, 17, and 18), the synchronization fails with a fatal error during the schema inspection phase (Stage 2), even if schemas_query is strictly limited to [public].

time=2026-03-06T18:47:15.853Z level=DEBUG msg="Inspecting managed schemas." config=schemas_query database=postgres time=2026-03-06T18:47:15.853Z level=DEBUG msg="Reading values from YAML." time=2026-03-06T18:47:15.853Z level=DEBUG msg="Executing SQL query:\nSELECT nspname, rolname\nFROM pg_catalog.pg_namespace\nJOIN pg_catalog.pg_roles ON pg_catalog.pg_roles.oid = nspowner\n-- Ensure ldap2pg can use.\nWHERE has_schema_privilege(CURRENT_USER, nspname, 'USAGE')\nORDER BY 1;\n" time=2026-03-06T18:47:15.855Z level=ERROR msg="Fatal error." err="inspect: schemas: ERROR: schema \"dbms_alert\" does not exist (SQLSTATE 3F000)"

To Reproduce
Steps to reproduce the behavior:

  • Provision an EDB Postgres Advanced Server cluster (e.g., using CloudNativePG with edb-postgres-advanced:18.1-standard-ubi9 image).
  • Configure ldap2pg.yml to only manage the public schema (schemas_query: [public]).
  • Run ldap2pg.
  • It crashes immediately on dbms_alert, dbms_assert, aq$_agent, or any other EDB proprietary package.

Root Cause Analysis
We did some reverse engineering and found the exact bottleneck.
EPAS achieves Oracle compatibility by injecting proprietary PL/SQL packages (like dbms_alert, utl_file, aq$_agent) directly into pg_catalog.pg_namespace using a custom nspbodysrc column filled with '$EDBwrapped$' binaries.

In internal/inspect/stage2.go, ldap2pg fetches the managedSchemas from the YAML configuration into a Go slice. However, it then executes the hardcoded query from internal/inspect/sql/schemas.sql across the entire pg_namespace table:
SELECT nspname, rolname FROM pg_catalog.pg_namespace JOIN pg_catalog.pg_roles ON pg_catalog.pg_roles.oid = nspowner -- Ensure ldap2pg can use. WHERE has_schema_privilege(CURRENT_USER, nspname, 'USAGE') ORDER BY 1;

When the built-in Postgres C-function has_schema_privilege() evaluates these EDB package/schema hybrids, it cannot resolve them as standard schemas and throws a fatal transaction error (schema "dbms_alert" does not exist), crashing the whole query.
Because ldap2pg relies on client-side filtering (filtering the sq.Row() against managedSchemas slice after the query execution in Go), the query itself never survives the execution on an EPAS cluster.

Proposed Solution
Please consider changing the schema inspection logic to use server-side filtering.
If the managedSchemas list is passed to the schemas.sql query as an argument (e.g., AND nspname = ANY($1)), Postgres will filter the rows before evaluating has_schema_privilege().
This would prevent the C-function from touching unmanaged/proprietary schemas, making ldap2pg fully compatible with EDB Postgres Advanced Server and improving performance on standard Postgres instances with many schemas.

Current Workaround
Currently, the only way to make ldap2pg work on EPAS is to manually execute CREATE SCHEMA IF NOT EXISTS ... for all ~60 proprietary EDB objects (dbms_%, utl_%, aq$_%, etc.) so that has_schema_privilege evaluates them as physical schemas without crashing.

Environment:

  • PostgreSQL version: EDB Postgres Advanced Server (EPAS) 15.15, 17.9, 18.1
  • ldap2pg version: 6.5.1
  • OS: Kubernetes / CloudNativePG

Thank you for this amazing tool, hoping this edge-case can be fixed in a future release!
Zoli

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions