Skip to content

Commit faa7952

Browse files
Initial comit
0 parents  commit faa7952

File tree

4 files changed

+796
-0
lines changed

4 files changed

+796
-0
lines changed

README.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Random data generator for MySQL
2+
3+
Many times in my job i need to generate random data for a specific table in order to reproduce an issue.
4+
After writing many random generators for every table, I decided to write a random data generator, able to get the table structure and generate random data for it.
5+
Plase take into consideration that this is the first version and it doesn't support all field types yet!
6+
7+
**NOTICE**
8+
This is an early stage project.
9+
10+
## Supported fields:
11+
12+
|Field type|Generated values|
13+
|----------|----------------|
14+
|tinyint|0 ~ 0xFF|
15+
|smallint|0 ~ 0XFFFF|
16+
|mediumint|0 ~ 0xFFFFFF|
17+
|int - integer|0 ~ 0xFFFFFFFF|
18+
|bigint|0 ~ 0xFFFFFFFFFFFFFFFF|
19+
|float|0 ~ 1e8|
20+
|decimal(m,n)|0 ~ 10^(m-n)|
21+
|double|0 ~ 1000|
22+
|char(n)|up to n random chars|
23+
|varchar(n)|up to n random chars|
24+
|date|NOW() - 1 year ~ NOW()|
25+
|datetime|NOW() - 1 year ~ NOW()|
26+
|timestamp|NOW() - 1 year ~ NOW()|
27+
|time|00:00:00 ~ 23:59:59|
28+
|year|Current year - 1 ~ current year|
29+
|blob|up to 100 chars random paragraph|
30+
|text|up to 100 chars random paragraph|
31+
|mediumblob|up to 100 chars random paragraph|
32+
|mediumtext|up to 100 chars random paragraph|
33+
|longblob|up to 100 chars random paragraph|
34+
|longtext|up to 100 chars random paragraph|
35+
|varbinary|up to 100 chars random paragraph|
36+
|enum|A random item from the valid items list|
37+
|set|A random item from the valid items list|
38+
39+
### How strings are generated
40+
41+
- If field size < 10 the program generates a random "first name"
42+
- If the field size > 10 and < 30 the program generates a random "full name"
43+
- If the field size > 30 the program generates a "lorem ipsum" paragraph having up to 100 chars.
44+
45+
The program can detect if a field accepts NULLs and if it does, it will generate NULLs ramdomly (~ 10 % of the values).
46+
47+
## Usage
48+
`random-data-generator <database> <table> <number of rows> [options...]`
49+
50+
## Options
51+
|Option|Description|
52+
|------|-----------|
53+
|--host|Host name/ip|
54+
|--port|Port number|
55+
|--user|Username|
56+
|--password|Password|
57+
|--bulk-size|Number of rows per INSERT statement (Default: 1000)|
58+
|--debug|Show some debug information|
59+
60+
### Example
61+
```
62+
CREATE DATABASE IF NOT EXISTS test;
63+
64+
CREATE TABLE `test`.`t3` (
65+
`id` int(11) NOT NULL AUTO_INCREMENT,
66+
`tcol01` tinyint(4) DEFAULT NULL,
67+
`tcol02` smallint(6) DEFAULT NULL,
68+
`tcol03` mediumint(9) DEFAULT NULL,
69+
`tcol04` int(11) DEFAULT NULL,
70+
`tcol05` bigint(20) DEFAULT NULL,
71+
`tcol06` float DEFAULT NULL,
72+
`tcol07` double DEFAULT NULL,
73+
`tcol08` decimal(10,2) DEFAULT NULL,
74+
`tcol09` date DEFAULT NULL,
75+
`tcol10` datetime DEFAULT NULL,
76+
`tcol11` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
77+
`tcol12` time DEFAULT NULL,
78+
`tcol13` year(4) DEFAULT NULL,
79+
`tcol14` varchar(100) DEFAULT NULL,
80+
`tcol15` char(2) DEFAULT NULL,
81+
`tcol16` blob,
82+
`tcol17` text,
83+
`tcol18` mediumtext,
84+
`tcol19` mediumblob,
85+
`tcol20` longblob,
86+
`tcol21` longtext,
87+
`tcol22` mediumtext,
88+
`tcol23` varchar(3) DEFAULT NULL,
89+
`tcol24` varbinary(10) DEFAULT NULL,
90+
`tcol25` enum('a','b','c') DEFAULT NULL,
91+
`tcol26` set('red','green','blue') DEFAULT NULL,
92+
`tcol27` float(5,3) DEFAULT NULL,
93+
`tcol28` double(4,2) DEFAULT NULL,
94+
PRIMARY KEY (`id`)
95+
) ENGINE=InnoDB;
96+
```
97+
To generate 10K random rows, just run:
98+
```
99+
random-data-load test t3 100000 --max-threads=8 --user=root --password=root
100+
```
101+
```
102+
mysql> select * from t3 limit 1\G
103+
*************************** 1. row ***************************
104+
id: 1
105+
tcol01: 10
106+
tcol02: 173
107+
tcol03: 1700
108+
tcol04: 13498
109+
tcol05: 33239373
110+
tcol06: 44846.4
111+
tcol07: 5300.23
112+
tcol08: 11360967.75
113+
tcol09: 2017-09-04
114+
tcol10: 2016-11-02 23:11:25
115+
tcol11: 2017-03-03 08:11:40
116+
tcol12: 03:19:39
117+
tcol13: 2017
118+
tcol14: repellat maxime nostrum provident maiores ut quo voluptas.
119+
tcol15: Th
120+
tcol16: Walter
121+
tcol17: quo repellat accusamus quidem odi
122+
tcol18: esse laboriosam nobis libero aut dolores e
123+
tcol19: Carlos Willia
124+
tcol20: et nostrum iusto ipsa sunt recusa
125+
tcol21: a accusantium laboriosam voluptas facilis.
126+
tcol22: laudantium quo unde molestiae consequatur magnam.
127+
tcol23: Pet
128+
tcol24: Richard
129+
tcol25: c
130+
tcol26: green
131+
tcol27: 47.430
132+
tcol28: 6.12
133+
1 row in set (0.00 sec)
134+
```
135+
136+
## To do
137+
- [ ] Add suport for all data types.
138+
- [ ] Add supporrt for foreign keys.
139+
- [ ] Support config files to override default values/ranges.
140+
- [ ] Support custom functions via LUA plugins.

