/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.synth.sql;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Random;
/**
* A random data generator class.
*/
public class RandomGen {
private Random random = new Random();
/**
* Create a new random instance with a fixed seed value.
*/
public RandomGen() {
random.setSeed(12);
}
/**
* Get the next integer that is smaller than max.
*
* @param max the upper limit (exclusive)
* @return the random value
*/
public int getInt(int max) {
return max == 0 ? 0 : random.nextInt(max);
}
/**
* Get the next gaussian value.
*
* @return the value
*/
public double nextGaussian() {
return random.nextGaussian();
}
/**
* Get the next random value that is at most max but probably much lower.
*
* @param max the maximum value
* @return the value
*/
public int getLog(int max) {
if (max == 0) {
return 0;
}
while (true) {
int d = Math.abs((int) (random.nextGaussian() / 2. * max));
if (d < max) {
return d;
}
}
}
/**
* Get a number of random bytes.
*
* @param data the target buffer
*/
public void getBytes(byte[] data) {
random.nextBytes(data);
}
/**
* Get a boolean that is true with the given probability in percent.
*
* @param percent the probability
* @return the boolean value
*/
public boolean getBoolean(int percent) {
return random.nextInt(100) <= percent;
}
/**
* Get a random string with the given length.
*
* @param len the length
* @return the string
*/
public String randomString(int len) {
StringBuilder buff = new StringBuilder();
for (int i = 0; i < len; i++) {
String from = (i % 2 == 0) ? "bdfghklmnpqrst" : "aeiou";
buff.append(from.charAt(getInt(from.length())));
}
return buff.toString();
}
/**
* Get a random integer. In 10% of the cases, Integer.MAX_VALUE is returned,
* in 10% of the cases Integer.MIN_VALUE. Also in the 10% of the cases, a
* random value between those extremes is returned. In 20% of the cases,
* this method returns 0. In 10% of the cases, a gaussian value in the range
* -200 and +1800 is returned. In all other cases, a gaussian value in the
* range -5 and +20 is returned.
*
* @return the random value
*/
public int getRandomInt() {
switch (random.nextInt(10)) {
case 0:
return Integer.MAX_VALUE;
case 1:
return Integer.MIN_VALUE;
case 2:
return random.nextInt();
case 3:
case 4:
return 0;
case 5:
return (int) (random.nextGaussian() * 2000) - 200;
default:
return (int) (random.nextGaussian() * 20) - 5;
}
}
/**
* Get a random long. The algorithm is similar to a random int.
*
* @return the random value
*/
public long getRandomLong() {
switch (random.nextInt(10)) {
case 0:
return Long.MAX_VALUE;
case 1:
return Long.MIN_VALUE;
case 2:
return random.nextLong();
case 3:
case 4:
return 0;
case 5:
return (int) (random.nextGaussian() * 20000) - 2000;
default:
return (int) (random.nextGaussian() * 200) - 50;
}
}
/**
* Get a random double. The algorithm is similar to a random int.
*
* @return the random value
*/
public double getRandomDouble() {
switch (random.nextInt(10)) {
case 0:
return Double.MIN_VALUE;
case 1:
return Double.MAX_VALUE;
case 2:
return Float.MIN_VALUE;
case 3:
return Float.MAX_VALUE;
case 4:
return random.nextDouble();
case 5:
case 6:
return 0;
case 7:
return random.nextGaussian() * 20000. - 2000.;
default:
return random.nextGaussian() * 200. - 50.;
}
}
/**
* Get a random boolean.
*
* @return the random value
*/
public boolean nextBoolean() {
return random.nextBoolean();
}
/**
* Get a random integer array. In 10% of the cases, null is returned.
*
* @return the array
*/
public int[] getIntArray() {
switch (random.nextInt(10)) {
case 0:
return null;
default:
int len = getInt(100);
int[] list = new int[len];
for (int i = 0; i < len; i++) {
list[i] = getRandomInt();
}
return list;
}
}
/**
* Get a random byte array. In 10% of the cases, null is returned.
*
* @return the array
*/
public byte[] getByteArray() {
switch (random.nextInt(10)) {
case 0:
return null;
default:
int len = getInt(100);
byte[] list = new byte[len];
random.nextBytes(list);
return list;
}
}
/**
* Get a random time value. In 10% of the cases, null is returned.
*
* @return the value
*/
public Time randomTime() {
if (random.nextInt(10) == 0) {
return null;
}
StringBuilder buff = new StringBuilder();
buff.append(getInt(24));
buff.append(':');
buff.append(getInt(24));
buff.append(':');
buff.append(getInt(24));
return Time.valueOf(buff.toString());
}
/**
* Get a random timestamp value. In 10% of the cases, null is returned.
*
* @return the value
*/
public Timestamp randomTimestamp() {
if (random.nextInt(10) == 0) {
return null;
}
StringBuilder buff = new StringBuilder();
buff.append(getInt(10) + 2000);
buff.append('-');
int month = getInt(12) + 1;
if (month < 10) {
buff.append('0');
}
buff.append(month);
buff.append('-');
int day = getInt(28) + 1;
if (day < 10) {
buff.append('0');
}
buff.append(day);
buff.append(' ');
int hour = getInt(24);
if (hour < 10) {
buff.append('0');
}
buff.append(hour);
buff.append(':');
int minute = getInt(60);
if (minute < 10) {
buff.append('0');
}
buff.append(minute);
buff.append(':');
int second = getInt(60);
if (second < 10) {
buff.append('0');
}
buff.append(second);
// TODO test timestamp nanos
return Timestamp.valueOf(buff.toString());
}
/**
* Get a random date value. In 10% of the cases, null is returned.
*
* @return the value
*/
public Date randomDate() {
if (random.nextInt(10) == 0) {
return null;
}
StringBuilder buff = new StringBuilder();
buff.append(getInt(10) + 2000);
buff.append('-');
int month = getInt(12) + 1;
if (month < 10) {
buff.append('0');
}
buff.append(month);
buff.append('-');
int day = getInt(28) + 1;
if (day < 10) {
buff.append('0');
}
buff.append(day);
return Date.valueOf(buff.toString());
}
/**
* Randomly modify a SQL statement.
*
* @param sql the original SQL statement
* @return the modified statement
*/
public String modify(String sql) {
int len = getLog(10);
for (int i = 0; i < len; i++) {
int pos = getInt(sql.length());
if (getBoolean(50)) {
String badChars = "abcABCDEF\u00ef\u00f6\u00fcC1230=<>+\"\\*%&/()=?$_-.:,;{}[]";
// auml, ouml, uuml
char bad = badChars.charAt(getInt(badChars.length()));
sql = sql.substring(0, pos) + bad + sql.substring(pos);
} else {
if (pos >= sql.length()) {
sql = sql.substring(0, pos);
} else {
sql = sql.substring(0, pos) + sql.substring(pos + 1);
}
}
}
return sql;
}
/**
* Set the seed value.
*
* @param seed the new seed value
*/
public void setSeed(int seed) {
random.setSeed(seed);
}
}