J'ai créé quelque chose comme ceci:
begin;
create table test (
id integer
);
insert into test(id) select generate_series(1,100);
create or replace function trg_check_max_4_updated_records()
returns trigger as $$
declare
counter_ integer := 0;
tablename_ text := 'temptable';
begin
raise notice 'trigger fired';
select count(42) into counter_
from pg_catalog.pg_tables where tablename = tablename_;
if counter_ = 0 then
raise notice 'Creating table %', tablename_;
execute 'create temporary table ' || tablename_ || ' (counter integer) on commit drop';
execute 'insert into ' || tablename_ || ' (counter) values(1)';
execute 'select counter from ' || tablename_ into counter_;
raise notice 'Actual value for counter= [%]', counter_;
else
execute 'select counter from ' || tablename_ into counter_;
execute 'update ' || tablename_ || ' set counter = counter + 1';
raise notice 'updating';
execute 'select counter from ' || tablename_ into counter_;
raise notice 'Actual value for counter= [%]', counter_;
if counter_ > 4 then
raise exception 'Cannot change more than 4 rows in one trancation';
end if;
end if;
return new;
end; $$ language plpgsql;
create trigger trg_bu_test before
update on test
for each row
execute procedure trg_check_max_4_updated_records();
update test set id = 10 where id <= 1;
update test set id = 10 where id <= 2;
update test set id = 10 where id <= 3;
update test set id = 10 where id <= 4;
update test set id = 10 where id <= 5;
rollback;
L'idée principale est d'avoir un déclencheur sur « avant la mise à jour pour chaque ligne » qui crée (si nécessaire) une table temporaire (qui est tombé à la fin de la transaction). Dans cette table, il n'y a qu'une ligne avec une valeur, c'est-à-dire le nombre de lignes mises à jour dans la transaction en cours. Pour chaque mise à jour, la valeur est incrémentée. Si la valeur est supérieure à 4, la transaction est arrêtée.
Mais je pense que c'est une mauvaise solution pour votre problème. Quel est le problème pour exécuter une mauvaise requête que vous avez écrite, deux fois, de sorte que vous aurez 8 lignes modifiées. Qu'en est-il des lignes de suppression ou de les tronquer?
Je considérais l'utilisation de la requête normale + rollback si les lignes affectées sont supérieures à max, et cela semble être la meilleure valeur que je vois. Eh bien dans 99% + il y aura de bonnes requêtes (4 lignes max mises à jour) mais ce n'est qu'une sécurité supplémentaire pour le système. La table avec ce 'problème' est assez énorme et critique pour le système, donc la restaurer après qu'une telle requête mal posée peut être pénible pour tout le monde. Merci à tous pour vos réponses. Je ne sais pas lequel accepter parce que tous les aider :) – sbczk
Pourquoi voulez-vous faire cela? Peut-être y a-t-il un moyen beaucoup plus facile de le faire qu'une requête aussi étrange. De plus ... l'utilisation de count (si possible) sera plus lente pendant que la table se développe. –
Donc, vous pensez que lorsque vous avez changé 4 lignes max, la requête ne peut pas être mal traitée? Cela ressemble à une sorte de faux sentiment de sécurité. –