Има място за подобрения:
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
Основни точки
-
PostgreSQL 8.4 въведе
USING
клауза заEXECUTE
, което е полезно по няколко причини. Резюме в ръководството:Командният низ може да използва стойности на параметри, които са посочени в командата като
$1, $2
и т.н. Тези символи се отнасят до стойности, предоставени вUSING
клауза. Този метод често е за предпочитане пред вмъкването на стойности на данни в командния низ като текст:той избягва излишните разходи по време на изпълнение за преобразуване на стойностите в текст и обратно и е много по-малко податлив на атаки с инжектиране на SQL, тъй като няма нужда от цитиране или избягване.IOW, това е по-безопасно и по-бързо от изграждането на низ на заявка с текстово представяне на параметрите, дори когато е дезинфекциран с
quote_literal()
.
Обърнете внимание, че$1, $2
в низа на заявката се отнасят до предоставените стойности вUSING
клауза, не към параметрите на функцията. -
Докато връщате
SELECT * FROM lookups.countries
, можете да опроститеRETURN
декларация, както е показано:RETURNS SETOF lookups.countries
В PostgreSQL има съставен тип, дефиниран автоматично за всяка таблица. Използваи го. Ефектът е, че функцията зависи от типа и получавате съобщение за грешка, ако се опитате да промените таблицата. Пуснете и създайте отново функцията в такъв случай.
Това може да е желателно или не - като цяло е така! Искате да сте наясно със страничните ефекти, ако промените таблиците. По начина, по който го имате, вашата функция ще се счупи безшумно и ще предизвика изключение при следващото си извикване.
-
Ако предоставите изрична настройка по подразбиране за втория параметър в декларацията, както е показано, можете (но не е необходимо) да опростите извикването, в случай че не искате да зададете горна граница с
ends_with
.SELECT * FROM report_get_countries_new('Zaire');
вместо:
SELECT * FROM report_get_countries_new('Zaire', NULL);
Имайте предвид претоварването на функциите в този контекст.
-
Не цитирайте името на езика
дори и това да се толерира (засега). Това е идентификатор.'plpgsql' -
Можете да зададете променлива по време на декларация. Спестява допълнителна стъпка.
-
Параметрите са наименувани в заглавката. Изхвърлете безсмислените редове:
starts_with ALIAS FOR $1; ends_with ALIAS FOR $2;