PostgreSQL Source Code  git master
pseudorandomfuncs.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pseudorandomfuncs.c
4  * Functions giving SQL access to a pseudorandom number generator.
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/utils/adt/pseudorandomfuncs.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include <math.h>
17 
18 #include "common/pg_prng.h"
19 #include "miscadmin.h"
20 #include "utils/fmgrprotos.h"
21 #include "utils/numeric.h"
22 #include "utils/timestamp.h"
23 
24 /* Shared PRNG state used by all the random functions */
26 static bool prng_seed_set = false;
27 
28 /*
29  * initialize_prng() -
30  *
31  * Initialize (seed) the PRNG, if not done yet in this process.
32  */
33 static void
35 {
36  if (unlikely(!prng_seed_set))
37  {
38  /*
39  * If possible, seed the PRNG using high-quality random bits. Should
40  * that fail for some reason, we fall back on a lower-quality seed
41  * based on current time and PID.
42  */
44  {
46  uint64 iseed;
47 
48  /* Mix the PID with the most predictable bits of the timestamp */
49  iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
50  pg_prng_seed(&prng_state, iseed);
51  }
52  prng_seed_set = true;
53  }
54 }
55 
56 /*
57  * setseed() -
58  *
59  * Seed the PRNG from a specified value in the range [-1.0, 1.0].
60  */
61 Datum
63 {
64  float8 seed = PG_GETARG_FLOAT8(0);
65 
66  if (seed < -1 || seed > 1 || isnan(seed))
67  ereport(ERROR,
68  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
69  errmsg("setseed parameter %g is out of allowed range [-1,1]",
70  seed));
71 
72  pg_prng_fseed(&prng_state, seed);
73  prng_seed_set = true;
74 
76 }
77 
78 /*
79  * drandom() -
80  *
81  * Returns a random number chosen uniformly in the range [0.0, 1.0).
82  */
83 Datum
85 {
86  float8 result;
87 
89 
90  /* pg_prng_double produces desired result range [0.0, 1.0) */
91  result = pg_prng_double(&prng_state);
92 
93  PG_RETURN_FLOAT8(result);
94 }
95 
96 /*
97  * drandom_normal() -
98  *
99  * Returns a random number from a normal distribution.
100  */
101 Datum
103 {
104  float8 mean = PG_GETARG_FLOAT8(0);
105  float8 stddev = PG_GETARG_FLOAT8(1);
106  float8 result,
107  z;
108 
109  initialize_prng();
110 
111  /* Get random value from standard normal(mean = 0.0, stddev = 1.0) */
113  /* Transform the normal standard variable (z) */
114  /* using the target normal distribution parameters */
115  result = (stddev * z) + mean;
116 
117  PG_RETURN_FLOAT8(result);
118 }
119 
120 /*
121  * int4random() -
122  *
123  * Returns a random 32-bit integer chosen uniformly in the specified range.
124  */
125 Datum
127 {
128  int32 rmin = PG_GETARG_INT32(0);
129  int32 rmax = PG_GETARG_INT32(1);
130  int32 result;
131 
132  if (rmin > rmax)
133  ereport(ERROR,
134  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
135  errmsg("lower bound must be less than or equal to upper bound"));
136 
137  initialize_prng();
138 
139  result = (int32) pg_prng_int64_range(&prng_state, rmin, rmax);
140 
141  PG_RETURN_INT32(result);
142 }
143 
144 /*
145  * int8random() -
146  *
147  * Returns a random 64-bit integer chosen uniformly in the specified range.
148  */
149 Datum
151 {
152  int64 rmin = PG_GETARG_INT64(0);
153  int64 rmax = PG_GETARG_INT64(1);
154  int64 result;
155 
156  if (rmin > rmax)
157  ereport(ERROR,
158  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
159  errmsg("lower bound must be less than or equal to upper bound"));
160 
161  initialize_prng();
162 
163  result = pg_prng_int64_range(&prng_state, rmin, rmax);
164 
165  PG_RETURN_INT64(result);
166 }
167 
168 /*
169  * numeric_random() -
170  *
171  * Returns a random numeric value chosen uniformly in the specified range.
172  */
173 Datum
175 {
176  Numeric rmin = PG_GETARG_NUMERIC(0);
177  Numeric rmax = PG_GETARG_NUMERIC(1);
178  Numeric result;
179 
180  initialize_prng();
181 
182  result = random_numeric(&prng_state, rmin, rmax);
183 
184  PG_RETURN_NUMERIC(result);
185 }
Numeric random_numeric(pg_prng_state *state, Numeric rmin, Numeric rmax)
Definition: numeric.c:4228
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1654
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1618
signed int int32
Definition: c.h:494
double float8
Definition: c.h:630
#define unlikely(x)
Definition: c.h:311
int64 TimestampTz
Definition: timestamp.h:39
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:367
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
int MyProcPid
Definition: globals.c:45
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:78
#define PG_RETURN_NUMERIC(x)
Definition: numeric.h:80
int64 pg_prng_int64_range(pg_prng_state *state, int64 rmin, int64 rmax)
Definition: pg_prng.c:192
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:268
void pg_prng_seed(pg_prng_state *state, uint64 seed)
Definition: pg_prng.c:89
double pg_prng_double_normal(pg_prng_state *state)
Definition: pg_prng.c:290
void pg_prng_fseed(pg_prng_state *state, double fseed)
Definition: pg_prng.c:102
#define pg_prng_strong_seed(state)
Definition: pg_prng.h:46
uintptr_t Datum
Definition: postgres.h:64
static void initialize_prng(void)
Datum numeric_random(PG_FUNCTION_ARGS)
static pg_prng_state prng_state
Datum int4random(PG_FUNCTION_ARGS)
Datum setseed(PG_FUNCTION_ARGS)
static bool prng_seed_set
Datum drandom(PG_FUNCTION_ARGS)
Datum drandom_normal(PG_FUNCTION_ARGS)
Datum int8random(PG_FUNCTION_ARGS)