サンプルプログラム

サンプルプログラム 1

/*
 * testlibpq.c : Postgres フロントエンドライブラリ Libpq
 *               C バージョンのテスト
 *
 *
 */
#include <stdio.h>
#include "libpq-fe.h"

void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         i,
                j;

    /* FILE *debug; */

    PGconn     *conn;
    PGresult   *res;

    /*
     * バックエンドとの接続に必要なパラメータをセットしてプログラムを
     * 開始します.
     * パラメータが NULL であれば,環境変数を探して妥当と思われる値を
     * 使おうとしますが,見つからない場合は,システムデフォルトの定数
     * を使います.
     */
    pghost = NULL;              /* バックエンドが動作しているサーバのホスト名 */
    pgport = NULL;              /* バックエンドのポート番号 */
    pgoptions = NULL;           /* バックエンドのスタートアップオプション */ 
    pgtty = NULL;               /* バックエンドのデバッグ用 tty */

    dbName = "template1";

    /* データベースへ接続 */
    conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);

    /*
     * バックエンドとの接続が成功したことを確認
     */
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        fprintf(stderr, " データベース '%s' への接続に失敗しました \n", dbName);
        fprintf(stderr, "%s", PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /* debug = fopen("/tmp/trace.out","w"); */
    /* PQtrace(conn, debug);  */

    /* トランザクションブロックの開始 */
    res = PQexec(conn, "BEGIN");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "BEGIN コマンドの実行に失敗しました \n");
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * メモリリークを防ぐため,必要がなくなったら,すぐに
     * PQclear(PGresult) しましょう
     */
    PQclear(res);

    /*
     * データベースのシステムカタログ,pg_database からインスタンスを
     * 取り出す
     */
    res = PQexec(conn, "DECLARE mycursor CURSOR FOR select * from pg_database");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "DECLARE CURSOR コマンドの実行に失敗しました \n");
        PQclear(res);
        exit_nicely(conn);
    }
    PQclear(res);
    res = PQexec(conn, "FETCH ALL in mycursor");
    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "FETCH ALL コマンドがタプルを正しく返しませんでした \n");
        PQclear(res);
        exit_nicely(conn);
    }

    /* まず属性名を表示 */
    nFields = PQnfields(res);
    for (i = 0; i < nFields; i++)
        printf("%-15s", PQfname(res, i));
    printf("\n\n");

    /* 次にインスタンスを表示 */
    for (i = 0; i < PQntuples(res); i++)
    {
        for (j = 0; j < nFields; j++)
            printf("%-15s", PQgetvalue(res, i, j));
        printf("\n");
    }
    PQclear(res);

    /* カーソルを閉じる */
    res = PQexec(conn, "CLOSE mycursor");
    PQclear(res);

    /* トランザクションをコミット */
    res = PQexec(conn, "COMMIT");
    PQclear(res);

    /* データベースとの接続を閉じ,後始末 */
    PQfinish(conn);

    /* fclose(debug); */
}

サンプルプログラム 2

/*
 * testlibpq2.c : 非同期通知インターフェースのテスト
 *
 * まずこのプログラムを実行し,それから他のウィンドウで psql から
 *
 *   NOTIFY TBL2;
 *
 * としてみてください.
 *
 * もうちょっと凝ってみたい場合は,次のようにします.
 * まず以下のようなデータベースをつくります.
 *
 *   CREATE TABLE TBL1 (i int4);
 *
 *   CREATE TABLE TBL2 (i int4);
 *
 *   CREATE RULE r1 AS ON INSERT TO TBL1 DO
 *     (INSERT INTO TBL2 values (new.i); NOTIFY TBL2);
 *
 * そして
 *
 *   INSERT INTO TBL1 values (10);
 *
 * としてください.
 *
 */
#include <stdio.h>
#include "libpq-fe.h"

void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         i,
                j;

    PGconn     *conn;
    PGresult   *res;
    PGnotify   *notify;

    /*
     * バックエンドとの接続に必要なパラメータをセットしてプログラムを
     * 開始します.
     * パラメータが NULL であれば,環境変数を探して妥当と思われる値を
     * 使おうとしますが,見つからない場合は,システムデフォルトの定数
     * を使います.
     * 
     */
    pghost = NULL;              /* バックエンドが動作しているサーバのホスト名 */
    pgport = NULL;              /* バックエンドのポート番号 */
    pgoptions = NULL;           /* バックエンドのスタートアップオプション */ 
    pgtty = NULL;               /* バックエンドのデバッグ用 tty */
    dbName = getenv("USER");    /* これは読者のテスト用データベースの名前に
                                   適宜置き換えてください */

    /* データベースへ接続 */
    conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);

    /*
     * バックエンドとの接続が成功したことを確認
     */
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        fprintf(stderr, " データベース '%s' への接続に失敗しました \n", dbName);
        fprintf(stderr, "%s", PQerrorMessage(conn));
        exit_nicely(conn);
    }

    res = PQexec(conn, "LISTEN TBL2");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "LISTEN コマンドの実行に失敗しました \n");
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * メモリリークを防ぐため,必要がなくなったら,すぐに
     * PQclear(PGresult) しましょう
     */
    PQclear(res);

    while (1)
    {

        /*
         * チェックの繰り返しの間,ちょっとだけウエイトを入れます.
         * select() ではウエイトを入れると効率的です.
         */
        sleep(1);
        /* バックエンドの非同期メッセージを取り込む */
        PQconsumeInput(conn);
        /* 非同期通知メッセージのチェック */
        while ((notify = PQnotifies(conn)) != NULL)
        {
            fprintf(stderr,
                 " 非同期通知 '%s' を PID '%d' のバックエンドから受けました \n",
                    notify->relname, notify->be_pid);
            free(notify);
        }
    }

    /* データベースとの接続を閉じ,後始末 */
    PQfinish(conn);

}

