Thread: Re: [DOCS] bug in 8.0 manual, section 37.6, PL/Perl Triggers

Re: [DOCS] bug in 8.0 manual, section 37.6, PL/Perl Triggers

From
Bruce Momjian
Date:
Rainer Brandt wrote:
> Hi,
>
> All places that mention the trigger event info hash pointer $_TD
> end with the "->" characters.  The hash keys are omitted.
> That is certainly not what you wanted.
> (Also, the code examples will not compile under Perl.  (I didn't
> try, but can see that they won't.))
>
> Probably due to the character '>' and some Docbook -> HTML conversion?

Good catch. I have fixed CVS HEAD and 8.0.X.  Patch attached.  Thanks.

--
  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
Index: doc/src/sgml/cvs.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/cvs.sgml,v
retrieving revision 1.30
diff -c -c -r1.30 cvs.sgml
*** doc/src/sgml/cvs.sgml    6 Jan 2005 01:49:22 -0000    1.30
--- doc/src/sgml/cvs.sgml    22 Jan 2005 21:33:58 -0000
***************
*** 214,220 ****
     <programlisting>
               file1   file2   file3   file4   file5

!              1.1     1.1     1.1     1.1  /--1.1*      <-*-  TAG
               1.2*-   1.2     1.2    -1.2*-
               1.3  \- 1.3*-   1.3   / 1.3
               1.4          \  1.4  /  1.4
--- 214,220 ----
     <programlisting>
               file1   file2   file3   file4   file5

!              1.1     1.1     1.1     1.1  /--1.1*      <-*-  TAG
               1.2*-   1.2     1.2    -1.2*-
               1.3  \- 1.3*-   1.3   / 1.3
               1.4          \  1.4  /  1.4
Index: doc/src/sgml/indexcost.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/indexcost.sgml,v
retrieving revision 2.18
diff -c -c -r2.18 indexcost.sgml
*** doc/src/sgml/indexcost.sgml    29 Nov 2003 19:51:37 -0000    2.18
--- doc/src/sgml/indexcost.sgml    22 Jan 2005 21:33:59 -0000
***************
*** 205,211 ****

       <programlisting>
  *indexSelectivity = clauselist_selectivity(root, indexQuals,
!                                            rel->relid, JOIN_INNER);
       </programlisting>
      </para>
     </step>
--- 205,211 ----

       <programlisting>
  *indexSelectivity = clauselist_selectivity(root, indexQuals,
!                                            rel->relid, JOIN_INNER);
       </programlisting>
      </para>
     </step>
Index: doc/src/sgml/plhandler.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/plhandler.sgml,v
retrieving revision 1.4
diff -c -c -r1.4 plhandler.sgml
*** doc/src/sgml/plhandler.sgml    5 Jan 2005 23:42:03 -0000    1.4
--- doc/src/sgml/plhandler.sgml    22 Jan 2005 21:33:59 -0000
***************
*** 121,127 ****
          /*
           * Called as a trigger procedure
           */
!         TriggerData    *trigdata = (TriggerData *) fcinfo->context;

          retval = ...
      }
--- 121,127 ----
          /*
           * Called as a trigger procedure
           */
!         TriggerData    *trigdata = (TriggerData *) fcinfo->context;

          retval = ...
      }
Index: doc/src/sgml/release.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/release.sgml,v
retrieving revision 1.321
diff -c -c -r1.321 release.sgml
*** doc/src/sgml/release.sgml    15 Jan 2005 21:11:46 -0000    1.321
--- doc/src/sgml/release.sgml    22 Jan 2005 21:34:22 -0000
***************
*** 7138,7144 ****
       <programlisting>
  Fix many CLUSTER failures (Tom)
  Allow ALTER TABLE RENAME works on indexes (Tom)
! Fix plpgsql to handle datetime->timestamp and timespan->interval (Bruce)
  New configure --with-setproctitle switch to use setproctitle() (Marc, Bruce)
  Fix the off by one errors in ResultSet from 6.5.3, and more.
  jdbc ResultSet fixes (Joseph Shraibman)
--- 7138,7144 ----
       <programlisting>
  Fix many CLUSTER failures (Tom)
  Allow ALTER TABLE RENAME works on indexes (Tom)
! Fix plpgsql to handle datetime->timestamp and timespan->interval (Bruce)
  New configure --with-setproctitle switch to use setproctitle() (Marc, Bruce)
  Fix the off by one errors in ResultSet from 6.5.3, and more.
  jdbc ResultSet fixes (Joseph Shraibman)
***************
*** 8017,8023 ****
       <programlisting>
  Bug Fixes
  ---------
! Fix text<->float8 and text<->float4 conversion functions(Thomas)
  Fix for creating tables with mixed-case constraints(Billy)
  Change exp()/pow() behavior to generate error on underflow/overflow(Jan)
  Fix bug in pg_dump -z
