42.5. Acceso a la base de datos desde PL/Tcl #

En esta sección, seguimos la convención habitual de Tcl de utilizar signos de interrogación, en lugar de corchetes, para indicar un elemento opcional en una sinopsis de sintaxis. Los siguientes comandos están disponibles para acceder a la base de datos desde el cuerpo de una función PL/Tcl:

spi_exec ?-count n? ?-array name? command ?loop-body?

Ejecuta un comando SQL dado como una cadena. Un error en el comando hace que se lance un error. De lo contrario, el valor de retorno de spi_exec es el número de filas procesadas (seleccionadas, insertadas, actualizadas o eliminadas) por el comando, o cero si el comando es una sentencia de utilidad. Además, si el comando es una sentencia SELECT, los valores de las columnas seleccionadas se colocan en variables de Tcl como se describe a continuación.

El valor opcional -count le dice a spi_exec que se detenga una vez que se hayan recuperado n filas, como si la consulta incluyera una cláusula LIMIT. Si n es cero, la consulta se ejecuta hasta completarse, lo mismo que cuando se omite -count.

Si el comando es una sentencia SELECT, los valores de las columnas del resultado se colocan en variables de Tcl que llevan el nombre de las columnas. Si se proporciona la opción -array, los valores de las columnas se almacenan en su lugar en elementos del array asociativo nombrado, con los nombres de las columnas utilizados como índices del array. Además, el número de fila actual dentro del resultado (contando desde cero) se almacena en el elemento del array llamado .tupno, a menos que ese nombre esté en uso como un nombre de columna en el resultado.

Si el comando es una sentencia SELECT y no se proporciona un script de loop-body, entonces solo la primera fila de los resultados se almacena en variables de Tcl o elementos del array; las filas restantes, si las hay, se ignoran. No se realiza ningún almacenamiento si la consulta no devuelve filas. (Este caso se puede detectar comprobando el resultado de spi_exec). Por ejemplo:

spi_exec "SELECT count(*) AS cnt FROM pg_proc"

establecerá la variable Tcl $cnt al número de filas en el catálogo del sistema pg_proc.

Si se proporciona el argumento opcional loop-body, es un fragmento de script de Tcl que se ejecuta una vez para cada fila en el resultado de la consulta. (loop-body se ignora si el comando dado no es un SELECT). Los valores de las columnas de la fila actual se almacenan en variables de Tcl o elementos del array antes de cada iteración. Por ejemplo:

spi_exec -array C "SELECT * FROM pg_class" {
    elog DEBUG "have table $C(relname)"
}

imprimirá un mensaje de registro para cada fila de pg_class. Esta característica funciona de manera similar a otras estructuras de bucle de Tcl; en particular, continue y break funcionan de la manera habitual dentro del cuerpo del bucle.

Si una columna de un resultado de consulta es null, la variable de destino para ella se elimina (unset) en lugar de establecerse.

spi_prepare query typelist

Prepara y guarda un plan de consulta para una ejecución posterior. El plan guardado se conservará durante la vida de la sesión actual.

La consulta puede usar parámetros, es decir, marcadores de posición para valores que se proporcionarán cada vez que el plan se ejecute realmente. En la cadena de consulta, haz referencia a los parámetros mediante los símbolos $1 ... $n. Si la consulta utiliza parámetros, los nombres de los tipos de parámetros deben proporcionarse como una lista de Tcl. (Escribe una lista vacía para typelist si no se utilizan parámetros).

El valor de retorno de spi_prepare is a query ID que se utilizará en llamadas posteriores a spi_execp. Consulta spi_execp para ver un ejemplo.

spi_execp ?-count n? ?-array name? ?-nulls string? queryid ?value-list? ?loop-body?

Ejecuta una consulta previamente preparada con spi_prepare. queryid es el ID devuelto por spi_prepare. Si la consulta hace referencia a parámetros, se debe proporcionar una value-list. Esta es una lista de Tcl con los valores reales para los parámetros. La lista debe tener la misma longitud que la lista de tipos de parámetros proporcionada anteriormente a spi_prepare. Omite value-list si la consulta no tiene parámetros.

El valor opcional para -nulls es una cadena de espacios y caracteres 'n' que le dice a spi_execp cuáles de los parámetros son valores null. Si se proporciona, debe tener exactamente la misma longitud que la value-list. Si no se proporciona, todos los valores de los parámetros se consideran no null.

Excepto por la forma en que se especifican la consulta y sus parámetros, spi_execp funciona igual que spi_exec. Las opciones -count, -array y loop-body son las mismas, y también lo es el valor del resultado.

Aquí tienes un ejemplo de una función PL/Tcl que utiliza un plan preparado:

CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
    if {![ info exists GD(plan) ]} {
        # preparar el plan guardado en la primera llamada
        set GD(plan) [ spi_prepare \
                "SELECT count(*) AS cnt FROM t1 WHERE num >= \$1 AND num <= \$2" \
                [ list int4 int4 ] ]
    }
    spi_execp -count 1 $GD(plan) [ list $1 $2 ]
    return $cnt
$$ LANGUAGE pltcl;

Necesitamos barras invertidas dentro de la cadena de consulta dada a spi_prepare para asegurar que los marcadores $n se pasen a spi_prepare tal cual, y no se reemplacen por la sustitución de variables de Tcl.

subtransaction command

El script de Tcl contenido en command se ejecuta dentro de una subtransacción SQL. Si el script devuelve un error, toda esa subtransacción se revierte antes de devolver el error al código Tcl circundante. Consulta Section 42.9 para más detalles y un ejemplo.

quote string

Duplica todas las apariciones de comillas simples y caracteres de barra invertida en la cadena dada. Esto se puede usar para entrecomillar de forma segura cadenas que se van a insertar en comandos SQL dados a spi_exec o spi_prepare. Por ejemplo, piensa en una cadena de comando SQL como:

"SELECT '$val' AS ret"

donde la variable Tcl val realmente contiene doesn't. Esto resultaría en la cadena de comando final:

SELECT 'doesn't' AS ret

lo que causaría un error de análisis durante spi_exec o spi_prepare. Para funcionar correctamente, el comando enviado debería contener:

SELECT 'doesn''t' AS ret

que se puede formar en PL/Tcl usando:

"SELECT '[ quote $val ]' AS ret"

Una ventaja de spi_execp es que no tienes que entrecomillar los valores de los parámetros como este, ya que los parámetros nunca se analizan como parte de una cadena de comando SQL.

elog level msg

Emite un mensaje de registro o error. Los niveles posibles son DEBUG, LOG, INFO, NOTICE, WARNING, ERROR y FATAL. ERROR lanza una condición de error; si esta no es capturada por el código Tcl circundante, el error se propaga a la consulta que llama, lo que hace que la transacción o subtransacción actual se aborte. Esto es efectivamente lo mismo que el comando error de Tcl. FATAL aborta la transacción y hace que la sesión actual se cierre. (Probablemente no haya una buena razón para usar este nivel de error en funciones PL/Tcl, pero se proporciona para completitud). Los otros niveles solo generan mensajes de diferentes niveles de prioridad. Si los mensajes de una prioridad particular se reportan al cliente, se escriben en el registro del servidor o ambos está controlado por las variables de configuración log_min_messages y client_min_messages. Consulta Chapter 19 y Section 42.8 para más información.