Skip to content

Publications: schema names containing dots are parsed incorrectly, breaking ALTER PUBLICATION #1089

Description

@Tr00d

Describe the bug

When creating or updating a publication with tables belonging to a schema whose name contains dots (e.g. "NextWare.Concierge.ConciergeServices"), postgres-meta constructs an invalid table identifier and the resulting SQL fails with:

relation "NextWare.Concierge.ConciergeServices.outbox" does not exist

Root cause

In PostgresMetaPublications.ts, both create and update parse the schema.table string by splitting on the first .:

const [schema, ...rest] = t.split('.')
const table = rest.join('.')
return `${ident(schema)}.${ident(table)}`

For a table passed as "NextWare.Concierge.ConciergeServices.outbox" this produces:

  • schema = "NextWare"
  • table = "Concierge.ConciergeServices.outbox"

Which generates "NextWare"."Concierge.ConciergeServices.outbox" instead of "NextWare.Concierge.ConciergeServices"."outbox".

PostgreSQL itself handles dot-schema names correctly when they are double-quoted (CREATE SCHEMA "parent.child" is valid), so this is not a PostgreSQL limitation — it's a parsing issue in this library.

To reproduce

CREATE SCHEMA "NextWare.Concierge.ConciergeServices";
CREATE TABLE "NextWare.Concierge.ConciergeServices".outbox (id serial primary key);

Then attempt to add that table to a publication via the Supabase dashboard or the pg-meta API.

Expected behavior

The SQL generated should be:

ALTER PUBLICATION my_pub ADD TABLE "NextWare.Concierge.ConciergeServices"."outbox"

Actual behavior

The SQL generated is:

ALTER PUBLICATION my_pub ADD TABLE "NextWare"."Concierge.ConciergeServices.outbox"
-- ERROR: relation "NextWare"."Concierge.ConciergeServices.outbox" does not exist

Proposed fix

The tables parameter currently uses a schema.table dotted string convention, which is ambiguous when schema names can contain dots. The cleanest fix without a breaking change would be to extend the accepted format to also allow { schema: string; table: string } objects:

tables?: (string | { schema: string; table: string })[] | null

And in the mapping:

.map((t) => {
  if (typeof t === 'object') {
    return `${ident(t.schema)}.${ident(t.table)}`
  }
  // existing string-splitting logic for backwards compatibility
  ...
})

The dashboard (and other callers) could then pass schema and table as separate fields, removing the ambiguity entirely.

Related

  • Reported downstream in supabase-community/realtime-csharp#46 — closed as "upstream limitation" but no upstream issue was ever filed.
  • The Realtime server itself handles dot-schema names correctly (it matches on pub.schemaname directly and uses format('%I.%I', ...) for quoting), so fixing this library is sufficient to unblock the full flow.

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