diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index d90bc15d411d33b1fab88256e0f3db622c75e549..a3eadb4bc400398137f02006a97e672765db4bc4 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.301 2005/12/28 01:29:58 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.302 2006/01/11 20:12:38 tgl Exp $ PostgreSQL documentation --> @@ -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 14bb593c2c27d6dbae2a3e5899f92b095ff0b345..2ceea8969a56d1f66501e617e6799be2b82c33cd 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.49 2005/10/15 02:49:29 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.50 2006/01/11 20:12:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 6eb5f72d9fa6487f73060767d9a003be5ea92795..258a9956f4a20293a17d11dfbf0848f32fcdaf0e 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.309 2006/01/08 07:00:25 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.310 2006/01/11 20:12:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 7b78e78fcc39bcd4930034904c0ac68df48b994a..6f5ec17c45178ee281b5b0fc9bbb7e4b9b5ea8bd 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.390 2006/01/08 07:00:25 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.391 2006/01/11 20:12:39 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -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 97fbfdc341e8e4afcc6c6b79d300c78c596edd08..8ca212852c2c1e9a41c102495c168f4021aa02c5 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.269 2006/01/08 07:00:26 neilc Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.270 2006/01/11 20:12:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 bd2e1328f8f39a0e4b1d4eef6eba75fa1ecf4200..d3495ffb481f522e266b2da9be7c660e79c56592 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 14b90ca1a1b0089878136645ec8e2d15be614957..faa73156dc21afb7b11c2c5e9dbf5987b401115a 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 7511c3f8d6753e18cc6615c8e6e799d8a1f01342..ed275b1f482163701207b140a8fef4b255b69c96 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 97fe608602a87a60f63a07b55fb58ade81d44739..7c58f950cbb535548cbacac4361e18d57a4c44b0 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.64 2005/10/15 02:49:51 momjian Exp $ + * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.65 2006/01/11 20:12:43 tgl Exp $ */ #include "postgres.h" @@ -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 3589a0cf5ddf19845352598bd0c3a60ca89dab0c..75acee647d5aaf95b39265cfcd77a422daaa42b4 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,