5.10. Esquemas #

5.10.1. Criação de esquema
5.10.2. O esquema público
5.10.3. O caminho de procura de esquema
5.10.4. Esquemas e privilégios
5.10.5. O esquema do catálogo do sistema
5.10.6. Padrões de uso
5.10.7. Portabilidade
5.10.8. Exemplo

Uma instância de bancos de dados PostgreSQL contém um ou mais bancos de dados com nome. As funções de banco de dados (identificadores de autorização/roles) e alguns poucos outros tipos de objeto são compartilhados por toda a instância. Uma conexão cliente com o servidor pode acessar um único banco de dados, aquele especificado no pedido de conexão.

Nota

Os usuários de uma instância não têm, necessariamente, o privilégio de acessar todos os bancos de dados da instância. O compartilhamento de nomes de funções de banco de dados (roles) significa que não pode haver duas funções de banco de dados diferentes com o mesmo nome, digamos, joe, em dois bancos de dados na mesma instância; mas o sistema pode ser configurado para permitir que joe acesse apenas alguns bancos de dados.

Um banco de dados contém um ou mais esquemas com nomes que, por sua vez, contêm tabelas. Os esquemas também contêm outros tipos de objetos com nome, incluindo tipos de dados, funções e operadores. Dentro de um mesmo esquema, dois objetos do mesmo tipo não podem ter o mesmo nome. Além disso, tabelas, sequências, índices, visões, visões materializadas e tabelas estrangeiras compartilham o mesmo espaço de nomes, de modo que, por exemplo, um índice e uma tabela devem ter nomes diferentes se estiverem no mesmo esquema. O mesmo nome de objeto pode ser usado em esquemas diferentes sem conflito; por exemplo, tanto esquema1 quanto meu_esquema podem conter uma tabela chamada minha_tabela. Ao contrário dos bancos de dados, os esquemas não são rigidamente separados: um usuário pode acessar objetos em qualquer um dos esquemas do banco de dados ao qual está conectado, se tiver os privilégios para fazer isto. [36]

Existem vários motivos pelos quais alguém pode querer usar esquemas:

Os esquemas são semelhantes aos diretórios de sistema operacional, exceto por não poderem ser aninhados.

5.10.1. Criação de esquema #

Para criar um esquema, é usado o comando CREATE SCHEMA. Dê ao esquema um nome de sua escolha. Por exemplo:

CREATE SCHEMA meu_esquema;

Para criar ou acessar objetos em um esquema, deve ser escrito um nome qualificado, consistindo do nome do esquema e do nome da tabela separados por ponto:

esquema.tabela

Pode ser usado em qualquer lugar onde um nome de tabela é esperado, incluindo os comandos de modificação de tabela e os comandos de acesso a dados discutidos nos próximos capítulos. (Por brevidade, falaremos apenas de tabelas, mas as mesmas ideias se aplicam a outros tipos de objetos com nome, como tipos de dados e funções.)

Na verdade, também pode ser usada a sintaxe ainda mais geral

banco_de_dados.esquema.tabela

mas, no momento, esta sintaxe existe apenas pelo motivo de manter a conformidade com o padrão SQL. Se for especificado um nome de banco de dados, este deverá ser igual ao nome do banco de dados ao qual se está conectado.

Então, para criar uma tabela no novo esquema, é usado:

CREATE TABLE meu_esquema.minha_tabela (
 ...
);

Para excluir um esquema vazio (onde todos os objetos do esquema já foram excluídos anteriormente), é usado:

DROP SCHEMA meu_esquema;

Para excluir um esquema, juntamente com todos os objetos que ele contém, é usado:

DROP SCHEMA meu_esquema CASCADE;

Veja a Seção 5.15 para conhecer a descrição do mecanismo geral por trás desta operação.

Muitas vezes deseja-se criar um esquema cujo dono é outro usuário (porque este é um dos modos utilizados para restringir as atividades dos usuários a espaços de nomes bem definidos). A sintaxe para esta operação é:

CREATE SCHEMA nome_do_esquema AUTHORIZATION nome_do_usuario;

Inclusive, pode ser omitido o nome do esquema e, neste caso, o nome do esquema será idêntico ao nome do usuário. Veja a Seção 5.10.6 para saber como isto pode ser útil.

Os nomes de esquemas começando por pg_ são reservados para uso pelo sistema, não podendo ser criados pelos usuários.

5.10.2. O esquema público #

