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

Started by Rafael Martinezalmost 18 years ago7 messagesgeneral
Jump to latest
#1Rafael 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/

#2Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rafael Martinez (#1)
Re: Problems with a C function, pg_uname(), and String concatenation.

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>:

Show quoted text

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

#3Rafael Martinez
r.m.guerrero@usit.uio.no
In reply to: Pavel Stehule (#2)
Re: Problems with a C function, pg_uname(), and String concatenation.

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/

#4Pavel Stehule
pavel.stehule@gmail.com
In reply to: Rafael Martinez (#3)
Re: Problems with a C function, pg_uname(), and String concatenation.

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

Show quoted text

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/

#5Glyn Astill
glynastill@yahoo.co.uk
In reply to: Pavel Stehule (#4)
Re: Problems with a C function, pg_uname(), and String concatenation.

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,

Then replace

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

with

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

__________________________________________________________
Not happy with your email address?.
Get the one you really want - millions of new email addresses available now at Yahoo! http://uk.docs.yahoo.com/ymail/new.html

#6Rafael Martinez
r.m.guerrero@usit.uio.no
In reply to: Pavel Stehule (#4)
Re: Problems with a C function, pg_uname(), and String concatenation.

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/

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Rafael Martinez (#1)
Re: Problems with a C function, pg_uname(), and String concatenation.

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