internal/getters/getters.go

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package getters
2+
3+
import (
4+
"fmt"
5+
"math"
6+
"math/rand"
7+
"time"
8+
9+
"github.com/icrowley/fake"
10+
)
11+
12+
const (
13+
nilFrequency = 10
14+
oneYear = 60 * 60 * 24 * 365 * time.Second
15+
)
16+
17+
type Getter interface {
18+
Value() interface{}
19+
}
20+
21+
type RandomInt struct {
22+
mask uint64
23+
allowNull bool
24+
}
25+
26+
func (r *RandomInt) Value() interface{} {
27+
rand.Seed(time.Now().UnixNano())
28+
return uint64(rand.Int63n(10e8)) & r.mask
29+
}
30+
31+
func NewRandomInt(mask uint64, allowNull bool) Getter {
32+
return &RandomInt{mask, allowNull}
33+
}
34+
35+
type RandomIntRange struct {
36+
min int64
37+
max int64
38+
allowNull bool
39+
}
40+
41+
func (r *RandomIntRange) Value() interface{} {
42+
rand.Seed(time.Now().UnixNano())
43+
limit := r.max - r.min + 1
44+
return r.min + rand.Int63n(limit)
45+
}
46+
47+
func NewRandomIntRange(min, max int64, allowNull bool) Getter {
48+
return &RandomIntRange{min, max, allowNull}
49+
}
50+
51+
type RandomDecimal struct {
52+
size float64
53+
allowNull bool
54+
}
55+
56+
func (r *RandomDecimal) Value() interface{} {
57+
rand.Seed(time.Now().UnixNano())
58+
f := rand.Float64() * float64(rand.Int63n(int64(math.Pow10(int(r.size)))))
59+
format := fmt.Sprintf("%%%0.1ff", r.size)
60+
return fmt.Sprintf(format, f)
61+
}
62+
63+
func NewRandomDecimal(size float64, allowNull bool) Getter {
64+
if size == 0 {
65+
size = 5.2
66+
}
67+
return &RandomDecimal{size, allowNull}
68+
}
69+
70+
type RandomString struct {
71+
maxSize float64
72+
allowNull bool
73+
}
74+
75+
func (r *RandomString) Value() interface{} {
76+
rand.Seed(time.Now().UnixNano())
77+
if r.allowNull && rand.Int63n(100) < nilFrequency {
78+
return nil
79+
}
80+
var s string
81+
maxSize := uint64(r.maxSize)
82+
if maxSize == 0 {
83+
maxSize = uint64(rand.Int63n(100))
84+
}
85+
86+
if maxSize <= 10 {
87+
s = fake.FirstName()
88+
} else if maxSize < 30 {
89+
s = fake.FullName()
90+
} else {
91+
s = fake.Sentence()
92+
}
93+
if len(s) > int(maxSize) {
94+
s = s[:int(maxSize)]
95+
}
96+
return s
97+
}
98+
99+
func NewRandomString(maxSize float64, allowNull bool) Getter {
100+
return &RandomString{maxSize, allowNull}
101+
}
102+
103+
type RandomDate struct {
104+
allowNull bool
105+
}
106+
107+
func (r *RandomDate) Value() interface{} {
108+
rand.Seed(time.Now().UnixNano())
109+
d := time.Now().Add(time.Duration(-1*int64(uint64(rand.Int63n(int64(oneYear))))) * time.Second)
110+
return d.Format("2006-01-02 15:03:04")
111+
}
112+
113+
func NewRandomDate(allowNull bool) Getter {
114+
return &RandomDate{allowNull}
115+
}
116+
117+
type RandomDateInRange struct {
118+
min string
119+
max string
120+
allowNull bool
121+
}
122+
123+
func (r *RandomDateInRange) Value() interface{} {
124+
d := time.Now().Add(time.Duration(-1*rand.Int63n(int64(oneYear.Seconds()))) * time.Second)
125+
return d.Format("2006-01-02 15:03:04")
126+
}
127+
128+
func NewRandomDateInRange(min, max string, allowNull bool) Getter {
129+
if min == "" {
130+
t := time.Now().Add(-1 * oneYear)
131+
min = t.Format("2006-01-02")
132+
}
133+
return &RandomDateInRange{min, max, allowNull}
134+
}
135+
136+
type RandomDateTimeInRange struct {
137+
min string
138+
max string
139+
allowNull bool
140+
}
141+
142+
func (r *RandomDateTimeInRange) Value() interface{} {
143+
d := time.Now().Add(time.Duration(-1*rand.Int63n(int64(oneYear.Seconds()))) * time.Second)
144+
return d.Format("2006-01-02 15:03:04")
145+
}
146+
147+
func NewRandomDateTimeInRange(min, max string, allowNull bool) Getter {
148+
if min == "" {
149+
t := time.Now().Add(-1 * oneYear)
150+
min = t.Format("2006-01-02")
151+
}
152+
return &RandomDateInRange{min, max, allowNull}
153+
}
154+
155+
func NewRandomDateTime(allowNull bool) Getter {
156+
return &RandomDateInRange{"", "", allowNull}
157+
}
158+
159+
// RandomTime Getter
160+
type RandomTime struct {
161+
allowNull bool
162+
}
163+
164+
func (r *RandomTime) Value() interface{} {
165+
rand.Seed(time.Now().UnixNano())
166+
h := rand.Int63n(24)
167+
m := rand.Int63n(60)
168+
s := rand.Int63n(60)
169+
return fmt.Sprintf("%02d:%02d:%02d", h, m, s)
170+
}
171+
172+
func NewRandomTime(allowNull bool) Getter {
173+
return &RandomTime{allowNull}
174+
}
175+
176+
// RandomEnum Getter
177+
type RandomEnum struct {
178+
allowedValues []string
179+
allowNull bool
180+
}
181+
182+
func (r *RandomEnum) Value() interface{} {
183+
rand.Seed(time.Now().UnixNano())
184+
if r.allowNull && rand.Int63n(100) < nilFrequency {
185+
return nil
186+
}
187+
i := rand.Int63n(int64(len(r.allowedValues)))
188+
return r.allowedValues[i]
189+
}
190+
191+
func NewRandomEnum(allowedValues []string, allowNull bool) Getter {
192+
return &RandomEnum{allowedValues, allowNull}
193+
}
194+
195+
// Constant Getter. Used for debugging
196+
type Constant struct {
197+
}
198+
199+
func (r *Constant) Value() interface{} {
200+
return "constant"
201+
}
202+
203+
func NewConstant() Getter {
204+
return &Constant{}
205+
}

0 commit comments

Comments
 (0)