2012-12-01 3 views
6

Ich arbeite mit der PostgreSQL C API. Beim Lesen der documentation wird angegeben, dass eine Abfrage beendet ist, wenn PQgetResult NULL zurückgibt und PQgetResult blockiert, wenn PQisBusy nicht 0 zurückgibt. PQisBusy gibt jedoch 1 zurück, wenn keine Eingabe mehr vorhanden ist. Daher kann ich PQgetResult nicht aufrufen und NULL abrufen. Daher kann ich nicht wissen, ob die Abfrage beendet ist. Gibt es eine andere Möglichkeit zu wissen, ob die Abfrage abgeschlossen ist? Habe ich die async API falsch verstanden?Postgres Async API Erkennung Ende der Abfrage

---- ----- edit

Die Grundidee, wie C-Code ist:

PQsendQuery(conn, query) 

while(true) 
{ 
    PQconsumeInput(conn) 
    if(PQisBusy(conn) == 0) 
    { 
     PGresult* res = PQgetResult(conn); 
     if(res) 
     { 
      //print result 
     } 
     else 
     { 
      //res == NULL 
      //indicates query is over 
      break; 
     } 
    } 
} 

Das Ergebnis gedruckt werden, aber die Schleife endet nie. Weil PQisBusy nur einmal 0 zurückgibt.

+1

Es könnte sich lohnen, diese mit Inhalt füllen mit Code aus, das zeigt, was du tust. –

+0

Ich denke, PQgetResult überprüft und wartet auf Besetztzeichen vor dem Zurückgeben des Ergebnisses. Also möglicherweise nicht erforderlich, wenn (PQisBusy (conn) == 0) überhaupt überprüfen. –

+0

@MuhammadUsama der Punkt des Codes ist, dass es nie blockieren kann, daher der Async. Ich weiß, dass es sinnlos ist, Async-I/O in einer ausgelasteten Schleife auszuführen, aber ich brauchte ein minimales Beispiel. – JustMaximumPower

Antwort

0

Ich kann ein Problem mit dem Code sehen, Sie überprüfen nicht Rückkehr der PQconsumeInput (conn) -Funktion. Es liegt in der Verantwortung von PQconsumeInput, die Besetztflagge zu löschen. Was passieren könnte, ist, dass PQconsumeInput fehlschlägt, ohne Daten zu verarbeiten und das Flag "Besetzt" zu löschen.

Ich denke, das Ergebnis von PQconsumeInput vor dem Aufruf von PQisBusy überprüfen sollte gut funktionieren.

while (PQconsumeInput(conn) == 1) 
{ 
    if(PQisBusy(conn) == 0) 
    { 
     PGresult* res = PQgetResult(conn); 
     if(res) 
     { 
      //print result 
     } 
     else 
     { 
      //res == NULL 
      //indicates query is over 
      break; 
     } 
    } 
} 
+0

PQconsumeInput Rückgabe 0 gibt einen Fehler in der Dokumentation angibt, dass auch im Falle eines Fehlers PQgetResult muss aufgerufen werden, bis es NULL zurückgibt. Der obige Code ist ebenfalls nur ein minimalistisches Beispiel. Im echten Code mache ich eine Fehlerüberprüfung. – JustMaximumPower

+0

Hinweis: Auch wenn PQresultStatus einen schwerwiegenden Fehler anzeigt, sollte PQgetResult aufgerufen werden, bis ein Nullzeiger zurückgegeben wird, damit libpq die Fehlerinformationen vollständig verarbeiten kann. –

+0

Entschuldigung, ich habe zu früh zurück gedrängt und jetzt kann ich meinen Kommentar nicht bearbeiten, also ignoriere bitte das obige. Dokument sagt "Auch wenn PQresultStatus einen schwerwiegenden Fehler anzeigt, sollte PQgetResult aufgerufen werden, bis es einen Nullzeiger zurückgibt, damit libpq die Fehlerinformationen vollständig verarbeiten kann." Also ich denke, es ist nur gültig für Fehler aufgetreten während PQGetResult Funktionsaufruf, nicht für Fehler in PQconsumeInput aufgetreten. Auch in Ihrem Fall warten Sie darauf, dass PQisBusy vor dem Aufruf von PQGetResult "not busy" zurückgibt und ich glaube, dass PQisBusy im Falle eines von der PQconsumeInput-Funktion zurückgegebenen Fehlers nicht vertrauenswürdig ist. –

