Re: Enum binary access

From: Petr Chmelar <chmelarp(at)fit(dot)vutbr(dot)cz>
To: Merlin Moncure <mmoncure(at)gmail(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Enum binary access
Date: 2012-09-26 12:34:10
Message-ID: 5062F642.6000601@fit.vutbr.cz
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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(at)fit(dot)vutbr(dot)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);
> }
>
>

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2012-09-26 12:39:36 Re: pg_reorg in core?
Previous Message Daymel Bonne Solís 2012-09-26 11:40:02 Re: system_information.triggers & truncate triggers