pg_synonym

CI PostgreSQL 15+Licença: PostgreSQL

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.

🇺🇸 Read in English

-- 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 TABLE na tabela real. Colunas novas não aparecem, DROP COLUMN e ALTER COLUMN TYPE são recusados (“other objects depend on it”) e o DROP TABLE exige CASCADE.
  • 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 CREATE no schema do sinônimo, como para criar uma view, e de USAGE no 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 ALTER ou DROP nela, 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 clang ou llvm? O seu pacote do PostgreSQL foi compilado com JIT e tenta gerar um “bitcode” LLVM, que esta extensão não precisa. Compile com make with_llvm=no e instale com sudo 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 SYNONYM vira 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 (use COPY (SELECT * FROM sinonimo) TO) e DDL como ALTER TABLE sinonimo. MERGE num sinônimo exige PostgreSQL 17 ou mais novo.
  • Renomear o destino é acompanhado. O sinônimo continua apontando para a tabela depois de RENAME ou SET 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_invoker na 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_synonym transforma os sinônimos existentes em views comuns e deixa o schema synonym para trás (DROP SCHEMA synonym remove).

Desempenho

  • Consultas: nenhum custo extra. O sinônimo é uma view simples, que o planner elimina.
  • DDL: os event triggers acrescentam trabalho a CREATE, ALTER e DROP de 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:

  1. Antes de DROP TABLE, DROP COLUMN ou ALTER COLUMN TYPE no 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.
  2. 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.
  3. 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.