summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2006-01-11 20:12:43 +0000
committerTom Lane2006-01-11 20:12:43 +0000
commitcef0dbbeee550269080f14eecde8d6fab25c9721 (patch)
tree1514bdec01b3fc8f0180dc7593c09964aafd8509
parent7e0a5dd6d74c6b70ed7e7c1d28c33e3d5d793e17 (diff)
Create a standard function pg_sleep() to sleep for a specified amount of time.
Replace the former ad-hoc implementation used in the regression tests. Joachim Wieland
-rw-r--r--doc/src/sgml/func.sgml50
-rw-r--r--src/backend/utils/adt/misc.c49
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.h2
-rw-r--r--src/include/utils/builtins.h1
-rw-r--r--src/test/regress/expected/stats.out4
-rw-r--r--src/test/regress/input/create_function_1.source5
-rw-r--r--src/test/regress/output/create_function_1.source4
-rw-r--r--src/test/regress/regress.c16
-rw-r--r--src/test/regress/sql/stats.sql2
10 files changed, 106 insertions, 29 deletions
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 21152055aa..40b92d27d5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -6170,6 +6170,56 @@ SELECT TIMESTAMP 'now'; -- incorrect for use with DEFAULT
</para>
</tip>
</sect2>
+
+ <sect2 id="functions-datetime-delay">
+ <title>Delaying Execution</title>
+
+ <indexterm>
+ <primary>pg_sleep</primary>
+ </indexterm>
+ <indexterm>
+ <primary>sleep</primary>
+ </indexterm>
+ <indexterm>
+ <primary>delay</primary>
+ </indexterm>
+
+ <para>
+ The following function is available to delay execution of the server
+ process:
+<synopsis>
+pg_sleep(<replaceable>seconds</replaceable>)
+</synopsis>
+
+ <function>pg_sleep</function> makes the current session's process
+ sleep until <replaceable>seconds</replaceable> seconds have
+ elapsed. <replaceable>seconds</replaceable> is a value of type
+ <type>double precision</>, so fractional-second delays can be specified.
+ For example:
+
+<programlisting>
+SELECT pg_sleep(1.5);
+</programlisting>
+ </para>
+
+ <note>
+ <para>
+ The effective resolution of the sleep interval is platform-specific;
+ 0.01 seconds is a common value. The sleep delay will be at least as long
+ as specified. It may be longer depending on factors such as server load.
+ </para>
+ </note>
+
+ <warning>
+ <para>
+ Make sure that your session does not hold more locks than necessary
+ when calling <function>pg_sleep</function>. Otherwise other sessions
+ might have to wait for your sleeping process, slowing down the entire
+ system.
+ </para>
+ </warning>
+ </sect2>
+
</sect1>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6e99faa45f..ccfaf2ca80 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -17,6 +17,7 @@
#include <sys/file.h>
#include <signal.h>
#include <dirent.h>
+#include <math.h>
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
@@ -259,3 +260,51 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
FreeDir(fctx->dirdesc);
SRF_RETURN_DONE(funcctx);
}
+
+
+/*
+ * pg_sleep - delay for N seconds
+ */
+Datum
+pg_sleep(PG_FUNCTION_ARGS)
+{
+ float8 secs = PG_GETARG_FLOAT8(0);
+ float8 endtime;
+
+ /*
+ * We break the requested sleep into segments of no more than 1 second,
+ * to put an upper bound on how long it will take us to respond to a
+ * cancel or die interrupt. (Note that pg_usleep is interruptible by
+ * signals on some platforms but not others.) Also, this method avoids
+ * exposing pg_usleep's upper bound on allowed delays.
+ *
+ * By computing the intended stop time initially, we avoid accumulation
+ * of extra delay across multiple sleeps. This also ensures we won't
+ * delay less than the specified time if pg_usleep is interrupted
+ * by other signals such as SIGHUP.
+ */
+
+#ifdef HAVE_INT64_TIMESTAMP
+#define GetNowFloat() ((float8) GetCurrentTimestamp() / 1000000.0)
+#else
+#define GetNowFloat() GetCurrentTimestamp()
+#endif
+
+ endtime = GetNowFloat() + secs;
+
+ for (;;)
+ {
+ float8 delay;
+
+ CHECK_FOR_INTERRUPTS();
+ delay = endtime - GetNowFloat();
+ if (delay >= 1.0)
+ pg_usleep(1000000L);
+ else if (delay > 0.0)
+ pg_usleep((long) ceil(delay * 1000000.0));
+ else
+ break;
+ }
+
+ PG_RETURN_VOID();
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 7234602c0e..629dd1a4d7 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200601081
+#define CATALOG_VERSION_NO 200601111
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index f1ff6a4866..b586b1eba9 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3025,6 +3025,8 @@ DATA(insert OID = 2624 ( pg_read_file PGNSP PGUID 12 f f t f v 3 25 "25 20 20"
DESCR("Read text from a file");
DATA(insert OID = 2625 ( pg_ls_dir PGNSP PGUID 12 f f t t v 1 25 "25" _null_ _null_ _null_ pg_ls_dir - _null_ ));
DESCR("List all files in a directory");
+DATA(insert OID = 2626 ( pg_sleep PGNSP PGUID 12 f f t f v 1 2278 "701" _null_ _null_ _null_ pg_sleep - _null_ ));
+DESCR("Sleep for the specified time in seconds");
/* Aggregates (moved here from pg_aggregate for 7.3) */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index f5ecf6789d..09945a0f41 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -387,6 +387,7 @@ extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
extern Datum pg_reload_conf(PG_FUNCTION_ARGS);
extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);
extern Datum pg_rotate_logfile(PG_FUNCTION_ARGS);
+extern Datum pg_sleep(PG_FUNCTION_ARGS);
/* not_in.c */
extern Datum int4notin(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index bd2e1328f8..d3495ffb48 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -36,8 +36,8 @@ SELECT count(*) FROM tenk2 WHERE unique1 = 1;
(1 row)
-- let stats collector catch up
-SELECT do_sleep(2);
- do_sleep
+SELECT pg_sleep(2.0);
+ pg_sleep
----------
(1 row)
diff --git a/src/test/regress/input/create_function_1.source b/src/test/regress/input/create_function_1.source
index 14b90ca1a1..faa73156dc 100644
--- a/src/test/regress/input/create_function_1.source
+++ b/src/test/regress/input/create_function_1.source
@@ -52,11 +52,6 @@ CREATE FUNCTION set_ttdummy (int4)
AS '@abs_builddir@/regress@DLSUFFIX@'
LANGUAGE 'C' STRICT;
-CREATE FUNCTION do_sleep (int4)
- RETURNS void
- AS '@abs_builddir@/regress@DLSUFFIX@'
- LANGUAGE 'C' STRICT;
-
-- Things that shouldn't work:
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
diff --git a/src/test/regress/output/create_function_1.source b/src/test/regress/output/create_function_1.source
index 7511c3f8d6..ed275b1f48 100644
--- a/src/test/regress/output/create_function_1.source
+++ b/src/test/regress/output/create_function_1.source
@@ -47,10 +47,6 @@ CREATE FUNCTION set_ttdummy (int4)
RETURNS int4
AS '@abs_builddir@/regress@DLSUFFIX@'
LANGUAGE 'C' STRICT;
-CREATE FUNCTION do_sleep (int4)
- RETURNS void
- AS '@abs_builddir@/regress@DLSUFFIX@'
- LANGUAGE 'C' STRICT;
-- Things that shouldn't work:
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
AS 'SELECT ''not an integer'';';
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 7cb6f82ce9..26eaa06b69 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -26,7 +26,6 @@ extern char *reverse_name(char *string);
extern int oldstyle_length(int n, text *t);
extern Datum int44in(PG_FUNCTION_ARGS);
extern Datum int44out(PG_FUNCTION_ARGS);
-extern Datum do_sleep(PG_FUNCTION_ARGS);
/*
@@ -735,18 +734,3 @@ int44out(PG_FUNCTION_ARGS)
*--walk = '\0';
PG_RETURN_CSTRING(result);
}
-
-/*
- * do_sleep - delay for N seconds
- */
-PG_FUNCTION_INFO_V1(do_sleep);
-
-Datum
-do_sleep(PG_FUNCTION_ARGS)
-{
- int32 secs = PG_GETARG_INT32(0);
-
- pg_usleep(secs * 1000000L);
-
- PG_RETURN_VOID();
-}
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 3589a0cf5d..75acee647d 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -26,7 +26,7 @@ SELECT count(*) FROM tenk2;
SELECT count(*) FROM tenk2 WHERE unique1 = 1;
-- let stats collector catch up
-SELECT do_sleep(2);
+SELECT pg_sleep(2.0);
-- check effects
SELECT st.seq_scan >= pr.seq_scan + 1,