Você deve se defender contra a injeção de SQL sempre que você transforma a entrada do usuário em código. Isso inclui nomes de tabelas e colunas provenientes de catálogos do sistema ou da entrada direta do usuário. Dessa forma, você também evita exceções triviais com identificadores não padrão. Existem basicamente três métodos embutidos:
1. format()
1ª consulta, higienizada:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('
ALTER TABLE %I ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)', _t);
END
$func$;
format()
requer Postgres 9.1 ou posterior. Use-o com o %I
especificador de formato. O nome da tabela sozinho pode ser ambíguo. Talvez seja necessário fornecer o nome do esquema para evitar alterar a tabela errada acidentalmente. Relacionado:
- INSERIR com o nome da tabela dinâmica na função de gatilho
- Como o search_path influencia a resolução do identificador e o "esquema atual"
Além:adicionar várias colunas com um único
ALTER TABLE
comando é mais barato. 2. regclass
Você também pode usar um cast para uma classe registrada (
regclass
) para o caso especial de existente nomes de tabelas. Opcionalmente qualificado pelo esquema. Isso falha imediatamente e normalmente para nomes de tabela que não são válidos e visíveis para o usuário chamador. A primeira consulta corrigida com uma conversão para regclass
:CREATE OR REPLACE FUNCTION foo(_t regclass)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'ALTER TABLE ' || _t || ' ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)';
END
$func$;
Ligar:
SELECT foo('table_name');
Ou:
SELECT foo('my_schema.table_name'::regclass);
Além:considere usar apenas
text
em vez de varchar(20)
. 3. quote_ident()
A 2ª consulta higienizada:
CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'UPDATE ' || _t -- sanitized with regclass
|| ' SET ' || quote_ident(_c) || ' = ''This is a test''';
END
$func$;
Para várias concatenações/interpolações,
format()
é mais limpo... Respostas relacionadas:
- Nome da tabela como parâmetro de função do PostgreSQL
- Funções do Postgres x consultas preparadas
Diferencia maiúsculas de minúsculas!
Esteja ciente de que identificadores sem aspas não convertido para minúsculas aqui. Quando usado como identificador no SQL [Postgres converte para minúsculas automaticamente][7]. Mas aqui passamos strings para SQL dinâmico. Quando escapado conforme demonstrado, identificadores CaMel-case (como
UserS
) será preservado por aspas duplas ("UserS"
), assim como outros nomes não padrão como "name with space"
"SELECT"
etc. Portanto, os nomes diferenciam maiúsculas de minúsculas neste contexto. Meu conselho permanente é usar identificadores legais de letras minúsculas exclusivamente e nunca se preocupar com isso.
Além disso:aspas simples são para valores, aspas duplas são para identificadores. Ver:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS