I found some random RULES in some database views that returns a SELECT which is exactly the view's select.
I did search through migrations and application code but found no definition/creation of those rules.
Does Postgres 8.4 creates RULE automatically on some views?
It is essentially the same to create a view or create a table and create a rule on SELECT. It is valid not only for 8.4, but till 9.6 inculsive:
...an ON SELECT rule effectively turns the table into a view
and further:
It is considered better style to write a CREATE VIEW command than to
create a real table and define an ON SELECT rule for it.
Related
I am about to model a PostgreSQL database, based on an Oracle database. The latter is old and its tables have been named after a 3-letter-scheme.
E.g. a table that holds parameters for tasks would be named TSK_PAR.
As I model the new database, I'd like to rename those tables to a more descriptive name using actual words. My problem is, that some parts of the software might rely on these old names until they're rewritten and adapted to the new scheme.
Is it possible to create something like an alias that's being used for the whole database?
E.g. I create a new task_parameters database, but add a TSK_PAR alias to it, so if a SELECT * FROM TSK_PAR is being used, it automatically refers to the new name?
Postgres has no synonyms like Oracle.
But for your intended use case, views should do just fine. A view that simply does select * from taks_parameters is automatically updateable (see here for an online example).
If you don't want to clutter your default schema (usually public) with all those views, you can create them in a different schema, and then adjust the user's search path to include that "synonym schema".
For example:
create schema synonyms;
create table public.task_parameters (
id integer primary key,
....
);
create view synonyms.task_par
as
select *
from public.task_parameters;
However, that approach has one annoying drawback: if a table is used by a view, the allowed DDL statements on it are limited, e.g. you can't drop a column or rename it.
As we manage our schema migrations using Liquibase, we always drop all views before applying "normal" migrations, then once everything is done, we simply re-create all views (by running the SQL scripts stored in Git). With that approach, ALTER TABLE statements never fail because there are not views using the tables. As creating a view is really quick, it doesn't add overhead when deploying a migration.
I'm in trouble with grant in postgresql (version 9.3).
I'm trying to restrict a ROLE 'client_1'. I want it to be able to do only select for one table. But there is inheritance between tables.
Here is my table structure:
CREATE TABLE public.table_a (...);
CREATE TABLE table_a_partitions.child_1 (...) INHERITS (public.table_a);
CREATE TABLE table_a_partitions.child_2 (...) INHERITS (public.table_a);
GRANT SELECT ON table_a_child_1 TO client_1;
It's okay when I do a select on child_2, there is an error, but if I do a SELECT * FROM table_a; for example it also reads the forbidden table child_2. I would my client access only child_1 (and some other in the future) results when he does SELECT * FROM table_a;.
Is there a simple way to solve this problem ?
Thank you
You would need to use a VIEW in PostgreSQL 9.3 to solve this problem. If you upgrade to 9.5, however, you could use row-level security.
As a note as to why, the grant check only occurs on the level of the initial relation queried. This means if you query a view, you need access to the view's contents, but the view owner (NOT YOU) needs access to the underlying relations. This allows a view to be useful for information hiding. Similarly with inheritance, this structure allows you to forbid rows to be inserted or queried directly from partitions of a table, but to allow different queries via the parent table. So this is a consequence of design priorities, not a bug.
Before row-level security, you would basically create a view and fold in user privilege criteria into the view (with partitioning/inheritance this is also a good idea for other reasons since your insert/update/delete triggers can return exactly what the db would do even though it cannot on a table).
As for row-level security, PostgreSQL 9.5 does allow you to specify row-level policies (conditions that get appended to insert/select/update/delete queries) and that provides something a little more manageable in some cases than the view approach.
I am adding distkey/sortkey to all my tables in redshift and would like to automate this. I am doing the following:
ALTER TABLE table RENAME TO tmp_table;
CREATE TABLE table
distkey(id)
sortkey(id)
AS
select * from tmp_table;
DROP TABLE tmp_table;
This works great, except the views don't get migrated. When you ALTER TABLE, the existing views would point to the tmp_table. Ideally I want to restore the views to the way before, possibly in the same query transaction or as part of a script.
In your migration procedure:
For each view execute:
select definition from pg_views where viewname = 'my_view';
And store all the results.
Execute for all views:
drop view 'my_view'; // or rename only to have a rollback option
Alter your tables
Execute the create view commands obtained in step 2
Just drop and recreate the views. That could be part of the script.
Views might not form part of a transaction, so some testing might be required.
I have column column with character varying(20) type, i want to increase it to 50
ALTER TABLE table ALTER COLUMN column TYPE character varying(50);
I get an error that view view_name depends on column "column". I wonder how can i alter column without dropping and recreating about 10 depending views?
The answer to your question can be found on this blog
PostgreSQL is very restrictive when it comes to modifying existing
objects. Very often when you try to ALTER TABLE or REPLACE VIEW it
tells you that you cannot do it, because there's another object
(typically a view or materialized view), which depends on the one you
want to modify. It seems that the only solution is to DROP dependent
objects, make desired changes to the target object and then recreate
dropped objects.
It is tedious and cumbersome, because those dependent objects can have
further dependencies, which also may have other dependencies and so
on. I created utility functions which can help in such situations.
The usage is very simple - you just have to call:
select deps_save_and_drop_dependencies(p_schema_name, p_object_name);
You
have to pass two arguments: the name of the schema and the name of the
object in that schema. This object can be a table, a view or a
materialized view. The function will drop all views and materialized
views dependent on p_schema_name.p_object_name and save DDL which
restores them in a helper table.
When you want to restore those dropped objects (for example when you
are done modyfing p_schema_name.p_object_name), you just need to make
another simple call:
select deps_restore_dependencies(p_schema_name,p_object_name);
and the dropped objects will be recreated.
These functions take care about:
dependencies hierarchy
proper order of dropping and creating views/materialized views across hierarchy
restoring comments and grants on views/materialized views
Click here
for a working sqlfiddle example or check this gist for a complete
source code
It's not possible, but a TODO feature. You should create a script that is able to handle such a thing as simple view creations.
I have a view, one of he column is timetaken type integer i want to change it as numeric.For this I used below syntax
ALTER VIEW view_timesheets ALTER COLUMN timetaken type numeric;
When I run this I got the exception as
"view_timesheets" is not a table, composite type, or foreign table
Please explain how to alter column type.Thank You
It is not possible. You will have to recreate the view by providing its complete definition. Also note that you cannot even CREATE OR REPLACE VIEW when you change the types of the columns. If you have views that depend on the view that changes you will have to DROP / CREATE them also.
In my company we use the strategy where everything that is recreatable in a database (like views, functions, etc.) is stored in a bunch of large SQL files which we execute everytime anything changes in the underlying table structures, so we don't have to care for dependant views.
The view part in these files is basically like:
DROP VIEW IF EXISTS vw_a CASCADE;
CREATE OR REPLACE VIEW vw_a AS
...;
DROP VIEW IF EXISTS vw_b_depending_on_a CASCADE;
CREATE OR REPLACE VIEW vw_b_depending_on_a AS
...;
Of course the second CASCADE as well as the OR REPLACE seems useless, but they maek it possible to copy&paste changed definitions easily into a running dev database without much thinking.
I have also faced a similar problem while converting the column type of view.
I used the CAST() operator to convert the type from Integer to Varchar(5).
I had a column named age which is of type Integer in my table. So the view query created using that table was also having the type as Integer. So I used the CAST() operator in my view query to change the column type.
CASE
WHEN vhcl_insp_dtls.age = 0 THEN CAST('NEW' AS VARCHAR(5))
ELSE CAST(vhcl_insp_dtls.age AS VARCHAR(5))
END AS age,
So In this way, you can modify your view query without dropping it.