Thank you for the detailed feedback, Amit.

You're right on both points. I had been comparing STATISTICS against INDEX
and treating the difference as an inconsistency, but as you point out,
INDEX ownership is special — it's tied to the table and intentionally not
user-adjustable. STATISTICS follows the same ownership model as VIEW (the
creator becomes the owner), which is consistent and by design.

I also verified locally that my reproduction script was flawed: the
"must be owner" error was caused by a schema search path issue, not an
ownership restriction. The script did not demonstrate what I claimed.

I'm withdrawing this proposal. Thanks again for taking the time to review
it.

On Tue, Mar 10, 2026 at 11:07 PM Amit Khandekar <[email protected]>
wrote:

> On Sat, 14 Feb 2026 at 14:18, Shin Berg <[email protected]> wrote:
> >
> > Hi,
> >
> > I'd like to raise a small consistency issue between how INDEX and
> extended STATISTICS handle object ownership, and ask whether aligning them
> would be desirable.
> >
> > Current behavior (tested on REL_17_STABLE):
> >
> > - When a superuser creates an INDEX on another user's table, the index
> is owned by the *table owner* (see catalog/index.c: index relation's
> relowner is set from the heap relation's relowner).
> > - When a superuser creates STATISTICS on another user's table, the
> statistics object is owned by the *current user* (statscmds.c: stxowner =
> GetUserId()).
>
> I will try to divide the problem into two questions:
>
> 1. Should the statistics object's owner be permanently associated with
> the table owner?
>
> From the docs, it does look like the current behaviour is intentional.
>
> https://www.postgresql.org/docs/current/sql-createstatistics.html :
> "You must be the owner of a table to create a statistics object
> reading it. Once created, however, the ownership of the statistics
> object is independent of the underlying table(s)."
>
> So I think we should not change the behaviour where the statistics
> object is created with independent ownership.
>
> With indexes, the behaviour has always been that it is associated with
> the table:
>
> postgres=# alter INDEX shared_schema.idx_bob owner to bob1;
> WARNING:  cannot change owner of index "idx_bob"
> HINT:  Change the ownership of the index's table instead.
>
> 2. Regardless of that, should the "create statistics" create the stat
> object with the same ownership as the table's, if it's the superuser
> who is creating the statistics?
>
> I think, since there is no permanent association of ownership between
> the table and the statistics, it makes sense for the user who is
> running the create command to own the statistics, regardless of who
> the user is, provided that the user has privileges.
>
> >
> > So in a scenario where a DBA creates both an index and extended
> statistics on a user's table, the table owner can DROP the index (because
> they own it) but cannot DROP the statistics object (they get "does not
> exist" when lacking ownership, which hides the real permission issue).
>
> The permission error should be emitted if the DROP is on the right
> schema. See below.
>
> > That can cause operational friction in multi-tenant or shared-schema
> setups (e.g. the table owner cannot drop the statistics to resolve
> dependency issues before altering the table).
>
> Maybe, make sure the table owner (and not the superuser) is creating
> the statistics?
>
> >
> > Reproduction (as superuser, then as table owner):
> >
> >   CREATE SCHEMA shared_schema;
> >   CREATE USER bob;
> >   GRANT USAGE, CREATE ON SCHEMA shared_schema TO bob;
> >
> >   SET ROLE bob;
> >   CREATE TABLE shared_schema.bob_table (a int, b int);
> >   RESET ROLE;
> >
> >   CREATE INDEX idx_bob ON shared_schema.bob_table(a);
> >   CREATE STATISTICS stat_bob ON a, b FROM shared_schema.bob_table;
> >
> >   SELECT 'INDEX', c.relname, pg_get_userbyid(c.relowner) FROM pg_index i
> >     JOIN pg_class c ON c.oid = i.indexrelid
> >     WHERE indrelid = 'shared_schema.bob_table'::regclass
> >   UNION ALL
> >   SELECT 'STATISTICS', stxname, pg_get_userbyid(stxowner) FROM
> pg_statistic_ext
> >     WHERE stxrelid = 'shared_schema.bob_table'::regclass;
> >   -- INDEX owner = bob, STATISTICS owner = superuser
> >
> >   SET ROLE bob;
> >   DROP INDEX shared_schema.idx_bob;        -- succeeds
> >   DROP STATISTICS shared_schema.stat_bob;  -- ERROR: statistics object
> "..." does not exist
>
> The statistics object is created in the default schema, not the table's
> schema.
> postgres=>   DROP STATISTICS public.stat_bob;
> ERROR:  must be owner of statistics object public.stat_bob
>
> Thanks
> -Amit Khandekar
>

Reply via email to