--- 8017,8023 ----
       <programlisting>
  Bug Fixes
  ---------
! Fix text<->float8 and text<->float4 conversion functions(Thomas)
  Fix for creating tables with mixed-case constraints(Billy)
  Change exp()/pow() behavior to generate error on underflow/overflow(Jan)
  Fix bug in pg_dump -z
***************
*** 9225,9231 ****
          using an axis-crossing algorithm(Thomas)
  Add routine to convert circle-box(Thomas)
  Merge conflicting operators for different geometric data types(Thomas)
! Replace distance operator "<===>" with "<->"(Thomas)
  Replace "above" operator "!^" with ">^" and "below" operator "!|" with "<^"(Thomas)
  Add routines for text trimming on both ends, substring, and string position(Thomas)
  Added conversion routines circle(box) and poly(circle)(Thomas)
--- 9225,9231 ----
          using an axis-crossing algorithm(Thomas)
  Add routine to convert circle-box(Thomas)
  Merge conflicting operators for different geometric data types(Thomas)
! Replace distance operator "<===>" with "<->"(Thomas)
  Replace "above" operator "!^" with ">^" and "below" operator "!|" with "<^"(Thomas)
  Add routines for text trimming on both ends, substring, and string position(Thomas)
  Added conversion routines circle(box) and poly(circle)(Thomas)
***************
*** 10093,10101 ****
     char(N), varchar(N), date and time.

     The following are aliases to existing postgres types:
!                 smallint -> int2
!                 integer, int -> int4
!                 float, real  -> float4
     char(N) and varchar(N) are implemented as truncated text types. In
     addition, char(N) does blank-padding.
   * single-quote (') is used for quoting string literals; '' (in addition to
--- 10093,10101 ----
     char(N), varchar(N), date and time.

     The following are aliases to existing postgres types:
!                 smallint -> int2
!                 integer, int -> int4
!                 float, real  -> float4
     char(N) and varchar(N) are implemented as truncated text types. In
     addition, char(N) does blank-padding.
   * single-quote (') is used for quoting string literals; '' (in addition to
Index: doc/src/sgml/rules.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/rules.sgml,v
retrieving revision 1.37
diff -c -c -r1.37 rules.sgml
*** doc/src/sgml/rules.sgml    30 Dec 2004 03:13:56 -0000    1.37
--- doc/src/sgml/rules.sgml    22 Jan 2005 21:34:27 -0000
***************
*** 1565,1590 ****

  <literallayout class="monospaced">
  Nested Loop
!   ->  Merge Join
!         ->  Seq Scan
!               ->  Sort
!                     ->  Seq Scan on s
!         ->  Seq Scan
!               ->  Sort
!                     ->  Seq Scan on shoelace_arrive
!   ->  Seq Scan on shoelace_data
  </literallayout>

      while omitting the extra range table entry would result in a

  <literallayout class="monospaced">
  Merge Join
!   ->  Seq Scan
!         ->  Sort
!               ->  Seq Scan on s
!   ->  Seq Scan
!         ->  Sort
!               ->  Seq Scan on shoelace_arrive
  </literallayout>

      which produces exactly the same entries in the log table.  Thus,
--- 1565,1590 ----

  <literallayout class="monospaced">
  Nested Loop
!   ->  Merge Join
!         ->  Seq Scan
!               ->  Sort
!                     ->  Seq Scan on s
!         ->  Seq Scan
!               ->  Sort
!                     ->  Seq Scan on shoelace_arrive
!   ->  Seq Scan on shoelace_data
  </literallayout>

      while omitting the extra range table entry would result in a

  <literallayout class="monospaced">
  Merge Join
!   ->  Seq Scan
!         ->  Sort
!               ->  Seq Scan on s
!   ->  Seq Scan
!         ->  Sort
!               ->  Seq Scan on shoelace_arrive
  </literallayout>

      which produces exactly the same entries in the log table.  Thus,
***************
*** 1943,1950 ****

  <literallayout class="monospaced">
  Nestloop
!   ->  Index Scan using comp_hostidx on computer
!   ->  Index Scan using soft_hostidx on software
  </literallayout>

      So there would be not that much difference in speed between
--- 1943,1950 ----

  <literallayout class="monospaced">
  Nestloop
!   ->  Index Scan using comp_hostidx on computer
!   ->  Index Scan using soft_hostidx on software
  </literallayout>

      So there would be not that much difference in speed between
***************
*** 1973,1981 ****

  <literallayout class="monospaced">
  Hash Join
!   ->  Seq Scan on software
!   ->  Hash
!     ->  Index Scan using comp_hostidx on computer
  </literallayout>

      The other possible command is
--- 1973,1981 ----

  <literallayout class="monospaced">
  Hash Join
!   ->  Seq Scan on software
!   ->  Hash
!     ->  Index Scan using comp_hostidx on computer
  </literallayout>

      The other possible command is
***************
*** 1989,1996 ****

  <literallayout class="monospaced">
  Nestloop
!   ->  Index Scan using comp_hostidx on computer
!   ->  Index Scan using soft_hostidx on software
  </literallayout>

      This shows, that the planner does not realize that the
--- 1989,1996 ----

  <literallayout class="monospaced">
  Nestloop
!   ->  Index Scan using comp_hostidx on computer
!   ->  Index Scan using soft_hostidx on software
  </literallayout>

      This shows, that the planner does not realize that the
***************
*** 2030,2037 ****

  <ProgramListing>
  Nestloop
!   ->  Index Scan using comp_manufidx on computer
!   ->  Index Scan using soft_hostidx on software
  </ProgramListing>

      In any of these cases, the extra commands from the rule system
--- 2030,2037 ----

  <ProgramListing>
  Nestloop
!   ->  Index Scan using comp_manufidx on computer
!   ->  Index Scan using soft_hostidx on software
  </ProgramListing>

      In any of these cases, the extra commands from the rule system
Index: doc/src/sgml/spi.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v
retrieving revision 1.37
diff -c -c -r1.37 spi.sgml
*** doc/src/sgml/spi.sgml    30 Dec 2004 21:45:37 -0000    1.37
--- doc/src/sgml/spi.sgml    22 Jan 2005 21:34:32 -0000
***************
*** 2931,2949 ****
       */
      if (ret == SPI_OK_SELECT && SPI_processed > 0)
      {
!         TupleDesc tupdesc = SPI_tuptable->tupdesc;
          SPITupleTable *tuptable = SPI_tuptable;
          char buf[8192];
          int i, j;

          for (j = 0; j < proc; j++)
          {
!             HeapTuple tuple = tuptable->vals[j];

!             for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
                  snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
                          SPI_getvalue(tuple, tupdesc, i),
!                         (i == tupdesc->natts) ? " " : " |");
              elog (INFO, "EXECQ: %s", buf);
          }
      }
--- 2931,2949 ----
       */
      if (ret == SPI_OK_SELECT && SPI_processed > 0)
      {
!         TupleDesc tupdesc = SPI_tuptable->tupdesc;
          SPITupleTable *tuptable = SPI_tuptable;
          char buf[8192];
          int i, j;

          for (j = 0; j < proc; j++)
          {
!             HeapTuple tuple = tuptable->vals[j];

!             for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
                  snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
                          SPI_getvalue(tuple, tupdesc, i),
!                         (i == tupdesc->natts) ? " " : " |");
              elog (INFO, "EXECQ: %s", buf);
          }
      }
