Re: [NOVICE] connectby(... pos_of_sibling) - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [NOVICE] connectby(... pos_of_sibling)
Date
Msg-id 200307180350.h6I3oBt02636@candle.pha.pa.us
Whole thread Raw
Responses Re: [NOVICE] connectby(... pos_of_sibling)  (Joe Conway <mail@joeconway.com>)
List pgsql-patches
Joe, would you comment on this change to tablefunc connectby?

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

Nabil Sayegh wrote:
> Am Son, 2003-06-22 um 02.09 schrieb Joe Conway:
>
> > Sounds like all that's needed for your case. But to be complete, in
> > addition to changing tablefunc.c we'd have to:
> > 1) come up with a new function call signature that makes sense and does
> > not cause backward compatibility problems for other people
> > 2) make needed changes to tablefunc.sql.in
> > 3) adjust the README.tablefunc appropriately
> > 4) adjust the regression test for new functionality
> > 5) be sure we don't break any of the old cases
> >
> > If you want to submit a complete patch, it would be gratefully accepted
> > -- for review at least ;-)
>
> Here's the patch, at least for steps 1-3
> I don't know anything about regression tests :(
>
> However, I included a patch against 7.3.3
>
> bye
> --
>  e-Trolley Sayegh & John, Nabil Sayegh
>  Tel.: 0700 etrolley /// 0700 38765539
>  Fax.: +49 69 8299381-8
>  PGP : http://www.e-trolley.de

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster

--
  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
diff -rc postgresql-7.3.3/contrib/tablefunc/README.tablefunc
postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/README.tablefunc
*** postgresql-7.3.3/contrib/tablefunc/README.tablefunc    Sat Nov 23 02:54:23 2002
--- postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/README.tablefunc    Wed Jun 25 19:54:01 2003
***************
*** 60,68 ****
        - requires anonymous composite type syntax in the FROM clause. See
          the instructions in the documentation below.

!     connectby(text relname, text keyid_fld, text parent_keyid_fld,
!                 text start_with, int max_depth [, text branch_delim])
        - returns keyid, parent_keyid, level, and an optional branch string
        - requires anonymous composite type syntax in the FROM clause. See
          the instructions in the documentation below.

--- 60,70 ----
        - requires anonymous composite type syntax in the FROM clause. See
          the instructions in the documentation below.

!     connectby(text relname, text keyid_fld, text parent_keyid_fld
!                 [, text orderby_fld], text start_with, int max_depth
!                                 [, text branch_delim])
        - returns keyid, parent_keyid, level, and an optional branch string
+         and an optional serial column for ordering siblings
        - requires anonymous composite type syntax in the FROM clause. See
          the instructions in the documentation below.

***************
*** 333,345 ****
  ==================================================================
  Name

! connectby(text, text, text, text, int[, text]) - returns a set
      representing a hierarchy (tree structure)

  Synopsis

! connectby(text relname, text keyid_fld, text parent_keyid_fld,
!             text start_with, int max_depth [, text branch_delim])

  Inputs

--- 335,348 ----
  ==================================================================
  Name

! connectby(text, text, text[, text], text, text, int[, text]) - returns a set
      representing a hierarchy (tree structure)

  Synopsis

! connectby(text relname, text keyid_fld, text parent_keyid_fld
!             [, text orderby_fld], text start_with, int max_depth
!                         [, text branch_delim])

  Inputs

***************
*** 355,360 ****
--- 358,368 ----

      Name of the key_parent field

+   orderby_fld
+
+     If optional ordering of siblings is desired:
+     Name of the field to order siblings
+
    start_with

      root value of the tree input as a text value regardless of keyid_fld type
***************
*** 381,386 ****
--- 389,404 ----

      SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0)
        AS t(keyid text, parent_keyid text, level int);
+
+         - or -
+
+     SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~')
+       AS t(keyid text, parent_keyid text, level int, branch text, pos int);
+
+         - or -
+
+     SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0)
+       AS t(keyid text, parent_keyid text, level int, pos int);

  Notes

***************
*** 401,422 ****
    5. The parameters representing table and field names must include double
       quotes if the names are mixed-case or contain special characters.


  Example usage

! CREATE TABLE connectby_tree(keyid text, parent_keyid text);

