6

私は PostgreSQL C API を使用しています。ドキュメントを読むと、PQgetResult が NULL を返すとクエリが終了し、PQisBusy が 0 を返さない場合は PQgetResult がブロックされると記載されています。しかし、PQisBusy はそれ以上入力がない場合は 1 を返すため、PQgetResult を呼び出して NULL を取得することはできません。したがって、クエリが終了したかどうかはわかりません。クエリが完了したかどうかを知る他の方法はありますか? 非同期 API を誤解していませんか?

- - 編集 - - -

C コードとしての基本的な考え方は次のとおりです。

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;
        }
    }
}

結果は出力されますが、ループは決して終了しません。PQisBusy は一度だけ 0 を返すためです。

4

3 に答える 3

4

PQsetSingleRowMode必要なのは、PQgetResult毎回1行返すことだと思います。

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

通常、libpq は SQL コマンドの結果全体を収集し、単一の PGresult としてアプリケーションに返します。これは、多数の行を返すコマンドでは機能しない可能性があります。このような場合、アプリケーションは単一行モードで PQsendQuery と PQgetResult を使用できます。このモードでは、サーバーから受信した結果行が一度に 1 行ずつアプリケーションに返されます。

クエリが行を返す場合、それらは個々の PGresult オブジェクトとして返されます。これは、ステータス コードが PGRES_TUPLES_OK ではなく PGRES_SINGLE_TUPLE であることを除いて、通常のクエリ結果のように見えます。最後の行の後、またはクエリがゼロ行を返した場合はすぐに、ステータスが PGRES_TUPLES_OK のゼロ行オブジェクトが返されます。これは、これ以上行が到着しないというシグナルです。

サンプル コードを確認してください: https://github.com/markokr/libpq-rowproc-demos/blob/master/demo-onerow-async.c

于 2012-12-10T15:56:26.913 に答える
1

コメントのリンクから理解したことに基づいて、次のようなことを試してみます (へのパラメーターselect()と他の関数呼び出しはまったく異なる場合があります)。

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 */

}
于 2012-12-07T14:54:31.010 に答える
0

コードに問題が 1 つあります。PQconsumeInput(conn) 関数の戻り値をチェックしていません。ビジーフラグをクリアするのは PQconsumeInput の責任です。PQconsumeInput が、データを処理せずにビジー フラグをクリアせずに失敗する可能性があります。

PQisBusy を呼び出す前に PQconsumeInput の結果をチェックするとうまくいくはずです。

while (PQconsumeInput(conn) == 1) 
{
  if(PQisBusy(conn) == 0)
  {
        PGresult* res = PQgetResult(conn);
        if(res)
        {
            //print result
        }
        else
        {
            //res == NULL
            //indicates query is over
            break;
        }
    }
}
于 2012-12-04T09:32:47.597 に答える