Index: doc/src/sgml/trigger.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v
retrieving revision 1.39
diff -c -c -r1.39 trigger.sgml
*** doc/src/sgml/trigger.sgml    30 Dec 2004 03:13:56 -0000    1.39
--- doc/src/sgml/trigger.sgml    22 Jan 2005 21:34:33 -0000
***************
*** 271,280 ****
  </programlisting>
      which expands to
  <programlisting>
! ((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
  </programlisting>
      If this returns true, then it is safe to cast
!     <literal>fcinfo->context</> to type <literal>TriggerData
      *</literal> and make use of the pointed-to
      <structname>TriggerData</> structure.  The function must
      <emphasis>not</emphasis> alter the <structname>TriggerData</>
--- 271,280 ----
  </programlisting>
      which expands to
  <programlisting>
! ((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
  </programlisting>
      If this returns true, then it is safe to cast
!     <literal>fcinfo->context</> to type <literal>TriggerData
      *</literal> and make use of the pointed-to
      <structname>TriggerData</> structure.  The function must
      <emphasis>not</emphasis> alter the <structname>TriggerData</>
***************
*** 393,400 ****
          A pointer to a structure describing the relation that the trigger fired for.
          Look at <filename>utils/rel.h</> for details about
          this structure.  The most interesting things are
!         <literal>tg_relation->rd_att</> (descriptor of the relation
!         tuples) and <literal>tg_relation->rd_rel->relname</>
          (relation name; the type is not <type>char*</> but
          <type>NameData</>; use
          <literal>SPI_getrelname(tg_relation)</> to get a <type>char*</> if you
--- 393,400 ----
          A pointer to a structure describing the relation that the trigger fired for.
          Look at <filename>utils/rel.h</> for details about
          this structure.  The most interesting things are
!         <literal>tg_relation->rd_att</> (descriptor of the relation
!         tuples) and <literal>tg_relation->rd_rel->relname</>
          (relation name; the type is not <type>char*</> but
          <type>NameData</>; use
          <literal>SPI_getrelname(tg_relation)</> to get a <type>char*</> if you
***************
*** 541,547 ****
  Datum
  trigf(PG_FUNCTION_ARGS)
  {
!     TriggerData *trigdata = (TriggerData *) fcinfo->context;
      TupleDesc   tupdesc;
      HeapTuple   rettuple;
      char       *when;
--- 541,547 ----
  Datum
  trigf(PG_FUNCTION_ARGS)
  {
!     TriggerData *trigdata = (TriggerData *) fcinfo->context;
      TupleDesc   tupdesc;
      HeapTuple   rettuple;
      char       *when;
***************
*** 554,575 ****
          elog(ERROR, "trigf: not called by trigger manager");

      /* tuple to return to executor */
!     if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
!         rettuple = trigdata->tg_newtuple;
      else
!         rettuple = trigdata->tg_trigtuple;

      /* check for null values */
!     if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)
!         && TRIGGER_FIRED_BEFORE(trigdata->tg_event))
          checknull = true;

!     if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
          when = "before";
      else
          when = "after ";

!     tupdesc = trigdata->tg_relation->rd_att;

      /* connect to SPI manager */
      if ((ret = SPI_connect()) < 0)
--- 554,575 ----
          elog(ERROR, "trigf: not called by trigger manager");

      /* tuple to return to executor */
!     if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
!         rettuple = trigdata->tg_newtuple;
      else
!         rettuple = trigdata->tg_trigtuple;

      /* check for null values */
!     if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)
!         && TRIGGER_FIRED_BEFORE(trigdata->tg_event))
          checknull = true;

!     if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
          when = "before";
      else
          when = "after ";

!     tupdesc = trigdata->tg_relation->rd_att;

      /* connect to SPI manager */
      if ((ret = SPI_connect()) < 0)
***************
*** 582,589 ****
          elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when, ret);

      /* count(*) returns int8, so be careful to convert */
!     i = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[0],
!                                     SPI_tuptable->tupdesc,
                                      1,
                                      &isnull));

--- 582,589 ----
          elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when, ret);

      /* count(*) returns int8, so be careful to convert */
