This can be done.
The column default for your serial
primary key is typically defined as:
ALTER TABLE schema_a.tbl ALTER COLUMN tbl_id
SET DEFAULT nextval('schema_a.tbl_tbl_id_seq'::regclass);
Two options:
1. Move sequence (my preference)
to the public
schema - or any schema with sufficient privileges:
GRANT USAGE ON SCHEMA public TO public; -- or: my_group
Moving the sequence to another schema is easy:
ALTER SEQUENCE schema_a.tbl_tbl_id_seq SET SCHEMA public;
Now you can grant USAGE
:
GRANT USAGE ON SEQUENCE public.tbl_tbl_id_seq TO public; -- or: my_group
That preserves all references (incl. column defaults).
2. Function wrapper with SECURITY DEFINER
If you cannot move the sequence for some reason (can't think of one), you can alternatively wrap access to it in functions of your own with SECURITY DEFINER
. Again, create those functions in the public
schema (or any schema with sufficient privileges for your users):
CREATE OR REPLACE FUNCTION public.next_tbl_tbl_id_seq()
RETURNS bigint AS
$func$
SELECT nextval('schema_a.tbl_tbl_id_seq'::regclass)
$func$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = schema_a, pg_temp;
ALTER FUNCTION shop.f_deswap_name(text) OWNER TO owning_role;
Where owning_role
is the owner of the sequence or any role with sufficient privileges. Similar function for currval()
...
Be sure to read the chapter "Writing SECURITY DEFINER Functions Safely" in the manual.
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.
Best Answer
Internally, a view is just a table with a rule, so this makes sense.
See here: https://postgresql.org/docs/9.5/static/rules-views.html