Nas seções anteriores foram criadas tabelas sem que fosse especificado nenhum nome de esquema. Por padrão, essas tabelas (e outros objetos) são colocadas automaticamente no esquema chamado public. Todo banco de dados novo possui esse esquema. Portanto, as duas formas abaixo são equivalentes:

CREATE TABLE produtos ( ... );

e

CREATE TABLE public.produtos ( ... );

5.10.3. O caminho de procura de esquema #

Os nomes qualificados são desagradáveis de escrever, sendo geralmente melhor não associar a aplicação a um esquema específico. Por isso, geralmente as tabelas são referenciadas por meio de nomes não qualificados, formados apenas pelo nome da tabela. O sistema determina qual tabela está sendo referenciada seguindo o caminho de procura, o qual é uma lista de esquemas para procura. A primeira tabela correspondente encontrada no caminho de procura é assumida como sendo a tabela desejada. Não havendo nenhuma correspondência no caminho de procura é relatado um erro, mesmo que um nome de tabela correspondendo ao nome procurado exista em outro esquema no banco de dados.

A capacidade de criar objetos com o mesmo nome em esquemas diferentes dificulta escrever uma consulta que faz referência exatamente aos mesmos objetos todas as vezes. Também abre a possibilidade para os usuários alterarem o comportamento das consultas de outros usuários de forma maliciosa ou acidental. Devido à prevalência de nomes não qualificados em consultas, e seu uso interno no PostgreSQL, adicionar um esquema ao search_path confia realmente que todos os usuários tenham o privilégio CREATE nesse esquema. Quando você executa uma consulta comum, um usuário mal-intencionado, capaz de criar objetos em um esquema no seu caminho de procura, pode assumir o controle e executar funções SQL arbitrárias como se você as tivesse executando.

O primeiro nome de esquema no caminho de procura é chamado de esquema corrente. Além de ser o primeiro esquema a ser procurado, também é o esquema onde as novas tabelas são criadas quando o comando CREATE TABLE não especifica o nome do esquema.

Para mostrar o caminho de procura corrente, pode ser usado:

SHOW search_path;

Na configuração padrão esse comando retorna:

   search_path
-----------------
 "$user", public
(1 linha)

O primeiro elemento especifica que deve ser procurado o esquema com o mesmo nome do usuário corrente. Se esse esquema não existir, esta entrada será ignorada. O segundo elemento se refere ao esquema público visto anteriormente.

O primeiro esquema existente no caminho de procura é o local padrão para a criação dos novos objetos. Esta é a razão pela qual, por padrão, os objetos são criados no esquema público. Quando os objetos são referenciados em qualquer outro contexto sem a qualificação pelo esquema (comandos de modificação de tabelas, modificação de dados ou consultas) o caminho de procura é percorrido até que o objeto correspondente seja encontrado. Portanto, na configuração padrão qualquer acesso não qualificado somente pode fazer referência ao esquema público.

Para incluir o novo esquema no caminho, é usado:

SET search_path TO meu_esquema,public;

(O esquema $user foi omitido, por não haver necessidade imediata dele). Dessa forma, a tabela pode ser acessada sem ser qualificada pelo esquema:

DROP TABLE minha_tabela;

Também, como meu_esquema é o primeiro elemento do caminho, os novos objetos serão criados nesse esquema por padrão.

Também poderia ter sido escrito

SET search_path TO meu_esquema;

e, então, não teríamos mais acesso ao esquema público sem qualificação explícita. Não há nada de especial no esquema público, exceto por existir por padrão. Pode ser excluído também.

Veja também a Seção 9.27 para conhecer outras maneiras de tratar o caminho de procura de esquema.

O caminho de procura funciona para nomes de tipos de dados, nomes de funções e nomes de operadores, da mesma maneira que funciona para nomes de tabelas. Os nomes dos tipos de dados e das funções podem ser qualificados exatamente da mesma maneira que os nomes das tabelas. Se for necessário escrever um nome de operador qualificado em uma expressão, existe uma maneira especial de fazê-lo, devendo ser escrito:

OPERATOR(esquema.operador)

Isto é necessário para evitar uma ambiguidade de sintaxe. Por exemplo:

SELECT 3 OPERATOR(pg_catalog.+) 4;

Na prática, geralmente se confia no caminho de procura para os operadores, não sendo necessário escrever algo tão feio assim.

5.10.4. Esquemas e privilégios #

