Обсуждение: Triggers in C - Segmentation Fault

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

Triggers in C - Segmentation Fault

От
"Chris Coleman"
Дата:
Hi,

I have written a couple of trigger functions in C that utilise the SPI
interface.  They are both row level triggers, one a before trigger and
one an after trigger.

If the triggers are called with an update statement that only affects
one row then both are excecuted correctly and without error.  But if I
try to update multiple rows then this fails.

The before trigger is excecuted and returns, but before the after
trigger is excecuted the server terminates the connection.  Looking in
the logs then it shows the server crashing with a signal 11 (SIGSEGV).

The triggers are compiled / run on SUSE 9.3, Postgres 8.03 using gcc
version 3.3.5 20050117


The output is shown below:
INFO:  Cleanup: EXIT
INFO:  Cleanup: EXIT 2
server closed the connection unexpectedly
    This probably means the server terminated abnormally
    before or while processing the request.

The seccond INFO line is prited directly beore the return statement at
the end of the first trigger.

Any information or ideas would be greatly appreciated.

Many Thanks
Chris Coleman

The code for the triggers is below:
(I have removed most of the app specific code from the triggers - but
the resutls are identical wether it is present or not.)

/* SQL */

CREATE OR REPLACE FUNCTION trig_cleanupexistingrelationships()
  RETURNS "trigger" AS
'$libdir/chrisc/trig_cleanupexistingrelationships.so',
'trig_cleanupexistingrelationships'
  LANGUAGE 'c' VOLATILE;
ALTER FUNCTION trig_cleanupexistingrelationships() OWNER TO postgres;

CREATE OR REPLACE FUNCTION trig_calculatenewrelationships()
  RETURNS "trigger" AS
'$libdir/chrisc/trig_calculatenewrelationships.so',
'trig_calculatenewrelationships'
  LANGUAGE 'c' VOLATILE;
ALTER FUNCTION trig_calculatenewrelationships() OWNER TO postgres;


/////////////////////////////////////////////
// THE BEFORE TRIGGER
//

/* Prototypes*/
extern Datum trig_cleanupexistingrelationships(PG_FUNCTION_ARGS);

/* Implementation */
PG_FUNCTION_INFO_V1(trig_cleanupexistingrelationships);