!     i = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[0],
!                                     SPI_tuptable->tupdesc,
                                      1,
                                      &isnull));

Index: doc/src/sgml/xfunc.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v
retrieving revision 1.96
diff -c -c -r1.96 xfunc.sgml
*** doc/src/sgml/xfunc.sgml    14 Jan 2005 21:46:09 -0000    1.96
--- doc/src/sgml/xfunc.sgml    22 Jan 2005 21:34:44 -0000
***************
*** 1482,1489 ****
  {
      Point     *new_point = (Point *) palloc(sizeof(Point));

!     new_point->x = pointx->x;
!     new_point->y = pointy->y;

      return new_point;
  }
--- 1482,1489 ----
  {
      Point     *new_point = (Point *) palloc(sizeof(Point));

!     new_point->x = pointx->x;
!     new_point->y = pointy->y;

      return new_point;
  }
***************
*** 1665,1672 ****
      Point     *pointy = PG_GETARG_POINT_P(1);
      Point     *new_point = (Point *) palloc(sizeof(Point));

!     new_point->x = pointx->x;
!     new_point->y = pointy->y;

      PG_RETURN_POINT_P(new_point);
  }
--- 1665,1672 ----
      Point     *pointy = PG_GETARG_POINT_P(1);
      Point     *new_point = (Point *) palloc(sizeof(Point));

!     new_point->x = pointx->x;
!     new_point->y = pointy->y;

      PG_RETURN_POINT_P(new_point);
  }
***************
*** 2447,2453 ****
      if (SRF_IS_FIRSTCALL())
      {
          funcctx = SRF_FIRSTCALL_INIT();
!         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
          /* One-time setup code appears here: */
          <replaceable>user code</replaceable>
          <replaceable>if returning composite</replaceable>
--- 2447,2453 ----
      if (SRF_IS_FIRSTCALL())
      {
          funcctx = SRF_FIRSTCALL_INIT();
!         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
          /* One-time setup code appears here: */
          <replaceable>user code</replaceable>
          <replaceable>if returning composite</replaceable>
***************
*** 2503,2509 ****
          funcctx = SRF_FIRSTCALL_INIT();

          /* switch to memory context appropriate for multiple function calls */
!         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

          /* total number of tuples to be returned */
          funcctx->max_calls = PG_GETARG_UINT32(0);
--- 2503,2509 ----
          funcctx = SRF_FIRSTCALL_INIT();

          /* switch to memory context appropriate for multiple function calls */
!         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

          /* total number of tuples to be returned */
          funcctx->max_calls = PG_GETARG_UINT32(0);