42.2. Функции и аргументы PL/Tcl#

42.2. Функции и аргументы PL/Tcl

42.2. Функции и аргументы PL/Tcl

Для создания функции на языке PL/Tcl используйте стандартный синтаксис CREATE FUNCTION:

CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
    # PL/Tcl function body
$$ LANGUAGE pltcl;

PL/TclU остается тем же, за исключением того, что язык должен быть указан как pltclu.

Тело функции представляет собой просто фрагмент скрипта Tcl. При вызове функции значения аргументов передаются в скрипт Tcl в виде переменных с именами 1 ... n. Результат возвращается из кода Tcl обычным образом с помощью оператора return. В процедуре возвращаемое значение из кода Tcl игнорируется.

Например, функция, возвращающая большее из двух целочисленных значений, может быть определена следующим образом:

CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
    if {$1 > $2} {return $1}
    return $2
$$ LANGUAGE pltcl STRICT;

Обратите внимание на условие STRICT, которое позволяет нам избежать необходимости обрабатывать пустые значения ввода: если передается пустое значение, функция вообще не будет вызвана, а автоматически вернет пустой результат.

В нестрогой функции, если фактическое значение аргумента равно NULL, соответствующая переменная $n будет установлена в пустую строку. Чтобы определить, является ли определенный аргумент NULL, используйте функцию argisnull. Например, предположим, что мы хотим, чтобы функция tcl_max с одним NULL-аргументом и одним ненулевым аргументом возвращала ненулевой аргумент, а не NULL:

CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
    if {[argisnull 1]} {
        if {[argisnull 2]} { return_null }
        return $2
    }
    if {[argisnull 2]} { return $1 }
    if {$1 > $2} {return $1}
    return $2
$$ LANGUAGE pltcl;

Как показано выше, чтобы вернуть значение NULL из функции PL/Tcl, выполните return_null. Это можно сделать независимо от того, является ли функция строгой или нет.

Аргументы типа Composite передаются в функцию как массивы Tcl. Имена элементов массива являются именами атрибутов составного типа. Если атрибут в переданной строке имеет значение null, он не будет отображаться в массиве. Вот пример:

CREATE TABLE employee (
    name text,
    salary integer,
    age integer
);

CREATE FUNCTION overpaid(employee) RETURNS boolean AS $$
    if {200000.0 < $1(salary)} {
        return "t"
    }
    if {$1(age) < 30 && 100000.0 < $1(salary)} {
        return "t"
    }
    return "f"
$$ LANGUAGE pltcl;

Функции PL/Tcl также могут возвращать результаты в составном типе. Для этого код Tcl должен возвращать список пар имя столбца/значение, соответствующих ожидаемому типу результата. Любые имена столбцов, не указанные из списка, возвращаются как NULL, и возникает ошибка, если есть неожиданные имена столбцов. Вот пример:

CREATE FUNCTION square_cube(in int, out squared int, out cubed int) AS $$
    return [list squared [expr {$1 * $1}] cubed [expr {$1 * $1 * $1}]]
$$ LANGUAGE pltcl;

Выходные аргументы процедур возвращаются таким же образом, например:

CREATE PROCEDURE tcl_triple(INOUT a integer, INOUT b integer) AS $$
    return [list a [expr {$1 * 3}] b [expr {$2 * 3}]]
$$ LANGUAGE pltcl;

CALL tcl_triple(5, 10);

Подсказка

Результирующий список может быть создан из массивного представления желаемой кортежа с помощью команды Tcl array get. Например:

CREATE FUNCTION raise_pay(employee, delta int) RETURNS employee AS $$
    set 1(salary) [expr {$1(salary) + $2}]
    return [array get 1]
$$ LANGUAGE pltcl;

Функции PL/Tcl могут возвращать наборы. Для этого код на Tcl должен вызывать return_next один раз для каждой возвращаемой строки, передавая соответствующее значение при возвращении скалярного типа или список пар имя столбца/значение при возвращении составного типа. Вот пример возвращения скалярного типа:

CREATE FUNCTION sequence(int, int) RETURNS SETOF int AS $$
    for {set i $1} {$i < $2} {incr i} {
        return_next $i
    }
$$ LANGUAGE pltcl;

и вот один, возвращающий составной тип:

CREATE FUNCTION table_of_squares(int, int) RETURNS TABLE (x int, x2 int) AS $$
    for {set i $1} {$i < $2} {incr i} {
        return_next [list x $i x2 [expr {$i * $i}]]
    }
$$ LANGUAGE pltcl;