27.16. Programas exemplo

Estes exemplos, e outros, podem ser encontrados no diretório src/test/examples na distribuição do código fonte.

Exemplo 27-1. Programa exemplo da libpq nº 1

/*
 * testlibpq.c
 *
 *      Testa a versão C da LIBPQ, a biblioteca de interface com o POSTGRES
 */
#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"

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

int
main(int argc, char **argv)
{
    const char  *conninfo;
    PGconn      *conn;
    PGresult    *res;
    int         nFields;
    int         i,
                j;

    /*
     * Se o usuário fornecer o parâmetro na linha de comando, este é
     * utilizado na cadeia de caracteres conninfo; senão, o padrão é
     * definir dbname=template1 e utilizar as variáveis de ambiente,
     * ou o valor padrão, para todos os outros parâmetros de conexão.
     */
    if (argc > 1)
        conninfo = argv[1];
    else
        conninfo = "dbname = template1";

    /* Realizar a conexão com o banco de dados */
    conn = PQconnectdb(conninfo);

    /* Verificar se a conexão com o servidor foi bem-sucedida */
    if (PQstatus(conn) != CONNECTION_OK)
    {
        fprintf(stderr, "A conexão com o banco de dados falhou: %s",
            PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /*
     * O caso de teste envolve a utilização de um cursor, motivo pelo qual
     * é necessário estar dentro de um bloco de transação. Tudo poderia
     * ser feito com uma única execução de "select * from pg_database"
     * utilizando a função PQexec(), mas seria muito trivial para servir
     * como um bom exemplo.
     */

    /* Iniciar o bloco de transação */
    res = PQexec(conn, "BEGIN");
    if (PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "O comando BEGIN falhou: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * Para evitar vazamento de memória é necessário chamar PQclear PGresult
     * sempre que este não é mais necessário.
     */
    PQclear(res);

    /*
     * Trazer as linhas de pg_database, o catálogo de bancos de dados
     */
    res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
    if (PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "DECLARE CURSOR falhou: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }
    PQclear(res);

    res = PQexec(conn, "FETCH ALL IN myportal");
    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "FETCH ALL falhou: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }

    /* primeiro, imprimir os nomes dos atributos */
    nFields = PQnfields(res);
    for (i = 0; i < nFields; i++)
        printf("%-15s", PQfname(res, i));
    printf("\n");

    /* em seguida, imprimir as linhas */
    for (i = 0; i < PQntuples(res); i++)
    {
        for (j = 0; j < nFields; j++)
            printf("%-15s", PQgetvalue(res, i, j));
        printf("\n");
    }

    PQclear(res);

    /* fechar o portal ... sem se importar com a verificação de erros ... */
    res = PQexec(conn, "CLOSE myportal");
    PQclear(res);

    /* encerrar a transação */
    res = PQexec(conn, "END");
    PQclear(res);

    /* fechar a conexão com o banco de dados e limpar */
    PQfinish(conn);

    return 0;
}

Execução do programa com o comando SQL mudado para "DECLARE myportal CURSOR FOR select datname, datistemplate, datallowconn from pg_database where datdba=1": [1]

$ gcc testlibpq.c -o testlibpq \
> -I /usr/local/pgsql/include/ \
> -L /usr/local/pgsql/lib/ -lpq
$ ./testlibpq "host=localhost user=teste password=teste dbname=teste"

datname        datistemplate  datallowconn
template1      t              t
template0      t              f

Exemplo 27-2. Programa exemplo da libpq nº 2

/*
 * testlibpq2.c
 *
 *      Teste da interface de notificação assíncrona
 *
 * Este programa deve ser iniciado e, depois, usando o psql em outra janela
 * deve ser executado:
 *   NOTIFY TBL2;
 * Deve ser repetido quatro vezes para que este programa termine.
 *
 * Ou, para aprimorar, deve-se tentar:
 * carregar o banco de dados com os seguintes comandos
 * (presentes no arquivo src/test/examples/testlibpq2.sql):
 *
 *   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);
 *
 * e executar este comando quatro vezes:
 *
 *   INSERT INTO TBL1 VALUES (10);
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include "libpq-fe.h"

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

int
main(int argc, char **argv)
{
    const char *conninfo;
    PGconn     *conn;
    PGresult   *res;
    PGnotify   *notify;
    int        nnotifies;

    /*
     * Se o usuário fornecer o parâmetro na linha de comando, este é
     * utilizado na cadeia de caracteres conninfo; senão, o padrão é
     * definir dbname=template1 e utilizar as variáveis de ambiente,
     * ou o valor padrão, para todos os outros parâmetros de conexão.
     */
    if (argc > 1)
        conninfo = argv[1];
    else
        conninfo = "dbname = template1";

    /* Realizar a conexão com o banco de dados */
    conn = PQconnectdb(conninfo);

    /* Verificar se a conexão com o servidor foi bem-sucedida */
    if (PQstatus(conn) != CONNECTION_OK)
    {
        fprintf(stderr, "A conexão com o banco de dados falhou: %s",
            PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /*
     * Submeter o comando LISTEN para ativar as notificações
     * das regras de NOTIFY.
     */
    res = PQexec(conn, "LISTEN TBL2");
    if (PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "O comando LISTEN falhou: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * Para evitar vazamento de memória é necessário chamar PQclear PGresult
     * sempre que este não é mais necessário.
     */
    PQclear(res);

    /* Sair após receber quatro notificações. */
    nnotifies = 0;
    while (nnotifies < 4)
    {
        /*
         * Adormecer até que alguma coisa aconteça na conexão.
         * É utilizado select(2) para aguardar pela entrada, mas
         * também poderia ser utilizado poll() ou algo semelhante.
         */
        int     sock;
        fd_set  input_mask;

        sock = PQsocket(conn);

        if (sock < 0)
            break;                  /* não deve acontecer */

        FD_ZERO(&input_mask);
        FD_SET(sock, &input_mask);

        if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
        {
            fprintf(stderr, "select() falhou: %s\n", strerror(errno));
            exit_nicely(conn);
        }

        /* Verificar a entrada */
        PQconsumeInput(conn);
        while ((notify = PQnotifies(conn)) != NULL)
        {
            fprintf(stderr,
                "ASYNC NOTIFY '%s' recebida do servidor com pid %d\n",
                 notify->relname, notify->be_pid);
            PQfreemem(notify);
            nnotifies++;
        }
    }

    fprintf(stderr, "Terminado.\n");

    /* fechar a conexão com o banco de dados e limpar */
    PQfinish(conn);

    return 0;
}

Execução do programa exemplo: [2]

$ gcc testlibpq2.c -o testlibpq2 \
> -I /usr/local/pgsql/include/ \
> -L /usr/local/pgsql/lib/ -lpq
$ ./testlibpq2

ASYNC NOTIFY 'tbl2' recebida do servidor com pid 5685
ASYNC NOTIFY 'tbl2' recebida do servidor com pid 5685
ASYNC NOTIFY 'tbl2' recebida do servidor com pid 5685
ASYNC NOTIFY 'tbl2' recebida do servidor com pid 5685
Terminado.

Exemplo 27-3. Programa exemplo da libpq nº 3

/*
 * testlibpq3.c
 *
 *      Teste de parâmetros fora-de-linha e E/S binária
 *
 * Antes de executar este exemplo, o banco de dados deve ser carregado
 * com os seguintes comandos
 * (fornecidos no arquivo src/test/examples/testlibpq3.sql):
 *
 * CREATE TABLE test1 (i int4, t text, b bytea);
 *
 * INSERT INTO test1 values (1, 'joe''s place', '\\000\\001\\002\\003\\004');
 * INSERT INTO test1 values (2, 'ho there', '\\004\\003\\002\\001\\000');
 *
 * A saída esperada é:
 *
 * tupla 0: possui
 *  i = (4 bytes) 1
 *  t = (11 bytes) 'joe's place'
 *  b = (5 bytes) \000\001\002\003\004
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "libpq-fe.h"

/* for ntohl/htonl */
#include <netinet/in.h>
#include <arpa/inet.h>


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

int
main(int argc, char **argv)
{
    const char  *conninfo;
    PGconn      *conn;
    PGresult    *res;
    const char  *paramValues[1];
    int         i,
                j;
    int         i_fnum,
                t_fnum,
                b_fnum;

    /*
     * Se o usuário fornecer o parâmetro na linha de comando, este é
     * utilizado na cadeia de caracteres conninfo; senão, o padrão é
     * definir dbname=template1 e utilizar as variáveis de ambiente,
     * ou o valor padrão, para todos os outros parâmetros de conexão.
     */
    if (argc > 1)
        conninfo = argv[1];
    else
        conninfo = "dbname = template1";

    /* Make a connection to the database */
    conn = PQconnectdb(conninfo);

    /* Check to see that the backend connection was successfully made */
    if (PQstatus(conn) != CONNECTION_OK)
    {
        fprintf(stderr, "Connection to database failed: %s",
               PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /*
     * O objetivo deste programa é mostrar a utilização de PQexecParams()
     * com parâmetros fora-de-linha, assim como a transmissão binária dos
     * resultados. Utilizando parâmetros fora-de-linha pode-se evitar o
     * trabalho entediante de colocar apóstrofos e escapes. Deve ser
     * observado que não é necessário fazer nada especial com o apóstrofo
     * presente no valor do parâmetro.
     */

    /* Abaixo está o valor do parâmetro fora-de-linha */
    paramValues[0] = "joe's place";

    res = PQexecParams(conn,
                       "SELECT * FROM test1 WHERE t = $1",
                       1,           /* um parâmetro */
                       NULL,        /* o servidor deduz o tipo do parâmetro */
                       paramValues,
                       NULL,        /* não é necessário o comprimento do
                                       parâmetro, porque é texto */
                       NULL,        /* o padrão é todos os parâmetros no
                                       formato texto */
                       1);          /* solicitar resultados binários */

    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "SELECT falhou: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }

    /* Utilizar PQfnumber para evitar assumir a ordem dos campos no resultado */
    i_fnum = PQfnumber(res, "i");
    t_fnum = PQfnumber(res, "t");
    b_fnum = PQfnumber(res, "b");

    for (i = 0; i < PQntuples(res); i++)
    {
        char    *iptr;
        char    *tptr;
        char    *bptr;
        int     blen;
        int     ival;

        /* Obter os valores dos campos (ignorada a possibilidade de serem nulos) */
        iptr = PQgetvalue(res, i, i_fnum);
        tptr = PQgetvalue(res, i, t_fnum);
        bptr = PQgetvalue(res, i, b_fnum);

        /*
         * A representação de INT4 está na ordem de bytes da rede,
         * sendo melhor transformar para a ordem de bytes local.
         */
        ival = ntohl(*((uint32_t *) iptr));

        /*
         * A representação binária de TEXT é texto, e como a libpq anexa
         * um byte zero, funciona perfeitamente bem como uma cadeia de
         * caracteres C.
         *
         * A representação binária de BYTEA é um grupo de bytes, podendo
         * incluir nulos, portanto é necessário prestar atenção no
         * comprimento do campo.
         */
        blen = PQgetlength(res, i, b_fnum);

        printf("tupla %d: possui\n", i);
        printf(" i = (%d bytes) %d\n",
               PQgetlength(res, i, i_fnum), ival);
        printf(" t = (%d bytes) '%s'\n",
               PQgetlength(res, i, t_fnum), tptr);
        printf(" b = (%d bytes) ", blen);
        for (j = 0; j < blen; j++)
            printf("\\%03o", bptr[j]);
        printf("\n\n");
    }

    PQclear(res);

    /* fechar a conexão com o banco de dados e limpar */
    PQfinish(conn);

    return 0;
}

Execução do programa exemplo: [3]

$ gcc testlibpq3.c -o testlibpq3 \
> -I /usr/local/pgsql/include/ \
> -L /usr/local/pgsql/lib/ -lpq
$ ./testlibpq3 "host=localhost user=teste password=teste dbname=teste"

tupla 0: possui
 i = (4 bytes) 1
 t = (11 bytes) 'joe's place'
 b = (5 bytes) \000\001\002\003\004

Notas

[1]

Acréscimo feito pelo tradutor.

[2]

Acréscimo feito pelo tradutor.

[3]

Acréscimo feito pelo tradutor.

SourceForge.net Logo CSS válido!