Eu tenho uma função de gatilho no PostgreSQL 12 que executa algo assim:
CREATE OR REPLACE FUNCTION "my_latlon_function"()
RETURNS trigger AS
$$
BEGIN
latcolumn:= (
SELECT column_name
FROM information_schema.columns
WHERE table_schema = TG_TABLE_SCHEMA
AND table_name = TG_TABLE_NAME
AND column_name ~* '.*lat.*'
);
loncolumn := (
SELECT column_name
FROM information_schema.columns
WHERE table_schema = TG_TABLE_SCHEMA
AND table_name = TG_TABLE_NAME
AND column_name ~* '.*lon.*'
);
EXECUTE 'select $1.' || loncolumn USING NEW INTO lon;
EXECUTE 'select $1.' || latcolumn USING NEW INTO lat;
-- do much stuff
RETURN NEW;
END
$$
LANGUAGE 'plpgsql';
O problema é que as colunas lat
e lon
têm letras maiúsculas em seu nome, por exemplo, myLatitude
e myLongitude
. A função trigger é capaz de recuperar esses nomes, isso não é problema.
O problema está nas duas EXECUTE
instruções em que parece que os nomes das colunas ficam em minúsculas conforme indicado por este erro (na QUERY subjacente quando o gatilho é acionado):
ERROR: column "mylongitude" not found in data type gpspoints
LINE 1: select $1.myLongitude
^
QUERY: select $1.myLongitude
CONTEXT: PL/pgSQL function my_latlon_function() line 24 at EXECUTE
********** Error **********
ERROR: column "mylongitude" not found in data type gpspoints
SQL state: 42703
Context: PL/pgSQL function my_latlon_function() line 24 at EXECUTE
Eu sei que o PostgreSQL precisa colocar os nomes das colunas que têm letras maiúsculas em seu nome entre aspas duplas. Portanto, tentei definir aspas duplas nas duas instruções EXECUTE como esta:
EXECUTE 'select $1.' || "loncolumn" USING NEW INTO lon;
EXECUTE 'select $1.' || "latcolumn" USING NEW INTO lat;
Mas o erro permanece exatamente o mesmo.
Se possível, como posso lidar com nomes de colunas CamelCase em uma função de gatilho do PostgreSQL?
Se não não, por quê?
Use
format
com o%I
espaço reservado para identificadores:Identificadores de aspas duplas automaticamente quando necessário com
format()
(como Laurenz demonstra) ouquote_ident()
. Ver:Além disso, sua função de gatilho pode ser mais eficiente assim:
db<>fique aqui
(Isso pressupõe que os nomes das colunas sempre correspondam sem ambiguidade!?)
Demonstrando
quote_ident()
. Com os nomes das colunas já citados corretamente, podemos simplesmenteconcat()
mais tarde.A tabela de catálogo
pg_catalog.pg_attribute
é notavelmente mais rápida queinformation_schema.columns
. Compare a saída desses dois comandos para entender o porquê:Ver:
Nesse caso específico, também podemos usar convenientemente
TG_RELID
em vez deTG_TABLE_SCHEMA
eTG_TABLE_NAME
.Além disso, atribuições individuais são comparativamente caras em PL/pgSQL. Tente manter seu número baixo.
Embora a diferença de desempenho ainda seja pequena, essa função de gatilho é chamada uma vez por linha inserida. Adiciona-se para grandes inserções ...
Além disso,
col ~* 'lon'
é exatamente equivalente acol ~* '.*lon.*'
.