Обсуждение: Problems with a C function, pg_uname(), and String concatenation.
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/
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 >
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/
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/ >
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/
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