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.
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:
Para permitir que muitos usuários usem o mesmo banco de dados sem que um interfira com os outros.
Para organizar objetos de banco de dados em grupos lógicos para torná-los mais fáceis de serem gerenciados.
Aplicações de terceiros podem ser colocadas em esquemas separados para não haver colisão entre nomes de objetos.
Os esquemas são semelhantes aos diretórios de sistema operacional, exceto por não poderem ser aninhados.
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 SCHEMAnome_do_esquemaAUTHORIZATIONnome_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.
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 ( ... );
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.
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.)
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_.
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.
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
.
É assim que o PostgreSQL vai se comportar
de fato se for criado um esquema de usuário para todos os
usuários.
nome_do_usuario.nome_da_tabela
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.
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.).