Datum
trig_cleanupexistingrelationships(PG_FUNCTION_ARGS)
{
    TriggerData *trigdata = (TriggerData *) fcinfo->context;

    TupleDesc tupdesc;
    HeapTuple rettuple, newtuple, oldtuple;
    int64 nResourceId, nNewParentId, nOldParentId, nNewResourceId;
    bool bIsNull;

    /* make sure it's called as a trigger at all */
    if(!CALLED_AS_TRIGGER(fcinfo))
    {
        elog(ERROR, "trig_cleanupexistingrelationships: not called by
trigger manager");
    }
    /* Check this is an after trigger */
    if(!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
    {
        elog(ERROR, "trig_cleanupexistingrelationships: must be called
as a before trigger");
    }

    /* check this is a row level trigger */
    if(!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
    {
        elog(ERROR, "trig_cleanupexistingrelationships: must be called as a
row level trigger");
    }

    /* tuple to return to executor */
    if(!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
    {
        elog(ERROR, "trig_cleanupexistingrelationships: must only be
called by an update event");
    }

    /* get the old and new tuples out - since this def an update by this */
    /* point we can guarntee neither is null */
    oldtuple = trigdata->tg_trigtuple;
    newtuple = trigdata->tg_newtuple;


    /* Check that it is not being made a parent of itself */
    nOldParentId =
        DatumGetInt64(SPI_getbinval(newtuple,
                                    tupdesc,
                                    RESOURCES_PARENTRESOURCE_ID,
                                    &bIsNull));

    /* tuple to return to executor */
    rettuple = trigdata->tg_newtuple;

    /* Get the tuple description */
    tupdesc = trigdata->tg_relation->rd_att;

    /* connect to SPI manager */
    if(SPI_connect() < 0)
    {
        elog(INFO, "trig_cleanupexistingrelationships: SPI_connect failed");
    }

    /* Get the old parent resource ids */
    nNewParentId =
        DatumGetInt64(SPI_getbinval(newtuple,
                                    tupdesc,
                                    RESOURCES_PARENTRESOURCE_ID,
                                    &bIsNull));
    /* old parent id */
    nOldParentId =
        DatumGetInt64(SPI_getbinval(oldtuple,
                                    tupdesc,
                                    RESOURCES_PARENTRESOURCE_ID,
                                    &bIsNull));
    /* new resource id */
    nNewResourceId =
        DatumGetInt64(SPI_getbinval(oldtuple,
                                    tupdesc,
                                    RESOURCES_ID,
                                    &bIsNull));

    /* Clean up SPI stuff */
    SPI_finish();
    elog(INFO, "Cleanup: EXIT");
    Datum d = PointerGetDatum(rettuple);
    elog(INFO, "Cleanup: EXIT 2");
    return d;
}


///////////////////////////////////////////
// THE AFTER TRIGGER
//

/* Prototypes*/
extern Datum trig_calculatenewrelationships(PG_FUNCTION_ARGS);

/* Implementation */
PG_FUNCTION_INFO_V1(trig_calculatenewrelationships);

Datum
trig_calculatenewrelationships(PG_FUNCTION_ARGS)
{
elog(INFO, "here a");
    TriggerData *trigdata = (TriggerData *) fcinfo->context;

    TupleDesc tupdesc;
    HeapTuple rettuple, starttuple;
    int64 nResourceId, nStartId, nOldParentId;
    bool bIsNull, bDoIt = false;
elog(INFO, "here b");
    /* make sure it's called as a trigger at all */
    if(!CALLED_AS_TRIGGER(fcinfo))
    {
        elog(ERROR, "trig_calculatenewrelationships: not called by trigger manager");
    }
elog(INFO, "here c");
    /* Check this is an after trigger */
    if(TRIGGER_FIRED_BEFORE(trigdata->tg_event))
    {
        elog(ERROR, "trig_calculatenewrelationships: must be called as
an after trigger");
    }
elog(INFO, "here d");
    /* check this is a row level trigger */
    if(!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
    {
        elog(ERROR, "trig_calculatenewrelationships: must be called as a row
level trigger");
    }
elog(INFO, "here e");
    /* connect to SPI manager */
    if(SPI_connect() < 0)
    {
        elog(ERROR, "trig_calculatenewrelationships: SPI_connect failed");
    }
elog(INFO, "here f");
    /* Get the tuple description */
    tupdesc = trigdata->tg_relation->rd_att;

    /* tuple to return to executor */
    elog(INFO, "here1");
    nOldParentId = -1;
    if(TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
    {
elog(INFO, "here2");
        /* Get the new parent resource id */
        nStartId =
            DatumGetInt64(SPI_getbinval(trigdata->tg_newtuple,
                                        tupdesc,
                                        RESOURCES_PARENTRESOURCE_ID,
                                        &bIsNull));
elog(INFO, "here3");
        /* Get the old parent resource id */
        nOldParentId =
            DatumGetInt64(SPI_getbinval(trigdata->tg_trigtuple,
                                        tupdesc,
                                        RESOURCES_PARENTRESOURCE_ID,
                                        &bIsNull));
elog(INFO, "here4");
    }
    else
    {
elog(INFO, "here5");
        /* Get the new parent resource id */
        nStartId =
            DatumGetInt64(SPI_getbinval(trigdata->tg_trigtuple,
                                        tupdesc,
                                        RESOURCES_PARENTRESOURCE_ID,
                                        &bIsNull));
elog(INFO, "here6");
    }

    /* Clean up SPI stuff */
    SPI_finish();

    /* since its an after trigger then we may as well return null */
    return PointerGetDatum(NULL);
}

Re: Triggers in C - Segmentation Fault

От
Martijn van Oosterhout
Дата:
On Thu, May 11, 2006 at 10:28:37AM +0100, Chris Coleman wrote:
> Hi,
>
> I have written a couple of trigger functions in C that utilise the SPI
> interface.  They are both row level triggers, one a before trigger and
> one an after trigger.
>
> If the triggers are called with an update statement that only affects
> one row then both are excecuted correctly and without error.  But if I
> try to update multiple rows then this fails.

Probably the easiest thing to do is make sure your functions are
compiled with debugging and enable core dump by running "ulimit -S -c
unlimited" before starting the server. You can then use gdb to
pin-point where it dies...

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: Triggers in C - Segmentation Fault

От
"Chris Coleman"
Дата:
Hi,

I have done the below command and restarted the server and built my
triggers with the -g command using gcc, but I cannot seem to find any
core files nor any reference to where postgres may place them. Where
would they normally appear?

Cheers
Chris

> Probably the easiest thing to do is make sure your functions are
> compiled with debugging and enable core dump by running "ulimit -S -c
> unlimited" before starting the server. You can then use gdb to
> pin-point where it dies...

Re: Triggers in C - Segmentation Fault

От
Martijn van Oosterhout
Дата:
The core file usually appears in the data directory of the backend.

If you still can't find it, you can try attaching gdb to the running
backend. After the connection has started, find the backend (not the
postmaster) and attach using:

gdb -p <pid>

Once connected, type "cont" and proceed with the actions to trigger the
segfault. When the segfault happens, gdb will catch it and you can type
"bt" to see where you are...

Have a ncie day,

On Mon, May 15, 2006 at 11:47:24AM +0100, Chris Coleman wrote:
> Hi,
>
> I have done the below command and restarted the server and built my
> triggers with the -g command using gcc, but I cannot seem to find any
> core files nor any reference to where postgres may place them. Where
> would they normally appear?
>
> Cheers
> Chris
>
> >Probably the easiest thing to do is make sure your functions are
> >compiled with debugging and enable core dump by running "ulimit -S -c
> >unlimited" before starting the server. You can then use gdb to
> >pin-point where it dies...
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: don't forget to increase your free space map settings

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

Вложения