Thread: Recent MemSet change to DirectFunctionCall1

Recent MemSet change to DirectFunctionCall1

From
Mark Halliwell
Date:
Following the instructions in doc/bug.template here is my bug report and a
possible patch for fixing it.  I hope I am correct in sending it here first
and not to another mailing list.

Cheers
Mark Halliwell


Your name        :    Mark Halliwell
Your email address    :    mark@transportservices.com.au


System Configuration
---------------------
  Architecture (example: Intel Pentium)      :    Intel Pentium

  Operating System (example: Linux 2.0.26 ELF)     :    Linux 2.4.18

  PostgreSQL version (example: PostgreSQL-7.3):   PostgreSQL-7.3

  Compiler used (example:  gcc 2.95.2)        :    gcc 2.96


Please enter a FULL description of your problem:
------------------------------------------------

I recently upgraded from 7.2.1 to 7.3 and found that one of my triggers
stopped working; it would report:
ERROR:  TIMESTAMP(-1073746888) precision must be between 0 and 6
The trigger is used to set the time a record changes and does the following
call:
DirectFunctionCall1(timestamp_in, CStringGetDatum("now"));
(My trigger was based upon the code in contrib/spi/moddatetime.c)

I had thought the timestamp_in (from backend/utils/adt/timestamp.c) function
should take just 1 argument, but if a third argument is passed, it will be
used for the precision.

DirectFunctionCall1 was recently changed to not MemSet the
FunctionCallInfoData
structure, and as a result, arguments after the first one will be garbage.
Thus, when timestamp_in is invoked by my trigger, it has a bad value for the
precision and therefore fails.


Please describe a way to repeat the problem.   Please try to provide a
concise reproducible example, if at all possible:
----------------------------------------------------------------------

A trigger which does:
DirectFunctionCall1(timestamp_in, CStringGetDatum("now"));
such as the example in contrib/spi/moddatetime.c should cause an error
something like this:
ERROR:  TIMESTAMP(-1073746888) precision must be between 0 and 6


If you know how this problem might be fixed, list the solution below:
---------------------------------------------------------------------

Now, if this is just a bug in that DirectFunctionCall3 should be used instead
of DirectFunctionCall1 both in contrib/spi/moddatetime.c and my own trigger,
please ignore the rest of this.

I understand from the comments in backend/utils/fmgr/fmgr.c and the cvs log
that the decision to remove the MemSet was quite deliberate (mainly, it seems,
for a speed increase).  If I put the MemSet back in, it solves my particular
problem.

However, I have come up with a possibly better solution.  As I am not very
familiar with the source I may be completely wrong here, but, it would seem
that the macro that return the arguments (PG_GETARG_DATUM(n)) should check
the nargs value in the FunctionCallInfoData structure.  I have tried out this
following patch and it seems to work OK.  (Output from diff -c)

*** /tmp/fmgr.h Sat Oct 26 08:17:32 2002
--- src/include/fmgr.h  Thu Jan  9 12:43:02 2003
***************
*** 167,173 ****

  /* Macros for fetching arguments of standard types */

! #define PG_GETARG_DATUM(n)     (fcinfo->arg[n])
  #define PG_GETARG_INT32(n)     DatumGetInt32(PG_GETARG_DATUM(n))
  #define PG_GETARG_UINT32(n)  DatumGetUInt32(PG_GETARG_DATUM(n))
  #define PG_GETARG_INT16(n)     DatumGetInt16(PG_GETARG_DATUM(n))
--- 167,173 ----

  /* Macros for fetching arguments of standard types */

! #define PG_GETARG_DATUM(n)       (n >= fcinfo->nargs ? NULL:fcinfo->arg[n])
  #define PG_GETARG_INT32(n)     DatumGetInt32(PG_GETARG_DATUM(n))
  #define PG_GETARG_UINT32(n)  DatumGetUInt32(PG_GETARG_DATUM(n))
  #define PG_GETARG_INT16(n)     DatumGetInt16(PG_GETARG_DATUM(n))


Re: Recent MemSet change to DirectFunctionCall1

From
Tom Lane
Date:
Mark Halliwell <mark@transportservices.com.au> writes:
> I recently upgraded from 7.2.1 to 7.3 and found that one of my triggers
> stopped working; it would report:
> ERROR:  TIMESTAMP(-1073746888) precision must be between 0 and 6
> The trigger is used to set the time a record changes and does the following
> call:
> DirectFunctionCall1(timestamp_in, CStringGetDatum("now"));
> (My trigger was based upon the code in contrib/spi/moddatetime.c)

This trigger is in error, as is moddatetime.c (I will fix the latter).
If you call a system function, it is up to you to call it with the
appropriate parameter list.

> ! #define PG_GETARG_DATUM(n)     (fcinfo->arg[n])
> --- 167,173 ----
> ! #define PG_GETARG_DATUM(n)       (n >= fcinfo->nargs ? NULL:fcinfo->arg[n])

This is certainly not a fix.  NULL is not even a valid value for
non-pointer argument types, and for those that are pointers, it would
mean instant core dump...

            regards, tom lane