Contesto : sto lavorando su http://sqlfiddle.com (il mio sito) e sto cercando di prevenire una via di abuso possibile lì. Spero che chiedendo di un problema che sto affrontando attualmente, non inavvertitamente peggiori il potenziale abuso, ma cosa puoi fare? Mi fido di voi gente.
Vorrei impedire a qualsiasi utente di inviare chiamate "commit" esplicite all'interno di un determinato blocco di transazioni. Dal contesto di SQL Fiddle, il blocco delle transazioni è il codice che viene eseguito sul pannello di destra. Fondamentalmente, sto eseguendo il ciclo ed eseguendo un elenco di comandi SQL in testo normale e voglio assicurarmi che tutte le modifiche apportate vengano ripristinate alla fine del batch. Normalmente, le loro modifiche vengono ripristinate, ma a volte c'è un'istruzione esplicita 'commit' nel testo, e quindi ovviamente il mio rollback non funzionerà. Questo commit esplicito è molto probabile da parte di un utente che tenta di interrompere lo schema su SQL Fiddle, quindi altre persone che ci lavorano vedranno errori.
Principale risultato desiderato : vorrei disabilitare i commit espliciti a livello JDBC, se possibile. Questo perché devo supportare più fornitori di backend di database, e ovviamente ognuno ha le sue stranezze a basso livello.
Opzione di fallback : se non è possibile configurare JDBC per disabilitare i commit espliciti, allora sarei aperto alle soluzioni per rilevare i commit espliciti durante l'elaborazione di un batch per ciascuno dei seguenti backend: SQL Server, Oracle, MySQL e PostgreSQL.
Per SQL Server, ho pensato a questa soluzione: analizzare il piano di query XML per l'istruzione prima di eseguirla e verificare la presenza di una voce corrispondente a questo XPath:
//*[@StatementType="COMMIT TRANSACTION"]
Penso che funzionerebbe abbastanza bene per SQL Server. Tuttavia, questo approccio non funziona con gli altri tipi di DB. L'output del piano di esecuzione XML di Oracle per commit espliciti non fa riferimento al fatto che si sta eseguendo un'istruzione commit (ma piuttosto semplicemente ripete l'output del piano di esecuzione dalle query che sta eseguendo il commit). PostgreSQL e MySQL non forniscono alcun output del piano di esecuzione (XML o altro) per commit espliciti.
Ciò mi lascia controllando l'effettiva affermazione della parola "commit". Funzionerebbe, tranne che ci possono essere tutti i tipi di variazioni possibili:
declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);
Quanto sopra è un esempio di SQL Server (che potrei aggirare), ma immagino che cose simili sarebbero possibili per Oracle, MySQL e PostgreSQL. Sbaglio su questa ipotesi? Forse non permetterebbero dichiarazioni di commit "dinamiche"? Sentiti libero di usare SQL Fiddle (preferibilmente non lo schema di esempio o qualcun altro probabilmente sta lavorando) per vedere se riesci a far accadere qualcosa di simile in Oracle, MySQL e PostgreSQL. Altrimenti, forse il semplice rilevamento delle stringhe potrebbe funzionare per quelli.
Ancora un'altra possibilità
Mi è venuta in mente un'altra opzione: se si conosce un modo per impostare uno di questi database in modalità di sola lettura, ad esempio in tale modalità non è possibile eseguire il commit di nulla, che potrebbe funzionare anche. Avrei ancora bisogno di consentire l'avvio delle transazioni e l'esecuzione del codice al loro interno, purché nulla potesse essere impegnato in quella modalità. È possibile?
Aggiornare
Quello che ho imparato di recente - questo in realtà non è un problema con PostgreSQL. Apparentemente i commit emessi all'interno di un blocco di transazione non si applicano se lo stesso blocco alla fine viene ripristinato (in Postgres). Quindi evviva Postgres!
Grazie al link di Phil al post SO, penso di poter usare l'hack DEFERRABLE INITIALLY DEFERRED per Oracle per realizzare ciò che sto cercando (verrà emesso un errore se viene emesso un commit, ma posso aggirare quello). Questo dovrebbe riguardare Oracle. (Ho pensato per un momento che le transazioni nidificate potrebbero funzionare qui, ma non sembra che Oracle supporti le transazioni nidificate? Comunque non sono riuscito a trovare nulla che funzionasse in questo modo).
Non ho ancora una soluzione per MySQL. Ho provato usando transazioni nidificate, ma non sembra funzionare. Sto seriamente pensando ad approcci più drastici per MySQL, come ad esempio non consentire altro che SELECTs sul lato destro o far cadere / ricreare il DB dopo ogni query. Né suona bene però.
Risoluzione
Quindi, ora ho implementato le soluzioni descritte per SQL Server e Oracle, e come ho già detto questo non è in realtà un problema per PostgreSQL. Per MySQL, ho fatto il passo un po 'sfortunato di limitare il pannello delle query a selezionare solo le istruzioni. DDL e DML per MySQL dovranno semplicemente essere inseriti nel pannello dello schema (lato sinistro). Spero che questo non rompa troppi vecchi violini, ma penso che sia semplicemente ciò che deve essere fatto per garantire la coerenza dei dati. Grazie!