Re: Enum binary access - Mailing list pgsql-hackers

From Petr Chmelar
Subject Re: Enum binary access
Date
Msg-id 5062F642.6000601@fit.vutbr.cz
Whole thread Raw
In response to Re: Enum binary access  (Merlin Moncure <mmoncure@gmail.com>)
List pgsql-hackers
Hi Merlin,

thanks, your code works perfectly.

Cheers,

Petr

On 10.9.2012 16:33, Merlin Moncure wrote:
> On Mon, Sep 10, 2012 at 8:42 AM, Petr Chmelar <chmelarp@fit.vutbr.cz> wrote:
>> Hi there,
>>
>> we tried to create the libpqtypes enum binary send but it doesn't work:
>>
>> // register types
>> PGregisterType user_def[] = { {"seqtype", enum_put, enum_get} };
>> PQregisterTypes(connector->getConn(), PQT_USERDEFINED, user_def, 1, 0);
>>
>> // enum_put throws format error
>> int enum_put (PGtypeArgs *args ) {
>>
>>      char *val = va_arg(args->ap, char *);
>>      char *out = NULL;
>>      int vallen = 0, len = 0, oid = 0;
>>      float sortorder = 0.0;
>>
>>      if (!args || !val) return 0;
>>
>>      /* expand buffer enough */
>>      vallen = strlen(val);
>>      len = sizeof(int) + sizeof(float) + (vallen * sizeof(char));
>>      if (args->put.expandBuffer(args, len) == -1) return -1;
>>
>>      /* put header (oid, sortorder) and value */
>>      out = args->put.out;
>>      memcpy(out, &oid, sizeof(int));
>>      out += sizeof(int);
>>      memcpy(out, &sortorder, sizeof(float));
>>      out += sizeof(float);
>>      memcpy(out, val, vallen);
>>
>>      return len;
>> }
>>
>> // enum_get (FYI, get works OK)
>> int enum_get (PGtypeArgs *args) {
>>      char *val = PQgetvalue(args->get.result, args->get.tup_num,
>> args->get.field_num);
>>      int len = PQgetlength(args->get.result, args->get.tup_num,
>> args->get.field_num);
>>          char **result = va_arg(args->ap, char **);
>>      *result = (char *) PQresultAlloc((PGresult *) args->get.result, len *
>> sizeof(char));
>>      memcpy(*result, val, len * sizeof(char));
>>          return 0;
>> }
>>
>> Postgres doesn't accept enum sent like this and throws format error. This
>> should be used as a prototype for derived types. There is no real "enum"
>> named type. Libpqypes doesn't seem to provide simplified binary manipulation
>> for enum types.
>>
>> What should we do, please? Can you fix it? I think there is more people that
>> need access enum types in binary mode.
> I was able to get it to work what I did:
>
> *) your 'get' routine should probably be allocating a terminating
> byte.  In binary situations, PQgetlength does not return the length of
> the null terminator.
>
> *) backend binary format for enums is just the label text string both
> on get and put side.  So your putting the oid and sort order was
> breaking the put side.  Removed that and everything worked.
>
> *) see (very messy quickly written) code below:
>
>
> #include "libpq-fe.h"
> #include "libpqtypes.h"
> #include "string.h"
>
>
> // enum_put throws format error
> int enum_put (PGtypeArgs *args ) {
>
>      char *val = va_arg(args->ap, char *);
>      char *out = NULL;
>      int vallen = 0, len = 0, oid = 0;
>      float sortorder = 0.0;
>
>      if (!args || !val) return 0;
>
>      /* expand buffer enough */
>      vallen = strlen(val);
>      if (args->put.expandBuffer(args, len) == -1) return -1;
>
>      out = args->put.out;
>      memcpy(out, val, vallen);
>
>      return len;
> }
>
> // enum_get (FYI, get works OK)
> int enum_get (PGtypeArgs *args) {
>      char *val = PQgetvalue(args->get.result, args->get.tup_num,
> args->get.field_num);
>      int len = PQgetlength(args->get.result, args->get.tup_num,
> args->get.field_num) + 1;
>          char **result = va_arg(args->ap, char **);
>      *result = (char *) PQresultAlloc((PGresult *) args->get.result,
> len * sizeof(char));
>      memcpy(*result, val, len * sizeof(char));
>      result[len] = 0;
>          return 0;
> }
>
>
> int main()
> {
>    PGtext t = "b";
>
>    PGconn *conn = PQconnectdb("port=5492 host=localhost");
>    PQinitTypes(conn);
>
>    PGregisterType user_def[] = { {"e", enum_put, enum_get} };
>
>    if(!PQregisterTypes(conn, PQT_USERDEFINED, user_def, 1, 0))
>      fprintf(stderr, "*ERROR: %s\n", PQgeterror());
>
>
>    PGresult *res = PQexecf(conn, "select %e", t);
>
>    if(!res)
>      fprintf(stderr, "*ERROR: %s\n", PQgeterror());
>
>    if (!PQgetf(res, 0, "%e", 0, &t))
>    {
>      fprintf(stderr, "*ERROR: %s\n", PQgeterror());
>    }
>
>    printf("%s\n", t);
>
>    PQclear(res);
> }
>
>




pgsql-hackers by date:

Previous
From: Daymel Bonne Solís
Date:
Subject: Re: system_information.triggers & truncate triggers
Next
From: Michael Paquier
Date:
Subject: Re: pg_reorg in core?