Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/pseudorandomfuncs.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * pseudorandomfuncs.c
4
 *    Functions giving SQL access to a pseudorandom number generator.
5
 *
6
 * Portions Copyright (c) 1996-2026, 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/date.h"
21
#include "utils/fmgrprotos.h"
22
#include "utils/numeric.h"
23
#include "utils/timestamp.h"
24
25
/* Shared PRNG state used by all the random functions */
26
static pg_prng_state prng_state;
27
static bool prng_seed_set = false;
28
29
/*
30
 * Macro for checking the range bounds of random(min, max) functions. Throws
31
 * an error if they're the wrong way round.
32
 */
33
#define CHECK_RANGE_BOUNDS(rmin, rmax) \
34
0
  do { \
35
0
    if ((rmin) > (rmax)) \
36
0
      ereport(ERROR, \
37
0
          errcode(ERRCODE_INVALID_PARAMETER_VALUE), \
38
0
          errmsg("lower bound must be less than or equal to upper bound")); \
39
0
  } while (0)
40
41
/*
42
 * initialize_prng() -
43
 *
44
 *  Initialize (seed) the PRNG, if not done yet in this process.
45
 */
46
static void
47
initialize_prng(void)
48
0
{
49
0
  if (unlikely(!prng_seed_set))
50
0
  {
51
    /*
52
     * If possible, seed the PRNG using high-quality random bits. Should
53
     * that fail for some reason, we fall back on a lower-quality seed
54
     * based on current time and PID.
55
     */
56
0
    if (unlikely(!pg_prng_strong_seed(&prng_state)))
57
0
    {
58
0
      TimestampTz now = GetCurrentTimestamp();
59
0
      uint64    iseed;
60
61
      /* Mix the PID with the most predictable bits of the timestamp */
62
0
      iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
63
0
      pg_prng_seed(&prng_state, iseed);
64
0
    }
65
0
    prng_seed_set = true;
66
0
  }
67
0
}
68
69
/*
70
 * setseed() -
71
 *
72
 *  Seed the PRNG from a specified value in the range [-1.0, 1.0].
73
 */
74
Datum
75
setseed(PG_FUNCTION_ARGS)
76
0
{
77
0
  float8    seed = PG_GETARG_FLOAT8(0);
78
79
0
  if (seed < -1 || seed > 1 || isnan(seed))
80
0
    ereport(ERROR,
81
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
82
0
        errmsg("setseed parameter %g is out of allowed range [-1,1]",
83
0
             seed));
84
85
0
  pg_prng_fseed(&prng_state, seed);
86
0
  prng_seed_set = true;
87
88
0
  PG_RETURN_VOID();
89
0
}
90
91
/*
92
 * drandom() -
93
 *
94
 *  Returns a random number chosen uniformly in the range [0.0, 1.0).
95
 */
96
Datum
97
drandom(PG_FUNCTION_ARGS)
98
0
{
99
0
  float8    result;
100
101
0
  initialize_prng();
102
103
  /* pg_prng_double produces desired result range [0.0, 1.0) */
104
0
  result = pg_prng_double(&prng_state);
105
106
0
  PG_RETURN_FLOAT8(result);
107
0
}
108
109
/*
110
 * drandom_normal() -
111
 *
112
 *  Returns a random number from a normal distribution.
113
 */
114
Datum
115
drandom_normal(PG_FUNCTION_ARGS)
116
0
{
117
0
  float8    mean = PG_GETARG_FLOAT8(0);
118
0
  float8    stddev = PG_GETARG_FLOAT8(1);
119
0
  float8    result,
120
0
        z;
121
122
0
  initialize_prng();
123
124
  /* Get random value from standard normal(mean = 0.0, stddev = 1.0) */
125
0
  z = pg_prng_double_normal(&prng_state);
126
  /* Transform the normal standard variable (z) */
127
  /* using the target normal distribution parameters */
128
0
  result = (stddev * z) + mean;
129
130
0
  PG_RETURN_FLOAT8(result);
131
0
}
132
133
/*
134
 * int4random() -
135
 *
136
 *  Returns a random 32-bit integer chosen uniformly in the specified range.
137
 */
138
Datum
139
int4random(PG_FUNCTION_ARGS)
140
0
{
141
0
  int32   rmin = PG_GETARG_INT32(0);
142
0
  int32   rmax = PG_GETARG_INT32(1);
143
0
  int32   result;
144
145
0
  CHECK_RANGE_BOUNDS(rmin, rmax);
146
147
0
  initialize_prng();
148
149
0
  result = (int32) pg_prng_int64_range(&prng_state, rmin, rmax);
150
151
0
  PG_RETURN_INT32(result);
152
0
}
153
154
/*
155
 * int8random() -
156
 *
157
 *  Returns a random 64-bit integer chosen uniformly in the specified range.
158
 */
