Table Function API patch (was Re: another SRF question) - Mailing list pgsql-patches

From Joe Conway
Subject Table Function API patch (was Re: another SRF question)
Date
Msg-id 3D2B495F.6030802@joeconway.com
Whole thread Raw
Responses Re: Table Function API patch (was Re: another SRF question)  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: Table Function API patch (was Re: another SRF question)  (Bruce Momjian <pgman@candle.pha.pa.us>)
List pgsql-patches
Neil Conway wrote:
> On Mon, Jul 08, 2002 at 03:52:24PM -0700, Joe Conway wrote:
>>Nice catch. Here's (I think) a proper fix. This assumes that if
>>(values[i] != NULL), the datum is the output of the appropriate "in"
>>function, otherwise the datum is NULL. It saves the extra pass through
>>the dvalues array too.
>>
>>I thought you might want to try it out now without waiting for the patch
>>to get into cvs. I tested it with a contrived test function and it
>>worked as desired.
>
>
> Great, seems to work fine here. Thanks for fixing that for me.
>

Here is a patch for the Table Function API. It fixes a bug found by Neil
Conway (BuildTupleFromCStrings sets NULL for pass-by-value types when
intended value is 0). It also implements some other improvements
suggested by Neil.

If there are no objections, please apply.

Thanks,

Joe


Index: src/backend/executor/execTuples.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/executor/execTuples.c,v
retrieving revision 1.53
diff -c -r1.53 execTuples.c
*** src/backend/executor/execTuples.c    20 Jun 2002 20:29:27 -0000    1.53
--- src/backend/executor/execTuples.c    8 Jul 2002 22:25:14 -0000
***************
*** 759,764 ****
--- 759,765 ----
      natts = tupdesc->natts;

      dvalues = (Datum *) palloc(natts * sizeof(Datum));
+     nulls = (char *) palloc(natts * sizeof(char));

      /* Call the "in" function for each attribute */
      for (i = 0; i < natts; i++)
***************
*** 772,793 ****
              dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]),
                                          ObjectIdGetDatum(attelem),
                                          Int32GetDatum(atttypmod));
          }
          else
              dvalues[i] = PointerGetDatum(NULL);
      }

      /*
       * Form a tuple
       */
-     nulls = (char *) palloc(natts * sizeof(char));
-     for (i = 0; i < natts; i++)
-     {
-         if (DatumGetPointer(dvalues[i]) != NULL)
-             nulls[i] = ' ';
-         else
-             nulls[i] = 'n';
-     }
      tuple = heap_formtuple(tupdesc, dvalues, nulls);

      return tuple;
--- 773,790 ----
              dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]),
                                          ObjectIdGetDatum(attelem),
                                          Int32GetDatum(atttypmod));
+             nulls[i] = ' ';
          }
          else
+         {
              dvalues[i] = PointerGetDatum(NULL);
+             nulls[i] = 'n';
+         }
      }

      /*
       * Form a tuple
       */
      tuple = heap_formtuple(tupdesc, dvalues, nulls);

      return tuple;
Index: src/backend/utils/fmgr/funcapi.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/utils/fmgr/funcapi.c,v
retrieving revision 1.1
diff -c -r1.1 funcapi.c
*** src/backend/utils/fmgr/funcapi.c    20 Jun 2002 20:37:00 -0000    1.1
--- src/backend/utils/fmgr/funcapi.c    9 Jul 2002 18:21:15 -0000
***************
*** 52,58 ****
          retval->call_cntr = 0;
          retval->max_calls = 0;
          retval->slot = NULL;
!         retval->fctx = NULL;
          retval->attinmeta = NULL;
          retval->fmctx = fcinfo->flinfo->fn_mcxt;

--- 52,58 ----
          retval->call_cntr = 0;
          retval->max_calls = 0;
          retval->slot = NULL;
!         retval->user_fctx = NULL;
          retval->attinmeta = NULL;
          retval->fmctx = fcinfo->flinfo->fn_mcxt;

***************
*** 71,76 ****
--- 71,93 ----
          /* never reached, but keep compiler happy */
          retval = NULL;
      }
+
+     return retval;
+ }
+
+ /*
+  * per_MultiFuncCall
+  *
+  * Do Multi-function per-call setup
+  */
+ FuncCallContext *
+ per_MultiFuncCall(PG_FUNCTION_ARGS)
+ {
+     FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
+
+     /* make sure we start with a fresh slot */
+     if(retval->slot != NULL)
+         ExecClearTuple(retval->slot);

      return retval;
  }
