Re: Writing triggers in C++ - Mailing list pgsql-hackers

From Florian G. Pflug
Subject Re: Writing triggers in C++
Date
Msg-id 45D3453E.6000001@phlo.org
Whole thread Raw
In response to Re: Writing triggers in C++  (Alvaro Herrera <alvherre@commandprompt.com>)
Responses Re: Writing triggers in C++  (Andreas Seltenreich <andreas+pg@gate450.dyndns.org>)
List pgsql-hackers
Alvaro Herrera wrote:
> Florian G. Pflug wrote:
>> Alvaro Herrera wrote:
>>> Florian G. Pflug wrote:
>>>> Andreas Pflug wrote:
>>>>> Tom Lane wrote:
>>>>>> Jacob Rief <jacob.rief@gmx.at> writes:
>>>>>>
>>>>>>> I tried to write a trigger using C++.
>>>>>>>   
>>>>>> That is most likely not going to work anyway, because the backend
>>>>>> operating environment is C not C++.  If you dumb it down enough
>>>>>> --- no exceptions, no RTTI, no use of C++ library --- then it might
>>>>>> work, 
>>>>> I can confirm that it does work this way.
>>>> I've written an aggregate function that uses c++ stl hashes, and it 
>>>> seems to work pretty well. I'd think that using exceptions should be
>>>> fine, as long as you make sure to _always_ catch any exception that
>>>> might be thrown inside your own c++ code, and don't let it propagate
>>>> into backend code. STL allows you to specify custom allocator classes
>>>> as template parameters to hash, vector and the like. You can use that
>>>> to let STL allocate memory from the correct memory context.
>>> What happens if Postgres raises an elog(ERROR) in the code you're
>>> catching exceptions in?  Is it propagated outwards?
>> In my case, the only possible source of an elog(ERROR) would palloc(), 
>> when the machine is out of memory (Does it even throw elog(ERROR), or
>> does it return NULL just as malloc() ?). Since this is rather unlikely,
>> and would probably lead to a postgres shutdown anyway, I didn't really
>> care about that case.
> 
> No, an out-of-memory leads to elog(ERROR), which rolls back the current
> transaction.  This releases some memory so the system can continue
> working.  In fact we periodically see out-of-memory reports, and they
> certainly _don't_ cause a general shutdown.

Sorry, I explained my point badly. What I actually meant is that in my
specific use-case (Lots of small transaction, non of which use much 
memory), the only reason for out-of-memory conditions I've even seen
was some application gone wild that ate up all available memory. In that 
case, postgres dies sooner or later, because any memory freed during 
rollback is immediatly used by that other application. In general, of 
course, you're right.

>> You're right of course that this is different for triggers - they're 
>> much more likely to call SPI functions or otherwise interact with the
>> backend than my rather self-contained aggregate function. Still, I'd 
>> think that an elog(ERROR) would propagate outwards - but any C++
>> destructors of local (stack-allocated) objects wouldn't be called.
> 
> Probably stack allocation doesn't matter much, as I think that would be
> unwinded by the longjmp call.  I don't know a lot about C++, but if
> there are allocations in the data area then those would probably not be
> freed.  But it makes me wonder -- is longjmp very compatible with C++
> exceptions at all?  I know that it causes problems with POSIX thread
> cancel_push() and cancel_pop() for example (meaning, they can't be
> used).

Yeah, the memory taken by stack-allocated objects is freed (basically by
just resetting the stack pointer). But normally, C++ would call the 
destructor of a stack-allocated objects _before_ resetting the 
stack-pointer. Since setjmp/longjmp don't know anything about C++, they
will omit this step. Whether this causes problems or not depends on the
objects that you allocated on the stack...

>> So, to be safe, I guess one would need to surround any call that could
>> call elog(ERROR) with an appropriate handler that translates the 
>> elog(ERROR) into a C++ exception. This C++ exception would have to be
>> translated back into an elog(ERROR) at the outmost level of C++ code.
> 
> Sort of a PG_RE_THROW() in the exception handler, I guess.
> 
>> Maybe we should create some wiki page or pgfoundry project that collects
>> all glue code, tipps and tricks that people invented to glue C++ into
>> the postgres backend.
> 
> If it can be made to work, sure; in techdocs.

I was thinking that two pairs of macros,
PG_BEGIN_CPP, PG_END_CPP and
PG_CPP_BEGIN_BACKEND, PG_CPP_END_BACKEND
should be able to take care of the exception handling issues.

You'd need to wrap any code-block that calls postgres functions that 
might do an elog(ERROR) inside PG_CPP_BEGIN_BACKEND, PG_CPP_END_BACKEND.

Vice versa, any block of c++ code that is called from the backend would
need to start with PG_BEGIN_CPP, and end with PG_END_CPP.

Do you see any other possible problems, aside from memory managemt issues?

greetings, Florian Pflug



pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: HOT WIP Patch - version 1
Next
From: "Florian G. Pflug"
Date:
Subject: Re: Writing triggers in C++