How to login to postgreSQL at the top level? - postgresql

I have Postgres 9.6 installed on mac os. When I enter the command:
$ psql (it takes me to below prompt)
bar=#
bar=# \conninfo
You are connected to database "bar" as user "bar" via socket in "/tmp" at port "5432".
How do I get out of database bar and be at the top level so that when I enter command:
CREATE DATABASE postgis_in_action;
CREATE SCHEMA ch07;
CREATE TABLE ch07.bag_o_rasters(rid serial primary key, rast_name text, rast raster);
database postgis_in_action will be created and within this database ch07 schema will be created and not nested inside database "bar" and the table will be created within ch07 schema under postgis_in_action database?

After creating the new database you need to switch to it. Otherwise the create schema will be run in the database to which you initially connected. In psql you can do that using \connect
bar=# CREATE DATABASE postgis_in_action;
bar=# \connect postgis_in_action
You are now connected to database "postgis_in_action" as user "postgres".
CREATE SCHEMA ch07;
CREATE TABLE ch07.bag_o_rasters(rid serial primary key, rast_name text, rast raster);
I would strongly recommend you create a regular user to do your work. Do not do everything as the superuser. E.g.:
bar=# create user ace password '*******';
bar=# create CREATE DATABASE postgis_in_action owner ace;
\connect postgis_in_action ace
Password for user ace:
You are now connected to database "postgis_in_action" as user "ace".
postgis_in_action=>

Maybe you have an experience with other databases, but this is the Postgres. Schemas are nested in databases, and you cannot to connect to schema (in Postgres). If you want create the database, then you use CREATE DATABASE ch07 instead CREATE SCHEMA ch06.
Instance (Postgres Cluster)
|
v
-------------------- ...
| |
v v
Database1 Database2
|
----------------------- ...
| | |
v v v
public schema1 schema2
|
----------------------- ...
| | |
v v v
table1 table2 table3
In this case the Postgres is similar to MS SQL, and very different to Oracle. Schema in Postgres and Oracle are different things.
When you connect to Postgres, then you have to specify target database. You cannot to connect just to server, or you cannot to connect to schema. Schemas (in Postgres) are like directories. You can specify an order of searching of schemas. You can set SEARCH_PATH per connect, per user or in an session (it is analogy of PATH in MS Win or UNIX).

Related

Setting privileges on foreign table on Postgres

How do foreign table privileges work? A simple example where both source_db and destination_db are Postgres databases.
source_db:
-- create user for user mapping
CREATE USER fdw_user WITH PASSWORD 'secret';
-- create table
CREATE TABLE data (value TEXT);
-- set privileges
GRANT ALL ON TABLE data TO fdw_user;
destination_db:
-- create extension
CREATE EXTENSION postgres_fdw;
-- create server
CREATE SERVER remote_source
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'source.domain.com', dbname 'source_db');
-- create user mapping
CREATE USER MAPPING
FOR PUBLIC
SERVER remote_source
OPTIONS (user 'fdw_user', password 'secret');
-- create foreign table
CREATE FOREIGN TABLE data_from_source(value TEXT)
SERVER remote_source
OPTIONS (table_name 'data');
Now setting privileges for any user in destination_db seems to have no effect, like
GRANT SELECT ON TABLE data_from_source TO localuser;
How can I set privileges on foreign table?
The problem was PgAdmin III. ACL of foreign table changed but PgAdmin did not show it. Psql on command line \dp+ data_from_source shows the ACL as expected.

Granting local user permissions to a foreign db table in postgres

I set up a connection to a foreign db using dblink_connect according to the docs:
CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw OPTIONS (hostaddr '127.0.0.1', dbname 'foreign_test_db');
CREATE USER test_user WITH PASSWORD 'secret';
CREATE USER MAPPING FOR test_user SERVER fdtest OPTIONS (user 'test_user', password 'secret');
GRANT USAGE ON FOREIGN SERVER fdtest TO regress_dblink_user;
GRANT SELECT ON TABLE foo TO test_user;
\c - regress_dblink_user
SELECT dblink_connect('myconn', 'fdtest');
SELECT * FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
The final 'GRANT SELECT' appears to infer that if it is meant to grant select permissions to local user test_user to the table foo on the fdtest foreign data wrapper. However, how I would interpret this command is that it is granting permissions to test_user to select on local table foo (which does not exist). As expected, when I run this command I get an error:
ERROR: relation "foo" does not exist
I would love to know how to actually accomplish this. I would like to be able to restrict local users to only access certain tables from a foreign data wrapper.
You'll have to connect to the remote database and run the GRANT statement there.
Of course you could do that via dblink, but then you'd have to connect with a superuser or the owner of the table.
The connection they show is a loop back connection, it just connects back to the same server and (apparently) database you are already in. This is useful for testing purposes. So granting the permission on the local server is the same thing as granting it on the remote server, as they are the same server.
They do not show the creation of the table, you can find it in the regression test contrib/dblink/sql/dblink.sql (from which the example in the doc derives) as:
CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));

