Hi, Following up on my earlier proposal — I've gone ahead and written a patch rather than waiting for feedback.
The fix is in CreateStatistics(): after opening the relation, stxowner is set to rel->rd_rel->relowner instead of GetUserId(). The permission check is left using GetUserId() so that only the relation owner (or a superuser) can create statistics, but the ownership recorded in pg_statistic_ext now matches what CREATE INDEX does. A regression test is included in stats_ext.sql to verify that the statistics owner equals the table owner when a superuser creates the statistics object. Patch attached. Thanks, Joshua-Shin On Thu, Feb 26, 2026 at 6:52 PM Shin Berg <[email protected]> wrote: > Gentle ping on this thread — any thoughts or concerns about the > proposed alignment? > > Thanks. > > On Sat, Feb 14, 2026 at 5:48 PM 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()). >> >> 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). 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). >> >> 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 >> >> I'm not sure if the current STATISTICS ownership behavior was >> intentional. If it wasn't, would it make sense to assign the statistics >> object's owner to the relation owner (same as INDEX) for consistency and to >> avoid the above scenario? >> >> Thanks for your time. >> >
0001-Make-CREATE-STATISTICS-assign-ownership-to-the-relat.patch
Description: Binary data
