Desejo criar um novo nome de tabela com base em um existente anexando um sufixo a ele. Uma função PL/pgSQL do Postgres 9.5 obtém o nome da tabela existente passado como regclass
tipo e retorna o novo nome como uma string. Estou usando format()
para construir o novo nome e normalmente usaria o %I
espaço reservado. Isso funciona desde que o nome da tabela passado não corresponda a nenhuma palavra-chave PL/pgSQL. Nesse caso, independentemente do tipo de componente que eu escolher ( %I
ou %s
), a citação está errada.
Considere a seguinte função:
CREATE OR REPLACE FUNCTION make_name(old_name regclass)
RETURNS text
LANGUAGE plpgsql AS
$$
BEGIN
RETURN format('%I_new', old_name);
END;
$$;
Além disso, suponha que haja duas tabelas: treenode
e overlay
. Chamar esta função para ambos resulta nos seguintes novos nomes:
SELECT make_name('overlay'::regclass);
make_name
-------------------
"""overlay"""_new
(1 row)
SELECT make_name('treenode'::regclass);
make_name
--------------
treenode_new
(1 row)
Acontece que overlay
também é uma função PL/pgSQL (assim como format
, mas treenode
não é), que parece alterar o comportamento de citação. Se %s
for usado com format()
, o resultado seria "overlay"_new
. O mesmo acontece quando utilizo a ||
operadora. Se eu usar text
como tipo de parâmetro de entrada, tudo funcionará conforme o esperado, mas prefiro usar regclass
.
Existe uma maneira de formatar uma string com um regclass
nome de tabela de correspondência de palavra-chave (por exemplo overlay
) sem aspas, assim como é o caso de um regclass
nome de tabela de correspondência de palavra-chave (por exemplo treenode
)?
Explicação
Vou percorrer as várias camadas de mal-entendidos, uma a uma - chegando a uma solução simples e segura.
0.A razão pela qual
1.overlay
está entre aspas não é porque é um nome de função, mas porque é uma palavra reservada .Além disso, não
overlay()
é uma "função PL/pgSQL" (nem palavra-chave PL/pgSQL), é uma função SQL padrão incorporada ao núcleo do Postgres ( , então C por trás das cortinas). Na verdade, PL/pgSQL não tem nada a ver com nada disso.LANGUAGE internal
Um simples erro de lógica.
Isso escaparia de qualquer identificador não padrão com aspas antes de '_new' ser anexado e falharia mesmo com
text
o tipo de entrada. Você deve acrescentar '_new' antes de citar tudo:Mas isso ainda não funcionará para
2.regclass
. Continue lendo.Não faz sentido adicionar aspas a uma
3.regclass
variável com%I
, pois sua representação de texto já é citada automaticamente quando necessário. (Semelhante aquote_ident()
, mas não pode ser NULL; já que a entradaregclass
não pode ser NULL para começar.) Você o aplicaria duas vezes . Sempre use%s
pararegclass
entrada (a string como está).
4.format()
é um exagero para isso. Basta usarquote_ident()
:Mais importante , como mencionado acima, a
text
representação de umaregclass
variável é automaticamente escapada. Isso está embutido no elenco. Para obter o texto bruto, recupere-diretamente do catálogo do sistema .pg_class
Umregclass
valor é apenas ooid
desta tabela internamente.Solução
Isso faz o que você está procurando:
Teste
Observe que
overlay_new
é um identificador perfeitamente legal, portanto não é citado.Se você quiser o nome sem escape (sem aspas), basta usar:
A única maneira que consegui pensar foi agrupar a chamada para a
format
função datranslate
seguinte maneira:Esta postagem processa a saída do formato e remove os "caracteres.
Não sei se alguém tem uma solução mais elegante. Pensei em btrim, rtrim etc... mas precisaria de uma chamada para cada um.