Thread: libpq 7.4 and binary cursor

libpq 7.4 and binary cursor

From
Stephane Raimbault
Date:
Hi,

It seems some changes occured in network protocol between 7.3 and 7.4.


In my simple libray above libpq, I used this call to extract float8 with
a binary cursor (on x86) :

-----------------------------------------------
memcpy(&float8,      PQgetvalue(pg_res, tup_num, field_num),      PQfsize(pg_res, field_num));
-----------------------------------------------

Now with PostgreSQL 7.4, I replaced this memcpy by theses lines :

-----------------------------------------------
union {double d; int64_t i64;
} swap;
uint32_t tab_uint32[2];

/* Read two uint32 */
memcpy(tab_uint32, PQgetvalue(pg_res, tup_num, field_num), 8);

/* Swap MSB -> LSB */
tab_uint32[0] = ntohl(tab_uint32[0]);
tab_uint32[1] = ntohl(tab_uint32[1]);

/* Fusion */
swap.i64 = tab_uint32[0];
swap.i64 <<= 32;
swap.i64 |= tab_uint32[1];

/* Cast */
return swap.d;
------------------------------------------------

Is it the right method to extract binary data ? Don't exist a easiest
method ?

Thank you.

Stephane





Re: libpq 7.4 and binary cursor

From
"Jeroen T. Vermeulen"
Date:
On Thu, Jun 10, 2004 at 04:30:27PM +0200, Stephane Raimbault wrote:

> union {
>     double d; 
>     int64_t i64;
> } swap;
> uint32_t tab_uint32[2];
[...]

> /* Fusion */
> swap.i64 = tab_uint32[0];
> swap.i64 <<= 32;
> swap.i64 |= tab_uint32[1];
> 
> /* Cast */
> return swap.d;

This trick may work on some compilers and/or platforms, but it's not
correct C.  The language does not guarantee that the members of a union
will be allocated in the exact same address, or even that they will
overlap.  What if it registerizes swap.d and/or swap.i64?  It may even
recognize one of the two as uninitialized, and the other as a dead value.
That will get you very compact code, but not the effect you want.

To see how it may go wrong, imagine your compiler implemented "union"
as "#define union struct".  I think this is all described in the C FAQ,
BTW.


Jeroen



Re: libpq 7.4 and binary cursor

From
Tom Lane
Date:
"Jeroen T. Vermeulen" <jtv@xs4all.nl> writes:
> This trick may work on some compilers and/or platforms, but it's not
> correct C.  The language does not guarantee that the members of a union
> will be allocated in the exact same address, or even that they will
> overlap.

Nonsense.  C99 6.7.2.1:
      A pointer  to  a  union  object, suitably converted, points to      each of its members (or if a member is a
bit-field,then  to      the unit in which it resides), and vice versa.
 

It does say that the results of fetching a union member other than
the one last stored to are implementation-dependent, but not that
the implementation can choose to put them in different places.
        regards, tom lane


Re: libpq 7.4 and binary cursor

From
"Jeroen T. Vermeulen"
Date:
On Thu, Jun 10, 2004 at 11:39:25AM -0400, Tom Lane wrote:
> Nonsense.  C99 6.7.2.1:
> 
>        A pointer  to  a  union  object, suitably converted, points to
>        each of its members (or if a member is a bit-field, then  to
>        the unit in which it resides), and vice versa.
> 
> It does say that the results of fetching a union member other than
> the one last stored to are implementation-dependent, but not that
> the implementation can choose to put them in different places.

I stand corrected.  Perhaps this is something that changed in C99 because
too many programs used this trick, or because enough platforms supported 
it.

Note, however, that this is about pointers to unions (and ``suitably
converted,'' whatever that means; there are cases where pointer type
conversions may involve the addition or subtraction of an offset, so there
are situations where you need to be careful about how exactly you convert
your pointers).  The code we're talking about had a union object, but no
pointers.  So the part about registerization still holds.


Jeroen



Re: libpq 7.4 and binary cursor

From
L J Bayuk
Date:
Stephane Raimbault wrote:
> 
> It seems some changes occured in network protocol between 7.3 and 7.4.

Big understatement! It was completely redesigned.

> In my simple libray above libpq, I used this call to extract float8 with
> a binary cursor (on x86) :
> ...

Pre-7.4, binary data came back in the server's byte order. Starting 7.4,
data always comes back in "network data order", which is big-endian,
regardless of server or client architecture. This is a big improvement, so
you can now portably deal with binary data. The proper way to do so in the
client is to use the ntohs() and ntohl() functions to turn network data
order into native order.