Received: from localhost (maia-3.hub.org [200.46.204.184]) by postgresql.org (Postfix) with ESMTP id C3DA99FB5C7 for ; Wed, 23 May 2007 13:20:26 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.184]) (amavisd-maia, port 10024) with ESMTP id 13161-04 for ; Wed, 23 May 2007 13:20:03 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.5 Received: from relay.mail.twtelecom.net (relay.mail.twtelecom.net [64.129.67.76]) by postgresql.org (Postfix) with ESMTP id C72E19FB602 for ; Wed, 23 May 2007 13:20:03 -0300 (ADT) Received: from localhost (localhost.localdomain [127.0.0.1]) by relay.mail.twtelecom.net (Postfix) with ESMTP id CD2CF588515 for ; Wed, 23 May 2007 10:20:02 -0600 (MDT) X-Virus-Scanned: amavisd-new at twtelecom.net Received: from relay.mail.twtelecom.net ([127.0.0.1]) by localhost (relay-3.dnvr.twtelecom.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id I8tsDNR8BGQA for ; Wed, 23 May 2007 10:20:01 -0600 (MDT) Received: from mailblocker.ateb.com (ateb.com [66.193.74.200]) by relay.mail.twtelecom.net (Postfix) with ESMTP id 5216258823F for ; Wed, 23 May 2007 10:20:01 -0600 (MDT) X-IronPort-AV: E=Sophos;i="4.14,570,1170651600"; d="scan'208";a="75427" Received: from unknown (HELO sr002-2k3exc.ateb.com) ([192.168.100.228]) by mailblocker.ateb.com with SMTP; 23 May 2007 12:20:01 -0400 Received: from 192.168.100.14 ([192.168.100.14]) by sr002-2k3exc.ateb.com ([192.168.100.228]) with Microsoft Exchange Server HTTP-DAV ; Wed, 23 May 2007 16:20:00 +0000 Received: from jhereg by sr002-2k3exc.ateb.com; 23 May 2007 12:19:44 -0400 Subject: Re: How do you convert PostgreSQL internal binary field to C datatypes From: Reid Thompson Reply-To: Reid.Thompson@ateb.com To: Jeff Lynn Cc: pgsql-interfaces@postgresql.org In-Reply-To: <46546220.4060209@rogers.com> References: <46546220.4060209@rogers.com> Content-Type: text/plain Content-Transfer-Encoding: 7bit Date: Wed, 23 May 2007 12:19:44 -0400 Message-Id: <1179937184.9506.46.camel@jhereg> Mime-Version: 1.0 X-Mailer: Evolution 2.11.2 X-Virus-Scanned: Maia Mailguard 1.0.1 X-Archive-Number: 200705/48 X-Sequence-Number: 6555 On Wed, 2007-05-23 at 11:47 -0400, Jeff Lynn wrote: > I give up! What ever data returned from the binary output of > PGgetvalue() is, I don't know how to convert it into StringInfo, which > is being used by a few routines that "seems" to convert internal binary > format into float8. By casting the returned data into StringInfo, > crashes the function. > > If PostgreSQL support only a half baked C API, may as well don't bother. > > So I gave up. I will not use PostgreSQL until there is a simple way to > extract data directly into C or C++ data type. Is one expect to fetch > data in text, then use text to int, text to double, text to date > function before you can make any business logic works? > > Thanks all of you trying to help. Appreciated! > > Jeff > > > ---------------------------(end of broadcast)--------------------------- > TIP 3: Have you checked our extensive FAQ? > > http://www.postgresql.org/docs/faq I would think that using the info provided at these links should enable what you wish.... LINK 1: http://developer.postgresql.org/cvsweb.cgi/pgsql/src/backend/libpq/pqformat.c?rev=1.45;content-type=text%2Fplain /* -------------------------------- * pq_sendfloat4 - append a float4 to a StringInfo buffer * * The point of this routine is to localize knowledge of the external binary * representation of float4, which is a component of several datatypes. * * We currently assume that float4 should be byte-swapped in the same way * as int4. This rule is not perfect but it gives us portability across * most IEEE-float-using architectures. * -------------------------------- */ void pq_sendfloat4(StringInfo buf, float4 f) { union { float4 f; uint32 i; } swap; swap.f = f; swap.i = htonl(swap.i); appendBinaryStringInfo(buf, (char *) &swap.i, 4); } LINK2: http://www.postgresql.org/docs/8.2/interactive/libpq-example.html Example 29-3. libpq Example Program 3 /* * testlibpq3.c * Test out-of-line parameters and binary I/O. * * Before running this, populate a database with the following commands * (provided in 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'); * * The expected output is: * * tuple 0: got * i = (4 bytes) 1 * t = (11 bytes) 'joe's place' * b = (5 bytes) \000\001\002\003\004 * * tuple 0: got * i = (4 bytes) 2 * t = (8 bytes) 'ho there' * b = (5 bytes) \004\003\002\001\000 */ #include #include #include #include #include "libpq-fe.h" /* for ntohl/htonl */ #include #include static void exit_nicely(PGconn *conn) { PQfinish(conn); exit(1); } /* * This function prints a query result that is a binary-format fetch from * a table defined as in the comment above. We split it out because the * main() function uses it twice. */ static void show_binary_results(PGresult *res) { int i, j; int i_fnum, t_fnum, b_fnum; /* Use PQfnumber to avoid assumptions about field order in result */ 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; /* Get the field values (we ignore possibility they are null!) */ iptr = PQgetvalue(res, i, i_fnum); tptr = PQgetvalue(res, i, t_fnum); bptr = PQgetvalue(res, i, b_fnum); /* * The binary representation of INT4 is in network byte order, which * we'd better coerce to the local byte order. */ ival = ntohl(*((uint32_t *) iptr)); /* * The binary representation of TEXT is, well, text, and since libpq * was nice enough to append a zero byte to it, it'll work just fine * as a C string. * * The binary representation of BYTEA is a bunch of bytes, which could * include embedded nulls so we have to pay attention to field length. */ blen = PQgetlength(res, i, b_fnum); printf("tuple %d: got\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"); } } int main(int argc, char **argv) { const char *conninfo; PGconn *conn; PGresult *res; const char *paramValues[1]; int paramLengths[1]; int paramFormats[1]; uint32_t binaryIntVal; /* * If the user supplies a parameter on the command line, use it as the * conninfo string; otherwise default to setting dbname=postgres and using * environment variables or defaults for all other connection parameters. */ if (argc > 1) conninfo = argv[1]; else conninfo = "dbname = 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); } /* * The point of this program is to illustrate use of PQexecParams() with * out-of-line parameters, as well as binary transmission of data. * * This first example transmits the parameters as text, but receives the * results in binary format. By using out-of-line parameters we can * avoid a lot of tedious mucking about with quoting and escaping, even * though the data is text. Notice how we don't have to do anything * special with the quote mark in the parameter value. */ /* Here is our out-of-line parameter value */ paramValues[0] = "joe's place"; res = PQexecParams(conn, "SELECT * FROM test1 WHERE t = $1", 1, /* one param */ NULL, /* let the backend deduce param type */ paramValues, NULL, /* don't need param lengths since text */ NULL, /* default to all text params */ 1); /* ask for binary results */ if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } show_binary_results(res); PQclear(res); /* * In this second example we transmit an integer parameter in binary * form, and again retrieve the results in binary form. * * Although we tell PQexecParams we are letting the backend deduce * parameter type, we really force the decision by casting the parameter * symbol in the query text. This is a good safety measure when sending * binary parameters. */ /* Convert integer value "2" to network byte order */ binaryIntVal = htonl((uint32_t) 2); /* Set up parameter arrays for PQexecParams */ paramValues[0] = (char *) &binaryIntVal; paramLengths[0] = sizeof(binaryIntVal); paramFormats[0] = 1; /* binary */ res = PQexecParams(conn, "SELECT * FROM test1 WHERE i = $1::int4", 1, /* one param */ NULL, /* let the backend deduce param type */ paramValues, paramLengths, paramFormats, 1); /* ask for binary results */ if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } show_binary_results(res); PQclear(res); /* close the connection to the database and cleanup */ PQfinish(conn); return 0; }