From 6a5d6847c0ac68ee33b60335a592dee84b5ca023 Mon Sep 17 00:00:00 2001 From: JeanArhancet Date: Fri, 19 Jul 2024 17:45:20 +0200 Subject: [PATCH 1/2] feat: add random function --- COMPAT.md | 2 +- Cargo.lock | 1 + core/Cargo.toml | 1 + core/expr.rs | 15 +++++++++++++++ core/function.rs | 3 +++ core/vdbe.rs | 27 ++++++++++++++++++++++++++- 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index c32e71e20..7eb47d080 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -90,7 +90,7 @@ This document describes the SQLite compatibility status of Limbo: | octet_length(X) | No | | | printf(FORMAT,...) | No | | | quote(X) | No | | -| random() | No | | +| random() | Yes | | | randomblob(N) | No | | | replace(X,Y,Z) | No | | | round(X) | No | | diff --git a/Cargo.lock b/Cargo.lock index 094f4bf99..27d64c8ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,6 +1005,7 @@ dependencies = [ "ordered-multimap", "polling", "pprof", + "rand", "regex", "rstest", "rusqlite", diff --git a/core/Cargo.toml b/core/Cargo.toml index fd0d36cc4..ac18b2b8d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -38,6 +38,7 @@ ordered-multimap = "0.7.1" sieve-cache = "0.1.4" sqlite3-parser = "0.11.0" thiserror = "1.0.61" +rand = "0.8.5" regex = "1.10.5" [target.'cfg(not(target_family = "windows"))'.dev-dependencies] diff --git a/core/expr.rs b/core/expr.rs index dfc79d634..938a55880 100644 --- a/core/expr.rs +++ b/core/expr.rs @@ -353,6 +353,21 @@ pub fn translate_expr( func: SingleRowFunc::Lower, }); + Ok(target_register) + } + SingleRowFunc::Random => { + if args.is_some() { + anyhow::bail!("Parse error: random function withargumentst"); + } + dbg!("random args", &args); + let regs = program.alloc_register(); + + program.emit_insn(Insn::Function { + start_reg: regs, + dest: target_register, + func: SingleRowFunc::Random, + }); + Ok(target_register) } } diff --git a/core/function.rs b/core/function.rs index 5bd12eb02..b01369f2e 100644 --- a/core/function.rs +++ b/core/function.rs @@ -34,6 +34,7 @@ pub enum SingleRowFunc { Abs, Upper, Lower, + Random, } impl ToString for SingleRowFunc { @@ -44,6 +45,7 @@ impl ToString for SingleRowFunc { SingleRowFunc::Abs => "abs".to_string(), SingleRowFunc::Upper => "upper".to_string(), SingleRowFunc::Lower => "lower".to_string(), + SingleRowFunc::Random => "random".to_string(), } } } @@ -71,6 +73,7 @@ impl FromStr for Func { "abs" => Ok(Func::SingleRow(SingleRowFunc::Abs)), "upper" => Ok(Func::SingleRow(SingleRowFunc::Upper)), "lower" => Ok(Func::SingleRow(SingleRowFunc::Lower)), + "random" => Ok(Func::SingleRow(SingleRowFunc::Random)), _ => Err(()), } } diff --git a/core/vdbe.rs b/core/vdbe.rs index f3857fbb4..71682cb65 100644 --- a/core/vdbe.rs +++ b/core/vdbe.rs @@ -5,6 +5,7 @@ use crate::schema::Table; use crate::types::{AggContext, Cursor, CursorResult, OwnedRecord, OwnedValue, Record}; use anyhow::Result; +use rand::Rng; use regex::Regex; use std::borrow::BorrowMut; use std::cell::RefCell; @@ -1289,6 +1290,10 @@ impl Program { } state.pc += 1; } + SingleRowFunc::Random => { + state.registers[*dest] = exec_random(); + state.pc += 1; + } }, } } @@ -1861,6 +1866,12 @@ fn exec_abs(reg: &OwnedValue) -> Option { } } +fn exec_random() -> OwnedValue { + let mut rng = rand::thread_rng(); + let random_number: i64 = rng.gen(); + OwnedValue::Integer(random_number) +} + // Implements LIKE pattern matching. fn exec_like(pattern: &str, text: &str) -> bool { let re = Regex::new(&pattern.replace('%', ".*").replace('_', ".").to_string()).unwrap(); @@ -1883,7 +1894,7 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool { #[cfg(test)] mod tests { - use super::{exec_abs, exec_if, exec_like, exec_lower, exec_upper, OwnedValue}; + use super::{exec_abs, exec_if, exec_like, exec_lower, exec_random, exec_upper, OwnedValue}; use std::rc::Rc; #[test] @@ -1935,6 +1946,20 @@ mod tests { assert!(!exec_like("%a.ab", "aaaa")); } + #[test] + fn test_random() { + match exec_random() { + OwnedValue::Integer(value) => { + // Check that the value is within the range of i64 + assert!( + value >= i64::MIN && value <= i64::MAX, + "Random number out of range" + ); + } + _ => panic!("exec_random did not return an Integer variant"), + } + } + #[test] fn test_exec_if() { let reg = OwnedValue::Integer(0); From a2d4d73ce5f3dca8141f8b2ffed582936d0cd65d Mon Sep 17 00:00:00 2001 From: JeanArhancet Date: Fri, 19 Jul 2024 21:22:14 +0200 Subject: [PATCH 2/2] refactor: use getrandom --- Cargo.lock | 4 +++- core/Cargo.toml | 2 +- core/expr.rs | 3 +-- core/vdbe.rs | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27d64c8ea..9be5c8555 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -737,8 +737,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -997,6 +999,7 @@ dependencies = [ "cfg_block", "criterion", "fallible-iterator 0.3.0", + "getrandom", "io-uring", "libc", "log", @@ -1005,7 +1008,6 @@ dependencies = [ "ordered-multimap", "polling", "pprof", - "rand", "regex", "rstest", "rusqlite", diff --git a/core/Cargo.toml b/core/Cargo.toml index ac18b2b8d..4a4dbe5b5 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -38,7 +38,7 @@ ordered-multimap = "0.7.1" sieve-cache = "0.1.4" sqlite3-parser = "0.11.0" thiserror = "1.0.61" -rand = "0.8.5" +getrandom = { version = "0.2.15", features = ["js"] } regex = "1.10.5" [target.'cfg(not(target_family = "windows"))'.dev-dependencies] diff --git a/core/expr.rs b/core/expr.rs index 938a55880..00a562034 100644 --- a/core/expr.rs +++ b/core/expr.rs @@ -357,9 +357,8 @@ pub fn translate_expr( } SingleRowFunc::Random => { if args.is_some() { - anyhow::bail!("Parse error: random function withargumentst"); + anyhow::bail!("Parse error: random function with arguments"); } - dbg!("random args", &args); let regs = program.alloc_register(); program.emit_insn(Insn::Function { diff --git a/core/vdbe.rs b/core/vdbe.rs index 71682cb65..1e82e7242 100644 --- a/core/vdbe.rs +++ b/core/vdbe.rs @@ -5,7 +5,6 @@ use crate::schema::Table; use crate::types::{AggContext, Cursor, CursorResult, OwnedRecord, OwnedValue, Record}; use anyhow::Result; -use rand::Rng; use regex::Regex; use std::borrow::BorrowMut; use std::cell::RefCell; @@ -1867,8 +1866,9 @@ fn exec_abs(reg: &OwnedValue) -> Option { } fn exec_random() -> OwnedValue { - let mut rng = rand::thread_rng(); - let random_number: i64 = rng.gen(); + let mut buf = [0u8; 8]; + getrandom::getrandom(&mut buf).unwrap(); + let random_number = i64::from_ne_bytes(buf); OwnedValue::Integer(random_number) }