1# ==== Purpose ====
2#
3# Generate a random number in such a way that the sequence of numbers
4# generated by successive calls can be deterministic.
5#
6# ==== Usage ====
7#
8# --let $rand_type= { int | float | decide | init }
9# [--let $rand_min= MIN_VALUE]
10# [--let $rand_max= MAX_VALUE]
11# [--let $rand_probability= THRESHOLD]
12# [--let $rand_seed= SEED]
13# --source include/rand.inc
14# --echo Random number: $rand
15#
16# Parameters:
17#
18#   $rand_type
19#     If set to 'int', generates an integer in the range
20#     [$rand_min, $rand_max).
21#
22#     If set to 'float', generates a floating point number in the
23#     range [$rand_min, $rand_max).
24#
25#     If set to 'decide', generates 1 with probability
26#     $rand_probability and 0 with probability 1-$rand_probability.
27#
28#     If set to 'init', does not generate $rand, but initializes
29#     the $rand_seed in case this is the first invocation.
30#
31#   $rand_min, $rand_max
32#     Range of values for $rand_type=int or $rand_type=float.
33#     These are evaluated in an SQL query, so may contain valid
34#     arithmetic operations.
35#
36#   $rand_probability
37#     Probability to get a '1' if $rand_type=decide.
38#     This is evaluated in an SQL query, so may contain valid
39#     arithmetic operations.
40#
41#   $rand_seed
42#     The seed value.  If you want to set the seed to a random number
43#     that is different for each invokation of the test, set
44#     $rand_seed to the empty string.  Normally, $rand_seed is only
45#     read in the first invokation of rand.inc.  If you want to reset
46#     the seed later, set $_rand_state to the empty string.
47#
48# ==== Implementation ====
49#
50# This RNG uses the following multiply-with-carry algorithm:
51#   int32 z, w;
52#   if (z == 0) z = 1;
53#   if (w == 0) w = 1;
54#   z = 36969 * (z & 65535) + (z >> 16);
55#   w = 18000 * (w & 65535) + (w >> 16);
56#   rand = (z << 16) + w;
57# In this implementation, z is stored in the low 32 bits and w in the
58# high 32 bits of $_rand_state.
59
60--let $_maxint32= ((1 << 32) - 1)
61
62if ($_rand_state == '')
63{
64  if ($rand_seed == '')
65  {
66    --let $rand_seed= `SELECT FLOOR(RAND() * (1 << 63))`
67  }
68  --let $write_var= $rand_seed
69  --let $write_to_file= $MYSQLTEST_VARDIR/tmp/rand_seed
70  --source include/write_var_to_file.inc
71  --let $_rand_state= $rand_seed
72  --let $_rand_lo= IF(($_rand_state) & $_maxint32 = 0, 1, ($_rand_state) & $_maxint32)
73  --let $_rand_hi= IF(($_rand_state) >> 32 = 0, 1, ($_rand_state) >> 32)
74  --let $_rand_state= `SELECT ((36969 * $_rand_lo + ($_rand_lo >> 16)) & $_maxint32) + (((18000 * ($_rand_hi & 65535) + ($_rand_hi >> 16)) & $_maxint32) << 32)`
75}
76
77--let $_rand_lo= IF(($_rand_state) & $_maxint32 = 0, 1, ($_rand_state) & $_maxint32)
78--let $_rand_hi= IF(($_rand_state) >> 32 = 0, 1, ($_rand_state) >> 32)
79--let $_rand_state= `SELECT ((36969 * $_rand_lo + ($_rand_lo >> 16)) & $_maxint32) + (((18000 * ($_rand_hi & 65535) + ($_rand_hi >> 16)) & $_maxint32) << 32)`
80--let $rand= ((($_rand_state << 16) + ($_rand_state >> 32)) & $_maxint32)
81
82if ($rand_type == decide)
83{
84  --let $_rand_probability= 0.5
85  if ($rand_probability != '')
86  {
87    --let $_rand_probability= $rand_probability
88  }
89  --let $rand= `SELECT IF($rand / (1 << 32) < ($rand_probability), 1, 0)`
90}
91if ($rand_type != decide)
92{
93  --let $_rand_min= 0
94  if ($rand_min)
95  {
96    --let $_rand_min= $rand_min
97  }
98  --let $_rand_max= 1
99  if ($rand_max)
100  {
101    --let $_rand_max= $rand_max
102  }
103  if ($rand_type == int)
104  {
105    --let $rand= `SELECT ($_rand_min) + ($rand % (($_rand_max) - ($_rand_min)))`
106  }
107  if ($rand_type == float)
108  {
109    --let $rand= `SELECT ($_rand_min) + ($rand * (($_rand_max) - ($_rand_min)) / (1 << 32))`
110  }
111}
112--error 0,1
113--remove_file $MYSQLTEST_VARDIR/tmp/rand_seed
114