Cannot access foreign table using Postgres FDW

I had a foreign table set up in Postgres 10. The role "role1" has been granted usage on the foreign server (fs) that was set up using the postgres superuser.
I imported the table using the import schema command:
IMPORT FOREIGN SCHEMA f_schema LIMIT TO (my_fdw_table) FROM fs INTO ls;
That worked fine.
However, when I try to query the table I get the following error:
SELECT * FROM my_fdw_table LIMIT 1;
ERROR: permission denied for view my_fdw_table
CONTEXT: remote SQL command: ...
My understanding is that FDW should treat views and tables the same.
It looks like the remote user that you used in the user mapping for your local user and the foreign server does not have the required permissions on the table (or the schema that contains it).
User "role1" should create user mapping for itself like:
CREATE USER MAPPING FOR role1 SERVER fs OPTIONS (USER 'role1', PASSWORD 'password1');
IMPORT FOREIGN SCHEMA f_schema LIMIT TO (my_fdw_table) FROM SERVER fs INTO ls;
Also, if "role1" is not an owner of the database, it should get access from its owner:
GRANT USAGE ON SCHEMA ls TO role1;
Assuming ls is local schema.

How can I change the owner of the public schema in databases created via the Google Console?

In Google's SQL Cloud Postgres service, when I create a database via the Web Console for a PostgreSQL instance, it automatically sets the owner of the database's default "public" schema to be cloudsqladmin. It seems I cannot change the ownership:
mydb=> \dn
List of schemas
Name | Owner
--------+---------------
public | cloudsqladmin
(1 row)
mydb=> alter schema public owner to postgres;
ERROR: must be owner of schema public
mydb=> \du
List of roles
Role name | Attributes | Member of
-------------------+------------------------------------------------+---------------------
cloudsqladmin | Superuser, Create role, Create DB, Replication | {}
cloudsqlagent | Create role, Create DB | {cloudsqlsuperuser}
cloudsqlreplica | Replication | {}
cloudsqlsuperuser | Create role, Create DB | {}
pg_signal_backend | Cannot login | {}
postgres | Create role, Create DB | {cloudsqlsuperuser}
mynewuser | Create role, Create DB | {cloudsqlsuperuser}
I also created a "mynewuser" through the web console, and cannot remove the "mynewuser" from the "cloudsqlsuperuser" group:
mydb=> alter group cloudsqlsuperuser drop user mynewuser;
ERROR: "cloudsqlsuperuser" can't be altered
If I wanted to create a database with a public schema that only a new user has access to (and owns), should I be doing this outside of the Google web ui? It seems like any databases I create are owned by cloudsqladmin, and any users I create are those "cloudsqlsuperuser" members. If I wanted to restrict permissions for a user, should I create that user normally via psql and bypass the web ui altogether?
From my experience, you seem to have to bypass the web ui / cli tool entirely.
When you create a database through the cli tool:
gcloud sql databases create DBNAME --instance INSTANCE
It assigns ownership to cloudsqlsuperuser, same as through the gui from the sounds of it.
When I have created a user specifically through the CLI tool:
gcloud sql users create USER 'host' --instance INSTANCE
Those users get the same permissions as cloudsqlsuperuser. In this case, it is possible to alter the ownership of the database. I had success through psql command connecting as the user I wanted to own the database and running:
ALTER DATABASE database OWNER TO user;
However if the user was created via psql (not glcoud cli), then the permission are not the same and the above failed.
I'd be tempted to create your instance, set the 'postgres' users password through the tool, then psql into the instance from there and do everything you need via sql commands. I think the tool does some things very nicely (as does the UI), but its a pain later on.
If anyone knows better, I'd love to hear how you can work with the default gcloud user.
Basically what happens here is that a usual CREATE DATABASE statement seems to create a new database based on the template0 database. This database is owned by cloudsqladmin. A role only Google has access to. When the gcloud or web GUI is used, it executes the following query:
CREATE DATABASE mydb TEMPLATE template1;
For template1 the owner is set to cloudsqlsuperuser a role that gets assigned to the postgres user, and other users created through the GUI.
So if you would like to create a database using sql with the appropriate privileges, just execute the statement above, and your public schema will then be owned by the cloudsqlsuperuser, and can be altered using the default postgres user, or other users created through the web GUI.
Connect to the database mydb by owner user (for exaple, it is mynewuser).
If you want to change the public schema owner, first you should make the user postgres owner of your database mydb:
mydb=> ALTER DATABASE mydb OWNER TO postgres;
After that, you can change the public schema owner:
mydb=> ALTER SCHEMA public OWNER TO postgres;
Besides, to remove your mynewuser from the cloudsqlsuperuser group (role) use:
mydb=> REVOKE cloudsqlsuperuser FROM mynewuser;
Note: The default postgres user in Google Cloud Platform's (GCP) Cloud SQL (PostgreSQL) is not a superuser of the instance. Also, all users created from the GCP web UI have cloudsqlsuperuser role by default, and the following attributes (privileges): CREATEROLE, CREATEDB and LOGIN. They don't have the SUPERUSER or REPLICATION attributes.

