Search code examples
sqlcpostgresqllibpq

libpq how to pass bulk data


I'm trying to pass multiple rows to a test table and I'm having trouble understanding how exactly it's done in libpq.

I've found commands for copying data that I believe are needed, but there aren't any examples as to how to use them. https://www.postgresql.org/docs/8.3/static/libpq-copy.html

Here's the code I've came up with, but I'm getting segmentation faults at the PQputCopyEnd function. I'm pretty lost here so any help would be great.

/*
 * testlibpq.c
 *
 *      Test the C version of libpq, the PostgreSQL frontend library.
 */
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <postgresql/libpq-fe.h>

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

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

    //std::string buffer = "key1\tcol11\tcol12\nley2\tcol21\tcol22";
    std::string buffer = "key1\tcol11\tcol12";


    if (argc > 1)
        conninfo = argv[1];
    else
        conninfo = "dbname=postgres host=129.24.26.136 user=postgres password=postgresUNM";

    /* 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);
    }

    //do stuff here
    res = PQexec(conn, "COPY cplusplustest from STDIN");
    int a = PQputCopyData(conn, buffer.c_str(), buffer.length());

    res = PQexec(conn, "COMMIT");

    int b = PQputCopyEnd(conn, errmsg);

    if (errmsg == NULL)
    {
        printf("worked.\n");
    }

    /* close the connection to the database and cleanup */
    PQfinish(conn);

    return 0;
}

Solution

    • postgres-8.3 is very old; please consider a more recent version
    • the errmsg argument to b = PQputCopyEnd(conn, errmsg); must be set to NULL (it is input for libpq, indicating that the client has aborted the copy) ( the manual is still rather vague, I agree.
    • I removed the C++.
    • The COMMIT should go after the CopyEnd.

    /*
     * testlibpq.c
     *
     *      Test the C version of libpq, the PostgreSQL frontend library.
     */
    #include <stdio.h>
    #include <string.h>     // <<--
    #include <stdlib.h>
    
    // #include <postgresql/libpq-fe.h> // <<--
    #include <libpq-fe.h>
    
    static void exit_nicely(PGconn *conn)
    {
        PQfinish(conn);
        exit(1);
    }
    int main(int argc, char **argv)
    {
        const char *conninfo, *errmsg;
        PGconn     *conn;
        PGresult   *res;
        int a,b; // <<--
    
        char buffer[] = "key1\tcol11\tcol12";
    
        if (argc > 1)
            conninfo = argv[1];
        else
            conninfo = "dbname=test host=/tmp/ user=postgres";
    
        /* 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);
        }
    
        //do stuff here
        errmsg = NULL;      // << HERE
        res = PQexec(conn, "COPY cplusplustest(key1,col11,col12) from STDIN;");
        a = PQputCopyData(conn, buffer, strlen(buffer) );
        b = PQputCopyEnd(conn, errmsg);
    
        printf("Res=%p a=%d,b=%d\n", res, a, b);
    
        if (errmsg )
            printf("Failed:%s\n", errmsg);
        else
            printf("worked.\n");
    
        res = PQexec(conn, "COMMIT;");      // <<-- HERE
    
        /* close the connection to the database and cleanup */
        PQfinish(conn);
    
        return 0;
    }