Por padrão, os usuários não podem acessar nenhum objeto em esquemas que não lhes pertençam. Para permitir o acesso, o proprietário do esquema deve conceder o privilégio USAGE no esquema. Por padrão, todos têm este privilégio no esquema public. Para permitir que os usuários utilizem os objetos em um esquema, pode ser necessário conceder privilégios adicionais, conforme apropriado para o objeto.

Um usuário também pode ter permissão para criar objetos no esquema de outro usuário. Para isto, é necessário conceder o privilégio CREATE no esquema. Em bancos de dados atualizados do PostgreSQL 14 ou anterior, todos têm este privilégio no esquema public. Alguns padrões da Seção 5.10.6 ocasionam a revogação deste privilégio:

REVOKE CREATE ON SCHEMA public FROM PUBLIC;

(O primeiro public refere-se ao esquema, enquanto o segundo PUBLIC significa qualquer usuário. No primeiro caso é um identificador, no segundo caso é uma palavra-chave, daí a diferença de minúsculas e maiúsculas; recorde-se das orientações feitas na Seção 4.1.1.)

5.10.5. O esquema do catálogo do sistema #

Além do esquema public e dos esquemas criados pelos usuários, cada banco de dados contém o esquema pg_catalog, contendo as tabelas do sistema e todos os tipos de dados, funções e operadores nativos. O pg_catalog é sempre parte efetiva do caminho de procura. Se não for colocado explicitamente no caminho de procura, então será procurado implicitamente antes dos esquemas do caminho de procura. Isto garante que os nomes nativos sempre podem ser encontrados. Entretanto, é possível colocar explicitamente o pg_catalog no final do caminho de procura, se for desejado que os nomes definidos pelo usuário prevaleçam sobre os nomes nativos.

Como os nomes das tabelas do sistema começam por pg_, é melhor evitar estes nomes para garantir que não haverá conflito se alguma versão futura definir uma tabela do sistema com o mesmo nome da sua tabela. (Com o caminho de procura padrão, uma referência não qualificada ao nome da sua tabela seria então resolvida como a tabela do sistema.) As tabelas do sistema continuarão seguindo a convenção de ter nomes começando por pg_, de modo que não entrarão em conflito com nomes não qualificados de tabelas de usuários, desde que os usuários evitem o prefixo pg_.

5.10.6. Padrões de uso #

Os esquemas podem ser usados ​​para organizar seus dados de diversas maneiras. Um padrão de uso de esquema seguro impede que usuários não confiáveis ​​alterem o comportamento das consultas de outros usuários. Quando um banco de dados não utiliza um padrão de uso de esquema seguro, os usuários que desejam consultar este banco de dados com segurança devem tomar medidas de proteção no início de cada sessão. Especificamente, eles iniciariam cada sessão definindo search_path como uma cadeia de caracteres vazia ou removendo esquemas que podem ser escritos por usuários que não sejam superusuários de search_path. Existem alguns padrões de uso facilmente suportados pela configuração padrão:

  • Restringir os usuários comuns aos esquemas privados dos usuários. Para implementar este padrão, primeiro certifique-se de que nenhum esquema tenha privilégios públicos de CREATE. Em seguida, para cada usuário que precisar criar objetos não temporários, deve ser criado um esquema com o mesmo nome deste usuário, como, por exemplo, CREATE SCHEMA alice AUTHORIZATION alice. (Lembre-se de que o caminho de procura padrão começa por $user, que é resolvido para o nome do usuário. Portanto, se cada usuário tiver um esquema separado, ele acessará seu próprio esquema por padrão.) Este padrão é um padrão de uso de esquema seguro, a menos que um usuário não confiável seja o dono do banco de dados, ou tenha recebido o privilégio ADMIN OPTION em uma role relevante, caso em que não existe um padrão de uso de esquema seguro.

    No PostgreSQL 15 e versões posteriores, a configuração padrão oferece suporte a este padrão de uso. Em versões anteriores, ou ao usar um banco de dados que foi atualizado de uma versão anterior, será necessário remover o privilégio público CREATE do esquema public (deve ser executado o comando REVOKE CREATE ON SCHEMA public FROM PUBLIC). Em seguida, considere auditar o esquema public em busca de objetos com nomes semelhantes aos objetos no esquema pg_catalog.

  • Remova o esquema público do caminho de procura padrão, modificando postgresql.conf ou executando ALTER ROLE ALL SET search_path = "$user". Em seguida, conceda privilégios para criar no esquema público. Somente nomes qualificados selecionarão objetos do esquema público. Embora referências qualificadas a tabelas sejam aceitáveis, chamadas para funções no esquema público serão inseguras ou não confiáveis. Se forem criadas funções ou extensões no esquema público, deve ser usado o primeiro padrão. Caso contrário, assim como no primeiro padrão, este é seguro, a menos que um usuário não confiável seja o dono do banco de dados ou tenha recebido a opção ADMIN OPTION em uma role relevante.

  • Mantenha o caminho de procura padrão e conceda privilégios para criar no esquema público. Todos os usuários acessam o esquema público implicitamente. Isto simula a situação em que os esquemas não estão disponíveis, proporcionando uma transição suave de/para um mundo sem suporte a esquemas. Entretanto, este nunca é um padrão seguro. Só é aceitável quando o banco de dados possui um único usuário ou alguns poucos usuários que confiam uns nos outros. Em bancos de dados atualizados do PostgreSQL 14 ou anterior, este é o padrão.

