Re: more custom C function fun

Lists: pgsql-general
From: "Dan \"Heron\" Myers" <heron(at)xnapid(dot)com>
To: pgsql-general(at)postgresql(dot)org
Subject: more custom C function fun
Date: 2008-05-06 05:43:40
Message-ID: [email protected]
Views: Whole Thread | Raw Message | Download mbox | Resend email
Lists: pgsql-general

I have a custom C function that takes two text*s and returns a text*.

My problem is with this code:

PG_FUNCTION_INFO_V1(get_agent);

PGMODULEEXPORT Datum get_agent(PG_FUNCTION_ARGS)
{
if(!PG_ARGISNULL(0))
{
text* calling_party = PG_GETARG_TEXT_P(0);

char* thestr = VARDATA(calling_party);
if(thestr[20] == ')')
{
PG_RETURN_TEXT_P(calling_party);
}
}
/* the other argument is ignored for now */
PG_RETURN_NULL();
}

The problem is, the comparison in the inner if statement is always true.
If I change to compare, say, thestr[0] == 'N', then it works as
expected (returning only those text*s whose first letter is N, returning
null for the rest).

However if I try to compare any character inside the text* with a
parenthesis (both '(' and ')'), then the equality is apparently always
true (the function never returns null, always returning calling_party),
whether or not there is any data in that column that contains a
parenthesis in that column.

Does anyone know of any oddities or whatnot I should be accounting for
when reading character data out of a text*?

- Dan


From: Martijn van Oosterhout <kleptog(at)svana(dot)org>
To: Dan Heron Myers <heron(at)xnapid(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: more custom C function fun
Date: 2008-05-06 06:48:26
Message-ID: [email protected]
Views: Whole Thread | Raw Message | Download mbox | Resend email
Lists: pgsql-general

On Mon, May 05, 2008 at 11:43:40PM -0600, Dan Heron Myers wrote:
> I have a custom C function that takes two text*s and returns a text*.
>
> text* calling_party = PG_GETARG_TEXT_P(0);
>
> char* thestr = VARDATA(calling_party);
> if(thestr[20] == ')')
> {
> PG_RETURN_TEXT_P(calling_party);
> }

You do realise that VARDATA does not return a null terminated string?
Try using something like text_to_cstring or using elog(NOTICE) to
display what's actually being compared.

Have a nice day,
--
Martijn van Oosterhout <kleptog(at)svana(dot)org> http://svana.org/kleptog/
> Please line up in a tree and maintain the heap invariant while
> boarding. Thank you for flying nlogn airlines.


From: "Dan \"Heron\" Myers" <heron(at)xnapid(dot)com>
To: Martijn van Oosterhout <kleptog(at)svana(dot)org>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: more custom C function fun
Date: 2008-05-06 15:39:50
Message-ID: [email protected]
Views: Whole Thread | Raw Message | Download mbox | Resend email
Lists: pgsql-general

Martijn van Oosterhout wrote:
> You do realise that VARDATA does not return a null terminated string?

I did not realize that... but it led me in the right direction.

> Try using something like text_to_cstring or using elog(NOTICE) to
> display what's actually being compared.

I've outputted some things with elog (which is the other thing I needed
to figure this out).

Using DatumToCString(mytextvariable), I get single-character-length
strings that do not match the data actually in the fields.

Using VARDATA(mytextvariable) as the char*, I get things like this (name
obscured) (using strlen to get the string's length):

string: "Hillary Clinton(6611)", length 21
string: "95555551234nton(6611)", length 21

Of course, then I realized that strlen isn't the right tool for the job;
I need: int len = VARSIZE(mytextvariable) - VARHDRSZ;

Using that with the VARDATA as my char*, I get this:

string: "Hillary Clinton(6611)" - length: 21
string: "95555551234" - length: 11

Which is what I need. Perhaps we could get some documentation about how
to use this stuff? I was unable to find any on the Postgres site, if
there is any.

Thanks for your help guys :)

- Dan


From: Martijn van Oosterhout <kleptog(at)svana(dot)org>
To: Dan Heron Myers <heron(at)xnapid(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: more custom C function fun
Date: 2008-05-06 15:59:44
Message-ID: [email protected]
Views: Whole Thread | Raw Message | Download mbox | Resend email
Lists: pgsql-general

On Tue, May 06, 2008 at 09:39:50AM -0600, Dan Heron Myers wrote:
> Using DatumToCString(mytextvariable), I get single-character-length
> strings that do not match the data actually in the fields.

Correct, because it's not a cstring. Pretending it is one gives you
garbage.

> Using VARDATA(mytextvariable) as the char*, I get things like this (name
> obscured) (using strlen to get the string's length):

Not null terminated.

> Which is what I need. Perhaps we could get some documentation about how
> to use this stuff? I was unable to find any on the Postgres site, if
> there is any.

Well, here's an example of how you should do it:

http://www.postgresql.org/docs/8.2/interactive/spi-examples.html

Not the most obvious place. The best place is the source,
utils/adt/text contains lots of functions on text variables, so you can
see how they work.

Have a nice day,
--
Martijn van Oosterhout <kleptog(at)svana(dot)org> http://svana.org/kleptog/
> Please line up in a tree and maintain the heap invariant while
> boarding. Thank you for flying nlogn airlines.