From 5e8b7b0b73b6d0aba4a5a05704601dd031ad0a49 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 4 Nov 2010 16:34:47 -0400
Subject: [PATCH] Allow moddatetime's target column to be of type timestamptz.

Dirk Heinrichs
---
 contrib/spi/moddatetime.c     | 36 +++++++++++++++++++++--------------
 doc/src/sgml/contrib-spi.sgml |  4 +++-
 2 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c
index 9a1addb78ad..f5a0d93ef5f 100644
--- a/contrib/spi/moddatetime.c
+++ b/contrib/spi/moddatetime.c
@@ -32,6 +32,7 @@ moddatetime(PG_FUNCTION_ARGS)
 	Trigger    *trigger;		/* to get trigger name */
 	int			nargs;			/* # of arguments */
 	int			attnum;			/* positional number of field to change */
+	Oid			atttypid;		/* type OID of field to change */
 	Datum		newdt;			/* The current datetime. */
 	char	  **args;			/* arguments */
 	char	   *relname;		/* triggered relation name */
@@ -75,12 +76,6 @@ moddatetime(PG_FUNCTION_ARGS)
 	/* must be the field layout? */
 	tupdesc = rel->rd_att;
 
-	/* Get the current datetime. */
-	newdt = DirectFunctionCall3(timestamp_in,
-								CStringGetDatum("now"),
-								ObjectIdGetDatum(InvalidOid),
-								Int32GetDatum(-1));
-
 	/*
 	 * This gets the position in the tuple of the field we want. args[0] being
 	 * the name of the field to update, as passed in from the trigger.
@@ -88,8 +83,8 @@ moddatetime(PG_FUNCTION_ARGS)
 	attnum = SPI_fnumber(tupdesc, args[0]);
 
 	/*
-	 * This is were we check to see if the field we are supposed to update
-	 * even exits.	The above function must return -1 if name not found?
+	 * This is where we check to see if the field we are supposed to update
+	 * even exists.	The above function must return -1 if name not found?
 	 */
 	if (attnum < 0)
 		ereport(ERROR,
@@ -98,20 +93,33 @@ moddatetime(PG_FUNCTION_ARGS)
 						relname, args[0])));
 
 	/*
-	 * OK, this is where we make sure the timestamp field that we are
-	 * modifying is really a timestamp field. Hay, error checking, what a
-	 * novel idea !-)
+	 * Check the target field has an allowed type, and get the current
+	 * datetime as a value of that type.
 	 */
-	if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
+	atttypid = SPI_gettypeid(tupdesc, attnum);
+	if (atttypid == TIMESTAMPOID)
+		newdt = DirectFunctionCall3(timestamp_in,
+									CStringGetDatum("now"),
+									ObjectIdGetDatum(InvalidOid),
+									Int32GetDatum(-1));
+	else if (atttypid == TIMESTAMPTZOID)
+		newdt = DirectFunctionCall3(timestamptz_in,
+									CStringGetDatum("now"),
+									ObjectIdGetDatum(InvalidOid),
+									Int32GetDatum(-1));
+	else
+	{
 		ereport(ERROR,
 				(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
-				 errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP",
+				 errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP or TIMESTAMPTZ",
 						args[0], relname)));
+		newdt = (Datum) 0;		/* keep compiler quiet */
+	}
 
 /* 1 is the number of items in the arrays attnum and newdt.
 	attnum is the positional number of the field to be updated.
 	newdt is the new datetime stamp.
-	NOTE that attnum and newdt are not arrays, but then a 1 ellement array
+	NOTE that attnum and newdt are not arrays, but then a 1 element array
 	is not an array any more then they are.  Thus, they can be considered a
 	one element array.
 */
diff --git a/doc/src/sgml/contrib-spi.sgml b/doc/src/sgml/contrib-spi.sgml
index 0f5a1f6787a..a8761f61b7a 100644
--- a/doc/src/sgml/contrib-spi.sgml
+++ b/doc/src/sgml/contrib-spi.sgml
@@ -211,7 +211,9 @@ CREATE TABLE mytab (
   <para>
    To use, create a <literal>BEFORE UPDATE</>
    trigger using this function.  Specify a single trigger
-   argument: the name of the <type>timestamp</> column to be modified.
+   argument: the name of the column to be modified.
+   The column must be of type <type>timestamp</> or <type>timestamp with
+   time zone</>.
   </para>
 
   <para>
-- 
GitLab