! INSERT INTO connectby_tree VALUES('row1',NULL);
! INSERT INTO connectby_tree VALUES('row2','row1');
! INSERT INTO connectby_tree VALUES('row3','row1');
! INSERT INTO connectby_tree VALUES('row4','row2');
! INSERT INTO connectby_tree VALUES('row5','row2');
! INSERT INTO connectby_tree VALUES('row6','row4');
! INSERT INTO connectby_tree VALUES('row7','row3');
! INSERT INTO connectby_tree VALUES('row8','row6');
! INSERT INTO connectby_tree VALUES('row9','row5');

! -- with branch
  SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0, '~')
   AS t(keyid text, parent_keyid text, level int, branch text);
   keyid | parent_keyid | level |       branch
--- 419,443 ----
    5. The parameters representing table and field names must include double
       quotes if the names are mixed-case or contain special characters.

+   6. If sorting of siblings is desired, the orderby_fld input parameter *and*
+      a name for the resulting serial field (type INT32) in the query column
+      definition must be given.

  Example usage

! CREATE TABLE connectby_tree(keyid text, parent_keyid text, pos int);

! INSERT INTO connectby_tree VALUES('row1',NULL, 0);
! INSERT INTO connectby_tree VALUES('row2','row1', 0);
! INSERT INTO connectby_tree VALUES('row3','row1', 0);
! INSERT INTO connectby_tree VALUES('row4','row2', 1);
! INSERT INTO connectby_tree VALUES('row5','row2', 0);
! INSERT INTO connectby_tree VALUES('row6','row4', 0);
! INSERT INTO connectby_tree VALUES('row7','row3', 0);
! INSERT INTO connectby_tree VALUES('row8','row6', 0);
! INSERT INTO connectby_tree VALUES('row9','row5', 0);

! -- with branch, without orderby_fld
  SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0, '~')
   AS t(keyid text, parent_keyid text, level int, branch text);
   keyid | parent_keyid | level |       branch
***************
*** 429,435 ****
   row9  | row5         |     2 | row2~row5~row9
  (6 rows)

! -- without branch
  SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0)
   AS t(keyid text, parent_keyid text, level int);
   keyid | parent_keyid | level
--- 450,456 ----
   row9  | row5         |     2 | row2~row5~row9
  (6 rows)

! -- without branch, without orderby_fld
  SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'row2', 0)
   AS t(keyid text, parent_keyid text, level int);
   keyid | parent_keyid | level
***************
*** 442,447 ****
--- 463,494 ----
   row9  | row5         |     2
  (6 rows)

+ -- with branch, with orderby_fld (notice that row5 comes before row4)
+ SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~')
+  AS t(keyid text, parent_keyid text, level int, branch text, pos int) ORDER BY t.pos;
+  keyid | parent_keyid | level |       branch        | pos
+ -------+--------------+-------+---------------------+-----
+  row2  |              |     0 | row2                |   1
+  row5  | row2         |     1 | row2~row5           |   2
+  row9  | row5         |     2 | row2~row5~row9      |   3
+  row4  | row2         |     1 | row2~row4           |   4
+  row6  | row4         |     2 | row2~row4~row6      |   5
+  row8  | row6         |     3 | row2~row4~row6~row8 |   6
+ (6 rows)
+
+ -- without branch, with orderby_fld (notice that row5 comes before row4)
+ SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid', 'pos', 'row2', 0)
+  AS t(keyid text, parent_keyid text, level int, pos int) ORDER BY t.pos;
+  keyid | parent_keyid | level | pos
+ -------+--------------+-------+-----
+  row2  |              |     0 |   1
+  row5  | row2         |     1 |   2
+  row9  | row5         |     2 |   3
+  row4  | row2         |     1 |   4
+  row6  | row4         |     2 |   5
+  row8  | row6         |     3 |   6
+ (6 rows)
+
  ==================================================================
  -- Joe Conway

diff -rc postgresql-7.3.3/contrib/tablefunc/tablefunc.c
postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/tablefunc.c
*** postgresql-7.3.3/contrib/tablefunc/tablefunc.c    Fri May 16 08:07:58 2003
--- postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/tablefunc.c    Wed Jun 25 19:58:28 2003
***************
*** 39,45 ****

  #include "tablefunc.h"

! static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch);
  static bool compatCrosstabTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
  static bool compatConnectbyTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
  static void get_normal_pair(float8 *x1, float8 *x2);
--- 39,45 ----

  #include "tablefunc.h"

