Ensure SQL rand()
functions do not hang indefinitely
This commit is contained in:
parent
bb0b10e38a
commit
9fa0a4fbb4
1 changed files with 60 additions and 31 deletions
|
@ -1,8 +1,8 @@
|
|||
use crate::cnf::ID_CHARS;
|
||||
use crate::err::Error;
|
||||
use crate::sql::datetime::Datetime;
|
||||
use crate::sql::uuid::Uuid;
|
||||
use crate::sql::value::Value;
|
||||
use chrono::{TimeZone, Utc};
|
||||
use nanoid::nanoid;
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use rand::prelude::IteratorRandom;
|
||||
|
@ -41,22 +41,39 @@ pub fn float((range,): (Option<(f64, f64)>,)) -> Result<Value, Error> {
|
|||
.into())
|
||||
}
|
||||
|
||||
pub fn guid((len,): (Option<usize>,)) -> Result<Value, Error> {
|
||||
// Only need 53 to uniquely identify all atoms in observable universe.
|
||||
const LIMIT: usize = 64;
|
||||
|
||||
let len = match len {
|
||||
Some(len) if len <= LIMIT => len,
|
||||
None => 20,
|
||||
_ => {
|
||||
pub fn guid((arg1, arg2): (Option<i64>, Option<i64>)) -> Result<Value, Error> {
|
||||
// Set a reasonable maximum length
|
||||
const LIMIT: i64 = 64;
|
||||
// Check the function input arguments
|
||||
let val = if let Some((min, max)) = arg1.zip(arg2) {
|
||||
match min {
|
||||
min if (1..=LIMIT).contains(&min) => match max {
|
||||
max if min <= max && max <= LIMIT => rand::thread_rng().gen_range(min as usize..=max as usize),
|
||||
max if max >= 1 && max <= min => rand::thread_rng().gen_range(max as usize..=min as usize),
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::guid"),
|
||||
message: format!("To generate a guid of between X and Y characters in length, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
}),
|
||||
},
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::guid"),
|
||||
message: format!("To generate a string of between X and Y characters in length, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
}),
|
||||
}
|
||||
} else if let Some(len) = arg1 {
|
||||
if (1..=LIMIT).contains(&len) {
|
||||
len as usize
|
||||
} else {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::guid"),
|
||||
message: format!("The maximum length of a GUID is {}.", LIMIT),
|
||||
})
|
||||
message: format!("To generate a string of X characters in length, the argument must be a positive number and no higher than {}.", LIMIT),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
20
|
||||
};
|
||||
|
||||
Ok(nanoid!(len, &ID_CHARS).into())
|
||||
// Generate the random guid
|
||||
Ok(nanoid!(val, &ID_CHARS).into())
|
||||
}
|
||||
|
||||
pub fn int((range,): (Option<(i64, i64)>,)) -> Result<Value, Error> {
|
||||
|
@ -73,14 +90,14 @@ pub fn int((range,): (Option<(i64, i64)>,)) -> Result<Value, Error> {
|
|||
}
|
||||
|
||||
pub fn string((arg1, arg2): (Option<i64>, Option<i64>)) -> Result<Value, Error> {
|
||||
// Limit how much time and bandwidth is spent.
|
||||
const LIMIT: i64 = 2i64.pow(16);
|
||||
|
||||
let len = if let Some((min, max)) = arg1.zip(arg2) {
|
||||
// Set a reasonable maximum length
|
||||
const LIMIT: i64 = 65536;
|
||||
// Check the function input arguments
|
||||
let val = if let Some((min, max)) = arg1.zip(arg2) {
|
||||
match min {
|
||||
min if (0..=LIMIT).contains(&min) => match max {
|
||||
min if (1..=LIMIT).contains(&min) => match max {
|
||||
max if min <= max && max <= LIMIT => rand::thread_rng().gen_range(min as usize..=max as usize),
|
||||
max if max >= 0 && max <= min => rand::thread_rng().gen_range(max as usize..=min as usize),
|
||||
max if max >= 1 && max <= min => rand::thread_rng().gen_range(max as usize..=min as usize),
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::string"),
|
||||
message: format!("To generate a string of between X and Y characters in length, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
|
@ -92,7 +109,7 @@ pub fn string((arg1, arg2): (Option<i64>, Option<i64>)) -> Result<Value, Error>
|
|||
}),
|
||||
}
|
||||
} else if let Some(len) = arg1 {
|
||||
if (0..=LIMIT).contains(&len) {
|
||||
if (1..=LIMIT).contains(&len) {
|
||||
len as usize
|
||||
} else {
|
||||
return Err(Error::InvalidArguments {
|
||||
|
@ -103,22 +120,34 @@ pub fn string((arg1, arg2): (Option<i64>, Option<i64>)) -> Result<Value, Error>
|
|||
} else {
|
||||
32
|
||||
};
|
||||
|
||||
Ok(Alphanumeric.sample_string(&mut rand::thread_rng(), len).into())
|
||||
// Generate the random string
|
||||
Ok(Alphanumeric.sample_string(&mut rand::thread_rng(), val).into())
|
||||
}
|
||||
|
||||
pub fn time((range,): (Option<(i64, i64)>,)) -> Result<Value, Error> {
|
||||
let i = if let Some((min, max)) = range {
|
||||
let range = if max < min {
|
||||
max..=min
|
||||
} else {
|
||||
min..=max
|
||||
};
|
||||
rand::thread_rng().gen_range(range)
|
||||
// Set the maximum valid seconds
|
||||
const LIMIT: i64 = 8210298412799;
|
||||
// Check the function input arguments
|
||||
let val = if let Some((min, max)) = range {
|
||||
match min {
|
||||
min if (1..=LIMIT).contains(&min) => match max {
|
||||
max if min <= max && max <= LIMIT => rand::thread_rng().gen_range(min..=max),
|
||||
max if max >= 1 && max <= min => rand::thread_rng().gen_range(max..=min),
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::time"),
|
||||
message: format!("To generate a time between X and Y seconds, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
}),
|
||||
},
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::time"),
|
||||
message: format!("To generate a time between X and Y seconds, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
rand::random::<i32>() as i64
|
||||
rand::thread_rng().gen_range(0..=LIMIT)
|
||||
};
|
||||
Ok(Datetime::from(i).into())
|
||||
// Generate the random time
|
||||
Ok(Utc.timestamp_opt(val, 0).earliest().unwrap().into())
|
||||
}
|
||||
|
||||
pub fn ulid(_: ()) -> Result<Value, Error> {
|
||||
|
|
Loading…
Reference in a new issue