Обсуждение: Internal function call from C-language function

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

Internal function call from C-language function

От
Zoltan Boszormenyi
Дата:
Hi,

I need to call date_part() from a C function.
How to do that?

Thanks in advance,
Zoltán Böszörményi


Re: Internal function call from C-language function

От
Martijn van Oosterhout
Дата:
On Thu, Dec 07, 2006 at 09:48:25AM +0100, Zoltan Boszormenyi wrote:
> Hi,
>
> I need to call date_part() from a C function.
> How to do that?

Look in fmgr.h for the functions {Oid,Direct,}FunctionCall* which
provide various ways to call other functions.

There's also FunctionCallInvoke() which is more efficient if you're
going to call it lots of times.

Have a nice day,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> From each according to his ability. To each according to his ability to litigate.

Вложения

Re: Internal function call from C-language function

От
Zoltan Boszormenyi
Дата:
Hi,

Martijn van Oosterhout írta:
> On Thu, Dec 07, 2006 at 09:48:25AM +0100, Zoltan Boszormenyi wrote:
>
>> Hi,
>>
>> I need to call date_part() from a C function.
>> How to do that?
>>
>
> Look in fmgr.h for the functions {Oid,Direct,}FunctionCall* which
> provide various ways to call other functions.
>
> There's also FunctionCallInvoke() which is more efficient if you're
> going to call it lots of times.
>
> Have a nice day,
>

thanks, I found the DirectFunctionCall family,
that wasn't the problem.

The real trick was that inside a C function,
I have to use timestamp_part(), as date_part()
doesn't even exists. The header catalog/pg_proc.h
proves it. date_part() is an SQL wrapper around
real C functions: timestamp[tz]_part(), time[tz]_part()
and interval_part().

However, I have another problem. I have this in the code:

       HeapTupleHeader t;
       Datum           timest;
       bool            isnull;

        t = PG_GETARG_HEAPTUPLEHEADER(0);
        timest = DatumGetTimestamp(GetAttributeByName(t, "ts_today",
&isnull));
        elog(NOTICE, "DatumGetTimestamp() OK, value is %s", isnull ?
"NULL" : "NOT NULL");

        if (isnull)
                PG_RETURN_BOOL(false);

        yeardatum = CStringGetDatum("year");
        elog(NOTICE, "CStringGetDatum() 1 OK");
        returndatum = DirectFunctionCall2(timestamp_part, yeardatum,
timest);
        elog(NOTICE, "date_part() 1 OK");
        year = DatumGetFloat8(returndatum);
        elog(NOTICE, "conversion 1 OK");

...

But I get this:

NOTICE:  PG_GETARG OK
NOTICE:  DatumGetTimestamp() OK, value is NOT NULL
NOTICE:  CStringGetDatum() 1 OK
ERROR:  invalid memory alloc request size 1951613700

So DirectFunctionCall2() fails. How can I fix it?

Best regards,
Zoltán


Re: Internal function call from C-language function

От
Martijn van Oosterhout
Дата:
On Thu, Dec 07, 2006 at 12:55:47PM +0100, Zoltan Boszormenyi wrote:
> However, I have another problem. I have this in the code:

<snip>

>        yeardatum = CStringGetDatum("year");
>        elog(NOTICE, "CStringGetDatum() 1 OK");
>        returndatum = DirectFunctionCall2(timestamp_part, yeardatum,
> timest);

You're passing a cstring as first argument, whereas I'm fairly sure you
should be passing text. When calling from C the're no argument
checking. I think what you're looking for is:

  yeardatum = text_in("year");

Or something like that.

Hope this helps,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> From each according to his ability. To each according to his ability to litigate.

Вложения

Re: Internal function call from C-language function

От
Zoltan Boszormenyi
Дата:
Martijn van Oosterhout írta:
> On Thu, Dec 07, 2006 at 12:55:47PM +0100, Zoltan Boszormenyi wrote:
>
>> However, I have another problem. I have this in the code:
>>
>
> <snip>
>
>
>>        yeardatum = CStringGetDatum("year");
>>        elog(NOTICE, "CStringGetDatum() 1 OK");
>>        returndatum = DirectFunctionCall2(timestamp_part, yeardatum,
>> timest);
>>
>
> You're passing a cstring as first argument, whereas I'm fairly sure you
> should be passing text. When calling from C the're no argument
> checking. I think what you're looking for is:
>
>   yeardatum = text_in("year");
>
> Or something like that.
>
> Hope this helps,
>

text_in() doesn't exists, it's textin() but I have to call it through
DirectFunctionCall1(), like this:

yeardatum = DirectFunctionCall1(textin, CStringGetDatum("year"));

However, the session crashes on the subsequent

returndatum = DirectFunctionCall2(timestamp_part, yeardatum, timest);

Best regards,

Zoltán


Re: Internal function call from C-language function

От
Martijn van Oosterhout
Дата:
On Thu, Dec 07, 2006 at 01:40:22PM +0100, Zoltan Boszormenyi wrote:
> text_in() doesn't exists, it's textin() but I have to call it through
> DirectFunctionCall1(), like this:
>
> yeardatum = DirectFunctionCall1(textin, CStringGetDatum("year"));
>
> However, the session crashes on the subsequent
>
> returndatum = DirectFunctionCall2(timestamp_part, yeardatum, timest);

It would be a good idea to actually find out where it crashes, that
would help you work out what the actual problem is. Just looking at the
code you posted, I only see this other bit that looks a bit suspect:

      Datum           timest;
      bool            isnull;

       t = PG_GETARG_HEAPTUPLEHEADER(0);
       timest = DatumGetTimestamp(GetAttributeByName(t, "ts_today", &isnull));