サンプルプログラム 3

/*
 * testlibpq3.c : Postgres フロントエンドライブラリ Libpq
 *                C バージョンのテスト
 *                バイナリカーソルのテスト
 *
 * 
 * まず以下のようなデータベースをつくります.
 *
 * CREATE TABLE test1 (i int4, d float4, p polygon);
 *
 * INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0,
 * 2.0)'::polygon);
 *
 * INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0,
 * 1.0)'::polygon);
 *
 * 出力は以下のようになるはずです:
 *
 *
 * タプル 0:
 * i = ( 4 バイト ) 1,
 * d = ( 4 バイト ) 3.567000,
 * p = ( 68 バイト ) 座標数 2       境界ボックス = (hi=3.000000,4.000000,
 * lo = 1.000000,2.000000)
 * タプル 1:
 * i = ( 4 バイト ) 2,
 * d = ( 4 バイト ) 89.050003,
 * p = ( 68 バイト ) 座標数 2       境界ボックス = (hi=4.000000,3.000000,
 * lo = 2.000000,1.000000)
 *
 */
#include <stdio.h>
#include "postgres.h"
#include "libpq-fe.h"
#include "utils/geo_decls.h"    /* POLYGON 型を使うのに必要 */

void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         i,
                j;
    int         i_fnum,
                d_fnum,
                p_fnum;
    PGconn     *conn;
    PGresult   *res;

    /*
     * バックエンドとの接続に必要なパラメータをセットしてプログラムを
     * 開始します.
     * パラメータが NULL であれば,環境変数を探して妥当と思われる値を
     * 使おうとしますが,見つからない場合は,システムデフォルトの定数
     * 使います.
     * 
     */
    pghost = NULL;              /* バックエンドが動作しているサーバのホスト名 */
    pgport = NULL;              /* バックエンドのポート番号 */
    pgoptions = NULL;           /* バックエンドのスタートアップオプション */ 
    pgtty = NULL;               /* バックエンドのデバッグ用 tty */
    dbName = getenv("USER");    /* これは読者のテスト用データベースの名前に
                                   適宜置き換えてください */

    /* データベースへ接続 */
    conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);

    /*
     * バックエンドとの接続が成功したことを確認
     */
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        fprintf(stderr, " データベース '%s' への接続に失敗しました \n", dbName);
        fprintf(stderr, "%s", PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /* トランザクションブロックの開始 */
    res = PQexec(conn, "BEGIN");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "BEGIN コマンドの実行に失敗しました \n");
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * メモリリークを防ぐため,必要がなくなったら,すぐに
     * PQclear(PGresult) しましょう
     */
    PQclear(res);

    /*
     * データベースのシステムカタログ,pg_database からインスタンスを
     * 取り出す
     */
    res = PQexec(conn, "DECLARE mycursor BINARY CURSOR FOR select * from test1");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "DECLARE CURSOR コマンドの実行に失敗しました \n");
        PQclear(res);
        exit_nicely(conn);
    }
    PQclear(res);

    res = PQexec(conn, "FETCH ALL in mycursor");
    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "FETCH ALL コマンドがタプルを正しく返しませんでした \n");
        PQclear(res);
        exit_nicely(conn);
    }

    i_fnum = PQfnumber(res, "i");
    d_fnum = PQfnumber(res, "d");
    p_fnum = PQfnumber(res, "p");

    for (i = 0; i < 3; i++)
    {
        printf("type[%d] = %d, size[%d] = %d\n",
               i, PQftype(res, i),
               i, PQfsize(res, i));
    }
    for (i = 0; i < PQntuples(res); i++)
    {
        int        *ival;
        float      *dval;
        int         plen;
        POLYGON    *pval;

        /*
         * テーブル上の三つのフィールドの型はわかっているので
         * ここでは変数に直接結び付けます
         */
        ival = (int *) PQgetvalue(res, i, i_fnum);
        dval = (float *) PQgetvalue(res, i, d_fnum);
        plen = PQgetlength(res, i, p_fnum);

        /*
         * plen はフィールド長の分を含んでいないので,VARHDSZ を
         * 加えます
         */
        pval = (POLYGON *) malloc(plen + VARHDRSZ);
        pval->size = plen;
        memmove((char *) &pval->npts, PQgetvalue(res, i, p_fnum), plen);
        printf(" タプル %d:\n", i);
        printf(" i = ( %d バイト ) %d,\n",
               PQgetlength(res, i, i_fnum), *ival);
        printf(" d = ( %d バイト ) %f,\n",
               PQgetlength(res, i, d_fnum), *dval);
        printf(" p = ( %d バイト ) 座標数 %d  \t 境界ボックス = (hi=%f,%f, lo = %f,%f)\n",
               plen,
               pval->npts,
               pval->boundbox.high.x,
               pval->boundbox.high.y,
               pval->boundbox.low.x,
               pval->boundbox.low.y);
    }
    PQclear(res);

    /* カーソルを閉じる */
    res = PQexec(conn, "CLOSE mycursor");
    PQclear(res);

    /* トランザクションをコミット */
    res = PQexec(conn, "COMMIT");
    PQclear(res);

    /* データベースとの接続を閉じ,後始末 */
    PQfinish(conn);

}