Coverage Report

Created: 2025-06-13 06:06

/src/postgres/src/backend/utils/adt/pseudorandomfuncs.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * pseudorandomfuncs.c
4
 *    Functions giving SQL access to a pseudorandom number generator.
5
 *
6
 * Portions Copyright (c) 1996-2025, 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 */
25
static pg_prng_state prng_state;
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
34
initialize_prng(void)
35
0
{
36
0
  if (unlikely(!prng_seed_set))
37
0
  {
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
     */
43
0
    if (unlikely(!pg_prng_strong_seed(&prng_state)))
44
0
    {
45
0
      TimestampTz now = GetCurrentTimestamp();
46
0
      uint64    iseed;
47
48
      /* Mix the PID with the most predictable bits of the timestamp */
49
0
      iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
50
0
      pg_prng_seed(&prng_state, iseed);
51
0
    }
52
0
    prng_seed_set = true;
53
0
  }
54
0
}
55
56
/*
57
 * setseed() -
58
 *
59
 *  Seed the PRNG from a specified value in the range [-1.0, 1.0].
60
 */
61
Datum
62
setseed(PG_FUNCTION_ARGS)
63
0
{
64
0
  float8    seed = PG_GETARG_FLOAT8(0);
65
66
0
  if (seed < -1 || seed > 1 || isnan(seed))
67
0
    ereport(ERROR,
68
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
69
0
        errmsg("setseed parameter %g is out of allowed range [-1,1]",
70
0
             seed));
71
72
0
  pg_prng_fseed(&prng_state, seed);
73
0
  prng_seed_set = true;
74
75
0
  PG_RETURN_VOID();
76
0
}
77
78
/*
79
 * drandom() -
80
 *
81
 *  Returns a random number chosen uniformly in the range [0.0, 1.0).
82
 */
83
Datum
84
drandom(PG_FUNCTION_ARGS)
85
0
{
86
0
  float8    result;
87
88
0
  initialize_prng();
89
90
  /* pg_prng_double produces desired result range [0.0, 1.0) */
91
0
  result = pg_prng_double(&prng_state);
92
93
0
  PG_RETURN_FLOAT8(result);
94
0
}
95
96
/*
97
 * drandom_normal() -
98
 *
99
 *  Returns a random number from a normal distribution.
100
 */
101
Datum
102
drandom_normal(PG_FUNCTION_ARGS)
103
0
{
104
0
  float8    mean = PG_GETARG_FLOAT8(0);
105
0
  float8    stddev = PG_GETARG_FLOAT8(1);
106
0
  float8    result,
107
0
        z;
108
109
0
  initialize_prng();
110
111
  /* Get random value from standard normal(mean = 0.0, stddev = 1.0) */
112
0
  z = pg_prng_double_normal(&prng_state);
113
  /* Transform the normal standard variable (z) */
114
  /* using the target normal distribution parameters */
115
0
  result = (stddev * z) + mean;
116
117
0
  PG_RETURN_FLOAT8(result);
118
0
}
119
120
/*
121
 * int4random() -
122
 *
123
 *  Returns a random 32-bit integer chosen uniformly in the specified range.
124
 */
125
Datum
126
int4random(PG_FUNCTION_ARGS)
127
0
{
128
0
  int32   rmin = PG_GETARG_INT32(0);
129
0
  int32   rmax = PG_GETARG_INT32(1);
130
0
  int32   result;
131
132
0
  if (rmin > rmax)
133
0
    ereport(ERROR,
134
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
135
0
        errmsg("lower bound must be less than or equal to upper bound"));
136
137
0
  initialize_prng();
138
139
0
  result = (int32) pg_prng_int64_range(&prng_state, rmin, rmax);
140
141
0
  PG_RETURN_INT32(result);
142
0
}
143
144
/*
145
 * int8random() -
146
 *
147
 *  Returns a random 64-bit integer chosen uniformly in the specified range.
148
 */
149
Datum
150
int8random(PG_FUNCTION_ARGS)
151
0
{
152
0
  int64   rmin = PG_GETARG_INT64(0);
153
0
  int64   rmax = PG_GETARG_INT64(1);
154
0
  int64   result;
155
156
0
  if (rmin > rmax)
157
0
    ereport(ERROR,
158
0
        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
159
0
        errmsg("lower bound must be less than or equal to upper bound"));
160
161
0
  initialize_prng();
162
163
0
  result = pg_prng_int64_range(&prng_state, rmin, rmax);
164
165
0
  PG_RETURN_INT64(result);
166
0
}
167
168
/*
169
 * numeric_random() -
170
 *
171
 *  Returns a random numeric value chosen uniformly in the specified range.
172
 */
173
Datum
174
numeric_random(PG_FUNCTION_ARGS)
175
0
{
176
0
  Numeric   rmin = PG_GETARG_NUMERIC(0);
177
0
  Numeric   rmax = PG_GETARG_NUMERIC(1);
178
0
  Numeric   result;
179
180
0
  initialize_prng();
181
182
0
  result = random_numeric(&prng_state, rmin, rmax);
183
184
0
  PG_RETURN_NUMERIC(result);
185
0
}