Contents
pg_synonym
CREATE SYNONYM para PostgreSQL. Dê a uma tabela ou view um segundo nome em outro schema, e continue lendo
e gravando por ele enquanto a tabela de verdade muda por baixo.
-- SQL Server: CREATE SYNONYM vendas.cliente FOR erp.clientes
SELECT synonym.create('vendas.cliente', 'erp.clientes');
SELECT * FROM vendas.cliente; -- lê erp.clientes
INSERT INTO vendas.cliente (nome) VALUES ('Ana'); -- grava em erp.clientes
Por quê?
SQL Server e Oracle têm sinônimos. As aplicações usam esse recurso para esconder onde a tabela está de verdade, em qual schema ou com qual nome. O PostgreSQL não tem, e as migrações costumam cair em uma de duas gambiarras:
- Uma view. Funciona até alguém rodar
ALTER TABLEna tabela real. Colunas novas não aparecem,DROP COLUMNeALTER COLUMN TYPEsão recusados (“other objects depend on it”) e oDROP TABLEexigeCASCADE. - Truques com
search_path. São globais, frágeis e invisíveis no código.
O pg_synonym traz sinônimos de verdade. Cada um é uma view atualizável, e a extensão mantém essa view em dia
com o destino automaticamente, qualquer que seja o ALTER TABLE.
Como usar
Criar e apagar
SELECT synonym.create('vendas.cliente', 'erp.clientes');
SELECT synonym.drop('vendas.cliente');
SELECT synonym.drop('vendas.cliente', if_exists => true);
DROP VIEW vendas.cliente, ou DROP OWNED BY o dono do sinônimo, também apagam o sinônimo.
Os nomes seguem as regras normais do PostgreSQL. Sem schema, o sinônimo vai para o primeiro schema do
search_path, e o destino é procurado pelo search_path. Nomes entre aspas funcionam:
synonym.create('app."Pedidos"', 'erp."Pedidos Antigos"').
Listar
SELECT * FROM synonym.list;
synonym | target | owner | status | created_at
----------------+---------------+-------+----------+-------------------------------
vendas.cliente | erp.clientes | ana | ok | 2026-10-19 15:47:28.03-03
vendas.produto | erp.produtos | ana | pending | 2026-10-19 15:48:02.11-03
| status | significado |
|---|---|
ok |
Funcionando. |
pending |
O destino ainda não existe. O sinônimo passa a funcionar assim que ele for criado. |
conflict |
Outro objeto já usa o nome do sinônimo. Renomeie ou apague esse objeto. |
out of sync |
Não deveria acontecer. Rode SELECT synonym.refresh();. |
Use como se fosse a tabela
SELECT ... FROM vendas.cliente JOIN ...;
INSERT INTO vendas.cliente (...) VALUES (...) RETURNING id;
INSERT ... ON CONFLICT (id) DO UPDATE ...;
UPDATE vendas.cliente SET ...;
DELETE FROM vendas.cliente WHERE ...;
Os defaults, as colunas identity, as constraints, os triggers e a segurança por linha (RLS) da tabela de destino continuam valendo. O planner enxerga direto a tabela real, então uma consulta pelo sinônimo é exatamente tão rápida quanto uma consulta na tabela.
Colinha SQL Server → PostgreSQL
| SQL Server | pg_synonym |
|---|---|
CREATE SYNONYM s.x FOR s.y |
SELECT synonym.create('s.x', 's.y') |
DROP SYNONYM s.x |
SELECT synonym.drop('s.x') |
DROP SYNONYM IF EXISTS s.x |
SELECT synonym.drop('s.x', if_exists => true) |
SELECT * FROM sys.synonyms |
SELECT * FROM synonym.list |
CREATE SYNONYM x FOR outrobanco.dbo.y |
Não suportado. Crie uma foreign table com postgres_fdw e aponte o sinônimo para ela |
O que ele mantém sincronizado
| Você faz isso no destino | O sinônimo |
|---|---|
ADD COLUMN |
mostra a coluna nova |
RENAME COLUMN |
usa o nome novo |
ALTER COLUMN ... TYPE |
usa o tipo novo (uma view comum bloquearia isso) |
DROP COLUMN |
perde a coluna (uma view comum bloquearia isso) |
RENAME TO, SET SCHEMA |
continua apontando para a mesma tabela, como uma view faria |
DROP TABLE |
continua definido e fica pending (sem precisar de CASCADE) |
| criar de novo | volta a funcionar, já com as colunas novas |
Também dá para criar um sinônimo antes do destino existir (ligação tardia, como no SQL Server). Ele fica
pending e passa a funcionar quando o destino for criado.
Views que você criar em cima de um sinônimo sobrevivem a mudanças inofensivas, como adicionar ou renomear
colunas. Mudanças que exigem reconstruir o sinônimo (DROP COLUMN, ALTER COLUMN TYPE, DROP TABLE) são
recusadas enquanto essas views existirem, que é o mesmo que o PostgreSQL faz com qualquer view. Use CASCADE
quando o comando aceitar.
Permissões
Um sinônimo nunca dá a ninguém mais acesso do que a pessoa já tem no destino.
- Toda view de sinônimo é criada com
security_invoker = true. Quem usa o sinônimo precisa ter os privilégios no destino, e as políticas de RLS do destino se aplicam a essa pessoa. - Para criar um sinônimo você precisa de privilégio
CREATEno schema do sinônimo, como para criar uma view, e deUSAGEno schema do destino, para poder citá-lo. Não precisa de nenhum privilégio na tabela de destino em si. - Só o dono do sinônimo, um membro do papel (role) dono ou um superusuário pode apagá-lo.
- O dono da tabela continua podendo dar
ALTERouDROPnela, mesmo que outros usuários tenham sinônimos apontando para ela.
Instalar a extensão exige superusuário, porque ela usa event triggers. Usar não exige.
Instalação
Requer PostgreSQL 15 ou mais novo. Não é preciso mexer em shared_preload_libraries nem reiniciar o servidor.
Linux (Debian / Ubuntu)
sudo apt install build-essential postgresql-server-dev-17 # use a versão do seu PostgreSQL
git clone https://github.com/Mazuco/pg_synonym.git
cd pg_synonym
make
sudo make install
Linux (Rocky / RHEL / Fedora, pacotes do PGDG)
sudo dnf install -y gcc make git redhat-rpm-config dnf-plugins-core
sudo dnf config-manager --set-enabled crb # Rocky 9 (no Rocky 8: --set-enabled powertools)
sudo dnf install -y postgresql17-devel
make PG_CONFIG=/usr/pgsql-17/bin/pg_config with_llvm=no
sudo make install PG_CONFIG=/usr/pgsql-17/bin/pg_config with_llvm=no
macOS (Homebrew)
brew install postgresql@17
make PG_CONFIG=$(brew --prefix postgresql@17)/bin/pg_config
make install PG_CONFIG=$(brew --prefix postgresql@17)/bin/pg_config
Docker (qualquer sistema, inclusive Windows)
docker build -t pg_synonym . # PostgreSQL 17 por padrão
docker build --build-arg PG_MAJOR=18 -t pg_synonym:18 .
docker run -d --name pgsyn -e POSTGRES_PASSWORD=postgres -p 5432:5432 pg_synonym
Erro de compilação falando de
clangoullvm? O seu pacote do PostgreSQL foi compilado com JIT e tenta gerar um “bitcode” LLVM, que esta extensão não precisa. Compile commake with_llvm=noe instale comsudo make with_llvm=no install.
Ativando no banco
CREATE EXTENSION pg_synonym; -- como superusuário
A extensão fica no seu próprio schema, synonym.
Limitações
- Tabelas, views, materialized views, tabelas particionadas e foreign tables podem ser destino. Funções, procedures e sequences ainda não.
- Não existe sintaxe nova. Extensões não podem criar comandos SQL, então o
CREATE SYNONYMvira uma chamada de função. - Sem sinônimos entre bancos. Aponte o sinônimo para uma foreign table do
postgres_fdw. - Sinônimo de sinônimo não é permitido. O SQL Server também não permite.
- O que uma view não faz também não funciona pelo sinônimo:
TRUNCATE,COPY sinonimo TO(useCOPY (SELECT * FROM sinonimo) TO) e DDL comoALTER TABLE sinonimo.MERGEnum sinônimo exige PostgreSQL 17 ou mais novo. - Renomear o destino é acompanhado. O sinônimo continua apontando para a tabela depois de
RENAMEouSET SCHEMA, como uma view faria. No SQL Server o vínculo é pelo nome. - Gerencie sinônimos só por estas funções. Renomear a view do sinônimo ou o schema dela, ou desligar o
security_invokerna mão, quebra o vínculo. Quando um sinônimo é reconstruído, GRANTs feitos à mão nele são refeitos do zero. DROP EXTENSION pg_synonymtransforma os sinônimos existentes em views comuns e deixa o schemasynonympara trás (DROP SCHEMA synonymremove).
Desempenho
- Consultas: nenhum custo extra. O sinônimo é uma view simples, que o planner elimina.
- DDL: os event triggers acrescentam trabalho a
CREATE,ALTEReDROPde tabelas e views. Medido no PostgreSQL 16: cerca de 0,4 ms por DDL sem sinônimos, e cerca de 11 ms por DDL com 500 sinônimos.
Como funciona
Um sinônimo é uma linha em synonym.catalog mais uma view
CREATE VIEW ... WITH (security_invoker = true) AS SELECT * FROM destino. Event triggers mantêm os dois
juntos:
- Antes de
DROP TABLE,DROP COLUMNouALTER COLUMN TYPEno destino, uma pequena função em C lê o comando, descobre quais sinônimos estão envolvidos e apaga as views deles, para o PostgreSQL não recusar o comando. - Depois de qualquer DDL em tabelas, views e schemas, uma função PL/pgSQL compara cada sinônimo com o destino e cria, estende, renomeia ou reconstrói a view conforme o necessário.
- Quando alguém apaga a view de um sinônimo diretamente (
DROP VIEW,DROP OWNED), o sinônimo é esquecido.
Se o comando falhar, a transação inteira é desfeita, inclusive o passo 1. Tirando cerca de 200 linhas de C comentado,
tudo é PL/pgSQL comum em pg_synonym--1.0.sql. A explicação linha a linha está em
docs/COMO_FUNCIONA.md.
Rodando os testes
make
sudo make install
make installcheck # precisa de um servidor rodando e de conexão como superusuário
Contribuindo
Issues e pull requests são bem-vindos. Qualquer mudança de comportamento deve vir com um teste de regressão em
test/sql/ e a saída esperada em test/expected/.
Licença
Distribuída sob a Licença PostgreSQL.