Thread: How can I get one OLD.* field in a dynamic query inside a trigger function ?

How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Bruno Baguette
Date:
Hello !

I'm trying to write a little trigger function with variable arguments
quantity (at least one, but can be 2,3,4 arguments).
Theses arguments are fields name, so only varchar variable.

Since it is a dynamic query, I use the EXECUTE statement as explained on
<http://www.postgresql.org/docs/8.3/interactive/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN>

CREATE OR REPLACE FUNCTION delete_acl_trigger() RETURNS trigger AS
$delete_acl_trigger$
DECLARE
BEGIN
   FOR i IN 0 .. TG_NARGS LOOP
     EXECUTE 'SELECT delete_acl(OLD.' || TG_ARGV[i] || ');';
   END LOOP;
   RETURN OLD;
END;
$delete_acl_trigger$ LANGUAGE plpgsql;

But, when the trigger is triggered, I receive this error message :
"Query failed: ERROR: OLD used in query that is not in a rule"

How can I get the value of the OLD.' || TG_ARGV[i] field ?

Many thanks in advance !

Kind regards,

--
Bruno Baguette - bruno.baguette@gmail.com

Re: How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Pavel Stehule
Date:
2009/10/24 Bruno Baguette <bruno.baguette@gmail.com>:
> Hello !
>
> I'm trying to write a little trigger function with variable arguments
> quantity (at least one, but can be 2,3,4 arguments).
> Theses arguments are fields name, so only varchar variable.
>
> Since it is a dynamic query, I use the EXECUTE statement as explained on
> <http://www.postgresql.org/docs/8.3/interactive/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN>
>
> CREATE OR REPLACE FUNCTION delete_acl_trigger() RETURNS trigger AS
> $delete_acl_trigger$
> DECLARE
> BEGIN
>  FOR i IN 0 .. TG_NARGS LOOP
>    EXECUTE 'SELECT delete_acl(OLD.' || TG_ARGV[i] || ');';
>  END LOOP;
>  RETURN OLD;
> END;
> $delete_acl_trigger$ LANGUAGE plpgsql;
>
> But, when the trigger is triggered, I receive this error message :
> "Query failed: ERROR: OLD used in query that is not in a rule"
>
> How can I get the value of the OLD.' || TG_ARGV[i] field ?

OLD is variable only in PLpgSQL procedure, - outside doesn't exists.
If you have a 8.4, you can use USING clause

EXPLAIN 'SELECT $1.' || TG_ARGV[i] INTO somevar USING OLD;

http://www.postgresql.org/docs/8.4/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

Regards
Pavel Stehule



>
> Many thanks in advance !
>
> Kind regards,
>
> --
> Bruno Baguette - bruno.baguette@gmail.com
>
> --
> Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-general
>

Re: How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Bruno Baguette
Date:
Le 24/10/09 06:46, Pavel Stehule a écrit :
> 2009/10/24 Bruno Baguette <bruno.baguette@gmail.com>:
>> Hello !
>>
>> I'm trying to write a little trigger function with variable arguments
>> quantity (at least one, but can be 2,3,4 arguments).
>> Theses arguments are fields name, so only varchar variable.
>>
>> Since it is a dynamic query, I use the EXECUTE statement as explained on
>> <http://www.postgresql.org/docs/8.3/interactive/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN>
>>
>> CREATE OR REPLACE FUNCTION delete_acl_trigger() RETURNS trigger AS
>> $delete_acl_trigger$
>> DECLARE
>> BEGIN
>>  FOR i IN 0 .. TG_NARGS LOOP
>>    EXECUTE 'SELECT delete_acl(OLD.' || TG_ARGV[i] || ');';
>>  END LOOP;
>>  RETURN OLD;
>> END;
>> $delete_acl_trigger$ LANGUAGE plpgsql;
>>
>> But, when the trigger is triggered, I receive this error message :
>> "Query failed: ERROR: OLD used in query that is not in a rule"
>>
>> How can I get the value of the OLD.' || TG_ARGV[i] field ?
>
> OLD is variable only in PLpgSQL procedure, - outside doesn't exists.
> If you have a 8.4, you can use USING clause
>
> EXPLAIN 'SELECT $1.' || TG_ARGV[i] INTO somevar USING OLD;
>
> http://www.postgresql.org/docs/8.4/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

