Documentation PostgreSQL 14.23 » Programmation serveur » Interface de programmation serveur » Exemples
Précédent Niveau supérieur Suivant
47.5. Visibilité des modifications de données Sommaire Chapitre 48. Processus en tâche de fond (background worker)

47.6. Exemples

Cette section contient un exemple très simple d'utilisation de SPI. La fonction C execq prend une commande SQL comme premier argument et un compteur de lignes comme second, exécute la commande en utilisant SPI_exec et renvoie le nombre de lignes qui ont été traitées par la commande. Vous trouverez des exemples plus complexes pour SPI dans l'arborescence source dans src/test/regress/regress.c et dans le module spi.

#include "postgres.h"
#include "executor/spi.h"
#include "utils/builtins.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(execq);
Datum
execq(PG_FUNCTION_ARGS)
{
 char *command;
 int cnt;
 int ret;
 uint64 proc;
 /* Convert given text object to a C string */
 command = text_to_cstring(PG_GETARG_TEXT_PP(0));
 cnt = PG_GETARG_INT32(1);
 SPI_connect();
 ret = SPI_exec(command, cnt);
 proc = SPI_processed;
 /*
 * Si des lignes ont été récupérées,
 * alors les afficher via elog(INFO).
 */
 if (ret > 0 && SPI_tuptable != NULL)
 {
 SPITupleTable *tuptable = SPI_tuptable;
 TupleDesc tupdesc = tuptable->tupdesc;
 char buf[8192];
 int64 j;
 for (j = 0; j < tuptable->numvals; j++)
 {
 HeapTuple tuple = tuptable->vals[j];
 int i;
 for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %s%s",
 SPI_getvalue(tuple, tupdesc, i),
 (i == tupdesc->natts) ? " " : " |");
 elog(INFO, "EXECQ: %s", buf);
 }
 }
 SPI_finish();
 pfree(command);
 PG_RETURN_INT64(proc);
}
 

Voici comment déclarer la fonction après l'avoir compilée en une bibliothèque partagée (les détails sont dans Section 38.10.5) :

CREATE FUNCTION execq(text, integer) RETURNS int8
 AS 'filename'
 LANGUAGE C STRICT;
 

Voici une session d'exemple :

=> SELECT execq('CREATE TABLE a (x integer)', 0);
 execq
-------
 0
(1 row)
=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)', 0));
INSERT 0 1
=> SELECT execq('SELECT * FROM a', 0);
INFO: EXECQ: 0 -- inséré par execq
INFO: EXECQ: 1 -- retourné par execq et inséré par l'INSERT précédent
 execq
-------
 2
(1 row)
=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a RETURNING *', 1);
INFO: EXECQ: 2 -- 0 + 2, puis exécution arrếté par décompte
 execq
-------
 1
(1 row)
=> SELECT execq('SELECT * FROM a', 10);
INFO: EXECQ: 0
INFO: EXECQ: 1
INFO: EXECQ: 2
 execq
-------
 3 -- 10 est seulement la valeur max, 3 est le nombre réel de lignes
(1 row)
=> SELECT execq('INSERT INTO a SELECT x + 10 FROM a', 1);
 execq
-------
 3 -- toutes les lignes traitées ; le nombre ne le stoppe pas car rien n'est renvoyé
(1 row)
=> SELECT * FROM a;
 x
----
 0
 1
 2
 10
 11
 12
(6 rows)
=> DELETE FROM a;
DELETE 6
=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INSERT 0 1
=> SELECT * FROM a;
 x
---
 1 -- 0 (aucune ligne dans a) + 1
(1 row)
=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1);
INFO: EXECQ: 1
INSERT 0 1
=> SELECT * FROM a;
 x
---
 1
 2 -- 1 (il y avait une ligne dans a) + 1
(2 rows)
-- Ceci montre la règle de visibilité de modifications de données.
-- execq est appelé deux fois et voir un nombre différent de lignes à chaque fois :
=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a;
INFO: EXECQ: 1 -- résultat du premier execq
INFO: EXECQ: 2
INFO: EXECQ: 1 -- résultat du deuxième execq
INFO: EXECQ: 2
INFO: EXECQ: 2
INSERT 0 2
=> SELECT * FROM a;
 x
---
 1
 2
 2 -- 2 lignes * 1 (x dans la première ligne)
 6 -- 3 lignes (2 + 1 juste inséré) * 2 (x dans la deuxième ligne)
(4 rows)
 

AltStyle によって変換されたページ (->オリジナル) /