Documentation PostgreSQL 14.22 » Programmation serveur » PL/Tcl -- Langage de procédures Tcl » Accès à la base de données depuis PL/Tcl

Précédent | Niveau supérieur | Suivant
44.4. Données globales avec PL/Tcl | Sommaire | 44.6. Fonctions triggers en PL/Tcl

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

Dans cette section, nous suivons la convention Tcl habituelle pour l'utilisation des points d'interrogation, plutôt que les crochets, pour indiquer un élément optionnel dans un synopsis de syntaxe. 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` d'arrêter une fois que `n` lignes ont été récupérées, tout comme si la requête incluait une clause `LIMIT`. Si `n` vaut zéro, la requête est exécutée jusqu'à sa fin, tout comme si `-count` était omis.

  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 les éléments d'un tableau associatif nommé, les noms des colonnes étant utilisés comme index du tableau. De plus, le numéro de ligne courant dans le résultat (en commençant par zéro) est enregistré dans l'élément de tableau nommé « `.tupno` », sauf si ce nom est utilisé comme nom de colonne dans le résultat.

  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 ou des éléments de tableau ; 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.

`subtransaction` `command`

  Le script Tcl contenu dans `command` est exécuté à l'intérieur d'une sous-transaction SQL. Si le script renvoie une erreur, la sous-transaction entière est annulée avant de renvoyer une erreur au code Tcl appelant. Voir Section 44.9 pour plus de détails et un exemple.

`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 20 et Section 44.8 pour plus d'informations.