Hello Pavel,

Thanks for your answer !

Unfortunately, I'm running PostgreSQL 8.3.7 (PostgreSQL 8.3.7 on
i586-mandriva-linux-gnu, compiled by GCC i586-mandriva-linux-gnu-gcc
(GCC) 4.2.3 (4.2.3-6mnb1)).

Since 8.4.1 is not available for Mandriva 2009.1, I can only have this
PostgreSQL version. (I don't have root access on that server).

Is there another way, usable in PostgreSQL 8.3.7, to solve my problem ?

Many thanks in advance !

Kind Regards,

--
Bruno Baguette - bruno.baguette@gmail.com

Re: How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Pavel Stehule
Date:
2009/10/24 Bruno Baguette <bruno.baguette@gmail.com>:
> Le 24/10/09 06:46, Pavel Stehule a écrit :
>>
>> 2009/10/24 Bruno Baguette <bruno.baguette@gmail.com>:
>>>
>>> Hello !
>>>
>>> I'm trying to write a little trigger function with variable arguments
>>> quantity (at least one, but can be 2,3,4 arguments).
>>> Theses arguments are fields name, so only varchar variable.
>>>
>>> Since it is a dynamic query, I use the EXECUTE statement as explained on
>>>
>>> <http://www.postgresql.org/docs/8.3/interactive/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN>
>>>
>>> CREATE OR REPLACE FUNCTION delete_acl_trigger() RETURNS trigger AS
>>> $delete_acl_trigger$
>>> DECLARE
>>> BEGIN
>>>  FOR i IN 0 .. TG_NARGS LOOP
>>>   EXECUTE 'SELECT delete_acl(OLD.' || TG_ARGV[i] || ');';
>>>  END LOOP;
>>>  RETURN OLD;
>>> END;
>>> $delete_acl_trigger$ LANGUAGE plpgsql;
>>>
>>> But, when the trigger is triggered, I receive this error message :
>>> "Query failed: ERROR: OLD used in query that is not in a rule"
>>>
>>> How can I get the value of the OLD.' || TG_ARGV[i] field ?
>>
>> OLD is variable only in PLpgSQL procedure, - outside doesn't exists.
>> If you have a 8.4, you can use USING clause
>>
>> EXPLAIN 'SELECT $1.' || TG_ARGV[i] INTO somevar USING OLD;
>>
>>
>> http://www.postgresql.org/docs/8.4/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
>
> Hello Pavel,
>
> Thanks for your answer !
>
> Unfortunately, I'm running PostgreSQL 8.3.7 (PostgreSQL 8.3.7 on
> i586-mandriva-linux-gnu, compiled by GCC i586-mandriva-linux-gnu-gcc (GCC)
> 4.2.3 (4.2.3-6mnb1)).
>
> Since 8.4.1 is not available for Mandriva 2009.1, I can only have this
> PostgreSQL version. (I don't have root access on that server).
>
> Is there another way, usable in PostgreSQL 8.3.7, to solve my problem ?

you can use plperl or plpython for this task.

Pavel

>
> Many thanks in advance !
>
> Kind Regards,
>
> --
> Bruno Baguette - bruno.baguette@gmail.com
>

Re: How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Bruno Baguette
Date:
Le 24/10/09 22:09, Pavel Stehule a écrit :
> you can use plperl or plpython for this task.
>
> Pavel

re-Hello Pavel,

I always used plpgsql because I *thought* it was the most powerfull
procedural language for stored procedures in PostgreSQL.

The fact that PL/pgSQL is most documented than PL/Tcl and PL/Perl (and
PL/Python *seems* to have very poor documentation) has probably made me
wrong.

Which one would you advise me to learn and use, instead of PL/pgSQL ?

Can you explain me why does PL/Perl and PL/Python can does this task
(using OLD in a dynamic query) where PL/pgSQL can't ?

Once again, thanks a lot for your tips ! :-)