159
Datum
160
int8random(PG_FUNCTION_ARGS)
161
0
{
162
0
  int64   rmin = PG_GETARG_INT64(0);
163
0
  int64   rmax = PG_GETARG_INT64(1);
164
0
  int64   result;
165
166
0
  CHECK_RANGE_BOUNDS(rmin, rmax);
167
168
0
  initialize_prng();
169
170
0
  result = pg_prng_int64_range(&prng_state, rmin, rmax);
171
172
0
  PG_RETURN_INT64(result);
173
0
}
174
175
/*
176
 * numeric_random() -
177
 *
178
 *  Returns a random numeric value chosen uniformly in the specified range.
179
 */
180
Datum
181
numeric_random(PG_FUNCTION_ARGS)
182
0
{
183
0
  Numeric   rmin = PG_GETARG_NUMERIC(0);
184
0
  Numeric   rmax = PG_GETARG_NUMERIC(1);
185
0
  Numeric   result;
186
187
  /* Leave range bound checking to random_numeric() */
188
189
0
  initialize_prng();
190
191
0
  result = random_numeric(&prng_state, rmin, rmax);
192
193
0
  PG_RETURN_NUMERIC(result);
194
0
}
195
196
197
/*
198
 * date_random() -
199
 *
200
 *  Returns a random date chosen uniformly in the specified range.
201
 */
202
Datum
203
date_random(PG_FUNCTION_ARGS)
204
0
{
205
0
  int32   rmin = (int32) PG_GETARG_DATEADT(0);
206
0
  int32   rmax = (int32) PG_GETARG_DATEADT(1);
207
0
  DateADT   result;
208
209
0
  CHECK_RANGE_BOUNDS(rmin, rmax);
210
211
0
  if (DATE_IS_NOBEGIN(rmin) || DATE_IS_NOEND(rmax))
212
0
    ereport(ERROR,
213
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
214
0
        errmsg("lower and upper bounds must be finite"));
215
216
0
  initialize_prng();
217
218
0
  result = (DateADT) pg_prng_int64_range(&prng_state, rmin, rmax);
219
220
0
  PG_RETURN_DATEADT(result);
221
0
}
222
223
/*
224
 * timestamp_random() -
225
 *
226
 *  Returns a random timestamp chosen uniformly in the specified range.
227
 */
228
Datum
229
timestamp_random(PG_FUNCTION_ARGS)
230
0
{
231
0
  int64   rmin = (int64) PG_GETARG_TIMESTAMP(0);
232
0
  int64   rmax = (int64) PG_GETARG_TIMESTAMP(1);
233
0
  Timestamp result;
234
235
0
  CHECK_RANGE_BOUNDS(rmin, rmax);
236
237
0
  if (TIMESTAMP_IS_NOBEGIN(rmin) || TIMESTAMP_IS_NOEND(rmax))
238
0
    ereport(ERROR,
239
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
240
0
        errmsg("lower and upper bounds must be finite"));
241
242
0
  initialize_prng();
243
244
0
  result = (Timestamp) pg_prng_int64_range(&prng_state, rmin, rmax);
245
246
0
  PG_RETURN_TIMESTAMP(result);
247
0
}
248
249
/*
250
 * timestamptz_random() -
251
 *
252
 *  Returns a random timestamptz chosen uniformly in the specified range.
253
 */
254
Datum
255
timestamptz_random(PG_FUNCTION_ARGS)
256
0
{
257
0
  int64   rmin = (int64) PG_GETARG_TIMESTAMPTZ(0);
258
0
  int64   rmax = (int64) PG_GETARG_TIMESTAMPTZ(1);
259
0
  TimestampTz result;
260
261
0
  CHECK_RANGE_BOUNDS(rmin, rmax);
262
263
0
  if (TIMESTAMP_IS_NOBEGIN(rmin) || TIMESTAMP_IS_NOEND(rmax))
264
0
    ereport(ERROR,
265
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
266
0
        errmsg("lower and upper bounds must be finite"));
267
268
0
  initialize_prng();
269
270
0
  result = (TimestampTz) pg_prng_int64_range(&prng_state, rmin, rmax);
271
272
0
  PG_RETURN_TIMESTAMPTZ(result);
273
0
}