! static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial);
  static bool compatCrosstabTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
  static bool compatConnectbyTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
  static void get_normal_pair(float8 *x1, float8 *x2);
***************
*** 48,68 ****
--- 48,73 ----
  static Tuplestorestate *connectby(char *relname,
            char *key_fld,
            char *parent_key_fld,
+             char *orderby_fld,
            char *branch_delim,
            char *start_with,
            int max_depth,
            bool show_branch,
+           bool show_serial,
            MemoryContext per_query_ctx,
            AttInMetadata *attinmeta);
  static Tuplestorestate *build_tuplestore_recursively(char *key_fld,
                               char *parent_key_fld,
                               char *relname,
+                              char *orderby_fld,
                               char *branch_delim,
                               char *start_with,
                               char *branch,
                               int level,
+                              int *serial,
                               int max_depth,
                               bool show_branch,
+                              bool show_serial,
                               MemoryContext per_query_ctx,
                               AttInMetadata *attinmeta,
                               Tuplestorestate *tupstore);
***************
*** 598,628 ****
   *
   * e.g. given table foo:
   *
!  *            keyid    parent_keyid
!  *            ------+--------------
!  *            row1    NULL
!  *            row2    row1
!  *            row3    row1
!  *            row4    row2
!  *            row5    row2
!  *            row6    row4
!  *            row7    row3
!  *            row8    row6
!  *            row9    row5
   *
   *
!  * connectby(text relname, text keyid_fld, text parent_keyid_fld,
!  *                        text start_with, int max_depth [, text branch_delim])
!  * connectby('foo', 'keyid', 'parent_keyid', 'row2', 0, '~') returns:
   *
!  *        keyid    parent_id    level     branch
   *        ------+-----------+--------+-----------------------
!  *        row2    NULL          0          row2
!  *        row4    row2          1          row2~row4
!  *        row6    row4          2          row2~row4~row6
!  *        row8    row6          3          row2~row4~row6~row8
!  *        row5    row2          1          row2~row5
!  *        row9    row5          2          row2~row5~row9
   *
   */
  PG_FUNCTION_INFO_V1(connectby_text);
--- 603,634 ----
   *
   * e.g. given table foo:
   *
!  *            keyid    parent_keyid pos
!  *            ------+------------+--
!  *            row1    NULL         0
!  *            row2    row1         0
!  *            row3    row1         0
!  *            row4    row2         1
!  *            row5    row2         0
!  *            row6    row4         0
!  *            row7    row3         0
!  *            row8    row6         0
!  *            row9    row5         0
   *
   *
!  * connectby(text relname, text keyid_fld, text parent_keyid_fld
!  *            [, text orderby_fld], text start_with, int max_depth
!  *            [, text branch_delim])
!  * connectby('foo', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~') returns:
   *
!  *        keyid    parent_id    level     branch             serial
   *        ------+-----------+--------+-----------------------
!  *        row2    NULL          0          row2                1
!  *        row5    row2          1          row2~row5           2
!  *        row9    row5          2          row2~row5~row9      3
!  *        row4    row2          1          row2~row4           4
!  *        row6    row4          2          row2~row4~row6      5
!  *        row8    row6          3          row2~row4~row6~row8 6
   *
   */
  PG_FUNCTION_INFO_V1(connectby_text);
***************
*** 640,645 ****
--- 646,652 ----
      int            max_depth = PG_GETARG_INT32(4);
      char       *branch_delim = NULL;
      bool        show_branch = false;
+     bool        show_serial = false;
      ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
      TupleDesc    tupdesc;
      AttInMetadata *attinmeta;
***************
*** 667,673 ****
      tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);

      /* does it meet our needs */
!     validateConnectbyTupleDesc(tupdesc, show_branch);

      /* OK, use it then */
      attinmeta = TupleDescGetAttInMetadata(tupdesc);
--- 674,680 ----
      tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);

      /* does it meet our needs */
!     validateConnectbyTupleDesc(tupdesc, show_branch, show_serial);

      /* OK, use it then */
      attinmeta = TupleDescGetAttInMetadata(tupdesc);
***************
*** 682,691 ****
--- 689,700 ----
      rsinfo->setResult = connectby(relname,
                                    key_fld,
                                    parent_key_fld,
+                                     NULL,
                                    branch_delim,
                                    start_with,
                                    max_depth,
                                    show_branch,
+                                   show_serial,
                                    per_query_ctx,
                                    attinmeta);
      rsinfo->setDesc = tupdesc;
