</table>
<para>
- The characteristics of the values returned by
- <literal><function>random()</function></literal> depend
- on the system implementation. It is not suitable for cryptographic
- applications; see <xref linkend="pgcrypto"/> module for an alternative.
- </para>
+ The <function>random()</function> function uses a simple linear
+ congruential algorithm. It is fast but not suitable for cryptographic
+ applications; see the <xref linkend="pgcrypto"/> module for a more
+ secure alternative.
+ If <function>setseed()</function> is called, the results of
+ subsequent <function>random()</function> calls in the current session are
+ repeatable by re-issuing <function>setseed()</function> with the same
+ argument.
+ </para>
<para>
Finally, <xref linkend="functions-math-trig-table"/> shows the
#include "catalog/pg_type.h"
#include "common/int.h"
#include "libpq/pqformat.h"
+#include "miscadmin.h"
#include "utils/array.h"
+#include "utils/backend_random.h"
#include "utils/float.h"
#include "utils/fmgrprotos.h"
#include "utils/sortsupport.h"
+#include "utils/timestamp.h"
/* Configurable GUC parameter */
float8 degree_c_one_half = 0.5;
float8 degree_c_one = 1.0;
+/* State for drandom() and setseed() */
+static bool drandom_seed_set = false;
+static unsigned short drandom_seed[3] = {0, 0, 0};
+
/* Local function prototypes */
static double sind_q1(double x);
static double cosd_q1(double x);
{
float8 result;
- /* result [0.0 - 1.0) */
- result = (double) random() / ((double) MAX_RANDOM_VALUE + 1);
+ /* Initialize random seed, if not done yet in this process */
+ if (unlikely(!drandom_seed_set))
+ {
+ /*
+ * If possible, initialize the seed using high-quality random bits.
+ * Should that fail for some reason, we fall back on a lower-quality
+ * seed based on current time and PID.
+ */
+ if (!pg_backend_random((char *) drandom_seed, sizeof(drandom_seed)))
+ {
+ TimestampTz now = GetCurrentTimestamp();
+ uint64 iseed;
+
+ /* Mix the PID with the most predictable bits of the timestamp */
+ iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
+ drandom_seed[0] = (unsigned short) iseed;
+ drandom_seed[1] = (unsigned short) (iseed >> 16);
+ drandom_seed[2] = (unsigned short) (iseed >> 32);
+ }
+ drandom_seed_set = true;
+ }
+
+ /* pg_erand48 produces desired result range [0.0 - 1.0) */
+ result = pg_erand48(drandom_seed);
PG_RETURN_FLOAT8(result);
}
setseed(PG_FUNCTION_ARGS)
{
float8 seed = PG_GETARG_FLOAT8(0);
- int iseed;
+ uint64 iseed;
- if (seed < -1 || seed > 1)
- elog(ERROR, "setseed parameter %f out of range [-1,1]", seed);
-
- iseed = (int) (seed * MAX_RANDOM_VALUE);
- srandom((unsigned int) iseed);
+ if (seed < -1 || seed > 1 || isnan(seed))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("setseed parameter %g is out of allowed range [-1,1]",
+ seed)));
+
+ /* Use sign bit + 47 fractional bits to fill drandom_seed[] */
+ iseed = (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF));
+ drandom_seed[0] = (unsigned short) iseed;
+ drandom_seed[1] = (unsigned short) (iseed >> 16);
+ drandom_seed[2] = (unsigned short) (iseed >> 32);
+ drandom_seed_set = true;
PG_RETURN_VOID();
}