41.5. Accès à la base de données depuis PL/Tcl

Les commandes suivantes sont disponibles pour accéder à la base de données depuis le corps d'une fonction PL/Tcl :

spi_exec [-count n] [-array name] command [loop-body]

Exécute une commande SQL donnée en tant que chaîne. Une erreur dans la commande lève une erreur. Sinon, la valeur de retour de spi_exec est le nombre de lignes intéressées dans le processus (sélection, insertion, mise à jour ou suppression) par la commande ou zéro si la commande est une instruction utilitaire. De plus, si la commande est une instruction SELECT, les valeurs des données sélectionnées sont placées dans des variables Tcl décrites ci-dessous.

La valeur optionnelle -count indique à spi_exec le nombre maximum de lignes à travailler dans la commande. L'effet de ceci est comparable à l'initialisation d'une requête en tant que curseur et de dire FETCH n.

Si la commande est une instruction SELECT, les valeurs des colonnes de résultat sont placées dans les variables Tcl nommées d'après les colonnes. Si l'option -array est donnée, les valeurs de colonnes sont stockées à la place dans un tableau associatif nommé, avec les noms des colonnes utilisés comme index du tableau.

Si la commande est une instruction SELECT et qu'aucun script loop-body n'est donné, alors seule la première ligne de résultats est stockée dans des variables Tcl ; les lignes suivantes sont ignorées. Aucun stockage n'intervient si la requête ne renvoie pas de ligne (ce cas est détectable avec le résultat de la fonction spi_exec). Par exemple :

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

initialisera la variable Tcl $cnt avec le nombre de lignes dans le catalogue système pg_proc.

Si l'argument loop-body optionnel est donné, il existe un morceau de script Tcl qui est exécuté une fois pour chaque ligne du résultat de la requête (loop-body est ignoré si la commande donnée n'est pas un SELECT). Les valeurs des colonnes de la ligne actuelle sont stockées dans des variables Tcl avant chaque itération. Par exemple :

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

affichera un message de trace pour chaque ligne de pg_class. Cette fonctionnalité travaille de façon similaire aux autres constructions de boucles de Tcl ; en particulier, continue et break fonctionnent de la même façon à l'intérieur de loop-body.

Si une colonne d'un résultat de la requête est NULL, la variable cible est « dés-initialisée » plutôt qu'initialisée.

spi_prepare query typelist

Prépare et sauvegarde un plan de requête pour une exécution future. Le plan sauvegardé sera conservé pour la durée de la session actuelle.

La requête peut utiliser des paramètres, c'est-à-dire des emplacements pour des valeurs à fournir lorsque le plan sera réellement exécuté. Dans la chaîne de requête, faites référence aux paramètres avec les symboles $1 ... $n. Si la requête utilise les paramètres, les noms des types de paramètre doivent être donnés dans une liste Tcl (écrivez une liste vide pour typelist si aucun paramètre n'est utilisé).

La valeur de retour de spi_prepare est l'identifiant de la requête à utiliser dans les appels suivants à spi_execp. Voir spi_execp pour un exemple.

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

Exécute une requête préparée précédemment avec spi_prepare. queryid est l'identifiant renvoyé par spi_prepare. Si la requête fait référence à des paramètres, une liste de valeurs (value-list) doit être fournie. C'est une liste Tcl des valeurs réelles des paramètres. La liste doit être de la même longueur que la liste de types de paramètres donnée précédemment lors de l'appel à spi_prepare. Oubliez-la si la requête n'a pas de paramètres.

La valeur optionnelle pour -nulls est une chaîne d'espaces et de caractères 'n' indiquant à spi_execp les paramètres nuls. Si indiqué, elle doit avoir exactement la même longueur que value-list. Si elle est omise, toutes les valeurs de paramètres sont non NULL.

Sauf si la requête et ses paramètres sont spécifiés, spi_execp fonctionne de la même façon que spi_exec. Les options -count, -array et loop-body sont identiques. Du coup, la valeur du résultat l'est aussi.

Voici un exemple d'une fonction PL/Tcl utilisant un plan préparé :

CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
    if {![ info exists GD(plan) ]} {
        # prépare le plan sauvegardé au premier appel
        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;
       

Nous avons besoin des antislashs à l'intérieur de la chaîne de la requête passée à spi_prepare pour s'assurer que les marqueurs $n sont passés au travers de spi_prepare sans transformation et ne sont pas remplacés avec la substitution de variables de Tcl.

spi_lastoid

Renvoie l'OID de la ligne insérée par le dernier appel à spi_exec ou spi_execp, si la commande était un INSERT d'une seule ligne et que la table modifiée contenait des OID (sinon, vous obtenez zéro).

quote string

Double toutes les occurrences de guillemet simple et d'antislash dans la chaîne donnée. Ceci peut être utilisé pour mettre entre guillemets des chaînes de façon sûr et pour qu'elles puissent être insérées dans des commandes SQL passées à spi_exec ou spi_prepare. Par exemple, pensez à une chaîne de commande SQL comme :

"SELECT '$val' AS ret"
       

où la variable Tcl val contient actuellement le mot doesn't. Ceci finirait avec la chaîne de commande :

SELECT 'doesn't' AS ret
       

qui va causer une erreur d'analyse lors de spi_exec ou de spi_prepare. Pour fonctionner correctement, la commande soumise devrait contenir :

SELECT 'doesn''t' AS ret
       

qui peut-être créé avec PL/Tcl en utilisant :

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

Un avantage de spi_execp est que vous n'avez pas à mettre entre guillemets des valeurs de paramètres comme ceux-ci car les paramètres ne sont jamais analysés comme faisant partie de la chaîne de la commande SQL.

elog level msg

Émet une trace ou un message d'erreur. Les niveaux possibles sont DEBUG, LOG, INFO, NOTICE, WARNING, ERROR et FATAL. ERROR élève une condition d'erreur ; si elle n'est pas récupérée par le code Tcl, l'erreur est propagée à la requête appelante, causant l'annulation de la transaction ou sous-transaction en cours. Ceci est en fait identique à la commande error. FATAL annule la transaction et fait que la session courante s'arrête (il n'existe probablement aucune raison d'utiliser ce niveau d'erreur dans les fonctions PL/Tcl mais il est fourni pour que tous les messages soient tout de même disponibles). Les autres niveaux génèrent seulement des messages de niveaux de priorité différent. Le fait que les messages d'un niveau de priorité particulier sont reportés au client, écrit dans les journaux du serveur ou les deux à la fois, est contrôlé par les variables de configuration log_min_messages et client_min_messages. Voir le Chapitre 18, Configuration du serveur pour plus d'informations.