The error is harmless but to get rid of it, I think you need to break this restore into two commands, as in:
dropdb -U postgres mydb && \
pg_restore --create --dbname=postgres --username=postgres pg_backup.dump
The --clean
option in pg_restore doesn't look like much but actually raises non-trivial problems.
For versions up to 9.1
The combination of --create
and --clean
in pg_restore options used to be an error in older PG versions (up to 9.1). There is indeed some contradiction between (quoting the 9.1 manpage):
--clean
Clean (drop) database objects before recreating them
and
--create
Create the database before restoring into it.
Because what's the point of cleaning inside a brand-new database?
Starting from version 9.2
The combination is now accepted and the doc says this (quoting the 9.3 manpage):
--clean
Clean (drop) database objects before recreating them. (This might generate some harmless error messages, if any objects were not present in the destination database.)
--create
Create the database before restoring into it. If --clean is also specified, drop and recreate the target database before connecting to it.
Now having both together leads to this kind of sequence during your restore:
DROP DATABASE mydb;
...
CREATE DATABASE mydb WITH TEMPLATE = template0... [other options]
...
CREATE SCHEMA public;
...
CREATE TABLE...
There is no DROP
for each individual object, only a DROP DATABASE
at the beginning. If not using --create
this would be the opposite.
Anyway this sequence raises the error of public
schema already existing because creating mydb
from template0
has imported it already (which is normal, it's the point of a template database).
I'm not sure why this case is not handled automatically by pg_restore
. Maybe this would cause undesirable side-effects when an admin decides to customize template0
and/or change the purpose of public
, even if we're not supposed to do that.
What you had originally was a correct syntax - for tables, not for schemas. As you did not have a table (dubbed 'relation' in the error message), it threw the not-found error.
I see you've already noticed this - I believe there is no better way of learning than to fix our own mistakes ;)
But there is something more. What you are doing above is too much on one hand, and not enough on the other.
Running the script, you
- create a schema
- create a role
- grant
SELECT
on all tables in the schema created in (1.) to this new role_
- and, finally, grant all privileges (
CREATE
and USAGE
) on the new schema to the new role
The problem lies within point (3.) You granted privileges on tables in replays
- but there are no tables in there! There might be some in the future, but at this point the schema is completely empty. This way, the GRANT
in (3.) does nothing - this way you are doing too much.
But what about the future tables?
There is a command for covering them: ALTER DEFAULT PRIVILEGES
. It applies not only to tables, but:
Currently [as of 9.4], only the privileges for tables (including views and foreign tables), sequences, functions, and types (including domains) can be altered.
There is one important limitation, too:
You can change default privileges only for objects that will be created by yourself or by roles that you are a member of.
This means that a table created by alice
, who is neither you nor a role than you are a member of (can be checked, for example, by using \du
in psql
), will not take the prescribed access rights. The optional FOR ROLE
clause is used for specifying the 'table creator' role you are a member of. In many cases, this implies it is a good idea to create all database objects using the same role - like mydatabase_owner
.
A small example to show this at work:
CREATE ROLE test_owner; -- cannot log in
CREATE SCHEMA replays AUTHORIZATION test_owner;
GRANT ALL ON SCHEMA replays TO test_owner;
SET ROLE TO test_owner; -- here we change the context,
-- so that the next statement is issued as the owner role
ALTER DEFAULT PRIVILEGES IN SCHEMA replays GRANT SELECT ON TABLES TO alice;
CREATE TABLE replays.replayer (r_id serial PRIMARY KEY);
RESET ROLE; -- changing the context back to the original role
CREATE TABLE replays.replay_event (re_id serial PRIMARY KEY);
-- and now compare the two
\dp replays.replayer
Access privileges
Schema │ Name │ Type │ Access privileges │ Column access privileges
─────────┼──────────┼───────┼───────────────────────────────┼──────────────────────────
replays │ replayer │ table │ alice=r/test_owner ↵│
│ │ │ test_owner=arwdDxt/test_owner │
\dp replays.replay_event
Access privileges
Schema │ Name │ Type │ Access privileges │ Column access privileges
─────────┼──────────────┼───────┼───────────────────┼──────────────────────────
replays │ replay_event │ table │ │
As you can see, alice
has no explicit rights on the latter table. (In this case, she can still SELECT
from the table, being a member of the public
pseudorole, but I didn't want to clutter the example by revoking the rights from public
.)
Best Answer
You need to first connect to the database that you need to check the stats from, and in that do the create extension, after which the query should work ;)