Kind regards,

--
Bruno Baguette - bruno.baguette@gmail.com


Re: How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Pavel Stehule
Date:
2009/10/24 Bruno Baguette <bruno.baguette@gmail.com>:
> Le 24/10/09 22:09, Pavel Stehule a écrit :
>>
>> you can use plperl or plpython for this task.
>>
>> Pavel
>
> re-Hello Pavel,
>
> I always used plpgsql because I *thought* it was the most powerfull
> procedural language for stored procedures in PostgreSQL.

plpgsql is best language for stored procedures, but simply it is not
for all. There are some issue still, but some significant limits are
removed in 8.4.

>
> The fact that PL/pgSQL is most documented than PL/Tcl and PL/Perl (and
> PL/Python *seems* to have very poor documentation) has probably made me
> wrong.
>
> Which one would you advise me to learn and use, instead of PL/pgSQL ?

It depends on what you are know (if you known better perl or pthon).
Usually I using mainly plpgsql and on some functions plperl and C.
plpgsql is good language as glue of SQL statements, plperl is good for
IO and CPAN libraries, and C should help with some processor intensive
functions.

>
> Can you explain me why does PL/Perl and PL/Python can does this task (using
> OLD in a dynamic query) where PL/pgSQL can't ?

External procedures (like procedures in plperl or plpython) has not
100% integrated SQL. Next, SQL row is mapped to perl's array and it
should be iterated. Plpgsql is similar to classic programming
languages. In mostly older languages you cannot iterate over
recordset.. plpgsql is static language like C, Pascal, ADA. Perl or
Python are dynamic languages, so you can do some tasks very simple.
And other not, because these languages are only on partially
integrated with SQL.

>
> Once again, thanks a lot for your tips ! :-)

with pleasure

Pavel
>
> Kind regards,
>
> --
> Bruno Baguette - bruno.baguette@gmail.com
>
>

Re: How can I get one OLD.* field in a dynamic query inside a trigger function ?

From
Bruno Baguette
Date:
Le 24/10/09 22:57, Pavel Stehule a écrit :
> 2009/10/24 Bruno Baguette <bruno.baguette@gmail.com>:
>> Which one would you advise me to learn and use, instead of PL/pgSQL ?
>
> It depends on what you are know (if you known better perl or pthon).
> Usually I using mainly plpgsql and on some functions plperl and C.
> plpgsql is good language as glue of SQL statements, plperl is good for
> IO and CPAN libraries, and C should help with some processor intensive
> functions.

Hello Pavel !

I've read the doc' about plperl and plpython, since I have notion of both.

Because plpython is not a trusted language, I finally took plperl.

In case somebody else does look for the same thing as I was looking for,
here's the new trigger function, rewritten using plperl :

####################################

CREATE OR REPLACE FUNCTION delete_acl_trigger() RETURNS trigger AS
$delete_acl_trigger$
if($_TD->{argc}>0)
{
   for(my $i=0; $i < $_TD->{argc} ; $i++)
   {
     my $acl_id = $_TD->{old}{$_TD->{"args"}[i]};
     my $rv = spi_exec_query("SELECT delete_acl($acl_id);");

     # DEBUG TOOLS
     # my $status = $rv->{status};
     # elog(NOTICE, 'RESULTAT : '.$status);
   }
   return;
}
else
{
   return;
}
$delete_acl_trigger$ LANGUAGE plperl;

####################################

Do I have to mention that it does perfectly what I expected ? :-)

If you have any comments or tips about that function, feel free to do so
  in order to improve it ! :-)

Pavel, many thanks for your tips and explanations !
They were very helpfull ! :-)

Kind regards,

--
Bruno Baguette - bruno.baguette@gmail.com