Обсуждение: difficulty extracting variable-sized field on triggered row

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

difficulty extracting variable-sized field on triggered row

От
"Glen W. Mabey"
Дата:
Hello,

I have been trying to write a trigger in C operating on each row
that would (as a first step) copy a field of type TEXT into a text*
variable.

I think that I've got the SPI_connect, SPI_fnumber, and SPI_getbinval
calls correct, but this gives me a Datum.

How do I convert a Datum to a text*?

The following is the best I could do, and it segfaults ...

Thank you,
Glen Mabey


    if( CALLED_AS_TRIGGER( fcinfo ) ) {
        elog(INFO, "unlink_file was called as a trigger." );
        trigdata = (TriggerData *) fcinfo->context;

        if( ( ret = SPI_connect() ) != SPI_OK_CONNECT ) {
            elog(INFO, "SPI_connect returned %d", ret);
        }

        file_name_colnumber = SPI_fnumber( trigdata->tg_relation->rd_att, "file_name" );

        if( file_name_colnumber == SPI_ERROR_NOATTRIBUTE ) {
            elog(INFO, "SPI_fnumber returned SPI_ERROR_NOATTRIBUTE" );
        }

        SPI_getbinval( trigdata->tg_trigtuple, trigdata->tg_relation->rd_att, file_name_colnumber, isnull );
        relative_filename_t = PG_DETOAST_DATUM( relative_filename_datum );

        if( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
            elog(INFO, "SPI_fnumber returned SPI_ERROR_NOATTRIBUTE" );
        }

        if( ( ret = SPI_finish() ) != SPI_OK_FINISH ) {
            elog(INFO, "SPI_finish returned %d", ret);
        }
    }


Re: difficulty extracting variable-sized field on triggered row

От
"Pavel Stehule"
Дата:
On 04/12/2007, Glen W. Mabey <Glen.Mabey@swri.org> wrote:
> Hello,
>
> I have been trying to write a trigger in C operating on each row
> that would (as a first step) copy a field of type TEXT into a text*
> variable.
>
> I think that I've got the SPI_connect, SPI_fnumber, and SPI_getbinval
> calls correct, but this gives me a Datum.
>
> How do I convert a Datum to a text*?
>

use macro DatumGetPointer(datum)

Pavel

Re: difficulty extracting variable-sized field on triggered row

От
"Glen W. Mabey"
Дата:
On Tue, Dec 04, 2007 at 09:10:21AM -0600, Pavel Stehule wrote:
> use macro DatumGetPointer(datum)

When I do that, I get the following compiler warning:

    warning: assignment from incompatible pointer type

which is what originally motivated me to look for another means, which
led me to use PG_DETOAST_DATUM.

Using DatumGetPointer also seg faults ...

Is there somewhere that I am not adequately checking for an error?

Thanks,
Glen

    TriggerData *trigdata;
    Datum relative_filename_datum;
    text *relative_filename_t;
    int file_name_colnumber, ret;
    bool *isnull;

    if( CALLED_AS_TRIGGER( fcinfo ) ) {
        elog(INFO, "unlink_file was called as a trigger." );
        trigdata = (TriggerData *) fcinfo->context;

        if( ( ret = SPI_connect() ) != SPI_OK_CONNECT ) {
            elog(INFO, "SPI_connect returned %d", ret);
        }

        file_name_colnumber = SPI_fnumber( trigdata->tg_relation->rd_att, "file_name" );

        if( file_name_colnumber == SPI_ERROR_NOATTRIBUTE ) {
            elog(INFO, "SPI_fnumber returned SPI_ERROR_NOATTRIBUTE" );
        }

        SPI_getbinval( trigdata->tg_trigtuple, trigdata->tg_relation->rd_att, file_name_colnumber, isnull );

        if( SPI_result == SPI_ERROR_NOATTRIBUTE ) {
            elog(INFO, "SPI_fnumber returned SPI_ERROR_NOATTRIBUTE" );
        }

        relative_filename_t = PG_DETOAST_DATUM( relative_filename_datum );

        if( ( ret = SPI_finish() ) != SPI_OK_FINISH ) {
            elog(INFO, "SPI_finish returned %d", ret);
        }

    }

Re: difficulty extracting variable-sized field on triggered row

От
Alvaro Herrera
Дата:
Glen W. Mabey escribió:

>     TriggerData *trigdata;
>     Datum relative_filename_datum;
>     text *relative_filename_t;
>     int file_name_colnumber, ret;
>     bool *isnull;

This is wrong.  Try

    bool isnull;

and later:

        SPI_getbinval( trigdata->tg_trigtuple, trigdata->tg_relation->rd_att, file_name_colnumber, &isnull );

--
Alvaro Herrera                  http://www.amazon.com/gp/registry/5ZYLFMCVHXC
"No hay ausente sin culpa ni presente sin disculpa" (Prov. francés)

Re: difficulty extracting variable-sized field on triggered row

