Há espaço para melhorias:
CREATE OR REPLACE FUNCTION report_get_countries_new (starts_with text
, ends_with text = NULL)
RETURNS SETOF lookups.countries AS
$func$
DECLARE
sql text := 'SELECT * FROM lookups.countries WHERE country_name >= $1';
BEGIN
IF ends_with IS NOT NULL THEN
sql := sql || ' AND country_name <= $2';
END IF;
RETURN QUERY EXECUTE sql
USING starts_with, ends_with;
END
$func$ LANGUAGE plpgsql;
-- the rest is default settings
Pontos principais
-
O PostgreSQL 8.4 introduziu oUSING
cláusula paraEXECUTE
, que é útil por vários motivos. Recapitulando no manual:
A string de comando pode usar valores de parâmetro, que são referenciados no comando como$1, $2
, etc. Esses símbolos referem-se a valores fornecidos noUSING
cláusula. Esse método geralmente é preferível a inserir valores de dados na string de comando como texto:ele evita a sobrecarga de tempo de execução de converter os valores em texto e vice-versa, e é muito menos propenso a ataques de injeção de SQL, pois não há necessidade de citação ou escape.
IOW, é mais seguro e rápido do que construir uma string de consulta com representação de texto de parâmetros, mesmo quando higienizada comquote_literal()
.
Observe que$1, $2
na string de consulta referem-se aos valores fornecidos noUSING
cláusula, não aos parâmetros da função.
-
Enquanto você retornaSELECT * FROM lookups.countries
, você pode simplificar oRETURN
declaração como demonstrado:
RETURNS SETOF lookups.countries
No PostgreSQL existe um tipo composto definido automaticamente para cada tabela. Use-o. O efeito é que a função depende do tipo e você recebe uma mensagem de erro se tentar alterar a tabela. Solte e recrie a função nesse caso.
Isso pode ou não ser desejável - geralmente é! Você quer estar ciente dos efeitos colaterais se alterar as tabelas. Do jeito que você tem, sua função quebraria silenciosamente e geraria uma exceção na próxima chamada.
-
Se você fornecer um padrão explícito para o segundo parâmetro na declaração como demonstrado, você pode (mas não precisa) simplificar a chamada caso não queira definir um limite superior comends_with
.
SELECT * FROM report_get_countries_new('Zaire');
ao invés de:
SELECT * FROM report_get_countries_new('Zaire', NULL);
Esteja ciente da sobrecarga de função neste contexto.
-
Não cite o nome do idioma
mesmo que isso seja tolerado (por enquanto). É um identificador.'plpgsql'
-
Você pode atribuir uma variável no momento da declaração. Salva uma etapa extra.
-
Os parâmetros são nomeados no cabeçalho. Solte as linhas sem sentido:
starts_with ALIAS FOR $1; ends_with ALIAS FOR $2;