Executing VACUUM by non-owner user
The documentation aboutVACUUM
clearly states it:
To vacuum a table, one must ordinarily be the table's owner or a superuser.
However, database owners are allowed to vacuum all tables in their databases,
except shared catalogs.
[...]
VACUUM cannot be executed inside a transaction block.
VACUUM
, that means you cannot GRANT
someone else to execute VACUUM
.
Period.
Therefore there is no escape: in order to run
VACUUM
you must to be either (i) the object owner or (ii) the database owner or,as you can imagine, (iii) one of the cluster superuser(s).
Why am I insisting on this? Because some friends of mine argued that it is always possible to escape restrictions with functions an
SECURITY DEFINER
options. In this particular case, one could think to define a function that executes VACUUM
, then apply the SECURITY DEFINER
option so that the function will run as the object owner, and then provide (i.e., GRANT
) execution permission to a normal user.
WRONG!
The fact that
VACUUM
cannot be executed within a transaction block means you cannot use such an approach, because a function is executed within a transaction block.
And if now you are asking yourself why
VACUUM
cannot be wrapped in a transaction block, just explain me how to ROLLBACK
a VACUUM
execution, it will be an interesting and fantasyland explaination!
So, what is going to happen if you define a
VACUUM
-function?
Let’s quickly see what the database does:
CREATE OR REPLACE FUNCTION
do_vacuum( t text )
RETURNS VOID
AS $$
BEGIN
EXECUTE 'VACUUM FULL VERBOSE '
|| quote_ident( t );
END
$$
LANGUAGE plpgsql;
VACUUM
cannot be invoked by a function (have I already written this?):
testdb=> select do_vacuum( 'foo' );
ERROR: VACUUM cannot be executed from a function
CONTEXT: SQL statement "VACUUM FULL VERBOSE foo"
PL/pgSQL function do_vacuum(text) line 3 at EXECUTE
VACUUM
cannot be invoked by a function (have I already written this?):
testdb=> CREATE OR REPLACE PROCEDURE
do_vacuum( t text )
AS $$
BEGIN
EXECUTE 'VACUUM FULL VERBOSE '
|| quote_ident( t );
END
$$
LANGUAGE plpgsql;
CREATE PROCEDURE
testdb=> CALL do_vacuum( 'foo' );
ERROR: VACUUM cannot be executed from a function
CONTEXT: SQL statement "VACUUM FULL VERBOSE foo"
PL/pgSQL function do_vacuum(text) line 3 at EXECUTE
Conclusions
VACUUM
cannot be wrapped in a transaction nor a routine, therefore in order to execute it you must be a “special” user, with special simply meaning the owner, or the database owner, or a superuser.