Tło : Pracuję na http://sqlfiddle.com (moja strona) i staram się zapobiec jednej możliwej nadużyciu. Mam nadzieję, że pytając o problem, który obecnie rozwiązuję, nie zwiększam nieumyślnie potencjalnego nadużycia, ale co możesz zrobić? Ufam wam, ludzie.
Chciałbym uniemożliwić użytkownikom wykonywanie wyraźnych wywołań „zatwierdzania” w ramach danego bloku transakcji. W kontekście SQL Fiddle blokiem transakcji jest kod wykonywany na panelu po prawej stronie. Zasadniczo zapętlam i wykonuję listę poleceń SQL w postaci jawnego tekstu i chcę mieć pewność, że wszystkie zmiany, które wprowadzą, zostaną wycofane na końcu partii. Zwykle ich zmiany są wycofywane, ale czasami w tekście jest wyraźne polecenie „zatwierdzenia”, więc moje wycofanie nie zadziała. To jawne zatwierdzenie jest bardzo prawdopodobne od użytkownika próbującego złamać schemat w SQL Fiddle, więc inne osoby pracujące nad nim zobaczą błędy.
Główny pożądany wynik : Jeśli to możliwe, chciałbym wyłączyć jawne zatwierdzenia na poziomie JDBC. To dlatego, że muszę obsługiwać wielu dostawców zaplecza bazy danych i oczywiście każdy ma swoje dziwactwa na niskim poziomie.
Opcja rezerwowa : jeśli nie jest możliwe skonfigurowanie JDBC do wyłączania jawnych zatwierdzeń, byłbym otwarty na rozwiązania do wykrywania jawnych zatwierdzeń podczas przetwarzania wsadu dla każdego z następujących backendów: SQL Server, Oracle, MySQL i PostgreSQL.
W przypadku programu SQL Server pomyślałem o tym rozwiązaniu: przeanalizuj plan zapytania XML dla instrukcji, zanim ją wykonam, i sprawdź, czy istnieje pozycja pasująca do tej XPath:
//*[@StatementType="COMMIT TRANSACTION"]
Myślę, że to działałoby całkiem dobrze dla SQL Server. Jednak to podejście nie działa w przypadku innych typów DB. Dane wyjściowe planu wykonania XML Oracle dla jawnych zatwierdzeń nie odnoszą się do faktu, że uruchamiasz instrukcję commit (a raczej po prostu powtarza dane wyjściowe planu wykonania z zapytań, które popełnia). PostgreSQL i MySQL nie zapewniają żadnych danych wyjściowych planu wykonania (XML lub w inny sposób) dla jawnych zatwierdzeń.
To pozostawia mi sprawdzenie faktycznej instrukcji pod kątem słowa „commit”. To by działało, z tym wyjątkiem, że mogą istnieć wszelkiego rodzaju warianty:
declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);
Powyższy przykład jest przykładem SQL Servera (który mógłbym obejść), ale przypuszczam, że podobne rzeczy byłyby możliwe w przypadku Oracle, MySQL i PostgreSQL. Czy mylę się przy tym założeniu? Może nie pozwolą na „dynamiczne” instrukcje zatwierdzania? Zachęcamy do skorzystania z SQL Fiddle (najlepiej nie z przykładowego schematu lub innej osoby, nad którą prawdopodobnie będzie pracował), aby sprawdzić, czy można zrobić coś podobnego w Oracle, MySQL i PostgreSQL. Jeśli nie, być może proste wykrywanie ciągu może być dla nich skuteczne.
Jeszcze jedna możliwość
Inna opcja przyszła mi do głowy - jeśli znasz sposób na ustawienie dowolnej z tych baz danych w trybie tylko do odczytu, na przykład w tym trybie nic nie może zostać popełnione, to też może działać. Musiałbym nadal zezwalać na uruchamianie transakcji i uruchamianie w nich kodu, tak długo, jak nic nie może zostać zatwierdzone w tym trybie. Czy to jest możliwe?
Aktualizacja
Czego się ostatnio nauczyłem - tak naprawdę nie jest to problem z PostgreSQL. Najwyraźniej zatwierdzenia wydane w ramach bloku transakcji nie będą miały zastosowania, jeśli ten sam blok ostatecznie zostanie wycofany (w Postgres). Więc Brawo dla Postgres!
Dzięki linkowi Phila do postu SO, myślę, że mogę użyć hakowania ODCZYTOWO POCZĄTKOWO ODRÓŻNIONEGO dla Oracle, aby osiągnąć to, czego szukam (błąd zostanie zgłoszony, jeśli zostanie wydane zatwierdzenie, ale mogę to obejść). To powinno zwrócić się do Oracle. (Przez chwilę myślałem, że transakcje zagnieżdżone mogą tu działać, ale nie wygląda na to, że Oracle obsługuje transakcje zagnieżdżone? W każdym razie nie mogłem znaleźć niczego, co działałoby w ten sposób).
Nie mam jeszcze rozwiązania dla MySQL. Próbowałem użyć transakcji zagnieżdżonych, ale wydaje się, że to nie działa. Poważnie myślę o bardziej drastycznych podejściach do MySQL, takich jak albo nie zezwalanie na nic oprócz SELECT po prawej stronie lub upuszczanie / odtwarzanie DB po każdym zapytaniu. Żaden z nich nie brzmi dobrze.
Rozkład
Wdrożyłem więc opisane rozwiązania dla SQL Server i Oracle, a jak już wspomniałem, nie jest to tak naprawdę problem dla PostgreSQL. W przypadku MySQL podjąłem nieco niefortunny krok polegający na ograniczeniu panelu zapytań tylko do wybierania instrukcji. DDL i DML dla MySQL należy po prostu wprowadzić w panelu schematu (po lewej stronie). Mam nadzieję, że nie złamie to zbyt wielu starych skrzypiec, ale myślę, że to po prostu to, co należy zrobić, aby zapewnić spójność danych. Dzięki!