Deaktivieren Sie explizite Commits in JDBC, erkennen Sie sie in SQL oder versetzen Sie die Datenbank in einen schreibgeschützten Zustand

12

Hintergrund : Ich arbeite an http://sqlfiddle.com (meiner Website) und versuche, einen möglichen Missbrauch zu verhindern. Ich hoffe, dass ich durch die Frage nach einem Problem, das ich gerade anspreche, den potenziellen Missbrauch nicht versehentlich verschlimmere, aber was können Sie tun? Ich vertraue euch Leuten.

Ich möchte verhindern, dass ein Benutzer innerhalb eines bestimmten Transaktionsblocks explizite Festschreibungsaufrufe ausgibt. Aus dem Kontext von SQL Fiddle ist der Transaktionsblock der Code, der auf der rechten Seite ausgeführt wird. Grundsätzlich durchlaufe ich eine Liste von Klartext-SQL-Befehlen und führe sie aus. Außerdem möchte ich sicherstellen, dass alle vorgenommenen Änderungen am Ende des Stapels rückgängig gemacht werden. Normalerweise werden ihre Änderungen zurückgesetzt, aber manchmal gibt es eine explizite Festschreibungsanweisung im Text, und so funktioniert mein Rollback natürlich nicht. Diese explizite Festschreibung stammt höchstwahrscheinlich von einem Benutzer, der versucht, das Schema in SQL Fiddle zu unterbrechen, sodass andere Personen, die daran arbeiten, Fehler sehen.

Gewünschtes Hauptergebnis : Ich möchte explizite Festschreibungen auf JDBC-Ebene deaktivieren, sofern dies möglich ist. Das liegt daran, dass ich mehrere Datenbank-Backend-Anbieter unterstützen muss, und natürlich hat jeder seine Macken auf der niedrigen Ebene.

Fallback-Option : Wenn es nicht möglich ist, JDBC so zu konfigurieren, dass explizite Commits deaktiviert werden, sind Lösungen zum Erkennen expliziter Commits während der Stapelverarbeitung für jedes der folgenden Backends verfügbar: SQL Server, Oracle, MySQL und PostgreSQL.

Bei SQL Server dachte ich an diese Lösung: Analysieren Sie den XML-Abfrageplan für die Anweisung, bevor Sie sie ausführen, und überprüfen Sie, ob ein Eintrag vorhanden ist, der diesem XPath entspricht:

//*[@StatementType="COMMIT TRANSACTION"]

Ich denke, das würde für SQL Server ziemlich gut funktionieren. Dieser Ansatz funktioniert jedoch nicht für die anderen DB-Typen. Die XML-Ausführungsplanausgabe von Oracle für explizite Festschreibungen enthält keinen Hinweis darauf, dass Sie eine Festschreibungsanweisung ausführen (sondern wiederholt einfach die Ausführungsplanausgabe der festgeschriebenen Abfragen). PostgreSQL und MySQL bieten überhaupt keine Ausgabe von Ausführungsplänen (XML oder anderweitig) für explizite Commits.

Das lässt mich die eigentliche Anweisung auf das Wort "commit" überprüfen. Dies würde funktionieren, es sei denn, es sind alle Arten von Variationen möglich:

declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);

Das Obige ist ein Beispiel für SQL Server (den ich umgehen könnte), aber ich würde annehmen, dass ähnliche Dinge für Oracle, MySQL und PostgreSQL möglich wären. Liege ich mit dieser Annahme falsch? Vielleicht würden sie keine "dynamischen" Festschreibungsanweisungen zulassen? Sie können auch SQL Fiddle verwenden (vorzugsweise nicht das Beispielschema oder eines, an dem wahrscheinlich jemand anderes arbeitet), um zu prüfen, ob in Oracle, MySQL und PostgreSQL etwas Ähnliches möglich ist. Andernfalls funktioniert möglicherweise die einfache Erkennung von Zeichenfolgen.

Noch eine andere Möglichkeit

Eine andere Option ist mir eingefallen - wenn Sie wissen, wie Sie eine dieser Datenbanken in einen schreibgeschützten Modus versetzen können, kann dies auch funktionieren, wenn Sie sich in diesem Modus befinden. Ich müsste weiterhin zulassen, dass Transaktionen gestartet und Code in ihnen ausgeführt werden, nur solange in diesem Modus nichts festgeschrieben werden kann. Ist das möglich?

Aktualisieren

Was ich kürzlich gelernt habe - das ist eigentlich kein Problem mit PostgreSQL. Offensichtlich werden innerhalb eines Transaktionsblocks ausgegebene Commits nicht angewendet, wenn derselbe Block schließlich zurückgesetzt wird (in Postgres). Also Hurra für Postgres!

