Replacing schema name when sharing sql script with other users - postgresql

When collaborating with colleagues I need to change the schema name every time I receive a SQL script (Postgres).
I am only an ordinary user of a corporate database (no permissions to change anything). Also, we are not allowed to create tables in PUBLIC schema. However, we can use (read-only) all the tables from BASE schema.
It is cumbersome for the team of users, where everybody is creating SQL scripts (mostly only for creating tables), which need to be shared amongst others. Every user has its own schema.
Is it possible to change the script below, where I will share the script to another user without the need for the other user to find/replace the schema, in this case, user1?
DROP TABLE IF EXISTS user1.table1;
CREATE TABLE user1.table1 AS
SELECT * FROM base.table1;

You can set the default schema at the start of the script (similar to what pg_dump generates):
set search_path = user1;
DROP TABLE IF EXISTS table1;
CREATE TABLE table1 AS
SELECT * FROM base.table1;
Because the search path was change to contain user1 as the first schema, tables will be searched in that schema when dropping and creating. And because the search path does not include any other schema, no other schema will be consulted.
If you
However the default search_path is "$user", public which means that any unqualified table will be searched or created in a schema with the same name as the current user.
Caution
Note that a DROP TABLE will drop the table in the first schema found in that case. So if table1 doesn't exist in the user's schema, but in the public schema, it would be dropped from the public schema. So for your use-case setting the path to exactly one schema might be more secure.

Related

Postgresql schema "public" does not exist

When I was working on postgresql database, I delete some users using command
=>set role "test-admin" ;
SET
=> drop owned by "test-admin" cascade;
DROP OWNED.
=> drop user "test-temp";
DROP ROLE
but when I do
\dn
List of schemas
Name | Owner
------+-------
(0 rows)
The public schema does not exist anymore. I can still see a bunch of users when run \du, I can also see names of database when do \l.
The error I saw is: "Error: could not find schema 'public' while looking for owner".
Looks like public schema was either dropped or not accessible. I did not drop schema explicitly.
My questions are:
why does public schema disappear?
will drop owner of schema public also drop public schema?
how can I bring it back?
Should I manually recreate it?
Since I can still see databases, how can I associate the database with public schema again?
I tried all the approaches I can think of (such as login as users with different privileges), the public schema is still no available.
Thanks for the help in advance.

Separate and restrict data access using schemas

I am an Oracle DBA, new to PostgreSQL. I have a requirement to separate some modules data, so that one module will not have access to read the data of another module.
I read about the use of schemas in PostgreSql which is somewhat different than the use of it in Oracle. However seems like it is recommended to use the method of different schemas for separation and management - just like in Oracle.
However, when I create 2 schemas - connected to the same database and same user - I can do a select from the other schema's table.
That is, for example, if I have schema A owning table a, and schema B owning table b, when I set the search path to schema B I can do a select on schema’s A table a without any problem.
I couldn't find a way to revoke this privilege from schema B.
The only I could find then to separate access to data, is using different roles, that is to create role A with schema A, and role B with schema B. then I can grant and revoke access from user B in order for it to see what I want from role's A tables.
Is this correct? Am I missing something?
if I have schema A owning table a
A schema does not "own" a table in Postgres - a user does. This is the same as in Oracle - the difference (and maybe where your confusion arises) is that in Oracle in a regular user can't create tables outside of a schema that has the same name as the user account.
So if user arthur creates a table in schema_a and one in schema_b, both tables are owned by arthur - not "the schema".
If you used different schemas/users in Oracle to separate data and to prevent access to the other user's tables, then you need two users and two schemas in Postgres as well.
The default search_path in Postgres is setup in a way, that (unqualified) tables are always first searched (and created) in a schema with the same name as the user running the statement.
So if you create two users and a schema with the user's name for each user, you pretty much have the same setup as in Oracle:
create user arthur with password 'foobar';
create schema arthur authorization arthur; --<< this is what Oracle does "automatically"
create user bob with password 'verysecret';
create schema bob authorization bob;
Now, if bob creates a table, that table is created in the schema bob and is owned by the user bob. User arthur has not privileges to access that table.
If you never need to share data between those users (or schemas), then you can create two databases, create two users and let both users create everything in the public schema of "their" database.

