Vous n'êtes pas identifié(e).
Pages : 1
Bonjour à tous,
J'essaye de faire un truc un peu biscornu...dans une fonction trigger, faire référence au nom d'une colonne mais via un paramètre (NEW.parametre)
je m'explique :
soit la table toto
create table toto (
a text,
b text );
et la table titi
create table titi (
c text
d text );
sur chaque table, je veux définir un trigger qui empêche la validation par exemple quand on essaye de saisir "pipot" dans toto(a) ou dans titi(c).
c'est simple à faire, pour chaque table une fonction trigger et son trigger
par contre je me demande si on peut ruser, et ne déclarer qu'une seule fonction trigger, qui soit appelée par chacun des deux trigger sur les tables toto et titi
la difficulté, c'est de référencer le nom des colonnes...si la fonction est appelée par le trigger de la table toto, ce sera new.a, mais si elle est appelée par le trigger de la table titi, ce sera new.c
comment faire ?
j'ai essayé en passant le nom de la colonne en argument du trigger via TG_ARGV, mais ça ne fonctionne pas
voilà ce que j'ai essayé de faire, tout d'abord ma fonction trigger :
create function verification (
begin
if (new.TG_ARGV[0] = 'pipot') then
raise exception ...
end if;
end;)
puis les deux triggers
create trigger verificationToto before insert on toto for each row execute procedure verification('a');
create trigger verificationTiti before insert on titi for each row execute procedure verification('c');
mais bien sur ça plante car il n'arrive pas à interpréter TG_ARGV[0]
une idée ? c'est faisable, pas faisable ? j'ai essayé de m'en sortir avec EXECUTE, mais là aussi j'ai pas réussi pour l'instant
Hors ligne
Ce n'est pas le vrai code de la fonction trigger, la déclaration est invalide, je pense ?
Mais de toutes façons, non, vous ne pourrez pas passer un nom de colonne en argument dans new. La substitution ne sera pas faite. PL/PgSQL est assez limité de ce point de vue.
Par contre rien ne vous empêche de regarder ce que vaut TG_TABLE_NAME ou TG_ARGV[0] dans votre bout de PL, et d'avoir un simple IF, qui regarde dans l'une ou l'autre des colonnes. C'est moins dynamique, mais au moins ça marchera.
On peut peut-être aussi faire une requête dynamique avec un EXEC dans le code PL, je ne l'ai jamais tenté pour un trigger (et donc pour accéder à NEW).
Marc.
Hors ligne
ok merci Marc...
Oui c'est ce que je vais finir par faire, je vais coder un IF dans ma fonction pour différencier selon tg_table_name...
Je pensais qu'il y avait une solution un peu plus élégante, un peu comme les fonctions eval() dans php ou javascript, mais apparemment le EXECUTE n'aime pas tellement avoir NEW dans son code... j'ai un message d'erreur qui me semble assez clair : "ERREUR: NEW utilisé dans une requête qui ne fait pas partie d'une règle - LINE 1 : SELECT NEW.name"
ci-dessous le code de ce que j'ai tenté avec EXECUTE
CREATE FUNCTION verification() RETURNS TRIGGER AS $$
DECLARE
mon_texte VARCHAR(32);
BEGIN
EXECUTE 'SELECT NEW.' || TG_ARGV[0] INTO mon_texte;
IF (mon_texte = 'pipot') THEN
RAISE EXCEPTION ...
END IF;
END;
$$ LANGUAGE PLPGSQL
pour info, j'ai trouvé ça
http://www.developpez.net/forums/d89744 … -debutant/
Le modérateur du site confirme bien que ce n'est pas possible en PL/PGSQL, il dit :
"Dans la commande EXECUTE requete INTO resultat, la requête ne doit faire référence à aucune variable plpgsql, y compris NEW. Il faut remplacer les références à NEW.champ par leurs valeurs réelles. "
Par contre il ajoute :
"Oui le plpgsql est un langage qui ne permet pas vraiment de se référer dynamiquement à des champs, un peu comme le SQL. C'est possible en revanche dans d'autres langages comme le pl/perl. "
Donc la solution serait peut-être d'écrire ma fonction verification() en pl/perl
un jour, quand j'aurais envie d'apprendre perl...
Hors ligne
Donc, même chose pour le modérateur ou moi
M'étonne pas. Le PL/PgSQL n'est pas fait pour ça. L'idée est justement d'avoir autant de choses 'constantes' (les requêtes SQL comprises) que possible dans le code, afin qu'il soit très performant à l'exécution (après une compilation initiale). Pas pour avoir les noms de colonnes ou d'objets dynamiques.
plperl est un exemple. Vous pouvez aussi essayer en plpython, plsh, pltcl, pljava, ou C, par exemple
Marc.
Hors ligne
ok merci...je vais tenter ma chance en plsh dès que j'ai un moment
Hors ligne
C'est un de ceux qui ne sont pas fournis directement avec le code (comme pljava). Je pense que c'est aussi le moins approprié pour ça…
Les langages supportés en standard sont là :
http://docs.postgresql.fr/9.0/server-programming.html
Pour les autres, ça veut dire les compiler soit-même, séparément.
Marc.
Hors ligne
oui je disais plsh car je ne connais ni perl ni python ni tcl/tk, mais vous avez sans doute raison, ce sera plus simple d'apprendre les rudiments de perl plutôt que de bricoler un truc soi-même avec plsh... je vais essayer de faire ça en perl à l'occasion
en fait, si je comprends bien, sous postgreSQL le langage pl/pgsql est à priori le langage le plus performant, sauf si on essaye de faire des trucs un peu biscornus comme ce que je voulais faire, auquel cas on peut se tourner vers un autre langage
autrement dit, pl/perl (par exemple) offre plus de souplesse que pl/pgsql, mais au prix de performances diminuées... En gros j'ai bien compris ?
(je fais mes premiers pas sur postgres, après quelques années passées sur oracle)
Hors ligne
C'est grosso modo ça: les accès aux données sont un peu plus rapides en PLPgSQL. Par contre, dès que l'algorithme va devenir complexe (entre autres, dès qu'on va vouloir jouer avec des expressions régulières, faire des opérations complexes sur des chaînes ou autres), le surcoût d'être dans Perl ou Python devient inférieur au gain apporté par utiliser un langage plus puissant.
Marc.
Hors ligne
ok, merci Marc pour cette discussion qui m'a été très utile.
Hors ligne
Pages : 1