Postgresql forgets grants after recreating tables

We use liquibase to manage and execute our database changes. On our DEV environment (and especially on local machines) we frequently recreate the tables to have a clean slate.
We have just migrated from MySQL to Postgres and are facing a problem related to these table recreations.
Initially we have granted our DB user with this:
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO mydbuser;
GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA public TO mydbuser;
This is executed through psql after connecting to our own DB (where public is the default/only schema).
Everything is fine until we ask liquibase to recreate the tables in which case it will drop all tables and create them again.
After that it appears that mydbuser has lost all its grants on the tables.
According to several resources (like this) we need to alter the default privileges, so we obey:
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO mydbuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO mydbuser;
GRANT SELECT, USAGE ON ALL SEQUENCES IN SCHEMA public TO mydbuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, USAGE ON SEQUENCES TO mydbuser;
However, although this seems very logical it changed nothing. All grants (even select) are still lost after recreating the tables.
What are we doing wrong or what else do we need to do?
UPDATE
\ddp shows:
Default access privileges
Owner | Schema | Type | Access privileges
----------+--------+----------+--------------------
postgres | public | sequence | mydb=rU/postgres
postgres | public | table | mydb=arwd/postgres
If trying to mimic what liquibase is doing in a simplified test case, it just works.
Quick demo with 9.3:
1) Create the objects from scratch with the postgres user:
postgres=# create database dbtest;
CREATE DATABASE
postgres=# create user mydbuser;
CREATE ROLE
postgres=# \c dbtest
You are now connected to database "dbtest" as user "postgres".
dbtest=# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO mydbuser;
ALTER DEFAULT PRIVILEGES
dbtest=# create table foobar(id int);
CREATE TABLE
2) In another session let's connect with mydbuser and see if SELECT is allowed.
dbtest=> select * from foobar;
id
----
(0 rows)
Result: Yes, it's allowed. Note the result of \ddp too:
dbtest=> \ddp
Default access privileges
Owner | Schema | Type | Access privileges
----------+--------+-------+------------------------
postgres | public | table | mydbuser=arwd/postgres
(1 row)
3) Let's have postgres drop the table and recreate it:
dbtest=# drop table foobar;
DROP TABLE
dbtest=# create table foobar(id int);
CREATE TABLE
4) See if mydbuser can still SELECT from it.
$ psql -d dbtest -U mydbuser
dbtest=> select * from foobar;
id
----
(0 rows)
Result: Yes, as expected.
5) See if another user can SELECT from it.
$ psql -d dbtest -U daniel
dbtest=> select * from foobar;
ERROR: permission denied for relation foobar
Result: No, as expected.
This does not explain what doesn't work for you, but you may compare the above with the set of commands issued by liquibase.