Обсуждение: Problems with a C function, pg_uname(), and String concatenation.

Поиск
Список
Период
Сортировка

Problems with a C function, pg_uname(), and String concatenation.

От
Rafael Martinez
Дата:
Hello

We have a function in C which is accessed via a view and which produces
a strange result when used together with || (String concatenation).

I can not find the problem. Any C/postgres guru with any idea of how to
fix it?

Here is the function and the result when used with ||:

-------------------------------------------
PG_UNAME()
-------------------------------------------
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include <sys/utsname.h>


#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif


PG_FUNCTION_INFO_V1(pg_uname);

Datum
pg_uname(PG_FUNCTION_ARGS)
{
     text *argument = PG_GETARG_TEXT_P(0);
     size_t argumentlen = VARSIZE(argument)-VARHDRSZ;

     text *result = (text *) palloc(256);
     char *option = (char *) palloc(argumentlen+1);

     char sysname[] = "sysname";
     char nodename[] = "nodename";
     char release[] = "release";
     char version[] = "version";
     char machine[] = "machine";
     char null[] = "null";

     struct utsname uname_pointer;
     uname(&uname_pointer);

     VARATT_SIZEP(result) = 256;

     memcpy(option,VARDATA(argument),argumentlen);
     option[argumentlen] = '\0';

     if (strcmp(option,sysname) == 0){

memcpy(VARDATA(result),uname_pointer.sysname,sizeof(uname_pointer.sysname));
     }
     else if (strcmp(option,nodename) == 0){

memcpy(VARDATA(result),uname_pointer.nodename,sizeof(uname_pointer.nodename));
     }
     else if (strcmp(option,release) == 0){

memcpy(VARDATA(result),uname_pointer.release,sizeof(uname_pointer.release));
     }
     else if (strcmp(option,version) == 0){

memcpy(VARDATA(result),uname_pointer.version,sizeof(uname_pointer.version));
     }
     else if (strcmp(option,machine) == 0){

memcpy(VARDATA(result),uname_pointer.machine,sizeof(uname_pointer.machine));
     }
     else{
         memcpy(VARDATA(result),null,sizeof(null));
     }

     pfree(option);
     PG_RETURN_TEXT_P(result);
}

-------------------------------------------

