Thread: Internal function call from C-language function
Hi, I need to call date_part() from a C function. How to do that? Thanks in advance, Zoltán Böszörményi
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.
Attachment
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
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.
Attachment
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
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.
Attachment
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
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
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.