check if materialized view is populated - postgresql

Using postgres 9.5.2 (python client)
Is there any way to check if a materialized view is populated using a query? One that does not raise a warning the view is not populated?

The quick answer:
SELECT relispopulated FROM pg_class WHERE relname = '<the table name>';
You can find more details about the pg_class table in the documentation. According to that, the field relispopulated should be true for everything but some materialized views, and I infer from that and from the name of the field, that it will give you what you want.

Related

Feedback on whether index was created on materialized views in postgresql

I created a unique index for a materialized view as :
create unique index if not exists matview_key on
matview (some_group_id, some_description);
I can't tell if it has been created
How do I see the index?
Thank you!
Two ways to verify index creation:
--In psql
\d matview
--Using SQL
select
*
from
pg_indexes
where
indexname = 'matview_key'
and
tablename = 'matview';
More information on pg_indexes.
Like has been commented, if the command finishes successfully and you don't get an error message, the index was created. Possible caveat: while the transaction is not committed, nobody else can see it (except the unique name is reserved now), and it still might get rolled back. Check in a separate transaction to be sure.
To be absolutely sure:
SELECT pg_get_indexdef(oid)
FROM pg_catalog.pg_class
WHERE relname = 'matview_key'
AND relkind = 'i'
-- AND relnamespace = 'public'::regnamespace -- optional, to make sure of the schema, too
This way you see whether an index of the given name exists, and also its exact definition to rule out a different index with the same name. Pure SQL, works from any client. (There is nothing special about an index on materialized views.)
Also filter for the schema to be absolutely sure. Would be the "default" schema (a.k.a. "current" schema) in your case, since you did not specify in the creation. See:
How does the search_path influence identifier resolution and the "current schema"
Related:
Create index if it does not exist
How to check if a table exists in a given schema
In psql:
\di public.matview_key
To only find indexes. Again, the schema is optional to narrow down.
Progress Reporting
If creating an index takes a long time, you can look up progress in pg_stat_progress_create_index since Postgres 12:
SELECT * FROM pg_stat_progress_create_index
-- WHERE relid = 'public.matview'::regclass -- optionally narrow down
Un alternative to looking into pg_indexes is pg_matviews (for a materialized view only)
select *
from pg_matviews
where matviewname = 'my_matview_name';

Postgres get out enough view information to reproduce it

Basically - I want to get out enough information from postgres to reproduce a view - I know I can do a
select * from pg_get_viewdef('my_view')
which gets me the select statement, but not the create part of it - which could be a normal view or a materialized view - and then there could grants and for a materialized view indexes.
I know I can work through all of that myself, but I'll probably get it wrong or miss something - is there an easier way in postgres? ie something that I can get out that gives me the complete ddl for reconstructing the view?
The easiest way to get the CREATE VIEW statement and all GRANTs is to run pg_dump:
pg_dump -t viewschema.viewname dbname
If you cannot use that, collecting the information is more difficult:
I recommend that you use the views pg_views and pg_matviews. They contain a column definition which contains the result of pg_get_viewdef. Just prepend CREATE VIEW or CREATE MATERIALIZED VIEW for the complete statement.
Permissions for views can be conveniently got from information_schema.table_privileges, but this view does not contain materialized views.
To get permissions directly from the metadata, you can use:
SELECT c.oid::regclass AS table_or_view
p.grantor::regrole,
p.grantee::regrole,
p.privilege_type,
p.is_grantable
FROM pg_class AS c
CROSS JOIN LATERAL aclexplode(c.relacl) AS p
WHERE c.relname = 'v';
Here, a - as grantee means PUBLIC.

Redshift view definition permissions issue

Running this query, even as postgres login, displays view_definition only for the views that are created by the current login.
select table_schema as schema_name, table_name as view_name, view_definition
from information_schema.views
where table_schema not in ('information_schema', 'pg_catalog')
order by schema_name, view_name;
Is there some way to get view definition for all views no matter who created them?
If not i plan to just make a job in my etl scheduler to reassign all views to owner postgres.
Information_schema.views returns NULL for view_definition if the current user (even admin) is not the owner of the view [1]. This is how it is designed in Postgres and since Redshift is based on Postgres 8.0.2, I assume it has a similar behavior.
The v_generate_view_ddl [2] admin view in AWS's GitHub repo could help in getting all view definitions.
References:
[1] Postgres Documentation - https://www.postgresql.org/docs/8.0/infoschema-views.html
[2] Redshift Admin View - https://github.com/awslabs/amazon-redshift-utils/blob/master/src/AdminViews/v_generate_view_ddl.sql
You could just use "show view" command and it will show the view definition irrespective of who created it in redshift.
show view <nameoftheview>

