Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Blokowanie UPDATE w triggerze
Nexces
post
Post #1





Grupa: Zarejestrowani
Postów: 4
Pomógł: 0
Dołączył: 22.02.2008

Ostrzeżenie: (0%)
-----


Witam,
sprawa ma się następująco:
mam dwie tabele o identycznej strukturze:
  1. CREATE TABLE IF NOT EXISTS `trtest1` (
  2. `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `value` varchar(30) character SET utf8 collate utf8_polish_ci NOT NULL,
  4. `ser` int(11) UNSIGNED NOT NULL,
  5. `time` int(11) NOT NULL,
  6. `info` text character SET utf8 collate utf8_polish_ci,
  7. PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

różnią się tylko nazwą...
mam trigger'a który w momencie modyfikacji wiersza/wierszy z pierwszej tabeli poprzednie "wersje" przenosi do drugiej (śledzenie zmian swoiste)

pole `ser` które jest w tym przypadku numerem seryjnym nie może zostać w żasdnym przypadku zmodyfikwane...
pókico wyprodukowałem coś takiego:
  1. DELIMITER //
  2. CREATE TRIGGER `test`.`backup` BEFORE UPDATE ON `test`.`trtest1`
  3. FOR EACH ROW begin IF new.ser!=old.ser then
  4. SET new.info:=concat_ws('\n',
  5. old.info,
  6. '------------------------------------',
  7. NOW(),
  8. 'Próba modyfikacji numeru seryjnego!!',
  9. '------------------------------------\n'
  10. );
  11. SET new.ser:=old.ser;
  12. SET new.value:=old.value;
  13. SET new.time:=old.time;
  14. else
  15. INSERT INTO trtest2 (value,ser,time,info) SELECT value,ser,time,info FROM trtest1 WHERE id=NEW.id;
  16. SET new.time=UNIX_TIMESTAMP();
  17. end IF;
  18. end
  19. //
  20. DELIMITER ;


sprawuje się genialnie natomiast jest to app rozwijany ciągle i muszę mieć możliwość dość lekkiego dodawania kolejnych kolumn do tych tabel (w tej chwili jest raptem 20)...

zastanawiam się czy można tak opisać tego triggera, żeby:
po 1:
w przypadku próby zmiany numeru seryjnego zablokował akcję modyfikując tylko pole info
lub
przywrócił poprzednie wartości wszystkim kolumnom (w tej chwili jest tak to zrobione, jednak jest to o tyle niewygodne, że każde pole muszę osobno wpisać, a chcę tego uniknąć)

po 2:
wygodniejsze kopiowanie... znowuż w tej chwili muszę wszystkie pola wypisać, bo id jest auto_increment
insert into trtest2 select * from trtest2;
daje niezbyt przyjemny efekt w postaci dublowania klucza...

z góry dzięki za wszelkie propozycje (:
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 4)
Cezar708
post
Post #2





Grupa: Zarejestrowani
Postów: 1 116
Pomógł: 119
Dołączył: 10.05.2005
Skąd: Poznań

Ostrzeżenie: (0%)
-----


zamiast TRIGGERA w takim przypadku proponuję napisać ZASADĘ (ang RULE), nadpisującą UPDATE, czyli:

  1. CREATE RULE update_trtest1 AS UPDATE ON UPDATE TO trtest1
  2. DO
  3. INSERT INTO trtest1(id, value, time, info)
  4. VALUES (new.id, new.value, new.time, new.info)
  5. ;


zauważ, że nie ma w `nowym` insercie ani słowa o `ser`, więc nie będzie nadpisany.

PS: Ja to robiłem na PostgreSQL nie wiem czy składnia jest poprawna dla MySQL, ewentualnie trochę wg specyfikacji MySQL
Go to the top of the page
+Quote Post
Nexces
post
Post #3





Grupa: Zarejestrowani
Postów: 4
Pomógł: 0
Dołączył: 22.02.2008

Ostrzeżenie: (0%)
-----


mysql chyba niezbyt potrafi coś takiego... poza tym :
- wygląda na to, że rekord nie zostanie wypchnięty d drugiej tabeli
- brak przechwycenia informacji o próbie modyfikacji
- następuje insert i nowy rekord, a nie faktyczny update... (zapomniałem dodać, że `ser` czyli numer seryjny jest unique i musi być unique w pierwszej tabeli, nie może się zdażyć sytuacja, że będą dwa rekordy z tym samym numerem seryjnym w pierwszej tabeli)
- dodatkowo mimo wszystko muszę wypisać kolejno kolumny... czego jak pisałem chciałbym uniknąć...
Go to the top of the page
+Quote Post
Cezar708
post
Post #4





Grupa: Zarejestrowani
Postów: 1 116
Pomógł: 119
Dołączył: 10.05.2005
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Cytat(Nexces @ 22.02.2008, 15:50:44 ) *
mysql chyba niezbyt potrafi coś takiego...

.. no fakt, też nic na ten temat nie znalazłem (może warto przejść na PostgreSQL?)
Cytat(Nexces @ 22.02.2008, 15:50:44 ) *
- wygląda na to, że rekord nie zostanie wypchnięty d drugiej tabeli

a dlaczego nie, to jest tylko ON UPDATE więc Twój insert działa dokładnie tak jak działał
Cytat(Nexces @ 22.02.2008, 15:50:44 ) *
- brak przechwycenia informacji o próbie modyfikacji

nie ma problemu, możesz i tę informację funkcjonalność do roli dopisać, żaden problem
Cytat(Nexces @ 22.02.2008, 15:50:44 ) *
- następuje insert i nowy rekord, a nie faktyczny update... (zapomniałem dodać, że `ser` czyli numer seryjny jest unique i musi być unique w pierwszej tabeli, nie może się zdażyć sytuacja, że będą dwa rekordy z tym samym numerem seryjnym w pierwszej tabeli)

faktycznie mój błąd, w roli po prostu zmień INSERT (...) na UPDATE (...) SET (...)
Cytat(Nexces @ 22.02.2008, 15:50:44 ) *
- dodatkowo mimo wszystko muszę wypisać kolejno kolumny... czego jak pisałem chciałbym uniknąć...

hmm tu można się zastanowić nad jedną sprawą, w MySQL jest coś takiego jak SHOW FIELDS (czy tam COLS lub FOR EACH ROW, nie pamiętam dokładnie) a potem poiterować po tego wyniku i odseparować tylko `ser`.. nie wiem czy da radę, nigdy nie próbowałem, może warto pomyśleć

Natomiast Twoje podejście ma jedną wadę, co by nie było UPDATE i tak się wykona.. więc jak ktoś by chciał zmienic ser to i tak by się zmienił.

Może również rozpatrzysz jedno podejście, tylko znowu nie jestem pewien, czy MySQL da sobie z tym radę
1. Użytkownikowi który łączy się z bazą poprzez skrypt PHP odbierasz prawa UPDATE do tej tabeli
2. Tworzysz widok, składający się tylko z kolumn, różnych od `ser`
3. Tworzysz ROLE lub TRIGGERA, na UPDATE (wiem, wiem, widoków nie można updatować, ale można na nie założyć triggery lub role, na pewno w PostgreSQL, w MySQL musisz sprawdzić tę możliwość)
4. Użytkownik łączący się przez skrypt może tylko wykonywać "UPDATE na WIDOKU", więc odcinasz go od możliwości zniszczenia kolumny `ser`

... nie wiem, czy pomogłem, ale niestety z MySQL zatrzymałem się w rozwoju, od dłuższego czasu go nie używam. Jeśli to nie jest problem to przenieś się na PostgreSQL i te wszystkie wymienione tutaj sprawy na pewno tam załatwisz,

Pozdrawiam
Go to the top of the page
+Quote Post
Nexces
post
Post #5





Grupa: Zarejestrowani
Postów: 4
Pomógł: 0
Dołączył: 22.02.2008

Ostrzeżenie: (0%)
-----


nie będę się przesiadał na inny system bazodanowy, którego absolutnie nie znam z tytułu jednej napotkanej niewygody (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)

dwa... nie mogę się przesiąść... to nie jest domowy projekcik (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)

zastanawiam się jeszcze czy nie dało by się transakcji zatrudnić do obsłużenia tego "przywrócenia" wiersza...
z tym, że po raz N-ty musiałbym się przebijać przez doc'sy do mysql'a i ćwiczyć...

próbowałem procedurki potworzyć, ale jak zobaczyłem jak mysql marnie sobie radzi z "odgadywaniem" moich intencji to zostawiłem to w cholerę na inny czas...

no nic... wątek zostawiam otwarty, a póki co opiszę tego triggera korzystająć z mojego początkowego pomysłu...

a i jeszcze jedno... nie mogę zdjąć uprawnienia UPDATE bo to app w phpie naskrobany i jakoś tak nie szczególnie chce mi się bawić w przelogowanie user'a do bazy na konkretne akcje...

trigger z tym przechwytem jest tylko po to, żeby ktoś kto nie daj boże ominął zabezpieczenia wewnętrzene appa nie mógł jakiejś dewastacji popełnić za dużej (zamierzam jeszcze parę rzeczy dorzucić do informacji o próbie zmiany numeru seryjnego)...

ps:
zawsze można php'a zatrudnić do sprawdzenia poprawności wszystkiego, ale wydaje mi się zbyteczne przeżucanie danych mysql<->php po parę razy żeby stwierdzić, że wszystko jest ok... mało wydajne...
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 21.09.2025 - 17:29