***************
*** 702,707 ****
--- 711,796 ----
      return (Datum) 0;
  }

+ PG_FUNCTION_INFO_V1(connectby_text_serial);
+
+ Datum
+ connectby_text_serial(PG_FUNCTION_ARGS)
+ {
+     char       *relname = GET_STR(PG_GETARG_TEXT_P(0));
+     char       *key_fld = GET_STR(PG_GETARG_TEXT_P(1));
+     char       *parent_key_fld = GET_STR(PG_GETARG_TEXT_P(2));
+     char       *orderby_fld = GET_STR(PG_GETARG_TEXT_P(3));
+     char       *start_with = GET_STR(PG_GETARG_TEXT_P(4));
+     int            max_depth = PG_GETARG_INT32(5);
+     char       *branch_delim = NULL;
+     bool        show_branch = false;
+     bool        show_serial = true;
+
+     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+     TupleDesc    tupdesc;
+     AttInMetadata *attinmeta;
+     MemoryContext per_query_ctx;
+     MemoryContext oldcontext;
+
+     /* check to see if caller supports us returning a tuplestore */
+     if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
+         elog(ERROR, "connectby: materialize mode required, but it is not "
+              "allowed in this context");
+
+     if (fcinfo->nargs == 7)
+     {
+         branch_delim = GET_STR(PG_GETARG_TEXT_P(6));
+         show_branch = true;
+     }
+     else
+         /* default is no show, tilde for the delimiter */
+         branch_delim = pstrdup("~");
+
+     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+     oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+     /* get the requested return tuple description */
+     tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+
+     /* does it meet our needs */
+     validateConnectbyTupleDesc(tupdesc, show_branch, show_serial);
+
+     /* OK, use it then */
+     attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
+     /* check to see if caller supports us returning a tuplestore */
+     if (!rsinfo->allowedModes & SFRM_Materialize)
+         elog(ERROR, "connectby requires Materialize mode, but it is not "
+              "allowed in this context");
+
+     /* OK, go to work */
+     rsinfo->returnMode = SFRM_Materialize;
+     rsinfo->setResult = connectby(relname,
+                                   key_fld,
+                                   parent_key_fld,
+                                     orderby_fld,
+                                   branch_delim,
+                                   start_with,
+                                   max_depth,
+                                   show_branch,
+                                   show_serial,
+                                   per_query_ctx,
+                                   attinmeta);
+     rsinfo->setDesc = tupdesc;
+
+     MemoryContextSwitchTo(oldcontext);
+
+     /*
+      * SFRM_Materialize mode expects us to return a NULL Datum. The actual
+      * tuples are in our tuplestore and passed back through
+      * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
+      * that we actually used to build our tuples with, so the caller can
+      * verify we did what it was expecting.
+      */
+     return (Datum) 0;
+ }
+
+
  /*
   * connectby - does the real work for connectby_text()
   */
***************
*** 709,718 ****
--- 798,809 ----
  connectby(char *relname,
            char *key_fld,
            char *parent_key_fld,
+             char *orderby_fld,
            char *branch_delim,
            char *start_with,
            int max_depth,
            bool show_branch,
+             bool show_serial,
            MemoryContext per_query_ctx,
            AttInMetadata *attinmeta)
  {
***************
*** 720,725 ****
--- 811,818 ----
      int            ret;
      MemoryContext oldcontext;

+     int serial = 1;
+
      /* Connect to SPI manager */
      if ((ret = SPI_connect()) < 0)
          elog(ERROR, "connectby: SPI_connect returned %d", ret);
***************
*** 736,747 ****
--- 829,843 ----
      tupstore = build_tuplestore_recursively(key_fld,
                                              parent_key_fld,
                                              relname,
+                                             orderby_fld,
                                              branch_delim,
                                              start_with,
                                              start_with, /* current_branch */
                                              0,    /* initial level is 0 */
+                                             &serial,    /* initial serial is 1 */
                                              max_depth,
                                              show_branch,
+                                             show_serial,
                                              per_query_ctx,
                                              attinmeta,
                                              tupstore);
***************
*** 759,770 ****
--- 855,869 ----
  build_tuplestore_recursively(char *key_fld,
                               char *parent_key_fld,
                               char *relname,
+                              char *orderby_fld,
                               char *branch_delim,
                               char *start_with,
                               char *branch,
                               int level,
+                              int *serial,
                               int max_depth,
                               bool show_branch,
+                              bool show_serial,
                               MemoryContext per_query_ctx,
                               AttInMetadata *attinmeta,
                               Tuplestorestate *tupstore)
***************
*** 774,791 ****
      StringInfo    sql = makeStringInfo();
      int            ret;
      int            proc;

      if (max_depth > 0 && level > max_depth)
          return tupstore;

      /* Build initial sql statement */
!     appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL",
                       key_fld,
                       parent_key_fld,
                       relname,
                       parent_key_fld,
                       start_with,
                       key_fld);

      /* Retrieve the desired rows */
      ret = SPI_exec(sql->data, 0);
