mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-22 16:35:30 +01:00
Merge branch 'tursodatabase:main' into main
This commit is contained in:
1
.github/workflows/stale.yml
vendored
1
.github/workflows/stale.yml
vendored
@@ -14,6 +14,7 @@ jobs:
|
||||
- name: Close stale pull requests
|
||||
uses: actions/stale@v6
|
||||
with:
|
||||
repo-token: ${{ secrets.STALE_GH_TOKEN }}
|
||||
operations-per-run: 1000
|
||||
ascending: true
|
||||
stale-pr-message: 'This pull request has been marked as stale due to inactivity. It will be closed in 7 days if no further activity occurs.'
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,5 +19,8 @@ env
|
||||
dist/
|
||||
.tmp/
|
||||
|
||||
|
||||
/testing/testing.db-wal
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
## 0.0.9 - 2024-12-12
|
||||
|
||||
### Added
|
||||
|
||||
* Improve CLI (Preston Thorpe)
|
||||
|
||||
* Add support for iif() function (Alex Miller)
|
||||
|
||||
* Add suport for last_insert_rowid() function (Krishna Vishal)
|
||||
|
||||
* Add support JOIN USING and NATURAL JOIN (Jussi Saurio)
|
||||
|
||||
12
COMPAT.md
12
COMPAT.md
@@ -112,7 +112,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
||||
| glob(X,Y) | Yes | |
|
||||
| hex(X) | Yes | |
|
||||
| ifnull(X,Y) | Yes | |
|
||||
| iif(X,Y,Z) | No | |
|
||||
| iif(X,Y,Z) | Yes | |
|
||||
| instr(X,Y) | Yes | |
|
||||
| last_insert_rowid() | Yes | |
|
||||
| length(X) | Yes | |
|
||||
@@ -128,7 +128,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
||||
| max(X,Y,...) | Yes | |
|
||||
| min(X,Y,...) | Yes | |
|
||||
| nullif(X,Y) | Yes | |
|
||||
| octet_length(X) | No | |
|
||||
| octet_length(X) | Yes | |
|
||||
| printf(FORMAT,...) | No | |
|
||||
| quote(X) | Yes | |
|
||||
| random() | Yes | |
|
||||
@@ -139,7 +139,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
||||
| rtrim(X) | Yes | |
|
||||
| rtrim(X,Y) | Yes | |
|
||||
| sign(X) | Yes | |
|
||||
| soundex(X) | No | |
|
||||
| soundex(X) | Yes | |
|
||||
| sqlite_compileoption_get(N) | No | |
|
||||
| sqlite_compileoption_used(X) | No | |
|
||||
| sqlite_offset(X) | No | |
|
||||
@@ -253,9 +253,9 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
|
||||
| AggStep | Yes |
|
||||
| And | No |
|
||||
| AutoCommit | No |
|
||||
| BitAnd | No |
|
||||
| BitNot | No |
|
||||
| BitOr | No |
|
||||
| BitAnd | Yes |
|
||||
| BitNot | Yes |
|
||||
| BitOr | Yes |
|
||||
| Blob | Yes |
|
||||
| Checkpoint | No |
|
||||
| Clear | No |
|
||||
|
||||
14
Cargo.lock
generated
14
Cargo.lock
generated
@@ -405,7 +405,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "core_tester"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1125,7 +1125,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "limbo"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1139,7 +1139,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "limbo-wasm"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
@@ -1149,7 +1149,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "limbo_core"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"cfg_block",
|
||||
"chrono",
|
||||
@@ -1184,7 +1184,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "limbo_sim"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"anarchist-readable-name-generator-lib",
|
||||
"env_logger 0.10.2",
|
||||
@@ -1197,7 +1197,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "limbo_sqlite3"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"env_logger 0.11.5",
|
||||
@@ -1641,7 +1641,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "py-limbo"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"limbo_core",
|
||||
|
||||
@@ -14,7 +14,7 @@ members = [
|
||||
exclude = ["perf/latency/limbo"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
authors = ["the Limbo authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
Install `limbo` with:
|
||||
|
||||
```
|
||||
```shell
|
||||
curl --proto '=https' --tlsv1.2 -LsSf \
|
||||
https://github.com/penberg/limbo/releases/latest/download/limbo-installer.sh | sh
|
||||
```
|
||||
@@ -96,6 +96,12 @@ print(res.fetchone())
|
||||
|
||||
## Developing
|
||||
|
||||
Build and run `limbo` cli:
|
||||
|
||||
```shell
|
||||
cargo run --package limbo --bin limbo database.db
|
||||
```
|
||||
|
||||
Run tests:
|
||||
|
||||
```console
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"collaborators": [
|
||||
"the Limbo authors"
|
||||
],
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.9",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
59
cli/main.rs
59
cli/main.rs
@@ -71,23 +71,49 @@ fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
println!("Limbo v{}", env!("CARGO_PKG_VERSION"));
|
||||
println!("Enter \".help\" for usage hints.");
|
||||
const PROMPT: &str = "limbo> ";
|
||||
let mut input_buff = String::new();
|
||||
let mut prompt = PROMPT.to_string();
|
||||
loop {
|
||||
let readline = rl.readline("limbo> ");
|
||||
let readline = rl.readline(&prompt);
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
let line = line.trim();
|
||||
if input_buff.is_empty() {
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
} else if line.starts_with('.') {
|
||||
if let Err(e) = handle_dot_command(io.clone(), &conn, line) {
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
rl.add_history_entry(line.to_owned())?;
|
||||
interrupt_count.store(0, Ordering::SeqCst);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if line.ends_with(';') {
|
||||
input_buff.push_str(line);
|
||||
input_buff.split(';').for_each(|stmt| {
|
||||
if let Err(e) =
|
||||
query(io.clone(), &conn, stmt, &opts.output_mode, &interrupt_count)
|
||||
{
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
});
|
||||
input_buff.clear();
|
||||
prompt = PROMPT.to_string();
|
||||
} else {
|
||||
input_buff.push_str(line);
|
||||
input_buff.push(' ');
|
||||
prompt = match calc_parens_offset(&input_buff) {
|
||||
n if n < 0 => String::from(")x!...>"),
|
||||
0 => String::from(" ...> "),
|
||||
n if n < 10 => format!("(x{}...> ", n),
|
||||
_ => String::from("(.....> "),
|
||||
};
|
||||
}
|
||||
rl.add_history_entry(line.to_owned())?;
|
||||
interrupt_count.store(0, Ordering::SeqCst);
|
||||
if line.trim().starts_with('.') {
|
||||
handle_dot_command(io.clone(), &conn, &line)?;
|
||||
} else {
|
||||
query(
|
||||
io.clone(),
|
||||
&conn,
|
||||
&line,
|
||||
&opts.output_mode,
|
||||
&interrupt_count,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
// At prompt, increment interrupt count
|
||||
@@ -97,6 +123,7 @@ fn main() -> anyhow::Result<()> {
|
||||
break;
|
||||
}
|
||||
println!("Use .quit to exit or press Ctrl-C again to force quit.");
|
||||
input_buff.clear();
|
||||
continue;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
@@ -113,6 +140,14 @@ fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calc_parens_offset(input: &str) -> i32 {
|
||||
input.chars().fold(0, |acc, c| match c {
|
||||
'(' => acc + 1,
|
||||
')' => acc - 1,
|
||||
_ => acc,
|
||||
})
|
||||
}
|
||||
|
||||
fn display_help_message() {
|
||||
let help_message = r#"
|
||||
Limbo SQL Shell Help
|
||||
|
||||
@@ -56,6 +56,7 @@ pub enum ScalarFunc {
|
||||
ConcatWs,
|
||||
Glob,
|
||||
IfNull,
|
||||
Iif,
|
||||
Instr,
|
||||
Like,
|
||||
Abs,
|
||||
@@ -75,6 +76,7 @@ pub enum ScalarFunc {
|
||||
Sign,
|
||||
Substr,
|
||||
Substring,
|
||||
Soundex,
|
||||
Date,
|
||||
Time,
|
||||
Typeof,
|
||||
@@ -99,6 +101,7 @@ impl Display for ScalarFunc {
|
||||
ScalarFunc::ConcatWs => "concat_ws".to_string(),
|
||||
ScalarFunc::Glob => "glob".to_string(),
|
||||
ScalarFunc::IfNull => "ifnull".to_string(),
|
||||
ScalarFunc::Iif => "iif".to_string(),
|
||||
ScalarFunc::Instr => "instr".to_string(),
|
||||
ScalarFunc::Like => "like(2)".to_string(),
|
||||
ScalarFunc::Abs => "abs".to_string(),
|
||||
@@ -118,6 +121,7 @@ impl Display for ScalarFunc {
|
||||
ScalarFunc::Sign => "sign".to_string(),
|
||||
ScalarFunc::Substr => "substr".to_string(),
|
||||
ScalarFunc::Substring => "substring".to_string(),
|
||||
ScalarFunc::Soundex => "soundex".to_string(),
|
||||
ScalarFunc::Date => "date".to_string(),
|
||||
ScalarFunc::Time => "time".to_string(),
|
||||
ScalarFunc::Typeof => "typeof".to_string(),
|
||||
@@ -180,6 +184,7 @@ impl Func {
|
||||
"concat_ws" => Ok(Func::Scalar(ScalarFunc::ConcatWs)),
|
||||
"glob" => Ok(Func::Scalar(ScalarFunc::Glob)),
|
||||
"ifnull" => Ok(Func::Scalar(ScalarFunc::IfNull)),
|
||||
"iif" => Ok(Func::Scalar(ScalarFunc::Iif)),
|
||||
"instr" => Ok(Func::Scalar(ScalarFunc::Instr)),
|
||||
"like" => Ok(Func::Scalar(ScalarFunc::Like)),
|
||||
"abs" => Ok(Func::Scalar(ScalarFunc::Abs)),
|
||||
@@ -210,6 +215,7 @@ impl Func {
|
||||
"hex" => Ok(Func::Scalar(ScalarFunc::Hex)),
|
||||
"unhex" => Ok(Func::Scalar(ScalarFunc::Unhex)),
|
||||
"zeroblob" => Ok(Func::Scalar(ScalarFunc::ZeroBlob)),
|
||||
"soundex" => Ok(Func::Scalar(ScalarFunc::Soundex)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,6 +694,20 @@ pub fn translate_expr(
|
||||
dest: target_register,
|
||||
});
|
||||
}
|
||||
ast::Operator::BitwiseAnd => {
|
||||
program.emit_insn(Insn::BitAnd {
|
||||
lhs: e1_reg,
|
||||
rhs: e2_reg,
|
||||
dest: target_register,
|
||||
});
|
||||
}
|
||||
ast::Operator::BitwiseOr => {
|
||||
program.emit_insn(Insn::BitOr {
|
||||
lhs: e1_reg,
|
||||
rhs: e2_reg,
|
||||
dest: target_register,
|
||||
});
|
||||
}
|
||||
other_unimplemented => todo!("{:?}", other_unimplemented),
|
||||
}
|
||||
Ok(target_register)
|
||||
@@ -1071,6 +1085,56 @@ pub fn translate_expr(
|
||||
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Iif => {
|
||||
let args = match args {
|
||||
Some(args) if args.len() == 3 => args,
|
||||
_ => crate::bail_parse_error!(
|
||||
"{} requires exactly 3 arguments",
|
||||
srf.to_string()
|
||||
),
|
||||
};
|
||||
let temp_reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[0],
|
||||
temp_reg,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
let jump_target_when_false = program.allocate_label();
|
||||
program.emit_insn_with_label_dependency(
|
||||
Insn::IfNot {
|
||||
reg: temp_reg,
|
||||
target_pc: jump_target_when_false,
|
||||
null_reg: 1,
|
||||
},
|
||||
jump_target_when_false,
|
||||
);
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[1],
|
||||
target_register,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
let jump_target_result = program.allocate_label();
|
||||
program.emit_insn_with_label_dependency(
|
||||
Insn::Goto {
|
||||
target_pc: jump_target_result,
|
||||
},
|
||||
jump_target_result,
|
||||
);
|
||||
program.resolve_label(jump_target_when_false, program.offset());
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[2],
|
||||
target_register,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
program.resolve_label(jump_target_result, program.offset());
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Glob | ScalarFunc::Like => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() < 2 {
|
||||
@@ -1119,6 +1183,7 @@ pub fn translate_expr(
|
||||
| ScalarFunc::Quote
|
||||
| ScalarFunc::RandomBlob
|
||||
| ScalarFunc::Sign
|
||||
| ScalarFunc::Soundex
|
||||
| ScalarFunc::ZeroBlob => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() != 1 {
|
||||
@@ -1664,6 +1729,69 @@ pub fn translate_expr(
|
||||
dest: target_register,
|
||||
});
|
||||
}
|
||||
program.mark_last_insn_constant();
|
||||
Ok(target_register)
|
||||
}
|
||||
(UnaryOperator::Negative, _) => {
|
||||
let reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
expr,
|
||||
reg,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
let zero_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Integer {
|
||||
value: -1,
|
||||
dest: zero_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::Multiply {
|
||||
lhs: zero_reg,
|
||||
rhs: reg,
|
||||
dest: target_register,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
(UnaryOperator::BitwiseNot, ast::Expr::Literal(ast::Literal::Numeric(num_val))) => {
|
||||
let maybe_int = num_val.parse::<i64>();
|
||||
if let Ok(val) = maybe_int {
|
||||
program.emit_insn(Insn::Integer {
|
||||
value: !val,
|
||||
dest: target_register,
|
||||
});
|
||||
} else {
|
||||
let num_val = num_val.parse::<f64>()? as i64;
|
||||
program.emit_insn(Insn::Integer {
|
||||
value: !num_val,
|
||||
dest: target_register,
|
||||
});
|
||||
}
|
||||
program.mark_last_insn_constant();
|
||||
Ok(target_register)
|
||||
}
|
||||
(UnaryOperator::BitwiseNot, ast::Expr::Literal(ast::Literal::Null)) => {
|
||||
program.emit_insn(Insn::Null {
|
||||
dest: target_register,
|
||||
dest_end: None,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
Ok(target_register)
|
||||
}
|
||||
(UnaryOperator::BitwiseNot, _) => {
|
||||
let reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
expr,
|
||||
reg,
|
||||
precomputed_exprs_to_registers,
|
||||
)?;
|
||||
program.emit_insn(Insn::BitNot {
|
||||
reg,
|
||||
dest: target_register,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
_ => todo!(),
|
||||
|
||||
@@ -70,6 +70,11 @@ fn resolve_aggregates(expr: &ast::Expr, aggs: &mut Vec<Aggregate>) -> bool {
|
||||
contains_aggregates |= resolve_aggregates(rhs, aggs);
|
||||
contains_aggregates
|
||||
}
|
||||
ast::Expr::Unary(_, expr) => {
|
||||
let mut contains_aggregates = false;
|
||||
contains_aggregates |= resolve_aggregates(expr, aggs);
|
||||
contains_aggregates
|
||||
}
|
||||
// TODO: handle other expressions that may contain aggregates
|
||||
_ => false,
|
||||
}
|
||||
|
||||
@@ -55,6 +55,33 @@ pub fn insn_to_str(
|
||||
0,
|
||||
format!("r[{}]=r[{}]/r[{}]", dest, lhs, rhs),
|
||||
),
|
||||
Insn::BitAnd { lhs, rhs, dest } => (
|
||||
"BitAnd",
|
||||
*lhs as i32,
|
||||
*rhs as i32,
|
||||
*dest as i32,
|
||||
OwnedValue::Text(Rc::new("".to_string())),
|
||||
0,
|
||||
format!("r[{}]=r[{}]&r[{}]", dest, lhs, rhs),
|
||||
),
|
||||
Insn::BitOr { lhs, rhs, dest } => (
|
||||
"BitOr",
|
||||
*lhs as i32,
|
||||
*rhs as i32,
|
||||
*dest as i32,
|
||||
OwnedValue::Text(Rc::new("".to_string())),
|
||||
0,
|
||||
format!("r[{}]=r[{}]|r[{}]", dest, lhs, rhs),
|
||||
),
|
||||
Insn::BitNot { reg, dest } => (
|
||||
"BitNot",
|
||||
*reg as i32,
|
||||
*dest as i32,
|
||||
0,
|
||||
OwnedValue::Text(Rc::new("".to_string())),
|
||||
0,
|
||||
format!("r[{}]=~r[{}]", dest, reg),
|
||||
),
|
||||
Insn::Null { dest, dest_end } => (
|
||||
"Null",
|
||||
0,
|
||||
|
||||
367
core/vdbe/mod.rs
367
core/vdbe/mod.rs
@@ -119,6 +119,23 @@ pub enum Insn {
|
||||
start_reg_b: usize,
|
||||
count: usize,
|
||||
},
|
||||
// Place the result of rhs bitwise AND lhs in third register.
|
||||
BitAnd {
|
||||
lhs: usize,
|
||||
rhs: usize,
|
||||
dest: usize,
|
||||
},
|
||||
// Place the result of rhs bitwise OR lhs in third register.
|
||||
BitOr {
|
||||
lhs: usize,
|
||||
rhs: usize,
|
||||
dest: usize,
|
||||
},
|
||||
// Place the result of bitwise NOT register P1 in dest register.
|
||||
BitNot {
|
||||
reg: usize,
|
||||
dest: usize,
|
||||
},
|
||||
// Jump to the instruction at address P1, P2, or P3 depending on whether in the most recent Compare instruction the P1 vector was less than, equal to, or greater than the P2 vector, respectively.
|
||||
Jump {
|
||||
target_pc_lt: BranchOffset,
|
||||
@@ -838,7 +855,7 @@ impl Program {
|
||||
}
|
||||
(OwnedValue::Integer(i), OwnedValue::Float(f))
|
||||
| (OwnedValue::Float(f), OwnedValue::Integer(i)) => {
|
||||
state.registers[dest] = OwnedValue::Float(*i as f64 * *f as f64);
|
||||
state.registers[dest] = OwnedValue::Float(*i as f64 * { *f });
|
||||
}
|
||||
(OwnedValue::Null, _) | (_, OwnedValue::Null) => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
@@ -1011,6 +1028,196 @@ impl Program {
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
Insn::BitAnd { lhs, rhs, dest } => {
|
||||
let lhs = *lhs;
|
||||
let rhs = *rhs;
|
||||
let dest = *dest;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
// handle 0 and null cases
|
||||
(OwnedValue::Null, _) | (_, OwnedValue::Null) => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
}
|
||||
(_, OwnedValue::Integer(0))
|
||||
| (OwnedValue::Integer(0), _)
|
||||
| (_, OwnedValue::Float(0.0))
|
||||
| (OwnedValue::Float(0.0), _) => {
|
||||
state.registers[dest] = OwnedValue::Integer(0);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh & rh);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(*lh as i64 & *rh as i64);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(*lh as i64 & rh);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh & *rh as i64);
|
||||
}
|
||||
(OwnedValue::Agg(aggctx), other) | (other, OwnedValue::Agg(aggctx)) => {
|
||||
match other {
|
||||
OwnedValue::Agg(aggctx2) => {
|
||||
match (aggctx.final_value(), aggctx2.final_value()) {
|
||||
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh & rh);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(*lh as i64 & *rh as i64);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(lh & *rh as i64);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(*lh as i64 & rh);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!(
|
||||
"{:?} {:?}",
|
||||
aggctx.final_value(),
|
||||
aggctx2.final_value()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
other => match (aggctx.final_value(), other) {
|
||||
(OwnedValue::Null, _) | (_, OwnedValue::Null) => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
}
|
||||
(_, OwnedValue::Integer(0))
|
||||
| (OwnedValue::Integer(0), _)
|
||||
| (_, OwnedValue::Float(0.0))
|
||||
| (OwnedValue::Float(0.0), _) => {
|
||||
state.registers[dest] = OwnedValue::Integer(0);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh & rh);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(*lh as i64 & rh);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(lh & *rh as i64);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("{:?} {:?}", aggctx.final_value(), other);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("{:?} {:?}", state.registers[lhs], state.registers[rhs]);
|
||||
}
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
Insn::BitOr { lhs, rhs, dest } => {
|
||||
let lhs = *lhs;
|
||||
let rhs = *rhs;
|
||||
let dest = *dest;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(OwnedValue::Null, _) | (_, OwnedValue::Null) => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh | rh);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(*lh as i64 | rh);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh | *rh as i64);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(*lh as i64 | *rh as i64);
|
||||
}
|
||||
(OwnedValue::Agg(aggctx), other) | (other, OwnedValue::Agg(aggctx)) => {
|
||||
match other {
|
||||
OwnedValue::Agg(aggctx2) => {
|
||||
let final_lhs = aggctx.final_value();
|
||||
let final_rhs = aggctx2.final_value();
|
||||
match (final_lhs, final_rhs) {
|
||||
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh | rh);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(*lh as i64 | *rh as i64);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(lh | *rh as i64);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(*lh as i64 | rh);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("{:?} {:?}", final_lhs, final_rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
other => match (aggctx.final_value(), other) {
|
||||
(OwnedValue::Null, _) | (_, OwnedValue::Null) => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] = OwnedValue::Integer(lh | rh);
|
||||
}
|
||||
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(*lh as i64 | rh);
|
||||
}
|
||||
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
|
||||
state.registers[dest] =
|
||||
OwnedValue::Integer(lh | *rh as i64);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("{:?} {:?}", aggctx.final_value(), other);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("{:?} {:?}", state.registers[lhs], state.registers[rhs]);
|
||||
}
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
Insn::BitNot { reg, dest } => {
|
||||
let reg = *reg;
|
||||
let dest = *dest;
|
||||
match &state.registers[reg] {
|
||||
OwnedValue::Integer(i) => state.registers[dest] = OwnedValue::Integer(!i),
|
||||
OwnedValue::Float(f) => {
|
||||
state.registers[dest] = OwnedValue::Integer(!{ *f as i64 })
|
||||
}
|
||||
OwnedValue::Null => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
}
|
||||
OwnedValue::Agg(aggctx) => match aggctx.final_value() {
|
||||
OwnedValue::Integer(i) => {
|
||||
state.registers[dest] = OwnedValue::Integer(!i);
|
||||
}
|
||||
OwnedValue::Float(f) => {
|
||||
state.registers[dest] = OwnedValue::Integer(!{ *f as i64 });
|
||||
}
|
||||
OwnedValue::Null => {
|
||||
state.registers[dest] = OwnedValue::Null;
|
||||
}
|
||||
_ => unimplemented!("{:?}", aggctx),
|
||||
},
|
||||
_ => {
|
||||
unimplemented!("{:?}", state.registers[reg]);
|
||||
}
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
Insn::Null { dest, dest_end } => {
|
||||
if let Some(dest_end) = dest_end {
|
||||
for i in *dest..=*dest_end {
|
||||
@@ -2106,6 +2313,13 @@ impl Program {
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::IfNull => {}
|
||||
ScalarFunc::Iif => {}
|
||||
ScalarFunc::Instr => {
|
||||
let reg_value = &state.registers[*start_reg];
|
||||
let pattern_value = &state.registers[*start_reg + 1];
|
||||
let result = exec_instr(reg_value, pattern_value);
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::LastInsertRowid => {
|
||||
if let Some(conn) = self.connection.upgrade() {
|
||||
state.registers[*dest] =
|
||||
@@ -2114,12 +2328,6 @@ impl Program {
|
||||
state.registers[*dest] = OwnedValue::Null;
|
||||
}
|
||||
}
|
||||
ScalarFunc::Instr => {
|
||||
let reg_value = &state.registers[*start_reg];
|
||||
let pattern_value = &state.registers[*start_reg + 1];
|
||||
let result = exec_instr(reg_value, pattern_value);
|
||||
state.registers[*dest] = result;
|
||||
}
|
||||
ScalarFunc::Like => {
|
||||
let pattern = &state.registers[*start_reg];
|
||||
let text = &state.registers[*start_reg + 1];
|
||||
@@ -2148,6 +2356,7 @@ impl Program {
|
||||
| ScalarFunc::Quote
|
||||
| ScalarFunc::RandomBlob
|
||||
| ScalarFunc::Sign
|
||||
| ScalarFunc::Soundex
|
||||
| ScalarFunc::ZeroBlob => {
|
||||
let reg_value = state.registers[*start_reg].borrow_mut();
|
||||
let result = match scalar_func {
|
||||
@@ -2162,6 +2371,7 @@ impl Program {
|
||||
ScalarFunc::Quote => Some(exec_quote(reg_value)),
|
||||
ScalarFunc::RandomBlob => Some(exec_randomblob(reg_value)),
|
||||
ScalarFunc::ZeroBlob => Some(exec_zeroblob(reg_value)),
|
||||
ScalarFunc::Soundex => Some(exec_soundex(reg_value)),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
state.registers[*dest] = result.unwrap_or(OwnedValue::Null);
|
||||
@@ -2672,6 +2882,96 @@ fn exec_sign(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
Some(OwnedValue::Integer(sign))
|
||||
}
|
||||
|
||||
/// Generates the Soundex code for a given word
|
||||
pub fn exec_soundex(reg: &OwnedValue) -> OwnedValue {
|
||||
let s = match reg {
|
||||
OwnedValue::Null => return OwnedValue::Text(Rc::new("?000".to_string())),
|
||||
OwnedValue::Text(s) => {
|
||||
// return ?000 if non ASCII alphabet character is found
|
||||
if !s.chars().all(|c| c.is_ascii_alphabetic()) {
|
||||
return OwnedValue::Text(Rc::new("?000".to_string()));
|
||||
}
|
||||
s.clone()
|
||||
}
|
||||
_ => return OwnedValue::Text(Rc::new("?000".to_string())), // For unsupported types, return NULL
|
||||
};
|
||||
|
||||
// Remove numbers and spaces
|
||||
let word: String = s
|
||||
.chars()
|
||||
.filter(|c| !c.is_digit(10))
|
||||
.collect::<String>()
|
||||
.replace(" ", "");
|
||||
if word.is_empty() {
|
||||
return OwnedValue::Text(Rc::new("0000".to_string()));
|
||||
}
|
||||
|
||||
let soundex_code = |c| match c {
|
||||
'b' | 'f' | 'p' | 'v' => Some('1'),
|
||||
'c' | 'g' | 'j' | 'k' | 'q' | 's' | 'x' | 'z' => Some('2'),
|
||||
'd' | 't' => Some('3'),
|
||||
'l' => Some('4'),
|
||||
'm' | 'n' => Some('5'),
|
||||
'r' => Some('6'),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Convert the word to lowercase for consistent lookups
|
||||
let word = word.to_lowercase();
|
||||
let first_letter = word.chars().next().unwrap();
|
||||
|
||||
// Remove all occurrences of 'h' and 'w' except the first letter
|
||||
let code: String = word
|
||||
.chars()
|
||||
.skip(1)
|
||||
.filter(|&ch| ch != 'h' && ch != 'w')
|
||||
.fold(first_letter.to_string(), |mut acc, ch| {
|
||||
acc.push(ch);
|
||||
acc
|
||||
});
|
||||
|
||||
// Replace consonants with digits based on Soundex mapping
|
||||
let tmp: String = code
|
||||
.chars()
|
||||
.map(|ch| match soundex_code(ch) {
|
||||
Some(code) => code.to_string(),
|
||||
None => ch.to_string(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Remove adjacent same digits
|
||||
let tmp = tmp.chars().fold(String::new(), |mut acc, ch| {
|
||||
if acc.chars().last() != Some(ch) {
|
||||
acc.push(ch);
|
||||
}
|
||||
acc
|
||||
});
|
||||
|
||||
// Remove all occurrences of a, e, i, o, u, y except the first letter
|
||||
let mut result = tmp
|
||||
.chars()
|
||||
.enumerate()
|
||||
.filter(|(i, ch)| *i == 0 || !matches!(ch, 'a' | 'e' | 'i' | 'o' | 'u' | 'y'))
|
||||
.map(|(_, ch)| ch)
|
||||
.collect::<String>();
|
||||
|
||||
// If the first symbol is a digit, replace it with the saved first letter
|
||||
if let Some(first_digit) = result.chars().next() {
|
||||
if first_digit.is_digit(10) {
|
||||
result.replace_range(0..1, &first_letter.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Append zeros if the result contains less than 4 characters
|
||||
while result.len() < 4 {
|
||||
result.push('0');
|
||||
}
|
||||
|
||||
// Retain the first 4 characters and convert to uppercase
|
||||
result.truncate(4);
|
||||
OwnedValue::Text(Rc::new(result.to_uppercase()))
|
||||
}
|
||||
|
||||
fn exec_abs(reg: &OwnedValue) -> Option<OwnedValue> {
|
||||
match reg {
|
||||
OwnedValue::Integer(x) => {
|
||||
@@ -3295,9 +3595,9 @@ mod tests {
|
||||
use super::{
|
||||
exec_abs, exec_char, exec_hex, exec_if, exec_instr, exec_length, exec_like, exec_lower,
|
||||
exec_ltrim, exec_max, exec_min, exec_nullif, exec_quote, exec_random, exec_randomblob,
|
||||
exec_round, exec_rtrim, exec_sign, exec_substring, exec_trim, exec_typeof, exec_unhex,
|
||||
exec_unicode, exec_upper, exec_zeroblob, execute_sqlite_version, get_new_rowid, AggContext,
|
||||
Cursor, CursorResult, LimboError, OwnedRecord, OwnedValue, Result,
|
||||
exec_round, exec_rtrim, exec_sign, exec_soundex, exec_substring, exec_trim, exec_typeof,
|
||||
exec_unhex, exec_unicode, exec_upper, exec_zeroblob, execute_sqlite_version, get_new_rowid,
|
||||
AggContext, Cursor, CursorResult, LimboError, OwnedRecord, OwnedValue, Result,
|
||||
};
|
||||
use mockall::{mock, predicate};
|
||||
use rand::{rngs::mock::StepRng, thread_rng};
|
||||
@@ -3627,6 +3927,53 @@ mod tests {
|
||||
assert_eq!(exec_rtrim(&input_str, Some(pattern_str)), expected_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_soundex() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Pfister")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("P236")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("husobee")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("H210")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Tymczak")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("T522")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Ashcraft")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("A261")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Robert")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("R163")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Rupert")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("R163")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Rubin")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("R150")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Kant")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("K530")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Knuth")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("K530")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("x")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("X000")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("闪电五连鞭")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("?000")));
|
||||
assert_eq!(exec_soundex(&input_str), expected_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upper_case() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Limbo")));
|
||||
|
||||
56
perf/latency/limbo/Cargo.lock
generated
56
perf/latency/limbo/Cargo.lock
generated
@@ -32,20 +32,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon 2.1.0",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.11"
|
||||
@@ -55,7 +41,7 @@ dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon 3.0.2",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
@@ -84,16 +70,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.2"
|
||||
@@ -192,9 +168,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.2"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
|
||||
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -202,11 +178,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.2"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
|
||||
checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
|
||||
dependencies = [
|
||||
"anstream 0.5.0",
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
@@ -214,9 +190,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.2"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -226,9 +202,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
@@ -321,7 +297,7 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9eeb342678d785662fd2514be38c459bb925f02b68dd2a3e0f21d7ef82d979dd"
|
||||
dependencies = [
|
||||
"anstream 0.6.11",
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
@@ -411,9 +387,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
@@ -545,7 +521,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "limbo_core"
|
||||
version = "0.0.5"
|
||||
version = "0.0.8"
|
||||
dependencies = [
|
||||
"cfg_block",
|
||||
"chrono",
|
||||
@@ -944,9 +920,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
||||
140
perf/latency/rusqlite/Cargo.lock
generated
140
perf/latency/rusqlite/Cargo.lock
generated
@@ -27,23 +27,24 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.5.0"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.2"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
@@ -60,17 +61,17 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "2.1.0"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -105,9 +106,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.2"
|
||||
version = "4.5.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
|
||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -115,9 +116,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.2"
|
||||
version = "4.5.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
|
||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -127,9 +128,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.2"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -139,9 +140,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
@@ -234,9 +235,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
@@ -302,9 +309,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -349,9 +356,9 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
@@ -394,7 +401,16 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -403,13 +419,29 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -418,38 +450,86 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
@@ -74,3 +74,12 @@ do_execsql_test select-string-agg-with-delimiter {
|
||||
do_execsql_test select-string-agg-with-column-delimiter {
|
||||
SELECT string_agg(name, id) FROM products;
|
||||
} {hat2cap3shirt4sweater5sweatshirt6shorts7jeans8sneakers9boots10coat11accessories}
|
||||
|
||||
do_execsql_test select-agg-unary {
|
||||
SELECT -max(age) FROM users;
|
||||
} {-100}
|
||||
|
||||
do_execsql_test select-agg-binary-unary {
|
||||
SELECT min(age) + -max(age) FROM users;
|
||||
} {-99}
|
||||
|
||||
|
||||
@@ -261,3 +261,103 @@ do_execsql_test divide-agg-int-agg-float {
|
||||
do_execsql_test divide-agg-float-agg-int {
|
||||
SELECT min(price) / min(id) from products
|
||||
} {1.0}
|
||||
|
||||
|
||||
do_execsql_test bitwise-and-int-null {
|
||||
SELECT 1234 & NULL
|
||||
} {}
|
||||
|
||||
do_execsql_test bitwise-and-int-int {
|
||||
SELECT 1234 & 1234
|
||||
} {1234}
|
||||
|
||||
do_execsql_test bitwise-and-int-float {
|
||||
SELECT 660 & 261.8
|
||||
} {4}
|
||||
|
||||
do_execsql_test bitwise-and-float-float {
|
||||
SELECT 660.63 & 261.8
|
||||
} {4}
|
||||
|
||||
do_execsql_test bitwise-and-float-int-rev {
|
||||
SELECT 261.8 & 660
|
||||
} {4}
|
||||
|
||||
do_execsql_test bitwise-and-int-agg-int {
|
||||
SELECT 8261 & sum(id) from products
|
||||
} {64}
|
||||
|
||||
do_execsql_test bitwise-and-int-agg-float {
|
||||
SELECT 1036.6 & sum(id) from products
|
||||
} {0}
|
||||
|
||||
do_execsql_test bitwise-and-int-agg-int-agg {
|
||||
SELECT sum(id) & sum(id) from products
|
||||
} {66}
|
||||
|
||||
|
||||
do_execsql_test bitwise-or-int-null {
|
||||
SELECT 1234 | NULL
|
||||
} {}
|
||||
|
||||
do_execsql_test bitwise-or-null-int {
|
||||
SELECT NULL | 1234
|
||||
} {}
|
||||
|
||||
do_execsql_test bitwise-or-int-int {
|
||||
SELECT 4321 | 1234
|
||||
} {5363}
|
||||
|
||||
do_execsql_test bitwise-or-int-float {
|
||||
SELECT 660 | 1234.0
|
||||
} {1750}
|
||||
|
||||
do_execsql_test bitwise-or-int-agg {
|
||||
SELECT 18823 | sum(id) from products
|
||||
} {18887}
|
||||
|
||||
do_execsql_test bitwise-or-float-float {
|
||||
SELECT 1234.6 | 5432.2
|
||||
} {5626}
|
||||
|
||||
do_execsql_test bitwise-and-int-agg-int-agg {
|
||||
SELECT sum(id) | sum(id) from products
|
||||
} {66}
|
||||
|
||||
|
||||
do_execsql_test bitwise-not-null {
|
||||
SELECT ~NULL
|
||||
} {}
|
||||
|
||||
do_execsql_test bitwise-not-int {
|
||||
SELECT ~1234
|
||||
} {-1235}
|
||||
|
||||
do_execsql_test bitwise-not-float {
|
||||
SELECT ~823.34
|
||||
} {-824}
|
||||
|
||||
do_execsql_test bitwise-not-scalar-float {
|
||||
SELECT ~abs(693.9)
|
||||
} {-694}
|
||||
|
||||
do_execsql_test bitwise-not-scalar-int {
|
||||
SELECT ~abs(7566)
|
||||
} {-7567}
|
||||
|
||||
do_execsql_test bitwise-not-agg-int {
|
||||
SELECT ~sum(693)
|
||||
} {-694}
|
||||
|
||||
do_execsql_test bitwise-not-agg-and-agg {
|
||||
SELECT ~sum(693) & sum(-302)
|
||||
} {-958}
|
||||
|
||||
do_execsql_test bitwise-not-agg-int {
|
||||
SELECT ~sum(693)
|
||||
} {-694}
|
||||
|
||||
do_execsql_test bitwise-not-zero {
|
||||
SELECT ~0
|
||||
} {-1}
|
||||
|
||||
|
||||
@@ -75,6 +75,14 @@ do_execsql_test ifnull-2 {
|
||||
select ifnull(null, 2);
|
||||
} {2}
|
||||
|
||||
do_execsql_test iif-true {
|
||||
select iif(1, 'pass', 'fail');
|
||||
} {pass}
|
||||
|
||||
do_execsql_test iif-false {
|
||||
select iif(0, 'fail', 'pass');
|
||||
} {pass}
|
||||
|
||||
do_execsql_test instr-str {
|
||||
select instr('limbo', 'im');
|
||||
} {2}
|
||||
@@ -771,3 +779,7 @@ do_execsql_test cast-in-where {
|
||||
select age from users where age = cast('45' as integer) limit 1;
|
||||
} {45}
|
||||
|
||||
# TODO: sqlite seems not enable soundex() by default unless build it with SQLITE_SOUNDEX enabled.
|
||||
# do_execsql_test soundex-text {
|
||||
# select soundex('Pfister'), soundex('husobee'), soundex('Tymczak'), soundex('Ashcraft'), soundex('Robert'), soundex('Rupert'), soundex('Rubin'), soundex('Kant'), soundex('Knuth'), soundex('x'), soundex('');
|
||||
# } {P236|H210|T522|A261|R163|R163|R150|K530|K530|X000|0000}
|
||||
@@ -792,6 +792,7 @@ impl ToTokens for Operator {
|
||||
Self::ArrowRightShift => s.append(TK_PTR, Some("->>")),
|
||||
Self::BitwiseAnd => s.append(TK_BITAND, None),
|
||||
Self::BitwiseOr => s.append(TK_BITOR, None),
|
||||
Self::BitwiseNot => s.append(TK_BITNOT, None),
|
||||
Self::Concat => s.append(TK_CONCAT, None),
|
||||
Self::Equals => s.append(TK_EQ, None),
|
||||
Self::Divide => s.append(TK_SLASH, None),
|
||||
|
||||
@@ -583,6 +583,8 @@ pub enum Operator {
|
||||
BitwiseAnd,
|
||||
/// `|`
|
||||
BitwiseOr,
|
||||
/// `~`
|
||||
BitwiseNot,
|
||||
/// String concatenation (`||`)
|
||||
Concat,
|
||||
/// `=` or `==`
|
||||
@@ -630,6 +632,7 @@ impl From<YYCODETYPE> for Operator {
|
||||
x if x == TK_NE as YYCODETYPE => Self::NotEquals,
|
||||
x if x == TK_BITAND as YYCODETYPE => Self::BitwiseAnd,
|
||||
x if x == TK_BITOR as YYCODETYPE => Self::BitwiseOr,
|
||||
x if x == TK_BITNOT as YYCODETYPE => Self::BitwiseNot,
|
||||
x if x == TK_LSHIFT as YYCODETYPE => Self::LeftShift,
|
||||
x if x == TK_RSHIFT as YYCODETYPE => Self::RightShift,
|
||||
x if x == TK_PLUS as YYCODETYPE => Self::Add,
|
||||
|
||||
Reference in New Issue
Block a user