martes, 31 de marzo de 2015

PostgreSQL: Interrumpir un lote de instrucciones

Complementando el artículo anterior, aquí se le puede encontrar utilidad al ejemplo tan extraño que utilicé en él (si piensas poner este artículo en práctica, no dejes de ver el anterior para que no te lleves sorpresas desagradables).

¿Y para qué voy yo a necesitar interrumpir un lote de instrucciones?


A veces hace falta lanzar de forma no interactiva un conjunto de sentencias SQL (lote) asumiendo que el conjunto se ejecutará correctamente. Para ello, se asume que en la base de datos se cumplen ciertas condiciones, que en el momento de lanzar el lote de instrucciones o durante su ejecución podrían no cumplirse.

Seguramente conozcas el concepto transacción en SQL. No siempre se puede hacer uso de esta característica, especialmente cuando el tamaño del lote produce grandes cambios en los datos (según la configuración de PostgreSQL, los ficheros WAL necesarios para la transacción podrían desbordarse).

¿Y si en medio del lote te interesa realizar alguna comprobación e interrumpir el proceso si no se dan las condiciones adecuadas?.

La solución propuesta


Cuando se produce un error, se puede detener el flujo de instrucciones (ver ON_ERROR_STOP en  psql). Por tanto, si se consigue generar un error de forma controlada, se podría utilizar para interrumpir el proceso.

Se podría crear un procedimiento almacenado que tras realizar las comprobaciones necesarias, lance una excepción cuando convenga. Sin embargo, eso requiere escribir código PL/SQL y tener privilegios para instalar procedimientos almacenados en la base de datos.

Pero hay una técnica mucho más simple y muchísimo menos intrusiva:

forzar una excepción al convertir de un tipo de dato a otro.

Por ejemplo, intentar convertir un texto no numérico en un número.

SELECT CASE WHEN (r_count = 0) THEN CAST('Nothing to process.'||r_count AS INTEGER)
            ELSE CAST(r_count AS INTEGER)
       END AS preprocessed_count
FROM (SELECT COUNT(*) AS r_count FROM preprocessed_data
     ) foo
;

Ese ejemplo permitiría interrumpir un lote si en la tabla preprocessed_data no hay nada, por ejemplo, porque acciones anteriores no han escrito en ella.

Enlaces


Enlaces de interés relacionados con este artículo:

(Actualizado 31/03/2015)