Dank Phils Link zum SO-Post kann ich den DEFERRABLE INITIALLY DEFERRED-Hack für Oracle verwenden, um das zu erreichen, wonach ich gesucht habe (ein Fehler wird ausgegeben, wenn ein Commit ausgegeben wird, aber ich kann das umgehen). Dies sollte sich an Oracle richten. (Ich dachte für einen Moment, dass verschachtelte Transaktionen hier funktionieren könnten, aber es sieht nicht so aus, als würde Oracle verschachtelte Transaktionen unterstützen? Trotzdem konnte ich nichts finden, was auf diese Weise funktionierte.)

Ich habe noch keine Lösung für MySQL. Versucht mit verschachtelten Transaktionen, aber das scheint nicht zu funktionieren. Ich denke ernsthaft über drastischere Ansätze für MySQL nach, z. B. entweder nichts anderes als SELECTs auf der rechten Seite zuzulassen oder die Datenbank nach jeder Abfrage zu löschen / neu zu erstellen. Weder klingt aber gut.

Auflösung

Daher habe ich jetzt die beschriebenen Lösungen für SQL Server und Oracle implementiert, und wie ich bereits erwähnt habe, ist dies für PostgreSQL eigentlich kein Problem. Für MySQL habe ich den etwas unglücklichen Schritt unternommen, den Abfrageeditor nur auf ausgewählte Anweisungen zu beschränken. DDL und DML für MySQL müssen einfach im Schemabereich (auf der linken Seite) eingegeben werden. Ich hoffe, dass dies nicht zu viele alte Probleme auflöst, aber ich denke, es ist einfach das, was getan werden muss, um die Datenkonsistenz sicherzustellen. Vielen Dank!

Jake Feasel
quelle
Erwähnenswert - Ich habe auch viel nach "Pre-Commit" -Triggern gesucht. Es scheint, dass diese nicht existieren, also ist das leider auch keine Option.
Jake Feasel
2
Für Oracle scheint dies eine gute Methode zu sein, um COMMITs abzufangen: stackoverflow.com/a/6463800/790702 Was er nicht erwähnt, ist, dass Sie in der Lage sein sollten, die Einschränkungsverletzung auch in Ihrem Code abzufangen, um die zweite Situation zu beenden auftreten.
Philᵀᴹ
@Phil das einzige Problem ist, dass ich nicht die Kontrolle über die Definition jeder der Tabellen habe (und nicht wirklich will) (diese sind auf der linken Seite definiert). Damit die DEFERRABLE INITIALLY DEFERRED-Klausel nicht da wäre (es sei denn, es gibt eine Möglichkeit, dies automatisch für alle Tabellen zu tun - etwa über einen System-Trigger, der auf die Erstellung von Tabellenanweisungen reagiert? Ugh)
Jake Feasel,
1
@NickChammas Ich muss Commits deaktivieren, damit ich das Schema (wie im linken Seitenbereich definiert) in einem festen Zustand halten kann. Es kann eine beliebige Anzahl von Personen geben, die Abfragen für dasselbe Schema schreiben, um das gleiche Problem zu lösen. Um zu verhindern, dass sie sich gegenseitig stören, muss sichergestellt sein, dass sich Struktur und Daten nicht ändern. Dies erfolgt über rückgängig gemachte Transaktionen. Dies geschieht jedoch nicht, wenn der Code auf der rechten Seite festgeschrieben wird.
Jake Feasel
2
@RickJames DDL erstellt implizite Commits in MySQL und Oracle, jedoch nicht in PostgreSQL oder SQL Server. Die Mechanismen, die ich im Anschluss an diesen Beitrag implementiert habe, behandeln dieses Problem. Was die Eingabe von beliebigem SQL angeht - das ist der springende Punkt!
Jake Feasel 20.06.12

Antworten:

3

Für Oracle scheint dies eine gute versteckte Methode zu sein, um COMMITs abzufangen:

/programming//a/6463800/790702

Was er nicht erwähnt, ist, dass Sie in der Lage sein sollten, die Einschränkungsverletzung auch in Ihrem Code zu erfassen, um das Auftreten der zweiten Situation zu stoppen.

Philᵀᴹ
quelle
Super, danke nochmal Phil. Ich konnte diese Technik für Oracle gut nutzen. Ich wünsche mir, dass andere Datenbanken aufgeschobene Einschränkungen unterstützen.
Jake Feasel
Keine Bange.
Kommen Sie