От
Tom Lane
Дата:
"Glen W. Mabey" <Glen.Mabey@swri.org> writes:
> Is there somewhere that I am not adequately checking for an error?

1. You're passing SPI_getbinval an uninitialized bool pointer.

2. You're discarding its result, which you need.

3. You're not checking for a null, and the error check you do have
   is wrong/redundant.

4. Use DatumGetTextP(), not DatumGetPointer nor PG_DETOAST_DATUM.

            regards, tom lane

Re: difficulty extracting variable-sized field on triggered row

От
Martijn van Oosterhout
Дата:
On Tue, Dec 04, 2007 at 09:26:46AM -0600, Glen W. Mabey wrote:
> On Tue, Dec 04, 2007 at 09:10:21AM -0600, Pavel Stehule wrote:
> > use macro DatumGetPointer(datum)
>
> When I do that, I get the following compiler warning:
>
>     warning: assignment from incompatible pointer type

Well yes, you're getting a (void*) which you need to cast to a (text*).
It's the generic cast for indirect types.

> Using DatumGetPointer also seg faults ...

What actually segfault? Not DatumGetPointer() since that's just a cast.

> Is there somewhere that I am not adequately checking for an error?

Depends what you're doing. Remember, a (text*) is a varlena object so
you need to use the VAR_DATA,VAR_LEN macros to access it. The string is
not nul-terminated for example. If you want to get a plain C-string,
use textout or DatumToCString or something similar.

However, DETOAST is the right step, because if you don't do that you
might be handed a toasted string.

Have a nice day,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Those who make peaceful revolution impossible will make violent revolution inevitable.
>  -- John F Kennedy

Вложения

Re: difficulty extracting variable-sized field on triggered row

От
"Glen W. Mabey"
Дата:
On Tue, Dec 04, 2007 at 09:53:37AM -0600, Tom Lane wrote:
> "Glen W. Mabey" <Glen.Mabey@swri.org> writes:
> > Is there somewhere that I am not adequately checking for an error?
>
> 1. You're passing SPI_getbinval an uninitialized bool pointer.

Doh!

> 2. You're discarding its result, which you need.

Ah yes, a change I made while trying to debug things.

> 3. You're not checking for a null, and the error check you do have
>    is wrong/redundant.

The field is constrained to be NOT NULL, so I wasn't worried about
checking that, but I don't see how the error check is wrong, according
to the description of SPI_getbinval at

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

What is then the appropriate way to check for failure of SPI_getbinval?

> 4. Use DatumGetTextP(), not DatumGetPointer nor PG_DETOAST_DATUM.

Searching for DatumGetTextP from the search text box at the top of
www.postgresql.org yields no hits, and a google search on DatumGetTextP
does not seem to turnip [sic] any direct documentation on this function.

Is there somewhere in the docs that I should have found this (and other
useful) functions?

Thank you very much,
Glen Mabey

Re: difficulty extracting variable-sized field on triggered row

От
Tom Lane
Дата:
"Glen W. Mabey" <Glen.Mabey@swri.org> writes:
> On Tue, Dec 04, 2007 at 09:53:37AM -0600, Tom Lane wrote:
>> 3. You're not checking for a null, and the error check you do have
>> is wrong/redundant.

> The field is constrained to be NOT NULL, so I wasn't worried about
> checking that, but I don't see how the error check is wrong,

Well, a check on the isnull state is a good idea anyway IMHO.
This code has no way of being sure that a NOT NULL constraint
exists, and dumping core if it's not there isn't my idea of being
robust.

What I didn't like about the error test was that it assumed that
SPI_ERROR_NOATTRIBUTE is and always will be the only possible
error code from SPI_getbinval.  I'd test for SPI_result != 0 instead.
(The "redundant" comment came from the thought that it's probably
pointless to be making this test at all, considering that you just
got the column number from SPI_fnumber on the same tupdesc.)

>> 4. Use DatumGetTextP(), not DatumGetPointer nor PG_DETOAST_DATUM.

> Is there somewhere in the docs that I should have found this (and other
> useful) functions?

fmgr.h, perhaps, or by looking at existing code that does more or less
what you want to do.  Postgres does not follow the model that you are
supposed to look only at the SGML docs to find out how to do server-side
programming.  We are open source and one of the biggest benefits of that
is that you can (and should) look at the source code to learn.

            regards, tom lane

Re: difficulty extracting variable-sized field on triggered row

От
Sam Mason
Дата:
On Tue, Dec 04, 2007 at 10:11:04AM -0600, Glen W. Mabey wrote:
> Searching for DatumGetTextP from the search text box at the top of
> www.postgresql.org yields no hits, and a google search on DatumGetTextP
> does not seem to turnip [sic] any direct documentation on this function.
>
> Is there somewhere in the docs that I should have found this (and other
> useful) functions?

I find the following tool helpful:

  http://doxygen.postgresql.org/


  Sam