LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pseudorandomfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 44 48 91.7 %
Date: 2024-04-28 19:11:06 Functions: 7 7 100.0 %
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-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 */
      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     1155406 : initialize_prng(void)
      35             : {
      36     1155406 :     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             :          */
      43         134 :         if (unlikely(!pg_prng_strong_seed(&prng_state)))
      44             :         {
      45           0 :             TimestampTz now = GetCurrentTimestamp();
      46             :             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             :         }
      52         134 :         prng_seed_set = true;
      53             :     }
      54     1155406 : }
      55             : 
      56             : /*
      57             :  * setseed() -
      58             :  *
      59             :  *  Seed the PRNG from a specified value in the range [-1.0, 1.0].
      60             :  */
      61             : Datum
      62           8 : setseed(PG_FUNCTION_ARGS)
      63             : {
      64           8 :     float8      seed = PG_GETARG_FLOAT8(0);
      65             : 
      66           8 :     if (seed < -1 || seed > 1 || isnan(seed))
      67           0 :         ereport(ERROR,
      68             :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      69             :                 errmsg("setseed parameter %g is out of allowed range [-1,1]",
      70             :                        seed));
      71             : 
      72           8 :     pg_prng_fseed(&prng_state, seed);
      73           8 :     prng_seed_set = true;
      74             : 
      75           8 :     PG_RETURN_VOID();
      76             : }
      77             : 
      78             : /*
      79             :  * drandom() -
      80             :  *
      81             :  *  Returns a random number chosen uniformly in the range [0.0, 1.0).
      82             :  */
      83             : Datum
      84     1000432 : drandom(PG_FUNCTION_ARGS)
      85             : {
      86             :     float8      result;
      87             : 
      88     1000432 :     initialize_prng();
      89             : 
      90             :     /* pg_prng_double produces desired result range [0.0, 1.0) */
      91     1000432 :     result = pg_prng_double(&prng_state);
      92             : 
      93     1000432 :     PG_RETURN_FLOAT8(result);
      94             : }
      95             : 
      96             : /*
      97             :  * drandom_normal() -
      98             :  *
      99             :  *  Returns a random number from a normal distribution.
     100             :  */
     101             : Datum
     102       25320 : drandom_normal(PG_FUNCTION_ARGS)
     103             : {
     104       25320 :     float8      mean = PG_GETARG_FLOAT8(0);
     105       25320 :     float8      stddev = PG_GETARG_FLOAT8(1);
     106             :     float8      result,
     107             :                 z;
     108             : 
     109       25320 :     initialize_prng();
     110             : 
     111             :     /* Get random value from standard normal(mean = 0.0, stddev = 1.0) */
     112       25320 :     z = pg_prng_double_normal(&prng_state);
     113             :     /* Transform the normal standard variable (z) */
     114             :     /* using the target normal distribution parameters */
     115       25320 :     result = (stddev * z) + mean;
     116             : 
     117       25320 :     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
     126       51132 : int4random(PG_FUNCTION_ARGS)
     127             : {
     128       51132 :     int32       rmin = PG_GETARG_INT32(0);
     129       51132 :     int32       rmax = PG_GETARG_INT32(1);
     130             :     int32       result;
     131             : 
     132       51132 :     if (rmin > rmax)
     133           6 :         ereport(ERROR,
     134             :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     135             :                 errmsg("lower bound must be less than or equal to upper bound"));
     136             : 
     137       51126 :     initialize_prng();
     138             : 
     139       51126 :     result = (int32) pg_prng_int64_range(&prng_state, rmin, rmax);
     140             : 
     141       51126 :     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
     150       45072 : int8random(PG_FUNCTION_ARGS)
     151             : {
     152       45072 :     int64       rmin = PG_GETARG_INT64(0);
     153       45072 :     int64       rmax = PG_GETARG_INT64(1);
     154             :     int64       result;
     155             : 
     156       45072 :     if (rmin > rmax)
     157           6 :         ereport(ERROR,
     158             :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     159             :                 errmsg("lower bound must be less than or equal to upper bound"));
     160             : 
     161       45066 :     initialize_prng();
     162             : 
     163       45066 :     result = pg_prng_int64_range(&prng_state, rmin, rmax);
     164             : 
     165       45066 :     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
     174       33462 : numeric_random(PG_FUNCTION_ARGS)
     175             : {
     176       33462 :     Numeric     rmin = PG_GETARG_NUMERIC(0);
     177       33462 :     Numeric     rmax = PG_GETARG_NUMERIC(1);
     178             :     Numeric     result;
     179             : 
     180       33462 :     initialize_prng();
     181             : 
     182       33462 :     result = random_numeric(&prng_state, rmin, rmax);
     183             : 
     184       33432 :     PG_RETURN_NUMERIC(result);
     185             : }

Generated by: LCOV version 1.14