Postgres materialized view hides some data - postgresql

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;

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.

Select * query for granted columns in postgres

I granted permission for read_only user in postgres for some columns of a table using
grant select(col1,col2) on mytable to read_only_user;
I want to use
SELECT * FROM mytable
query from read_only_user.But I'm getting permission denied in output.I don't want to create view for this. But somehow I want the select * query to work for that user(not explicitly telling what are the columns like select col1,col2 from mytable).
Help me guys.Thanks in advance...
You cannot do that, and you shouldn't try.
SELECT * should never be used in code, it is only for ad hoc queries.
What are the problems:
If the table definition changes, your program will break.
You probably retrieve unnecessary columns, which will cause unnecessary data to be processed and may keep PostgreSQL from choosing a better execution plan.

check if materialized view is populated

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.

How does view name get out of sync with view definition?

I tracked down a bug in my system to this anomaly - at least it's an anomaly in my system of 15 catalogs with similar but unequal schemas.
What causes the [TABLE_NAME] in [INFORMATION_SCHEMA].[VIEWS] to be different than the value in [VIEW_DEFINITION]?
It makes me think I don't understand something about Views or System Tables in SQL Server...
.
If you have renamed the view, the name changes, but the definition doesn't.
You should do this as a DROP/CREATE or an ALTER script, not by right-clicking or using sp_rename.
This is actually expected behavior for all modules. Here is a quick test using a simple stored procedure:
CREATE PROCEDURE dbo.proc_foo
AS
SELECT 1;
GO
-- rename it to proc_bar
EXEC sys.sp_rename N'dbo.proc_foo', N'proc_bar', N'OBJECT';
GO
-- check the definition from various sources
SELECT od = OBJECT_DEFINITION(OBJECT_ID(N'dbo.proc_bar')),
info_s = (SELECT ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = N'proc_bar' AND SCHEMA_NAME = N'dbo'),
sql_m = (SELECT definition FROM sys.sql_modules
WHERE [object_id] = OBJECT_ID(N'dbo.proc_bar'));
Results:
od info_s sql_m
----------------------------- ----------------------------- -----------------------------
CREATE PROCEDURE dbo.proc_foo CREATE PROCEDURE dbo.proc_foo CREATE PROCEDURE dbo.proc_foo
AS AS AS
SELECT 1; SELECT 1; SELECT 1;
In any case, you shouldn't be using INFORMATION_SCHEMA anyway...
The case against INFORMATION_SCHEMA views