Accessing table without using schema name

I am new with DB2.
I am not able to get data from a table without using the schema name. If I use a schema name with table name, I am able to fetch data.
Example:
SELECT * FROM TABLE_NAME;
It is giving me error, while
SELECT FROM SCHEMA_NAME.TABLE_NAME;
is fetching a result.
What do I have to set up not to always have to use the schema name?
By default, your username is used as the schema name for unqualified object names. You can see the current schema with, e.g. VALUES CURRENT SCHEMA. You can change the current schema for you current session with SET SCHEMA new_schema_name, or via e.g. a JDBC connection parameter. Most query tools also have a place to specify/change the current schema.
See the manual page for SET SCHEMA https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001016.html
The full rules for the qualification of unqualified objects is here https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000720.html#r0000720__unq-alias
E.g.
Unqualified alias, index, package, sequence, table, trigger, and view names are implicitly qualified by the default schema.
However, you can create a public alias for a table, module or sequence if you wish to be able to reference it regardless of your CURRENT SCHEMA value.
https://www.ibm.com/support/knowledgecenter/SSEPGG_11.5.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000910.html
(P.S. all the above assumes you are using Db2 LUW)
Try using SET SCHEMA to set the default schema to be used in the session:
SET SCHEMA SCHEMA_NAME;
SELECT * FROM TABLE_NAME;
When using DBeaver - right click on connection > Connection Settings > Initialization, and select your default DB and default Schema:
After that, open your SQL Script and select Active DB:

How to restrict a user from executing a COPY query in PostgreSQL?

I need to restrict a user in pgsql from executing copy statement. I can disallow execution of any of the CRUD operations.
COPY command can read from a table to somewhere or it can write to a table from somewhere (from file, another table or from a query).
I assume you want to restrict writing to any table.
In this case, just restrict UPDATE/INSERT/DELETE operations for that user:
revoke insert, delete, update on all tables in schema public from xxx;
Double-check that your user is not a superuser (in this case, all permissions checks are just ignored; so if it is, just alter role xxx nosuperuser;).
It's also worth to define default strategy for all new tables, revoking writing access from this role:
alter default privileges in schema public
revoke insert,update,delete on tables from xxx;
If you want to restrict reading with COPY from any table (like copy (select * from table1) to stdout;), you need also revoke reading access (i.e. SELECT permission) from all objects.
Note, that there is a variant of COPY which will work nevertheless – if it reads from "nowhere", i.e.:
copy (select 'blabla') to stdout;
or
copy (values('blabla')) to stdout;
or, even more extreme version, reading "nothing":
copy (select) to stdout;

Change owner of Postgres table automatically?

I have a database shared by many users, all the users are in a group "example" and the vast majority of objects in the database are owned by "example". Very occasionally a user will create a new table - that table gets assigned to the user who created it and so the other users are unable to alter the new table.
Is there a way to have the ownership of a table automatically set to the group "example" and not the user who created the table or a way to set up a trigger that happens after a CREATE TABALE or a way to set up group/permissions such that all users will be considered owners of objects regardless of who actually created them?
You could change the default privileges this way:
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO PUBLIC;
or to give write access:
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT,INSERT,UPDATE,DELETE ON TABLES TO PUBLIC;
https://www.postgresql.org/docs/9.0/static/sql-alterdefaultprivileges.html
You probably want to use an EVENT TRIGGER
This is doable in all versions of Pg from 9.3 forward but depending on your version might require different approaches since the structures for event triggers have improved significantly.
In earlier versions you could look through the table catalogs for items owned by the current user. In newer versions you can use pg_event_trigger_ddl_commands to get the information you need. you want to run the command at ddl end.