42.2. Funciones y argumentos en PL/Tcl #

Para crear una función en el lenguaje PL/Tcl, utiliza la sintaxis estándar de CREATE FUNCTION:

CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
    # cuerpo de la función PL/Tcl
$$ LANGUAGE pltcl;

PL/TclU es lo mismo, excepto que el lenguaje debe especificarse como pltclu.

El cuerpo de la función es simplemente un fragmento de script de Tcl. Cuando se llama a la función, los valores de los argumentos se pasan al script de Tcl como variables llamadas 1 ... n. El resultado se devuelve desde el código de Tcl de la manera habitual, con una sentencia return. En un procedimiento, el valor de retorno del código de Tcl es ignorado.

Por ejemplo, una función que devuelva el mayor de dos valores enteros podría definirse como:

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

Ten en cuenta la cláusula STRICT, que nos evita tener que pensar en valores de entrada null: si se pasa un valor null, la función no se llamará en absoluto, sino que simplemente devolverá un resultado null automáticamente.

En una función no estricta, si el valor real de un argumento es null, la variable $n correspondiente se establecerá en una cadena vacía. Para detectar si un argumento particular es null, utiliza la función argisnull. Por ejemplo, supongamos que queremos que tcl_max con un argumento null y uno no null devuelva el argumento no null, en lugar de 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;

Como se muestra arriba, para devolver un valor null desde una función PL/Tcl, ejecuta return_null. Esto se puede hacer tanto si la función es estricta como si no.

Los argumentos de tipo compuesto se pasan a la función como arrays de Tcl. Los nombres de los elementos del array son los nombres de los atributos del tipo compuesto. Si un atributo en la fila pasada tiene el valor null, no aparecerá en el array. Aquí tienes un ejemplo:

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;

Las funciones PL/Tcl también pueden devolver resultados de tipo compuesto. Para hacer esto, el código Tcl debe devolver una lista de pares nombre/valor de columna que coincidan con el tipo de resultado esperado. Cualquier nombre de columna omitido de la lista se devuelve como null, y se lanza un error si hay nombres de columna inesperados. Aquí tienes un ejemplo:

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;

Los argumentos de salida de los procedimientos se devuelven de la misma manera, por ejemplo:

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);

Tip

La lista de resultados se puede crear a partir de una representación en array de la tupla deseada con el comando Tcl array get. Por ejemplo:

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

Las funciones PL/Tcl pueden devolver conjuntos. Para hacer esto, el código Tcl debe llamar a return_next una vez por fila a devolver, pasando el valor apropiado al devolver un tipo escalar, o una lista de pares nombre/valor de columna al devolver un tipo compuesto. Aquí tienes un ejemplo que devuelve un tipo escalar:

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

y aquí tienes uno que devuelve un tipo compuesto:

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;