1

Nach dem, was ich über den Link in meinem Kommentar zu verstehen, würde ich so etwas wie dies (die Parameter select() und die anderen Funktionsaufrufe können ganz unterschiedlich sein) versuchen:

if (select(sock 1, &input_mask, NULL, NULL, NULL) < 0) { 

    fprintf(stderr, "select() failed: %s\n", strerror(errno)); 
    exit_nicely(conn); 
} 

PQconsumeInput(conn); 

while (PQisBusy(conn) != 0) { 

    /* wait here */ 

} 

while (PGresult* res = PQgetResult(conn)) { /* not sure this is OK, test for not null */ 

    /* do something with res */ 

} 
+0

Das hilft nicht. Ihr Code blockiert möglicherweise, seit Sie PQgetResult in einer Schleife ohne Test aufrufen, wenn die Verbindung ausgelastet ist. – JustMaximumPower

+0

Da es auf 'PQisBusy()' wartet, bis es nicht mehr beschäftigt ist und nur dann 'PQgetResult()' aufruft, denke ich ganz und gar nicht. (Ich kann mich sowieso irren.) Hast du das versucht? – dezso

+0

Wenn ich den Punkt von PQsendQuery nicht vollständig missverstanden habe, wird eine Abfrage in mehreren Chunks gesammelt, z. B. Fragmente einer großen Tabelle. Daher gibt PQisBusy return 0 nicht an, dass die Abfrage beendet ist, in diesem Fall wäre meine Frage Stimmung, sie zeigt nur an, dass eine Eingabe verfügbar ist. Es ist eigentlich keine gute Idee, diesen Code zu testen, indem man ihn testet; Der Code kann in Laborumgebungen nicht blockiert werden, aber das garantiert nicht, dass der Code in der Produktion nicht blockiert wird. – JustMaximumPower

3

Ich denke, Was Sie brauchen, ist PQsetSingleRowMode zu lassen PQgetResult eine Zeile jedes Mal zurückgeben.

von http://www.postgresql.org/docs/9.2/static/libpq-single-row-mode.html

Normalerweise sammelt libpq ein Gesamtergebnis des SQL-Befehl und gibt es auf die Anwendung als eine einzige PGresult. Dies kann für Befehle nicht funktionieren, die eine große Anzahl von Zeilen zurückgeben. In solchen Fällen können Anwendungen PQsendQuery und PQgetResult im Einzelzeilenmodus verwenden. In diesem Modus werden die Ergebniszeilen einmal an die Anwendung zurückgegeben, und zwar einmal um , da sie vom Server empfangen werden.

Wenn die Abfrage keine Zeilen zurückgibt, werden sie als einzelne PGresult Objekte zurückgegeben, die mit Ausnahme wie normale Abfrage-Ergebnisse aussehen Statuscode PGRES_SINGLE_TUPLE statt PGRES_TUPLES_OK haben. Nach der letzten Zeile oder sofort, wenn die Abfrage null Zeilen zurückgibt, wird ein Nullzeilenobjekt mit dem Status PGRES_TUPLES_OK zurückgegeben; Dies ist das Signal, dass keine Zeilen mehr ankommen werden.

Scheck aus dem Beispielcode: https://github.com/markokr/libpq-rowproc-demos/blob/master/demo-onerow-async.c

+0

Der Beispielcode, mit dem Sie verknüpften, wertet den Rückgabewert von PQresultStatus aus, um festzustellen, ob die Abfrage beendet ist. Ich mag den Stil nicht, aber ich denke, es ist die beste Lösung bisher. Dafür werde ich dir die Prämie geben, bevor sie verloren geht. – JustMaximumPower