You're calling DatumGetTimestamp() which would return a timestamp
(probably some structure) but you're storing it in a Datum. Just take
the result of GetAttributeByName directly.

Get at least a backtrace next time it crashes...

Have a nice day,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> From each according to his ability. To each according to his ability to litigate.

Вложения

Re: Internal function call from C-language function

От
Zoltan Boszormenyi
Дата:
Hi,

Martijn van Oosterhout írta:
> On Thu, Dec 07, 2006 at 01:40:22PM +0100, Zoltan Boszormenyi wrote:
>
>> text_in() doesn't exists, it's textin() but I have to call it through
>> DirectFunctionCall1(), like this:
>>
>> yeardatum = DirectFunctionCall1(textin, CStringGetDatum("year"));
>>
>> However, the session crashes on the subsequent
>>
>> returndatum = DirectFunctionCall2(timestamp_part, yeardatum, timest);
>>
>
> It would be a good idea to actually find out where it crashes, that
> would help you work out what the actual problem is. Just looking at the
> code you posted, I only see this other bit that looks a bit suspect:
>
>       Datum           timest;
>       bool            isnull;
>
>        t = PG_GETARG_HEAPTUPLEHEADER(0);
>        timest = DatumGetTimestamp(GetAttributeByName(t, "ts_today", &isnull));
>
> You're calling DatumGetTimestamp() which would return a timestamp
> (probably some structure) but you're storing it in a Datum. Just take
> the result of GetAttributeByName directly.
>

Thanks, that worked for me.

I have just one more question:
How can I get an Oid out of a Datum, i.e.
how do I know what type I get in a given Datum?
DatumGetObjectId() seems to give me an Oid that
was specifically stored as a Datum.

The function I am working on is made for an
INSERT RULE, something like this:

CREATE OR REPLACE FUNCTION
myfunc( row1 table1 ) RETURNS BOOL VOLATILE
LANGUAGE C AS 'myfunc.so', 'myfunc';

CREATE RULE rule_table1_insert
AS ON INSERT TO table1
DO INSTEAD (SELECT myfunc( new ) );

So I get the to-be-inserted row in my function.
In the function, depending on the passed in values
I need to insert some other table. To do it,
I need to use SPI_prepare() which needs the list of Oids.

> Get at least a backtrace next time it crashes...
>

And how exactly can I do that? psql only reports that
the backend crashed and unable to reset connection.
At that time the backend session is already gone, isn't it?

> Have a nice day,
>

Thanks, to you, too. You helped a lot.

Best regards,
Zoltán


Re: Internal function call from C-language function

От
Zoltan Boszormenyi
Дата:
Hi,

Zoltan Boszormenyi írta:
> Hi,
>
> Martijn van Oosterhout írta:
>> On Thu, Dec 07, 2006 at 01:40:22PM +0100, Zoltan Boszormenyi wrote:
>>
>>> text_in() doesn't exists, it's textin() but I have to call it through
>>> DirectFunctionCall1(), like this:
>>>
>>> yeardatum = DirectFunctionCall1(textin, CStringGetDatum("year"));
>>>
>>> However, the session crashes on the subsequent
>>>
>>> returndatum = DirectFunctionCall2(timestamp_part, yeardatum, timest);
>>>
>>
>> It would be a good idea to actually find out where it crashes, that
>> would help you work out what the actual problem is. Just looking at the
>> code you posted, I only see this other bit that looks a bit suspect:
>>
>>       Datum           timest;
>>       bool            isnull;
>>
>>        t = PG_GETARG_HEAPTUPLEHEADER(0);
>>        timest = DatumGetTimestamp(GetAttributeByName(t, "ts_today",
>> &isnull));
>>
>> You're calling DatumGetTimestamp() which would return a timestamp
>> (probably some structure) but you're storing it in a Datum. Just take
>> the result of GetAttributeByName directly.
>>
>
> Thanks, that worked for me.
>
> I have just one more question:
> How can I get an Oid out of a Datum, i.e.
> how do I know what type I get in a given Datum?
> DatumGetObjectId() seems to give me an Oid that
> was specifically stored as a Datum.

I have found the alternative solution.
If t is HeapTupleHeader then:

        Oid                     tupType;
        int32           tupTypmod;
        TupleDesc       tupDesc;

        tupType = HeapTupleHeaderGetTypeId(t);
        tupTypmod = HeapTupleHeaderGetTypMod(t);
        tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);

will give me the needed TupleDesc and I can use SPI_gettypeid().

Thanks and best regards,
Zoltán


Re: Internal function call from C-language function

От
Martijn van Oosterhout
Дата:
On Thu, Dec 07, 2006 at 06:01:13PM +0100, Zoltan Boszormenyi wrote:
> >I have just one more question:
> >How can I get an Oid out of a Datum, i.e.
> >how do I know what type I get in a given Datum?
> >DatumGetObjectId() seems to give me an Oid that
> >was specifically stored as a Datum.
>
> I have found the alternative solution.
> If t is HeapTupleHeader then:

<snip>

There is no way to tell what type is in a Datum, it's just that,
nothing else. The information about the actual type can come from
elsewhere, for example:

- If extracting from a tuple, the tuple descriptor has the type (as you found)
- If passed as argument, the fcinfo struct *may* have the type
information
- The SPI interface provide ways to get information also

On the other side, a Datum is abstract, and you can receive a Datum as
argument and pass it to other functions without needing to know what
type it is. But you better so it right because there is no type
checking on that level.

As for the backtrace, you can get gdb to attach to the backend after
you connect. Then when you get the segfault, gdb will catch it and show
you exactly where.

Have a nice day,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> From each according to his ability. To each according to his ability to litigate.

Вложения