Em qualquer padrão, para instalar aplicações compartilhadas (tabelas para serem usadas por todos, funções adicionais fornecidas por terceiros, etc.), elas devem ser colocadas em esquemas separados. É necessário conceder os privilégios apropriados para permitir que outros usuários as acessem. Os usuários poderão então fazer referência a estes objetos adicionais qualificando seus nomes com o nome do esquema, ou podem colocar os esquemas adicionais em seu caminho de procura, conforme prefiram.

5.10.7. Portabilidade #

No padrão SQL, a noção de objetos no mesmo esquema pertencentes a usuários diferentes não existe. Além disso, algumas implementações não permitem que se criem esquemas que tenham um nome diferente do seu dono. Na verdade, os conceitos de esquema e usuário são quase equivalentes em um sistema de banco de dados que implementa apenas o suporte básico de esquema especificado no padrão. Portanto, muitos usuários consideram que os nomes qualificados realmente consistem apenas em nome_do_usuario.nome_da_tabela. É assim que o PostgreSQL vai se comportar de fato se for criado um esquema de usuário para todos os usuários.

Além disso, não existe o conceito de esquema public no padrão SQL. Para máxima conformidade com o padrão, não deve ser usado o esquema public.

É claro que alguns sistemas de banco de dados SQL podem não implementar esquemas ou fornecer suporte a espaços de nomes, permitindo apenas o acesso cruzado entre bancos de dados (possivelmente limitado). Se for necessário trabalhar com um sistema assim, a portabilidade máxima será obtida sem o uso de esquemas.

5.10.8. Exemplo #

Exemplo 5.2. Exemplo do tradutor

Mostrar o banco de dados corrente, o caminho de procura, a lista de esquemas, a lista de tabelas e a lista de linguagens da usuária miriam.

$ psql -d miriam -U miriam -h localhost --password
Senha:
psql (18.1 (Debian 18.1-1.pgdg12+2))
Digite "help" para obter ajuda.

miriam=> SELECT datname AS "Banco",
       pg_get_userbyid(datdba) AS "Dono",
       pg_size_pretty(pg_database_size(datname)) AS "Tamanho",
       datcollate AS "Ordenação"
FROM pg_database
WHERE datname = current_database();

 Banco  |  Dono  | Tamanho |  Ordenação
--------+--------+---------+-------------
 miriam | miriam | 7742 kB | pt_BR.UTF-8
(1 linha)

miriam=> SHOW search_path;

   search_path
-----------------
 "$user", public
(1 linha)

miriam=> \dn

     Lista de esquemas
  Nome  |       Dono
--------+-------------------
 public | pg_database_owner
(1 linha)

miriam=> \dt

             Lista de tabelas
 Esquema |     Nome     |  Tipo  |  Dono
---------+--------------+--------+--------
 public  | minha_tabela | tabela | miriam
(1 linha)

miriam=> \dL

                      Lista de linguagens
  Nome   |   Dono   | Confiável |          Descrição
---------+----------+-----------+------------------------------
 plpgsql | postgres | t         | PL/pgSQL procedural language
(1 linha)




[36] Um esquema é uma coleção de objetos com nome; fornece uma maneira de agrupar estes objetos logicamente. Um esquema também é um qualificador de nome; fornece uma maneira de usar o mesmo nome natural para vários objetos e de evitar referências ambíguas a estes objetos. IBM DB2 – Schemas (N. T.).