The view we use is this one:
-------------------------------------------
SELECT pg_uname('sysname'::text) AS sysname,
        pg_uname('nodename'::text) AS nodename,
        pg_uname('release'::text) AS kernel,
        pg_uname('version'::text) AS version,
        pg_uname('machine'::text) AS machine,
        substr(version(), 11, 7) AS pgversion,
        to_char(pg_postmaster_start_time(),'YYYY-MM-DD
HH24:MM:SS'::text) AS pg_start,
        age(now(),pg_postmaster_start_time()) AS pg_uptime;
-------------------------------------------

A normal output from this view looks like this:

pgadmin=# SELECT * from sysinfo;

-[ RECORD 1 ]----------------------------------
sysname   | Linux
nodename  | dbpg-rt.uio.no
kernel    | 2.6.9-67.0.4.ELsmp
version   | #1 SMP Fri Jan 18 05:00:00 EST 2008
machine   | x86_64
pgversion |  8.2.6
pg_start  | 2008-06-10 10:06:28
pg_uptime | 20 days 23:59:24.971497


But, when used with ||, everything comming after attributes delivered by
pg_uname() disappears:

SELECT '***' || sysname || '***' as example from sysinfo ;

  example
----------
  ***Linux
(1 row)

Any ideas?
Thanks in advance for your time.

PS.- This is the section og the make file used to compile this function:
-----------------------------------------------------------------------
SERVER_INCLUDES += -I $(shell /usr/local/bin/pg_config --includedir)
SERVER_INCLUDES += -I $(shell /usr/local/bin/pg_config --includedir-server)

CFLAGS = $(SERVER_INCLUDES)
CC = gcc

pg_uname: pg_uname.c
      $(CC) $(CFLAGS) -fpic -c $<
           $(CC) $(CFLAGS) -shared -o $(basename $<).so $(basename $<).o
-----------------------------------------------------------------------

regards
--
  Rafael Martinez, <r.m.guerrero@usit.uio.no>
  Center for Information Technology Services
  University of Oslo, Norway

  PGP Public Key: http://folk.uio.no/rafael/

Re: Problems with a C function, pg_uname(), and String concatenation.

От
"Pavel Stehule"
Дата:
hello
try

memcpy(VARDATA(result),uname_pointer.release,strlen(uname_pointer.release));
SET_VARSIZE(result, strlen(uname_pointer.release) + VARHDRSZ);

Regards
Pave Stehule

2008/7/1 Rafael Martinez <r.m.guerrero@usit.uio.no>:
> Hello
>
> We have a function in C which is accessed via a view and which produces a
> strange result when used together with || (String concatenation).
>
> I can not find the problem. Any C/postgres guru with any idea of how to fix
> it?
>
> Here is the function and the result when used with ||:
>
> -------------------------------------------
> PG_UNAME()
> -------------------------------------------
> #include "postgres.h"
> #include <string.h>
> #include "fmgr.h"
> #include <sys/utsname.h>
>
>
> #ifdef PG_MODULE_MAGIC
> PG_MODULE_MAGIC;
> #endif
>
>
> PG_FUNCTION_INFO_V1(pg_uname);
>
> Datum
> pg_uname(PG_FUNCTION_ARGS)
> {
>    text *argument = PG_GETARG_TEXT_P(0);
>    size_t argumentlen = VARSIZE(argument)-VARHDRSZ;
>
>    text *result = (text *) palloc(256);
>    char *option = (char *) palloc(argumentlen+1);
>
>    char sysname[] = "sysname";
>    char nodename[] = "nodename";
>    char release[] = "release";
>    char version[] = "version";
>    char machine[] = "machine";
>    char null[] = "null";
>
>    struct utsname uname_pointer;
>    uname(&uname_pointer);
>
>    VARATT_SIZEP(result) = 256;
>
>    memcpy(option,VARDATA(argument),argumentlen);
>    option[argumentlen] = '\0';
>
>    if (strcmp(option,sysname) == 0){
>
> memcpy(VARDATA(result),uname_pointer.sysname,sizeof(uname_pointer.sysname));
>    }
>    else if (strcmp(option,nodename) == 0){
>
> memcpy(VARDATA(result),uname_pointer.nodename,sizeof(uname_pointer.nodename));
>    }
>    else if (strcmp(option,release) == 0){
>
> memcpy(VARDATA(result),uname_pointer.release,sizeof(uname_pointer.release));
>    }
>    else if (strcmp(option,version) == 0){
>
> memcpy(VARDATA(result),uname_pointer.version,sizeof(uname_pointer.version));
>    }
>    else if (strcmp(option,machine) == 0){
>
> memcpy(VARDATA(result),uname_pointer.machine,sizeof(uname_pointer.machine));
>    }
>    else{
>        memcpy(VARDATA(result),null,sizeof(null));
>    }
>
>    pfree(option);
>    PG_RETURN_TEXT_P(result);
> }
>
> -------------------------------------------
>
> The view we use is this one:
> -------------------------------------------
> SELECT pg_uname('sysname'::text) AS sysname,
>       pg_uname('nodename'::text) AS nodename,
>       pg_uname('release'::text) AS kernel,
>       pg_uname('version'::text) AS version,
>       pg_uname('machine'::text) AS machine,
>       substr(version(), 11, 7) AS pgversion,
>       to_char(pg_postmaster_start_time(),'YYYY-MM-DD HH24:MM:SS'::text) AS
> pg_start,
>       age(now(),pg_postmaster_start_time()) AS pg_uptime;
> -------------------------------------------
>
> A normal output from this view looks like this:
>
> pgadmin=# SELECT * from sysinfo;
>
> -[ RECORD 1 ]----------------------------------
> sysname   | Linux
> nodename  | dbpg-rt.uio.no
> kernel    | 2.6.9-67.0.4.ELsmp
> version   | #1 SMP Fri Jan 18 05:00:00 EST 2008
> machine   | x86_64
> pgversion |  8.2.6
> pg_start  | 2008-06-10 10:06:28
> pg_uptime | 20 days 23:59:24.971497
>
>
> But, when used with ||, everything comming after attributes delivered by
> pg_uname() disappears:
>
> SELECT '***' || sysname || '***' as example from sysinfo ;
>
>  example
> ----------
>  ***Linux
> (1 row)
>
> Any ideas?
> Thanks in advance for your time.
>
> PS.- This is the section og the make file used to compile this function:
> -----------------------------------------------------------------------
> SERVER_INCLUDES += -I $(shell /usr/local/bin/pg_config --includedir)
> SERVER_INCLUDES += -I $(shell /usr/local/bin/pg_config --includedir-server)
>
> CFLAGS = $(SERVER_INCLUDES)
> CC = gcc
>
> pg_uname: pg_uname.c
>          $(CC) $(CFLAGS) -fpic -c $<
>          $(CC) $(CFLAGS) -shared -o $(basename $<).so $(basename $<).o
> -----------------------------------------------------------------------
>
> regards
> --
>  Rafael Martinez, <r.m.guerrero@usit.uio.no>
>  Center for Information Technology Services
>  University of Oslo, Norway
>
>  PGP Public Key: http://folk.uio.no/rafael/
>
> --
> Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-general
>

Re: Problems with a C function, pg_uname(), and String concatenation.

От
Rafael Martinez
Дата:
Pavel Stehule wrote:
> hello
> try
>
> memcpy(VARDATA(result),uname_pointer.release,strlen(uname_pointer.release));
> SET_VARSIZE(result, strlen(uname_pointer.release) + VARHDRSZ);
>
[.........]

This a 8.2.x system. SET_VARSIZE is not available.

Thanks for your time.
regards
--
  Rafael Martinez, <r.m.guerrero@usit.uio.no>
  Center for Information Technology Services
  University of Oslo, Norway

  PGP Public Key: http://folk.uio.no/rafael/

Re: Problems with a C function, pg_uname(), and String concatenation.

От
"Pavel Stehule"
Дата:
2008/7/1 Rafael Martinez <r.m.guerrero@usit.uio.no>:
> Pavel Stehule wrote:
>>
>> hello
>> try
>>
>>
>> memcpy(VARDATA(result),uname_pointer.release,strlen(uname_pointer.release));
>> SET_VARSIZE(result, strlen(uname_pointer.release) + VARHDRSZ);
>>
> [.........]
>
> This a 8.2.x system. SET_VARSIZE is not available.
>

VARATT_SIZEP(result) = strlen(uname_pointer.release) + VARHDRSZ;

Pavel

> Thanks for your time.
> regards
> --
>  Rafael Martinez, <r.m.guerrero@usit.uio.no>
>  Center for Information Technology Services
>  University of Oslo, Norway
>
>  PGP Public Key: http://folk.uio.no/rafael/
>

Re: Problems with a C function, pg_uname(), and String concatenation.

От
Rafael Martinez
Дата:
Pavel Stehule wrote:
> 2008/7/1 Rafael Martinez <r.m.guerrero@usit.uio.no>:
>> Pavel Stehule wrote:
>>> hello
>>> try
>>>
>>>
>>> memcpy(VARDATA(result),uname_pointer.release,strlen(uname_pointer.release));
>>> SET_VARSIZE(result, strlen(uname_pointer.release) + VARHDRSZ);
>>>
>> [.........]
>>
>> This a 8.2.x system. SET_VARSIZE is not available.
>>
>
> VARATT_SIZEP(result) = strlen(uname_pointer.release) + VARHDRSZ;
>

Hello and thank you for your help.

Everything works perfect now with the new version of the function. Here
it is just in case somebody wants to use it:

-------------------------------------------------------
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include <sys/utsname.h>


#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif


PG_FUNCTION_INFO_V1(pg_uname);

Datum
pg_uname(PG_FUNCTION_ARGS)
{
     text *argument = PG_GETARG_TEXT_P(0);
     size_t argumentlen = VARSIZE(argument)-VARHDRSZ;

     text *result = (text *) palloc(256);
     char *option = (char *) palloc(argumentlen+1);

     char sysname[] = "sysname";
     char nodename[] = "nodename";
     char release[] = "release";
     char version[] = "version";
     char machine[] = "machine";
     char null[] = "null";

     struct utsname uname_pointer;
     uname(&uname_pointer);

     memcpy(option,VARDATA(argument),argumentlen);
     option[argumentlen] = '\0';

     if (strcmp(option,sysname) == 0){
       VARATT_SIZEP(result) = strlen(uname_pointer.sysname) + VARHDRSZ;

memcpy(VARDATA(result),uname_pointer.sysname,strlen(uname_pointer.sysname));
     }
     else if (strcmp(option,nodename) == 0){
       VARATT_SIZEP(result) = strlen(uname_pointer.nodename) + VARHDRSZ;

memcpy(VARDATA(result),uname_pointer.nodename,strlen(uname_pointer.nodename));
     }
     else if (strcmp(option,release) == 0){
       VARATT_SIZEP(result) = strlen(uname_pointer.release) + VARHDRSZ;

memcpy(VARDATA(result),uname_pointer.release,strlen(uname_pointer.release));
     }
     else if (strcmp(option,version) == 0){
       VARATT_SIZEP(result) = strlen(uname_pointer.version) + VARHDRSZ;

memcpy(VARDATA(result),uname_pointer.version,strlen(uname_pointer.version));
     }
     else if (strcmp(option,machine) == 0){
       VARATT_SIZEP(result) = strlen(uname_pointer.machine) + VARHDRSZ;

memcpy(VARDATA(result),uname_pointer.machine,strlen(uname_pointer.machine));
     }
     else{
       memcpy(VARDATA(result),null,sizeof(null));
     }

     pfree(option);
     PG_RETURN_TEXT_P(result);
}

-------------------------------------------------------


--
  Rafael Martinez, <r.m.guerrero@usit.uio.no>
  Center for Information Technology Services
  University of Oslo, Norway

  PGP Public Key: http://folk.uio.no/rafael/

Re: Problems with a C function, pg_uname(), and String concatenation.

От
Tom Lane
Дата:
Rafael Martinez <r.m.guerrero@usit.uio.no> writes:
> We have a function in C which is accessed via a view and which produces
> a strange result when used together with || (String concatenation).
> I can not find the problem. Any C/postgres guru with any idea of how to
> fix it?

You need to set the size of the text result correctly.  As is, you're
returning a 252-byte result containing embedded nulls and random
garbage.  Embedded nulls, in particular, are verboten.

The fixed-size palloc is okay (as long as you're sure it's enough),
but the length word should only count valid data.

            regards, tom lane