Question

Running the following query:

SELECT exists (
    SELECT
        schema_name 
    FROM
        information_schema.schemata 
    WHERE
        schema_name = 'public'
) AS schema_exists;

I am getting always FALSE, even if the public schema exists.

How should i check if this schema exists?

EDIT

I am using PostgreSQL version 8.4

Was it helpful?

Solution

The information from information_schema.schemata depends on the role you're connected with, so it's not really the right view to query to discover schemas in general.

The doc on information_schema.schemata in 9.3 says:

The view schemata contains all schemas in the current database that are owned by a currently enabled role.

However it's not quite clear (at least to me) from just that sentence, why you can't see public .

In a mailing-list post, Tom Lane has an explanation the goes a bit further:
See http://www.postgresql.org/message-id/11650.1357782995@sss.pgh.pa.us

His conclusion:

As things stand, a non-superuser won't see "public", "pg_catalog", nor even "information_schema" itself in this view, which seems a tad silly.

which looks exactly like the problem in this question.

Bottom line: use pg_namespace instead of information_schema.schemata


This was amended in version 9.4 to conform to what users expect. The current doc says:

The view schemata contains all schemas in the current database that the current user has access to (by way of being the owner or having some privilege).

USAGE privilege on a schema is now enough to get it from this view.

OTHER TIPS

I guess you can't see public schema because of the database role you are using to test schema existence. information_schema.schemata is actually a view with the following definition:

 SELECT 
    current_database()::information_schema.sql_identifier AS catalog_name,
    n.nspname::information_schema.sql_identifier AS schema_name,
    u.rolname::information_schema.sql_identifier AS schema_owner, 
    NULL::character varying::information_schema.sql_identifier AS default_character_set_catalog,
    NULL::character varying::information_schema.sql_identifier AS default_character_set_schema,
    NULL::character varying::information_schema.sql_identifier AS default_character_set_name,
    NULL::character varying::information_schema.character_data AS sql_path
   FROM pg_namespace n, pg_authid u
  WHERE n.nspowner = u.oid AND pg_has_role(n.nspowner, 'USAGE'::text);

This is also described in documentation.

You can get the definition of views in information_schema using \d+ in psql - \d+ information_schema.schemata in this case.

You should use pg_namespace instead of information_schema.schemata

(Posting as an answer from comments)

Referencing the pg_namespace table directly might be a decent workaround...

SELECT exists(select 1 from pg_namespace where nspname = 'public') as schema_exists;

I don't know what the exact differences are, but do know that namespaces "back" schemas internally in PostgreSQL.

Also, I believe those system pg_* tables are not guaranteed to stay consistent across versions, but it has been there since at least 7.3 (http://www.postgresql.org/docs/7.4/static/catalog-pg-namespace.html) and is there now (9.3.1).

That query that you wrote should have worked... Try this alternative:

select count(*) > 0 FROM information_schema.schemata WHERE schema_name = 'public';
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top