Postgres materialized view hides some data

First of all, I can not recreate this example in SQL fiddle, I got some error when I try select from view.
Problem:
I have a materialized view which fetches function parameters from my schema, based on information_schema. When I create it, it works just fine. When I refresh it, it works just fine. When I assign it to some role, and then refresh it - it loses about 75% of its contents, and refreshing does not work. Only thing that works is dropping and re creating the whole view.
Examples:
All examples was executed as superuser. Lets say that I have role:
CREATE ROLE table_owner NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE NOREPLICATION;
And I have materialized view like this:
CREATE MATERIALIZED VIEW function_def AS
SELECT
regexp_replace(r.specific_name::text, '^(.*)_[0-9]+$'::text, '\1'::text) AS function_name,
r.data_type AS output_type,
r.type_udt_name AS output_udt_name,
p.ordinal_position,
p.parameter_name,
p.data_type,
p.udt_schema,
regexp_replace(p.udt_name::text, '^_'::text, ''::text) AS udt_name
FROM information_schema.routines r
LEFT JOIN information_schema.parameters p ON p.specific_name::text = r.specific_name::text
WHERE 1 = 1 AND p.specific_schema::text = 'mySchema'::text
ORDER BY regexp_replace(r.specific_name::text, '^(.*)_[0-9]+$'::text, '\1'::text), p.ordinal_position
WITH DATA;
CREATE INDEX i_function_def_function_name ON function_def(function_name);
And lets say that in this point statement:
SElECT count(*) FROM function_def
returns 231 rows, which is correct number. Then I assign the ownership of view to some role:
ALTER TABLE function_def OWNER TO table_owner;
and select still returns 231 rows, which is correct number.
SElECT count(*) FROM function_def;
but when I refresh view like this:
REFRESH MATERIALIZED VIEW function_def WITH DATA;
and then:
SElECT count(*) FROM function_def;
the returned number of rows is constant 54, which is not correct.
I am quite puzzled here and would appreciate some help, or hint. Is this a postgres bug, or am I doing something wrong?
EDIT - solution:
As stated by Klin it is in fact a privilege issue! Because all my functions are owned by function_owner, this code has done the trick, and now everything is fine:
ALTER TABLE function_def OWNER TO function_owner;
GRANT SELECT ON TABLE function_def TO GROUP table_owner;
REFRESH MATERIALIZED VIEW is executed with the privileges of the view owner, i.e. table_owner in this case.
The user have no access to some functions and therefore he does not see some records in information_schema.routines.
You can check what functions are not accessible by table_owner by executing this query as superuser:
SELECT
regexp_replace(r.specific_name::text, '^(.*)_[0-9]+$'::text, '\1'::text) AS function_name,
r.data_type AS output_type,
r.type_udt_name AS output_udt_name,
p.ordinal_position,
p.parameter_name,
p.data_type,
p.udt_schema,
regexp_replace(p.udt_name::text, '^_'::text, ''::text) AS udt_name
FROM information_schema.routines r
LEFT JOIN information_schema.parameters p ON p.specific_name::text = r.specific_name::text
WHERE 1 = 1 AND p.specific_schema::text = 'mySchema'::text
EXCEPT
SELECT * FROM function_def;

Postgres: see query used to create materialized view?

I'm working in Postgres 9.4. Is there any way I can see the query that was used to create a materialized view?
Doing:
# \d my_view;
just shows me the column names and indexes of the view, not the command used to create it. And I can't see anything in the docs about this.
Thanks for your help.
This is stored in pg_matviews:
select definition
from pg_matview
where matviewname = 'my_view'
and schemaname = 'public';
You can also use pg_get_viewdef() as Craig has suggested:
select pg_get_viewdef('public.my_view', true);