LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pseudorandomfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.5 % 73 69
Test Date: 2026-03-12 03:15:11 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            Line data    Source code
       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              :     do { \
      35              :         if ((rmin) > (rmax)) \
      36              :             ereport(ERROR, \
      37              :                     errcode(ERRCODE_INVALID_PARAMETER_VALUE), \
      38              :                     errmsg("lower bound must be less than or equal to upper bound")); \
      39              :     } 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      1285937 : initialize_prng(void)
      48              : {
      49      1285937 :     if (unlikely(!prng_seed_set))
      50              :     {
      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           89 :         if (unlikely(!pg_prng_strong_seed(&prng_state)))
      57              :         {
      58            0 :             TimestampTz now = GetCurrentTimestamp();
      59              :             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              :         }
      65           89 :         prng_seed_set = true;
      66              :     }
      67      1285937 : }
      68              : 
      69              : /*
      70              :  * setseed() -
      71              :  *
      72              :  *  Seed the PRNG from a specified value in the range [-1.0, 1.0].
      73              :  */
      74              : Datum
      75            7 : setseed(PG_FUNCTION_ARGS)
      76              : {
      77            7 :     float8      seed = PG_GETARG_FLOAT8(0);
      78              : 
      79            7 :     if (seed < -1 || seed > 1 || isnan(seed))
      80            0 :         ereport(ERROR,
      81              :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      82              :                 errmsg("setseed parameter %g is out of allowed range [-1,1]",
      83              :                        seed));
      84              : 
      85            7 :     pg_prng_fseed(&prng_state, seed);
      86            7 :     prng_seed_set = true;
      87              : 
      88            7 :     PG_RETURN_VOID();
      89              : }
      90              : 
      91              : /*
      92              :  * drandom() -
      93              :  *
      94              :  *  Returns a random number chosen uniformly in the range [0.0, 1.0).
      95              :  */
      96              : Datum
      97      1208411 : drandom(PG_FUNCTION_ARGS)
      98              : {
      99              :     float8      result;
     100              : 
     101      1208411 :     initialize_prng();
     102              : 
     103              :     /* pg_prng_double produces desired result range [0.0, 1.0) */
     104      1208411 :     result = pg_prng_double(&prng_state);
     105              : 
     106      1208411 :     PG_RETURN_FLOAT8(result);
     107              : }
     108              : 
     109              : /*
     110              :  * drandom_normal() -
     111              :  *
     112              :  *  Returns a random number from a normal distribution.
     113              :  */
     114              : Datum
     115        12660 : drandom_normal(PG_FUNCTION_ARGS)
     116              : {
     117        12660 :     float8      mean = PG_GETARG_FLOAT8(0);
     118        12660 :     float8      stddev = PG_GETARG_FLOAT8(1);
     119              :     float8      result,
     120              :                 z;
     121              : 
     122        12660 :     initialize_prng();
     123              : 
     124              :     /* Get random value from standard normal(mean = 0.0, stddev = 1.0) */
     125        12660 :     z = pg_prng_double_normal(&prng_state);
     126              :     /* Transform the normal standard variable (z) */
     127              :     /* using the target normal distribution parameters */
     128        12660 :     result = (stddev * z) + mean;
     129              : 
     130        12660 :     PG_RETURN_FLOAT8(result);
     131              : }
     132              : 
     133              : /*
     134              :  * int4random() -
     135              :  *
     136              :  *  Returns a random 32-bit integer chosen uniformly in the specified range.
     137              :  */
     138              : Datum
     139        25572 : int4random(PG_FUNCTION_ARGS)
     140              : {
     141        25572 :     int32       rmin = PG_GETARG_INT32(0);
     142        25572 :     int32       rmax = PG_GETARG_INT32(1);
     143              :     int32       result;
     144              : 
     145        25572 :     CHECK_RANGE_BOUNDS(rmin, rmax);
     146              : 
     147        25569 :     initialize_prng();
     148              : 
     149        25569 :     result = (int32) pg_prng_int64_range(&prng_state, rmin, rmax);
     150              : 
     151        25569 :     PG_RETURN_INT32(result);
     152              : }
     153              : 
     154              : /*
     155              :  * int8random() -
     156              :  *
     157              :  *  Returns a random 64-bit integer chosen uniformly in the specified range.
     158              :  */
     159              : Datum
     160        22536 : int8random(PG_FUNCTION_ARGS)
     161              : {
     162        22536 :     int64       rmin = PG_GETARG_INT64(0);
     163        22536 :     int64       rmax = PG_GETARG_INT64(1);
     164              :     int64       result;
     165              : 
     166        22536 :     CHECK_RANGE_BOUNDS(rmin, rmax);
     167              : 
     168        22533 :     initialize_prng();
     169              : 
     170        22533 :     result = pg_prng_int64_range(&prng_state, rmin, rmax);
     171              : 
     172        22533 :     PG_RETURN_INT64(result);
     173              : }
     174              : 
     175              : /*
     176              :  * numeric_random() -
     177              :  *
     178              :  *  Returns a random numeric value chosen uniformly in the specified range.
     179              :  */
     180              : Datum
     181        16731 : numeric_random(PG_FUNCTION_ARGS)
     182              : {
     183        16731 :     Numeric     rmin = PG_GETARG_NUMERIC(0);
     184        16731 :     Numeric     rmax = PG_GETARG_NUMERIC(1);
     185              :     Numeric     result;
     186              : 
     187              :     /* Leave range bound checking to random_numeric() */
     188              : 
     189        16731 :     initialize_prng();
     190              : 
     191        16731 :     result = random_numeric(&prng_state, rmin, rmax);
     192              : 
     193        16716 :     PG_RETURN_NUMERIC(result);
     194              : }
     195              : 
     196              : 
     197              : /*
     198              :  * date_random() -
     199              :  *
     200              :  *  Returns a random date chosen uniformly in the specified range.
     201              :  */
     202              : Datum
     203           18 : date_random(PG_FUNCTION_ARGS)
     204              : {
     205           18 :     int32       rmin = (int32) PG_GETARG_DATEADT(0);
     206           18 :     int32       rmax = (int32) PG_GETARG_DATEADT(1);
     207              :     DateADT     result;
     208              : 
     209           18 :     CHECK_RANGE_BOUNDS(rmin, rmax);
     210              : 
     211           15 :     if (DATE_IS_NOBEGIN(rmin) || DATE_IS_NOEND(rmax))
     212            6 :         ereport(ERROR,
     213              :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     214              :                 errmsg("lower and upper bounds must be finite"));
     215              : 
     216            9 :     initialize_prng();
     217              : 
     218            9 :     result = (DateADT) pg_prng_int64_range(&prng_state, rmin, rmax);
     219              : 
     220            9 :     PG_RETURN_DATEADT(result);
     221              : }
     222              : 
     223              : /*
     224              :  * timestamp_random() -
     225              :  *
     226              :  *  Returns a random timestamp chosen uniformly in the specified range.
     227              :  */
     228              : Datum
     229           21 : timestamp_random(PG_FUNCTION_ARGS)
     230              : {
     231           21 :     int64       rmin = (int64) PG_GETARG_TIMESTAMP(0);
     232           21 :     int64       rmax = (int64) PG_GETARG_TIMESTAMP(1);
     233              :     Timestamp   result;
     234              : 
     235           21 :     CHECK_RANGE_BOUNDS(rmin, rmax);
     236              : 
     237           18 :     if (TIMESTAMP_IS_NOBEGIN(rmin) || TIMESTAMP_IS_NOEND(rmax))
     238            6 :         ereport(ERROR,
     239              :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     240              :                 errmsg("lower and upper bounds must be finite"));
     241              : 
     242           12 :     initialize_prng();
     243              : 
     244           12 :     result = (Timestamp) pg_prng_int64_range(&prng_state, rmin, rmax);
     245              : 
     246           12 :     PG_RETURN_TIMESTAMP(result);
     247              : }
     248              : 
     249              : /*
     250              :  * timestamptz_random() -
     251              :  *
     252              :  *  Returns a random timestamptz chosen uniformly in the specified range.
     253              :  */
     254              : Datum
     255           21 : timestamptz_random(PG_FUNCTION_ARGS)
     256              : {
     257           21 :     int64       rmin = (int64) PG_GETARG_TIMESTAMPTZ(0);
     258           21 :     int64       rmax = (int64) PG_GETARG_TIMESTAMPTZ(1);
     259              :     TimestampTz result;
     260              : 
     261           21 :     CHECK_RANGE_BOUNDS(rmin, rmax);
     262              : 
     263           18 :     if (TIMESTAMP_IS_NOBEGIN(rmin) || TIMESTAMP_IS_NOEND(rmax))
     264            6 :         ereport(ERROR,
     265              :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     266              :                 errmsg("lower and upper bounds must be finite"));
     267              : 
     268           12 :     initialize_prng();
     269              : 
     270           12 :     result = (TimestampTz) pg_prng_int64_range(&prng_state, rmin, rmax);
     271              : 
     272           12 :     PG_RETURN_TIMESTAMPTZ(result);
     273              : }
        

Generated by: LCOV version 2.0-1