Re: targetlist functions part 1 (was [HACKERS] targetlist - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: targetlist functions part 1 (was [HACKERS] targetlist
Date
Msg-id 200302031236.h13CaCc21123@candle.pha.pa.us
Whole thread Raw
In response to targetlist functions part 1 (was [HACKERS] targetlist functions proposals)  (Joe Conway <mail@joeconway.com>)
Responses Re: targetlist functions part 1 (was [HACKERS] targetlist
List pgsql-patches
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://momjian.postgresql.org/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Joe Conway wrote:
> Joe Conway wrote:
> > =================================================================
> > User interface proposal for multi-row function targetlist entries
> > =================================================================
> > 1. Only one targetlist entry may return a set.
> > 2. Each targetlist item (other than the set returning one) is
> >    repeated for each item in the returned set.
> >
>
> Having gotten no objections (actually, no response at all), I can only assume
> no one had heartburn with this change. The attached patch covers the first of
> the two proposals, i.e. restricting the target list to only one set returning
> function.
>
> It compiles cleanly, and passes all regression tests. If there are no
> objections, please apply.
>
> Any suggestions on where this should be documented (other than maybe sql-select)?
>
> Thanks,
>
> Joe
>
> p.s. Here's what the previous example now looks like:
> CREATE TABLE bar(f1 int, f2 text, f3 int);
> INSERT INTO bar VALUES(1, 'Hello', 42);
> INSERT INTO bar VALUES(2, 'Happy', 45);
>
> CREATE TABLE foo(a int, b text);
> INSERT INTO foo VALUES(42, 'World');
> INSERT INTO foo VALUES(42, 'Everyone');
> INSERT INTO foo VALUES(45, 'Birthday');
> INSERT INTO foo VALUES(45, 'New Year');
>
> CREATE TABLE foo2(a int, b text);
> INSERT INTO foo2 VALUES(42, '!!!!');
> INSERT INTO foo2 VALUES(42, '????');
> INSERT INTO foo2 VALUES(42, '####');
> INSERT INTO foo2 VALUES(45, '$$$$');
>
> CREATE OR REPLACE FUNCTION getfoo(int) RETURNS SETOF text AS '
>    SELECT b FROM foo WHERE a = $1
> ' language 'sql';
>
> CREATE OR REPLACE FUNCTION getfoo2(int) RETURNS SETOF text AS '
>    SELECT b FROM foo2 WHERE a = $1
> ' language 'sql';
>
> regression=# SELECT f1, f2, getfoo(f3) AS f4 FROM bar;
>   f1 |  f2   |    f4
> ----+-------+----------
>    1 | Hello | World
>    1 | Hello | Everyone
>    2 | Happy | Birthday
>    2 | Happy | New Year
> (4 rows)
>
> regression=# SELECT f1, f2, getfoo(f3) AS f4, getfoo2(f3) AS f5 FROM bar;
> ERROR:  Only one target list entry may return a set result
>

> Index: src/backend/parser/parse_clause.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_clause.c,v
> retrieving revision 1.103
> diff -c -r1.103 parse_clause.c
> *** src/backend/parser/parse_clause.c    16 Dec 2002 18:39:22 -0000    1.103
> --- src/backend/parser/parse_clause.c    12 Jan 2003 19:23:57 -0000
> ***************
> *** 1121,1127 ****
>        * the end of the target list.    This target is given resjunk = TRUE so
>        * that it will not be projected into the final tuple.
>        */
> !     target_result = transformTargetEntry(pstate, node, expr, NULL, true);
>       lappend(tlist, target_result);
>
>       return target_result;
> --- 1121,1127 ----
>        * the end of the target list.    This target is given resjunk = TRUE so
>        * that it will not be projected into the final tuple.
>        */
> !     target_result = transformTargetEntry(pstate, node, expr, NULL, true, NULL);
>       lappend(tlist, target_result);
>
>       return target_result;
> Index: src/backend/parser/parse_target.c
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_target.c,v
> retrieving revision 1.94
> diff -c -r1.94 parse_target.c
> *** src/backend/parser/parse_target.c    12 Dec 2002 20:35:13 -0000    1.94
> --- src/backend/parser/parse_target.c    12 Jan 2003 19:25:16 -0000
> ***************
> *** 42,54 ****
>    * colname    the column name to be assigned, or NULL if none yet set.
>    * resjunk    true if the target should be marked resjunk, ie, it is not
>    *            wanted in the final projected tuple.
>    */
>   TargetEntry *
>   transformTargetEntry(ParseState *pstate,
>                        Node *node,
>                        Node *expr,
>                        char *colname,
> !                      bool resjunk)
>   {
>       Oid            type_id;
>       int32        type_mod;
> --- 42,57 ----
>    * colname    the column name to be assigned, or NULL if none yet set.
>    * resjunk    true if the target should be marked resjunk, ie, it is not
>    *            wanted in the final projected tuple.
> +  * retset    if non-NULL, and the entry is a function expression, pass back
> +  *            expr->funcretset
>    */
>   TargetEntry *
>   transformTargetEntry(ParseState *pstate,
>                        Node *node,
>                        Node *expr,
>                        char *colname,
> !                      bool resjunk,
> !                      bool *retset)
>   {
>       Oid            type_id;
>       int32        type_mod;
> ***************
> *** 61,66 ****
> --- 64,72 ----
>       if (IsA(expr, RangeVar))
>           elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
>
> +     if (retset && IsA(expr, FuncExpr))
> +         *retset = ((FuncExpr *) expr)->funcretset;
> +
>       type_id = exprType(expr);
>       type_mod = exprTypmod(expr);
>
> ***************
> *** 93,102 ****
> --- 99,110 ----
>   List *
>   transformTargetList(ParseState *pstate, List *targetlist)
>   {
> +     bool        retset = false;
>       List       *p_target = NIL;
>
>       while (targetlist != NIL)
>       {
> +         bool        entry_retset = false;
>           ResTarget  *res = (ResTarget *) lfirst(targetlist);
>
>           if (IsA(res->val, ColumnRef))
> ***************
> *** 173,179 ****
>                                                           res->val,
>                                                           NULL,
>                                                           res->name,
> !                                                         false));
>               }
>           }
>           else if (IsA(res->val, InsertDefault))
> --- 181,188 ----
>                                                           res->val,
>                                                           NULL,
>                                                           res->name,
> !                                                         false,
> !                                                         &entry_retset));
>               }
>           }
>           else if (IsA(res->val, InsertDefault))
> ***************
> *** 194,201 ****
>                                                       res->val,
>                                                       NULL,
>                                                       res->name,
> !                                                     false));
>           }
>
>           targetlist = lnext(targetlist);
>       }
> --- 203,217 ----
>                                                       res->val,
>                                                       NULL,
>                                                       res->name,
> !                                                     false,
> !                                                     &entry_retset));
>           }
> +
> +         if (retset && entry_retset)
> +             elog(ERROR, "Only one target list entry may return a set result");
> +
> +         if (entry_retset)
> +             retset = true;
>
>           targetlist = lnext(targetlist);
>       }
> Index: src/include/parser/parse_target.h
> ===================================================================
> RCS file: /opt/src/cvs/pgsql-server/src/include/parser/parse_target.h,v
> retrieving revision 1.27
> diff -c -r1.27 parse_target.h
> *** src/include/parser/parse_target.h    18 Sep 2002 21:35:24 -0000    1.27
> --- src/include/parser/parse_target.h    12 Jan 2003 19:08:56 -0000
> ***************
> *** 20,26 ****
>   extern List *transformTargetList(ParseState *pstate, List *targetlist);
>   extern TargetEntry *transformTargetEntry(ParseState *pstate,
>                        Node *node, Node *expr,
> !                      char *colname, bool resjunk);
>   extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
>                         char *colname, int attrno,
>                         List *indirection);
> --- 20,26 ----
>   extern List *transformTargetList(ParseState *pstate, List *targetlist);
>   extern TargetEntry *transformTargetEntry(ParseState *pstate,
>                        Node *node, Node *expr,
> !                      char *colname, bool resjunk, bool *retset);
>   extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
>                         char *colname, int attrno,
>                         List *indirection);

>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to majordomo@postgresql.org so that your
> message can get through to the mailing list cleanly

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: pg_dump a specific schema
Next
From: Rod Taylor
Date:
Subject: Re: ALTER TABLE .. SET WITHOUT OIDS -- ROUND 2