--- 873,907 ----
      StringInfo    sql = makeStringInfo();
      int            ret;
      int            proc;
+     int            serial_column;

      if (max_depth > 0 && level > max_depth)
          return tupstore;

      /* Build initial sql statement */
!     if (!show_serial)
!     {
!         appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL",
                       key_fld,
                       parent_key_fld,
                       relname,
                       parent_key_fld,
                       start_with,
                       key_fld);
+                      serial_column=0;
+     }
+     else
+     {
+         appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL ORDER BY %s",
+                      key_fld,
+                      parent_key_fld,
+                      relname,
+                      parent_key_fld,
+                      start_with,
+                      key_fld,
+                      orderby_fld);
+                      serial_column=1;
+     }

      /* Retrieve the desired rows */
      ret = SPI_exec(sql->data, 0);
***************
*** 802,807 ****
--- 918,924 ----
          char       *current_key;
          char       *current_key_parent;
          char        current_level[INT32_STRLEN];
+         char        serial_str[INT32_STRLEN];
          char       *current_branch;
          char      **values;
          StringInfo    branchstr = NULL;
***************
*** 816,824 ****
          chk_current_key = makeStringInfo();

          if (show_branch)
!             values = (char **) palloc(CONNECTBY_NCOLS * sizeof(char *));
          else
!             values = (char **) palloc(CONNECTBY_NCOLS_NOBRANCH * sizeof(char *));

          /* First time through, do a little setup */
          if (level == 0)
--- 933,941 ----
          chk_current_key = makeStringInfo();

          if (show_branch)
!             values = (char **) palloc((CONNECTBY_NCOLS + serial_column) * sizeof(char *));
          else
!             values = (char **) palloc((CONNECTBY_NCOLS_NOBRANCH + serial_column) * sizeof(char *));

          /* First time through, do a little setup */
          if (level == 0)
***************
*** 847,852 ****
--- 964,979 ----
              if (show_branch)
                  values[3] = start_with;

+             /* root starts the serial with 1 */
+             if (show_serial)
+             {
+                 sprintf(serial_str, "%d", (*serial)++);
+                 if (show_branch)
+                     values[4] = serial_str;
+                 else
+                     values[3] = serial_str;
+             }
+
              /* construct the tuple */
              tuple = BuildTupleFromCStrings(attinmeta, values);

***************
*** 894,899 ****
--- 1021,1034 ----
              values[2] = current_level;
              if (show_branch)
                  values[3] = current_branch;
+             if (show_serial)
+             {
+                 sprintf(serial_str, "%d", (*serial)++);
+                 if (show_branch)
+                     values[4] = serial_str;
+                 else
+                     values[3] = serial_str;
+             }

              tuple = BuildTupleFromCStrings(attinmeta, values);

***************
*** 915,926 ****
--- 1050,1064 ----
              tupstore = build_tuplestore_recursively(key_fld,
                                                      parent_key_fld,
                                                      relname,
+                                                     orderby_fld,
                                                      branch_delim,
                                                      values[0],
                                                      current_branch,
                                                      level + 1,
+                                                     serial,
                                                      max_depth,
                                                      show_branch,
+                                                     show_serial,
                                                      per_query_ctx,
                                                      attinmeta,
                                                      tupstore);
***************
*** 944,961 ****
   * Check expected (query runtime) tupdesc suitable for Connectby
   */
  static void
! validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch)
  {
      /* are there the correct number of columns */
      if (show_branch)
      {
!         if (tupdesc->natts != CONNECTBY_NCOLS)
              elog(ERROR, "Query-specified return tuple not valid for Connectby: "
                   "wrong number of columns");
      }
      else
      {
!         if (tupdesc->natts != CONNECTBY_NCOLS_NOBRANCH)
              elog(ERROR, "Query-specified return tuple not valid for Connectby: "
                   "wrong number of columns");
      }
--- 1082,1104 ----
   * Check expected (query runtime) tupdesc suitable for Connectby
   */
  static void
! validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial)
  {
+     int serial_column=0;
+
+     if (show_serial)
+         serial_column=1;
+
      /* are there the correct number of columns */
      if (show_branch)
      {
!         if (tupdesc->natts != (CONNECTBY_NCOLS + serial_column))
              elog(ERROR, "Query-specified return tuple not valid for Connectby: "
                   "wrong number of columns");
      }
      else
      {
!         if (tupdesc->natts != CONNECTBY_NCOLS_NOBRANCH + serial_column)
              elog(ERROR, "Query-specified return tuple not valid for Connectby: "
                   "wrong number of columns");
      }
***************
*** 973,980 ****
      /* check that the type of the forth column is TEXT if applicable */
      if (show_branch && tupdesc->attrs[3]->atttypid != TEXTOID)
          elog(ERROR, "Query-specified return tuple not valid for Connectby: "
!              "third column must be type %s", format_type_be(TEXTOID));

      /* OK, the tupdesc is valid for our purposes */
  }

--- 1116,1133 ----
      /* check that the type of the forth column is TEXT if applicable */
      if (show_branch && tupdesc->attrs[3]->atttypid != TEXTOID)
          elog(ERROR, "Query-specified return tuple not valid for Connectby: "
!              "fourth column must be type %s", format_type_be(TEXTOID));

+     /* check that the type of the fifth column is INT4 */
+     if (show_branch && show_serial && tupdesc->attrs[4]->atttypid != INT4OID)
+         elog(ERROR, "Query-specified return tuple not valid for Connectby: "
+              "fifth column must be type %s", format_type_be(INT4OID));
+
+     /* check that the type of the fifth column is INT4 */
+     if (!show_branch && show_serial && tupdesc->attrs[3]->atttypid != INT4OID)
+         elog(ERROR, "Query-specified return tuple not valid for Connectby: "
+              "fourth column must be type %s", format_type_be(INT4OID));
+
      /* OK, the tupdesc is valid for our purposes */
  }

diff -rc postgresql-7.3.3/contrib/tablefunc/tablefunc.h
postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/tablefunc.h
*** postgresql-7.3.3/contrib/tablefunc/tablefunc.h    Wed Sep  4 22:31:08 2002
--- postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/tablefunc.h    Wed Jun 25 03:02:02 2003
***************
*** 35,39 ****
--- 35,40 ----
  extern Datum normal_rand(PG_FUNCTION_ARGS);
  extern Datum crosstab(PG_FUNCTION_ARGS);
  extern Datum connectby_text(PG_FUNCTION_ARGS);
+ extern Datum connectby_text_serial(PG_FUNCTION_ARGS);

  #endif   /* TABLEFUNC_H */
diff -rc postgresql-7.3.3/contrib/tablefunc/tablefunc.sql.in
postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/tablefunc.sql.in
*** postgresql-7.3.3/contrib/tablefunc/tablefunc.sql.in    Fri Oct 18 20:41:21 2002
--- postgresql-7.3.3-tablefunc_connectby_orderby_fld/contrib/tablefunc/tablefunc.sql.in    Wed Jun 25 19:23:38 2003
***************
*** 61,63 ****
--- 61,75 ----
  RETURNS setof record
  AS 'MODULE_PATHNAME','connectby_text'
  LANGUAGE 'C' STABLE STRICT;
+
+ -- These 2 take the name of a field to ORDER BY as 4th arg (for sorting siblings)
+
+ CREATE OR REPLACE FUNCTION connectby(text,text,text,text,text,int,text)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','connectby_text_serial'
+ LANGUAGE 'C' STABLE STRICT;
+
+ CREATE OR REPLACE FUNCTION connectby(text,text,text,text,text,int)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','connectby_text_serial'
+ LANGUAGE 'C' STABLE STRICT;

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [GENERAL] bytea char escaping
Next
From: Joe Conway
Date:
Subject: Re: [NOVICE] connectby(... pos_of_sibling)