backend_setQueryTimeout_02.patch

text/plain

Filename: backend_setQueryTimeout_02.patch
Type: text/plain
Part: 0
Message: Support for JDBC setQueryTimeout, et al.

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/storage/lmgr/proc.c 6 0
src/backend/tcop/postgres.c 25 10
src/backend/utils/adt/timestamp.c 47 0
src/include/catalog/catversion.h 1 1
src/include/catalog/pg_proc.h 2 0
src/include/utils/timestamp.h 5 0
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e4a7dd9..06c8fce 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -51,6 +51,8 @@
 /* GUC variables */
 int			DeadlockTimeout = 1000;
 int			StatementTimeout = 0;
+int                     SessionTimerTarget = 0;
+
 bool		log_lock_waits = false;
 
 /* Pointer to this process's PGPROC struct, if any */
@@ -1550,6 +1552,10 @@ CheckStatementTimeout(void)
 		/* Time to die */
 		statement_timeout_active = false;
 		cancel_from_timeout = true;
+
+                /* reset session timer.  Never fire twice. */
+                set_session_timer_ms(0);
+
 #ifdef HAVE_SETSID
 		/* try to signal whole process group */
 		kill(-MyProcPid, SIGINT);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cba90a9..769ac2c 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -2445,28 +2445,43 @@ exec_describe_portal_message(const char *portal_name)
 		pq_putemptymessage('n');	/* NoData */
 }
 
-
 /*
  * Convenience routines for starting/committing a single command.
  */
 static void
 start_xact_command(void)
 {
+        int64 timeout = 0;
+
 	if (!xact_started)
 	{
-		ereport(DEBUG3,
-				(errmsg_internal("StartTransactionCommand")));
+		ereport(DEBUG3, (errmsg_internal("StartTransactionCommand")));
 		StartTransactionCommand();
 
-		/* Set statement timeout running, if any */
-		/* NB: this mustn't be enabled until we are within an xact */
-		if (StatementTimeout > 0)
-			enable_sig_alarm(StatementTimeout, true);
-		else
-			cancel_from_timeout = false;
+                if (timeout == 0 || 
+                      (StatementTimeout > 0 && timeout > StatementTimeout)) {
+                   timeout = StatementTimeout;
+                }
+
+                /* Set statement timeout running, if any */
+                /* NB: this mustn't be enabled until we are within an xact */
+                if (StatementTimeout > 0)
+                   enable_sig_alarm(StatementTimeout, true);
+                else
+                   cancel_from_timeout = false;
 
 		xact_started = true;
-	}
+        }
+
+        timeout = get_session_timer_ms(); 
+        if (timeout > 0) {
+           if (StatementTimeout == 0 || timeout < StatementTimeout) {
+              ereport(DEBUG3, (errmsg_internal("Enable an once session timer")));
+              enable_sig_alarm(timeout, true);
+           } else {
+              cancel_from_timeout = false;
+           }
+        }
 }
 
 static void
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index c6e1d13..d998df6 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4824,3 +4824,50 @@ generate_series_timestamptz(PG_FUNCTION_ARGS)
 		SRF_RETURN_DONE(funcctx);
 	}
 }
+
+/* Session timer target, in ms */
+static int64 sessionTimerTarget; 
+
+Datum set_session_timer(PG_FUNCTION_ARGS)
+{
+   int64 ms = PG_GETARG_INT64(0);
+   set_session_timer_ms(ms);
+   PG_RETURN_DATUM(0);
+}
+   
+#ifndef HAVE_INT64_TIMESTAMP
+#error Assumes int64 impl of timestamp
+#endif
+
+void set_session_timer_ms(int64 ms)
+{
+   if (ms == 0) {
+      sessionTimerTarget = 0;
+   } else {
+      /* GetCurrentTimestamp is in us */
+      int64 time_now = GetCurrentTimestamp() / 1000;
+      sessionTimerTarget = time_now + ms;
+   }
+}
+
+int64 get_session_timer_ms()
+{
+   int64 ret = 0;
+   if (sessionTimerTarget != 0) {
+      int64 time_now = GetCurrentTimestamp() / 1000;
+      ret = sessionTimerTarget - time_now;
+
+      if (ret <= 0) {
+         /* Timer already passed.  This maybe possible if some statement 
+          * set the timer, finished so the timer is disabled, next statement 
+          * set the timer again, but too late.  We want to go through the
+          * same routine and fire the timer.  Return 1 ms.
+          */ 
+         ret = 1;
+      }
+
+      sessionTimerTarget = 0;
+   }
+
+   return ret;
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 910474c..904a821 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201010101
+#define CATALOG_VERSION_NO	201010102
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 61c6b27..308f014 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4849,6 +4849,8 @@ DATA(insert OID = 3113 (  last_value	PGNSP PGUID 12 1 0 0 f t f t f i 1 0 2283 "
 DESCR("fetch the last row value");
 DATA(insert OID = 3114 (  nth_value		PGNSP PGUID 12 1 0 0 f t f t f i 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ window_nth_value _null_ _null_ _null_ ));
 DESCR("fetch the Nth row value");
+DATA(insert OID = 3115 (  set_session_timer   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 20 "20" _null_ _null_ _null_ _null_ set_session_timer _null_ _null_ _null_ ));
+DESCR("Set a timer for the session");
 
 
 /*
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index db7b729..c60d109 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -310,6 +310,11 @@ extern Datum pg_conf_load_time(PG_FUNCTION_ARGS);
 extern Datum generate_series_timestamp(PG_FUNCTION_ARGS);
 extern Datum generate_series_timestamptz(PG_FUNCTION_ARGS);
 
+/* session timer, for jdbc setQueryTimeout and like */
+extern Datum set_session_timer(PG_FUNCTION_ARGS);
+extern void set_session_timer_ms(int64 ms);
+extern int64 get_session_timer_ms(void);
+
 /* Internal routines (not fmgr-callable) */
 
 extern TimestampTz GetCurrentTimestamp(void);