psycopg2.InternalError (Python)

Hallo zusammen,

ich bekomme beim Schicken einer SQL-Abfrage von Python aus an eine Postgres-DB folgende Fehlermeldung, was mich langsam echt zur Verzweiflung bringt :frowning:

psycopg2.InternalError: current transaction is  aborted, commands ignored until end of transaction block

Der Code selbst macht eigentlich nix wildes und hat bisher auch immer funktioniert. Er sieht in etwa so aus:

sql="""SELECT * from tabelle where  tabelle.gueltigvon < %s AND
          tabelle.ablaufdatum = %s 
          ... """

        parameter=(datum, datum, datum, datum,  nummer, nummer, nummer, nummer, nummer)
        curs.execute(sql,  parameter)
        row = curs.fetchall()

(natürlich kommen auch genau 9x %s vor, so dass datum und nummer jeweils eingesetzt wird. Ich hab das hier nur der Einfachheit halber verkürzt. Mit der Abfrage selbst, sollte es m.E. nichts zu tun haben)

Kann mir da jemand weiterhelfen??

Viele Grüße und vielen Dank!!
Hannes

Anscheinend ist dieser Code nicht dein Problem sondern ein Befehl, der vorher ausgeführt wurde.
Der hat einen Fehler verursacht und daraufhin wurde deine Transaktion beendet.

Ev. findest du im Log des Servers weitere Informationen.

Hallo ads,

danke für die schnelle Antwort!

Im Server-Logfile sehe ich im Grunde nochmal das, was mir auch Python ausgibt: Meine SQL-Abfrage zusammen mit der Meldug
current transaction is aborted, commands ignored until end of transaction block

An anderer Stelle habe ich gelesen, dass ggf. ein “Rollback” bzw. ein “Commit” das Problem einer fehlerhaften Transaktion beheben könnte.
Ich würde das ja ausprobieren, bin mir aber der Auswirkungen nicht so ganz im Klaren. Es geht um eine produktive Datenbank, auf die
über eine Software ständig neue Abfragen ausgeführt werden (auch seit dem Auftreten des Fehlers waren es wieder viele). Bewirkt denn
ein Rollback dann nur, dass fehlerhafte Transaktionen “zurückgerollt” werden oder muss ich auch Angst haben, dass sämtliche INSERTS oder
UPDATES seit Auftreten des Fehlers “rückgängig” gemacht werden?

Alle Aktionen, die seit dem Start der Transaktion durchgeführt wurden, werden zurückgerollt.

Klingt etwas makaber, aber: ist sowieso egal wieviele Aktionen in der Transaktion ausgeführt wurden. Sobald die Transaktion durch einen Fehler abgebrochen wurde, sind die Änderungen sowieso verloren.

Für dich wichtig ist: diese Fehlermeldung wird erst beim Ausführen von Anweisungen nach einem Fehler verursacht. Der eigentliche Fehler tritt irgendwo früher auf. Den musst du finden.

Mir scheint, Du hast das Konzept einer Transaktion nicht verstanden. Angenommen, Du startest eine Transaktion (TX), und in dieser TX machst Du erfolgreich erst einmal 100 Inserts. Und dann aber leider eine mit ungültigen Daten. Ab dann ist die TX ungültig. Du kannst weiter die DB mit Inserts bewerfen - es bringt aber nix. Du kommst da nur mittels ROLLBACK (oder auch COMMIT) raus, beides wird aber ein Rollback auslösen, und zwar für alles, was in dieser TX passiert ist. Dies gilt auch für die ersten 100 erfolgreichen Inserts.

So, und nun merkst Du Dir, daß nach jeder Aktion (Insert, Select, …) man den Rückgabewert prüft, ob die Aktion erfolgreich war. Tust Du das nicht, kannst Du nun nicht mehr nachvollziehen, ob es das erste, zehnte oder hunderste Insert war, welches Dir Deine TX zerhauen hat.

Ach ja: ich bin kein Phyton-Experte, aber vielleicht ist ja auch das eingang von Dir gezeigte schon falsch, nämlich dann, wenn PG Dein Datum nicht als Datum erkennt. Was genau bekommt denn der PG-Server als SQL übergeben?


Andreas

Ah, ok. Das heißt, es geht logischerweise nur um ein Rollback dieser Transaktion, in der mein Fehler auftritt (in einem Skript). Wenn dann nebenbei andere Programme Querys auf die gleiche Datenbank ausführen, hat das damit nichts zu tun. Die sind weiterhin ausgeführt worden und sind auch vom Rollback nicht betroffen.

Danke für den Hinweis, den Fehler im Programm VOR der Stelle mit dem fehlerspuckenden Query zu suchen. Dass heißt, dass in meinem Python-Code irgendwo davor ein Fehler drin sein wird. Aber ist denn dann ein Rollback überhaupt noch nötig?

An dieser Stelle noch mal der eindringliche Hinweis, den Rückgabewert jeder Anfrage zu prüfen.
Python kann dir dafür sicher nette Exceptions auslösen, die du abfangen kannst.


Aber ist denn dann ein Rollback überhaupt noch nötig?

Sicher musst du das. Woher soll die Datenbank sonst wissen, dass du deinen Fehler bemerkt hast?

ACK.