Index: src/include/funcapi.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/funcapi.h,v
retrieving revision 1.2
diff -c -r1.2 funcapi.h
*** src/include/funcapi.h    22 Jun 2002 04:08:07 -0000    1.2
--- src/include/funcapi.h    9 Jul 2002 18:17:27 -0000
***************
*** 65,86 ****
   */
  typedef struct
  {
!     /* Number of times we've been called before */
      uint32            call_cntr;

!     /* Maximum number of calls */
      uint32            max_calls;

!     /* pointer to result slot */
      TupleTableSlot *slot;

!     /* pointer to misc context info */
!     void           *fctx;
!
!     /* pointer to struct containing arrays of attribute type input metainfo */
      AttInMetadata       *attinmeta;

!     /* memory context used to initialize structure */
      MemoryContext    fmctx;

  }    FuncCallContext;
--- 65,121 ----
   */
  typedef struct
  {
!     /*
!      * Number of times we've been called before.
!      *
!      * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
!      * incremented for you every time SRF_RETURN_NEXT() is called.
!      */
      uint32            call_cntr;

!     /*
!      * OPTIONAL maximum number of calls
!      *
!      * max_calls is here for convenience ONLY and setting it is OPTIONAL.
!      * If not set, you must provide alternative means to know when the
!      * function is done.
!      */
      uint32            max_calls;

!     /*
!      * OPTIONAL pointer to result slot
!      *
!      * slot is for use when returning tuples (i.e. composite data types)
!      * and is not needed when returning base (i.e. scalar) data types.
!      */
      TupleTableSlot *slot;

!     /*
!      * OPTIONAL pointer to misc user provided context info
!      *
!      * user_fctx is for use as a pointer to your own struct to retain
!      * arbitrary context information between calls for your function.
!      */
!     void           *user_fctx;
!
!     /*
!      * OPTIONAL pointer to struct containing arrays of attribute type input
!      * metainfo
!      *
!      * attinmeta is for use when returning tuples (i.e. composite data types)
!      * and is not needed when returning base (i.e. scalar) data types. It
!      * is ONLY needed if you intend to use BuildTupleFromCStrings() to create
!      * the return tuple.
!      */
      AttInMetadata       *attinmeta;

!     /*
!      * memory context used to initialize structure
!      *
!      * fmctx is set by SRF_FIRSTCALL_INIT() for you, and used by
!      * SRF_RETURN_DONE() for cleanup. It is primarily for internal use
!      * by the API.
!      */
      MemoryContext    fmctx;

  }    FuncCallContext;
***************
*** 137,143 ****
   *     Datum                result;
   *     <user defined declarations>
   *
!  *     if(SRF_IS_FIRSTPASS())
   *     {
   *         <user defined code>
   *         funcctx = SRF_FIRSTCALL_INIT();
--- 172,178 ----
   *     Datum                result;
   *     <user defined declarations>
   *
!  *     if(SRF_IS_FIRSTCALL())
   *     {
   *         <user defined code>
   *         funcctx = SRF_FIRSTCALL_INIT();
***************
*** 148,154 ****
   *         <user defined code>
   *  }
   *     <user defined code>
!  *     funcctx = SRF_PERCALL_SETUP(funcctx);
   *     <user defined code>
   *
   *     if (funcctx->call_cntr < funcctx->max_calls)
--- 183,189 ----
   *         <user defined code>
   *  }
   *     <user defined code>
!  *     funcctx = SRF_PERCALL_SETUP();
   *     <user defined code>
   *
   *     if (funcctx->call_cntr < funcctx->max_calls)
***************
*** 167,180 ****

  /* from funcapi.c */
  extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
  extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);

! #define SRF_IS_FIRSTPASS() (fcinfo->flinfo->fn_extra == NULL)
  #define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo)
! #define SRF_PERCALL_SETUP(_funcctx) \
!     fcinfo->flinfo->fn_extra; \
!     if(_funcctx->slot != NULL) \
!         ExecClearTuple(_funcctx->slot)
  #define SRF_RETURN_NEXT(_funcctx, _result) \
      do { \
          ReturnSetInfo       *rsi; \
--- 202,213 ----

  /* from funcapi.c */
  extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
+ extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS);
  extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);

! #define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL)
  #define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo)
! #define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo)
  #define SRF_RETURN_NEXT(_funcctx, _result) \
      do { \
          ReturnSetInfo       *rsi; \

pgsql-patches by date:

Previous
From: nconway@klamath.dyndns.org (Neil Conway)
Date:
Subject: Re: UNIQUE predicate
Next
From: Rod Taylor
Date:
Subject: Between Node