Thread: dynamic field names in a function.

dynamic field names in a function.

From
Soma Interesting
Date:
I want to be able to reference NEW.field_0 though NEW.field_x where x is
coming from NEW.qty in a FOR loop of pl/pgsql function. Is this possible?

In other words:

FOR j IN 0..NEW.str LOOP

    ans := ''q'' || i || ''a'' || j;
    cor := ''q'' || i || ''c'' || j;
    eval := 'q'' || i || ''e'' || j;

    IF NEW.ans = NEW.cor
    THEN NEW.eval := 1;
    END IF;

END LOOP;


RE: dynamic field names in a function.

From
Jeff Eckermann
Date:
In my experience, the best way to find out answers like this is to try it
out and see.  Usually I find that I need to fiddle around with the syntax a
bit (I believe it's called debugging) before getting something to work.
Postgresql is very powerful; the capability to utilize that power comes at a
price.  In other words, be prepared to put in a solid investment if you want
to see a return.
(I'm not accustomed to preaching, but sometimes this just needs to be said).

> -----Original Message-----
> From:    Soma Interesting [SMTP:dfunct@telus.net]
> Sent:    Thursday, March 29, 2001 4:39 PM
> To:    pgsql-general@postgresql.org
> Subject:    [GENERAL] dynamic field names in a function.
>
>
> I want to be able to reference NEW.field_0 though NEW.field_x where x is
> coming from NEW.qty in a FOR loop of pl/pgsql function. Is this possible?
>
> In other words:
>
> FOR j IN 0..NEW.str LOOP
>
>     ans := ''q'' || i || ''a'' || j;
>     cor := ''q'' || i || ''c'' || j;
>     eval := 'q'' || i || ''e'' || j;
>
>     IF NEW.ans = NEW.cor
>     THEN NEW.eval := 1;
>     END IF;
>
> END LOOP;
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org

RE: dynamic field names in a function.

From
Soma Interesting
Date:
At 11:30 AM 3/30/2001 -0600, you wrote:
>In my experience, the best way to find out answers like this is to try it
>out and see.  Usually I find that I need to fiddle around with the syntax a
>bit (I believe it's called debugging) before getting something to work.
>Postgresql is very powerful; the capability to utilize that power comes at a
>price.  In other words, be prepared to put in a solid investment if you want
>to see a return.
>(I'm not accustomed to preaching, but sometimes this just needs to be said).

Well its good you don't do it often because your not very good at it. ;)

I've spent a reasonable about of time trying different approaches before
posting my question here. If I had the confidence that what I was trying to
do was certainly possible  with pl/pgsql - then I'd pursue it until I made
it work. I probably have more tenacity than you realize, despite it being
so very, very obvious by my trying to get an answer in this mailing list.

However, since I could declare a variable called id and have a column in
the table called id and perhaps I want to reference NEW.id where id is the
variable value not the column - then it would seem that whatever parser is
at work may have some ambiguities to cope with. Thus I begin to doubt if
its something that should be expected of pl/pgsql. I've not come across any
way to make a variable reference more explicit to the parser in the
postgres docs.... so I have no choice but to ask here. Then again it would
make good sense if the parser did evaluated variables before evaluating
field references... but the fact is, "I DON'T KNOW".

Thanks.


RE: dynamic field names in a function.

From
Soma Interesting
Date:
Please.

In the following, is there something I can do so that postgres will
evaluate NEW.qty to NEW.name, treating qty as a variable and evaluating it
before evaluating the field reference? At this time it errors on an INSERT
with: "record new has no field qty".

CREATE FUNCTION func_test() RETURNS opaque AS '
    DECLARE
        qty varchar(5);
    BEGIN

        qty := ''name'';
        NEW.qty := ''target'';
        return new;
    END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER func_test_trigger BEFORE INSERT
    ON test FOR EACH ROW
    EXECUTE PROCEDURE func_test ();


RE: dynamic field names in a function.

From
Soma Interesting
Date:
At 03:43 PM 3/30/2001 -0600, you wrote:
>I think I am beginning to understand your question.  You want to know
>whether a field name can be referenced using a variable as all or part of
>the field name?  I don't know for sure, but I can't make it work, and
>apparently you can't either.
>Your earlier message is still out on the wire, so someone more knowledgeable
>may still answer.
>If you expect the maximum number of question/answer pairs to be manageably
>small, you could do a series of actions for each field by name, incrementing
>a counter for each pair, and comparing the counter value to 'qty'.
>Horrible, I know, but the best I can suggest right now.

I'm going to quote your rephrasing of my question to the list, maybe your
words will carry more weight as "valid" question.

Another option would be to use Tcl or Pearl, would they be able to use
variables as all or part of the field name?


RE: dynamic field names in a function.

From
Jeff Eckermann
Date:
An alternative would be to do the the work at the application level, i.e.
the point where the data is collected.  You could use any language you like
for that.

> -----Original Message-----
> From:    Soma Interesting [SMTP:dfunct@telus.net]
> Sent:    Friday, March 30, 2001 3:59 PM
> To:    Jeff Eckermann; pgsql-general@postgresql.org
> Subject:    RE: [GENERAL] dynamic field names in a function.
>
> At 03:43 PM 3/30/2001 -0600, you wrote:
> >I think I am beginning to understand your question.  You want to know
> >whether a field name can be referenced using a variable as all or part of
> >the field name?  I don't know for sure, but I can't make it work, and
> >apparently you can't either.
> >Your earlier message is still out on the wire, so someone more
> knowledgeable
> >may still answer.
> >If you expect the maximum number of question/answer pairs to be
> manageably
> >small, you could do a series of actions for each field by name,
> incrementing
> >a counter for each pair, and comparing the counter value to 'qty'.
> >Horrible, I know, but the best I can suggest right now.
>
> I'm going to quote your rephrasing of my question to the list, maybe your
> words will carry more weight as "valid" question.
>
> Another option would be to use Tcl or Pearl, would they be able to use
> variables as all or part of the field name?

RE: dynamic field names in a function.

From
Soma Interesting
Date:
At 04:09 PM 3/30/2001 -0600, you wrote:
>An alternative would be to do the the work at the application level, i.e.
>the point where the data is collected.  You could use any language you like
>for that.

This has ran through my mind as an option - the project is a web
application with php and postgres, but a number of factors involved makes
it really undesirable to do this at the application level - to the point
that its worth my while to learn pl/pgsql, perl, or tcl to avoid it - or
possibly even C - none of which I know... yet :)

So I repeat the question, not to be obnoxious - but to be sure, "does
anyone *know* if any of the languages available for writing functions would
allow a field name to be referenced using a variable as all or part of the
field name?


Re: dynamic field names in a function.

From
will trillich
Date:
On Fri, Mar 30, 2001 at 10:57:42AM -0800, Soma Interesting wrote:
> In the following, is there something I can do so that postgres will
> evaluate NEW.qty to NEW.name, treating qty as a variable and evaluating it
> before evaluating the field reference? At this time it errors on an INSERT
> with: "record new has no field qty".
>
> CREATE FUNCTION func_test() RETURNS opaque AS '
>     DECLARE
>         qty varchar(5);
>     BEGIN
>
>         qty := ''name'';
>         NEW.qty := ''target'';
>         return new;
>     END;
> ' LANGUAGE 'plpgsql';

i was hoping for some such beast, too. apparently in 7.1 (doea
that even exist yet?) you can have one plpgsql procedure create a
string that happens to be plpgsql code that you can EXECUTE, and
as such you can have dynamically-created functions that'll do
what you want...

but from what i can tell, the answer to

    -- can you do this?
    select mytbl.[myvariable] ;

seems to be NO, since whatever is after the dot is taken as a
field name. (anybody who knows different is welcome to shoot me
down.)

if they had alternate syntax, such as

    table{"fieldexpression"}
    table->"fieldexpr"
    table("fieldexpr")

maybe it'd be simpler to incorporate in a future incarnation of
the parser...?

come to think of it, field names can get quoted to hinder
otherwise dangrous parsing:

    create table "this relation" ( "my field" as text ) ;
    select "this relation"."my field" ;

why not allow variable-substitution in those instances? (grumble,
grumble...)

--

HOWEVER -- we do have arrays, don't forget... sometimes they can
be bent to do more than intended (but usually not!)

    create table mailing(
        person_id serial,
        sent int4[],
        prefs varchar[],
        current int2
    );
    -- insert, update, munge and frob, then
    select person_id,sent[current] from something;

--

oh, and if your PostgreSQL instance is new enough, you might have
PERL built in, which could make all of this moot. (now we just
need someone to DOCUMENT the sucker so we know how perl can talk
back to postgres for cross-lookups and such...)

--
does a brain cell think?

will@serensoft.com
http://sourceforge.net/projects/newbiedoc -- we need your brain!
http://www.dontUthink.com/ -- your brain needs us!

Re: dynamic field names in a function.

From
Soma Interesting
Date:
At 05:47 PM 3/30/2001 -0600, you wrote:
>HOWEVER -- we do have arrays, don't forget... sometimes they can
>be bent to do more than intended (but usually not!)
>
>         create table mailing(
>                 person_id serial,
>                 sent int4[],
>                 prefs varchar[],
>                 current int2
>         );
>         -- insert, update, munge and frob, then
>         select person_id,sent[current] from something;
>
>--
>
>oh, and if your PostgreSQL instance is new enough, you might have
>PERL built in, which could make all of this moot. (now we just
>need someone to DOCUMENT the sucker so we know how perl can talk
>back to postgres for cross-lookups and such...)

Will, you are a powerful postgres wizard and never let anyone tell you
otherwise.

I may be able to use array's if postgres will allow using variables to
reference points in the array.

As for your comment about perl being built in, how can I find this out? I
guess just try CREATE LANGUAGE specifying perl?


plperl -- postgresql married to perl

From
will trillich
Date:
On Fri, Mar 30, 2001 at 04:39:21PM -0800, Soma Interesting wrote:
> At 05:47 PM 3/30/2001 -0600, you wrote:
> >HOWEVER -- we do have arrays, don't forget... sometimes they can
> >be bent to do more than intended (but usually not!)
> >
> >         create table mailing(
> >                 person_id serial,
> >                 sent int4[],
> >                 prefs varchar[],
> >                 current int2
> >         );
> >         -- insert, update, munge and frob, then
> >         select person_id,sent[current] from something;
> >
> >--
> >
> >oh, and if your PostgreSQL instance is new enough, you might have
> >PERL built in, which could make all of this moot. (now we just
> >need someone to DOCUMENT the sucker so we know how perl can talk
> >back to postgres for cross-lookups and such...)
>
> Will, you are a powerful postgres wizard and never let anyone tell you
> otherwise.

nice to know i can still fool some of the people some of the
time. :) let's just say i'm a half-hour ahead of you on at least
one topic... (probably at MOST, one topic.)

> I may be able to use array's if postgres will allow using variables to
> reference points in the array.
>
> As for your comment about perl being built in, how can I find this out? I
> guess just try CREATE LANGUAGE specifying perl?

oh, hell no. if it were that easy, my tone of voice would be much
more pleasing.

i'm using debian 2.2 (potato) where all we have to do is "apt-get
install" and the package is downloaded, installed and configured.
i've got 7.0.3potato which is a debian2.2 friendly incarnation --
i specifically installed it from samfundet.no/~tfheen because
on the debian user list, 'they' said it had perl built in.

alas... i do have fancy capabilities in 7.0.3 that weren't in
6.5.3, but still no plperl... bitchandmoan...

--

apparently what you're looking for is "plperl.so".

    % locate plperl
    /usr/share/doc/postgresql-doc/src/pl/plperl
    /usr/share/doc/postgresql-doc/src/pl/plperl/README

that document shows me how, if i HAD plperl, i could get it
active within postgresql...

maybe you should search the postgresql site for keyword "plperl"
and see where it takes you...

--
does a brain cell think?

will@serensoft.com
http://sourceforge.net/projects/newbiedoc -- we need your brain!
http://www.dontUthink.com/ -- your brain needs us!

Re: plperl -- postgresql married to perl

From
Soma Interesting
Date:
At 06:47 PM 3/30/2001 -0600, you wrote:
> > I may be able to use array's if postgres will allow using variables to
> > reference points in the array.


OK, so how do I reference a specific element of an array in a record within
pl/pgsql.

I've tried:

NEW.name[1]
NEW.name.1






Re: dynamic field names in a function.

From
"Eric G. Miller"
Date:
On Thu, Mar 29, 2001 at 02:38:31PM -0800, Soma Interesting wrote:
>
> I want to be able to reference NEW.field_0 though NEW.field_x where x is
> coming from NEW.qty in a FOR loop of pl/pgsql function. Is this possible?
>
> In other words:
>
> FOR j IN 0..NEW.str LOOP
>
>     ans := ''q'' || i || ''a'' || j;
>     cor := ''q'' || i || ''c'' || j;
>     eval := 'q'' || i || ''e'' || j;
>
>     IF NEW.ans = NEW.cor
>     THEN NEW.eval := 1;
>     END IF;
>
> END LOOP;

I think maybe querying system catalogs might help your approach.  I'm
not entirely clear on what you're trying to do, but you can get the name
of the relation that caused the trigger to fire (TG_RELNAME).  Then
query the pg_class table for the "oid" of the class where relnam =
TG_RELNAME, join with pg_attribute on pg_class.oid =
pg_attribute.attrelid and pg_attribute.attnum > 0 (to skip internal
system fields).  Then you have a set of records containing all of the
field names for the relation which you can compare to the concatenation
of your "field" and NEW.qty.  Hope this is making some sense.  Here's a
quick example query on a known relation called "units".

select pg_attribute.* from pg_attribute, pg_class
where pg_attribute.attrelid = pg_class.oid
and pg_class.relname = 'units'
and pg_attribute.attnum > 0;

You'll probably be most interested in "pg_attribute.attname".
--
Eric G. Miller <egm2@jps.net>

Re: dynamic field names in a function.

From
Tom Lane
Date:
Soma Interesting <dfunct@telus.net> writes:
> In the following, is there something I can do so that postgres will
> evaluate NEW.qty to NEW.name, treating qty as a variable and evaluating it
> before evaluating the field reference?

Plain PLSQL will not do this --- it wants to know field names when the
query is first compiled.  (This is a feature, not a bug, since it
implies that the query can be optimized during compilation.)

You could use PLTCL or PLPERL instead.  Both of them treat queries
as plain strings that you assemble out of whatever parts you please
and then pass to the query engine.  Of course you pay the cost of
re-planning the query from scratch every time --- there's no free lunch.

In 7.1, PLSQL can do that trick too, via its new EXECUTE statement.

            regards, tom lane

Re: dynamic field names in a function.

From
will trillich
Date:
On Sat, Mar 31, 2001 at 12:42:29AM -0500, Tom Lane wrote:
> Soma Interesting <dfunct@telus.net> writes:
> > In the following, is there something I can do so that postgres will
> > evaluate NEW.qty to NEW.name, treating qty as a variable and evaluating it
> > before evaluating the field reference?
>
> Plain PLSQL will not do this --- it wants to know field names when the
> query is first compiled.  (This is a feature, not a bug, since it
> implies that the query can be optimized during compilation.)
>
> You could use PLTCL or PLPERL instead.  Both of them treat queries
> as plain strings that you assemble out of whatever parts you please
> and then pass to the query engine.  Of course you pay the cost of
> re-planning the query from scratch every time --- there's no free lunch.

<ding ding ding> there's that magic word PLPERL again... !

HOW do you find out if your postgresql (mine's 7.0.3) can support
the plperl.so feature? And HOW do you go about installing it, if
it does? What parts are necessary?

--
does a brain cell think?

will@serensoft.com
http://sourceforge.net/projects/newbiedoc -- we need your brain!
http://www.dontUthink.com/ -- your brain needs us!

Re: plperl -- postgresql married to perl

From
will trillich
Date:
On Fri, Mar 30, 2001 at 06:02:27PM -0800, Soma Interesting wrote:
> At 06:47 PM 3/30/2001 -0600, you wrote:
> > > I may be able to use array's if postgres will allow using variables to
> > > reference points in the array.
>
>
> OK, so how do I reference a specific element of an array in a record within
> pl/pgsql.
>
> I've tried:
>
> NEW.name[1]
> NEW.name.1

hmm. maybe it's NEW that's the problem...?


    create table gunk(
        val varchar[]
    );

    insert into gunk
    values (
        '{"first string","another value","the end"}'
    ) ;

    select val[2] from gunk;

          val
    ---------------
     another value
    (1 row)

i'd think

    table.field[index]

should do the trick, even in plpgsql:

    myvar := select name[index] from new;

    myvar := new.name[somevariable];

    myary := new.name;
    myvar := myary[someindexvar];

no? (unless <guess> maybe the plpgsql compiler doesn't like
variable subscript values </guess>, which would warrant keel
hauling everyone responsible...)

--
does a brain cell think?

will@serensoft.com
http://sourceforge.net/projects/newbiedoc -- we need your brain!
http://www.dontUthink.com/ -- your brain needs us!

Re: dynamic field names in a function.

From
Tom Lane
Date:
will trillich <will@serensoft.com> writes:
> HOW do you find out if your postgresql (mine's 7.0.3) can support
> the plperl.so feature? And HOW do you go about installing it, if
> it does? What parts are necessary?

See
http://www.postgresql.org/devel-corner/docs/postgres/plperl.html
These are 7.1 docs but the info applies to 7.0 as well.

The main trick is that you need a Perl installation that has a shared
library for perl (libperl.so, not libperl.a).  This usually requires
building Perl from source, since it's not the default configuration.
It's easy enough if you build Perl from source, just say "yes" when
Perl's interactive configure script asks if you want a shlib.

            regards, tom lane

Re: dynamic field names in a function.

From
will trillich
Date:
On Sat, Mar 31, 2001 at 07:57:59PM -0500, Tom Lane wrote:
> will trillich <will@serensoft.com> writes:
> > HOW do you find out if your postgresql (mine's 7.0.3) can support
> > the plperl.so feature? And HOW do you go about installing it, if
> > it does? What parts are necessary?
>
> See
> http://www.postgresql.org/devel-corner/docs/postgres/plperl.html
> These are 7.1 docs but the info applies to 7.0 as well.
>
> The main trick is that you need a Perl installation that has a shared
> library for perl (libperl.so, not libperl.a).  This usually requires
> building Perl from source, since it's not the default configuration.
> It's easy enough if you build Perl from source, just say "yes" when
> Perl's interactive configure script asks if you want a shlib.

i thought it was looking for plperl.so... ?

thanks!

--
does a brain cell think?

will@serensoft.com
http://sourceforge.net/projects/newbiedoc -- we need your brain!
http://www.dontUthink.com/ -- your brain needs us!

Re: dynamic field names in a function.

From
Tom Lane
Date:
will trillich <will@serensoft.com> writes:
>> The main trick is that you need a Perl installation that has a shared
>> library for perl (libperl.so, not libperl.a).  This usually requires
>> building Perl from source, since it's not the default configuration.
>> It's easy enough if you build Perl from source, just say "yes" when
>> Perl's interactive configure script asks if you want a shlib.

> i thought it was looking for plperl.so... ?

But plperl.so depends on libperl.so.

            regards, tom lane

Re: dynamic field names in a function.

From
Soma Interesting
Date:
At 12:42 AM 3/31/2001 -0500, you wrote:
>Plain PLSQL will not do this --- it wants to know field names when the
>query is first compiled.  (This is a feature, not a bug, since it
>implies that the query can be optimized during compilation.)
>
>You could use PLTCL or PLPERL instead.  Both of them treat queries
>as plain strings that you assemble out of whatever parts you please
>and then pass to the query engine.  Of course you pay the cost of
>re-planning the query from scratch every time --- there's no free lunch.
>
>In 7.1, PLSQL can do that trick too, via its new EXECUTE statement.

You neglected to mention that triggers can't call perl functions. Had you
mentioned this - I'd not have bothered spending several days trying to get
perl working with postgres.

YOU SHOULD EXPLICITLY SAY THIS IN YOUR MANUAL!!!