Danke für den Hinweis, den Fehler im Programm VOR der Stelle mit dem fehlerspuckenden Query zu suchen. Dass heißt, dass in meinem Python-Code irgendwo davor ein Fehler drin sein wird. Aber ist denn dann ein Rollback überhaupt noch nötig?

Ja. Was soll denn die arme DB denn machen? Die TX ist kapott, die (dumme) Anwendung ignoriert dies aber und schickt weiter Befehle, als sei nix gewesen. Also wartet sie brav, bis ein ROLLBACK kommt (COMMIT geht auch, bewirk aber ein ROLLBACK). Von sich aus macht sie jedenfalls weder COMMIT (das machen andere Systeme wohl sporadisch …) noch ROLLBACK.


Andreas

@Andreas:

Das SQL sollte eigentlich passen, ich hab es mir zumindest ausgeben lassen und mal direkt über den pgAdmin ausgeführt. Da hat es geklappt. Das Script läuft auch generell schon seit Monaten so, nur dieses Mal ist ein Fehler aufgetreten :frowning:


@ads

Ok. Jetzt ist mir nur noch nicht ganz klar, wie ich den Rollback in meinen Python-Code integrieren soll. Ich meine, wenn wir von PSQL-Scripten reden, hat man die Transaktionen etwa so:

BEGINN
SELECT fehler;
ROLLBACK;
END

Aber ich schicke ja einfach per curs.execute ein sql an die Datenbank und habe weiter nichts mit BEGINN oder END definiert. Wäre dann alles innerhalb meines sql-Strings die Transaktion? Müsste ich dann im Except-Teil das Rollback setzen? Also so in der Art:

sql="SELECT blablabla ... "
rollback_sql = "ROLLBACK()"

        
try:
   curs.execute(sql)
   row = curs.fetchall()
except:
   curs.execute(rollback_sql)

Sorry, ich programmiere kein Python. Dafür musst du die Dokumentation zu Rate ziehen.

Da gehts mir auch garnicht um die Syntax - ich meinte nur, ob das vom Herangehen so sein sollte? Also vor allem, muss ich hier einen rollback machen, auch wenn ich vorher “nur” ein SELECT (und kein INSERT oder UPDATE) habe?

Ein SELECT kann auch fehlerhaft sein. Entweder falsche Syntax, es kann auf Tabellennamen zugreifen, die es gar nicht gibt. Oder das SELECT kann Funktionen aufrufen, die wiederum fehlerhaft sind.

Alle SELECTs sind auch in Transaktionen gekapselt.


Ich möchte den Ratschlag von akretschmer hier wiederholen: beschäftige dich bitte eingehend mit der Funktionsweise von Transaktionen. Und danach schau dir an, wie deine Programmiersprache mit Transaktionen umgeht und wie du Fehler abfängst.
Du solltest zuerst wissen, wie du mit deinen Werkzeugen umgehst, danach kannst du dich an die eigentliche Fehlersuche machen.

Ok, dann vielen Dank schonmal euch beiden!!

Also: Wenn du mit cursor.execute(sql) was in die DB schreibst, wird das von psycopg als Transaktion gekapselt. Das kann auch mit Dictionarys sehr umfangreich sein. Wenn alles klappt, kannst du ein conn.commit() hinterherwerfen, wenn nicht kommt das Rollback automatisch, bzw. es wurde ja bis dahin nichts fest in die DB geschrieben. Helfen tut dir das hier aber nicht, denn du machst ja ein select. Typeconversions werden im übrigen auch recht zuverlässig von psycopg2 erledigt.
Hast du mal probiert, das SQL händisch in der DB auszuführen, bzw. mal ein bisschen damit rumzuspielen, um den Fehler einzugrenzen? eventuell sind die DB-Meldungen auch ausagekräfiger. Greifen u.U. noch andere Prozesse auf die Tabelle zu, so das sie gelockt ist? Schliesslich scheint der Fehler aufzutreten, bevor psycopg2 ein Ergebnis liefern kann, denn sonst würde der Zugriff auf row einen index-out-of-range oder einfach nichts liefern. Du kannst auch mal den ganzen Traceback des Fehlers posten, da kann man auch sehen, was da passiert.

Gruß Uwe

PS: Nur zur Info, falls dort eine Lösung auftaucht: python-forum

EDIT: OK, jetzt hab ich alles gelesen :wink: Das SQL stimmt also und funktioniert. Das bedeutet, psycopg2 kann das auch ausführen, sofern es eine korrekte Verbindung vorfindet. Im schlimmsten Fall kommt halt nix zurück oder der Code danach liefert einen Fehler. Also muß der Fehler an der Verbindung liegen, erreichst du eventuell das Limit? Oder wird die Verbindung vorher geschlossen? Ggf. von einem anderen Prozess? Sicher, das die Tabelle nicht gelockt ist?
Du solltest auf jeden Fall das ganze Traceback des Fehlers posten (auch im Python-Forum :wink: ) , denn der liegt vermutlich irgendwo im Pythonteil.

n8 Uwe

EDIT2: Das sagen die Erfinder von psycopg2 dazu. Das Rolback würde dann wohl so funktionieren:

try:
    cursor.execute(sql, params)
    row = cursor.fetchall()
except:
    conn.rollback()

Das beseitigt jedoch nicht den Fehler sondern fängt nur dessen Folgen ab.