Skip to content

Commit

Permalink
Merge 'Add unhex(X) scalar function' from Lauri Virtanen
Browse files Browse the repository at this point in the history
This commit adds `unhex(X)` scalar function. Function with `unhex(X,Y)`
two arguments is not implemented yet.
Relates to issue #144

Closes #353
  • Loading branch information
penberg committed Oct 2, 2024
2 parents b2fd509 + adc6f9b commit 6fcd818
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 3 deletions.
2 changes: 1 addition & 1 deletion COMPAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ This document describes the SQLite compatibility status of Limbo:
| trim(X) | Yes | |
| trim(X,Y) | Yes | |
| typeof(X) | Yes | |
| unhex(X) | No | |
| unhex(X) | Yes | |
| unhex(X,Y) | No | |
| unicode(X) | Yes | |
| unlikely(X) | No | |
Expand Down
3 changes: 3 additions & 0 deletions core/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub enum ScalarFunc {
SqliteVersion,
UnixEpoch,
Hex,
Unhex,
ZeroBlob,
}

Expand Down Expand Up @@ -113,6 +114,7 @@ impl Display for ScalarFunc {
ScalarFunc::SqliteVersion => "sqlite_version".to_string(),
ScalarFunc::UnixEpoch => "unixepoch".to_string(),
ScalarFunc::Hex => "hex".to_string(),
ScalarFunc::Unhex => "unhex".to_string(),
ScalarFunc::ZeroBlob => "zeroblob".to_string(),
};
write!(f, "{}", str)
Expand Down Expand Up @@ -184,6 +186,7 @@ impl Func {
"json" => Ok(Func::Json(JsonFunc::Json)),
"unixepoch" => Ok(Func::Scalar(ScalarFunc::UnixEpoch)),
"hex" => Ok(Func::Scalar(ScalarFunc::Hex)),
"unhex" => Ok(Func::Scalar(ScalarFunc::Unhex)),
"zeroblob" => Ok(Func::Scalar(ScalarFunc::ZeroBlob)),
_ => Err(()),
}
Expand Down
3 changes: 2 additions & 1 deletion core/translate/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,8 @@ pub fn translate_expr(
ScalarFunc::Trim
| ScalarFunc::LTrim
| ScalarFunc::RTrim
| ScalarFunc::Round => {
| ScalarFunc::Round
| ScalarFunc::Unhex => {
let args = if let Some(args) = args {
if args.len() > 2 {
crate::bail_parse_error!(
Expand Down
49 changes: 48 additions & 1 deletion core/vdbe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,12 @@ impl Program {
let result = exec_hex(reg_value);
state.registers[*dest] = result;
}
ScalarFunc::Unhex => {
let reg_value = state.registers[*start_reg].clone();
let ignored_chars = state.registers.get(*start_reg + 1);
let result = exec_unhex(&reg_value, ignored_chars);
state.registers[*dest] = result;
}
ScalarFunc::Random => {
state.registers[*dest] = exec_random();
}
Expand Down Expand Up @@ -2173,6 +2179,20 @@ fn exec_hex(reg: &OwnedValue) -> OwnedValue {
}
}

fn exec_unhex(reg: &OwnedValue, ignored_chars: Option<&OwnedValue>) -> OwnedValue {
if ignored_chars.is_some() {
unimplemented!("unhex(X,Y) is not implemented");
}

match reg {
OwnedValue::Null => OwnedValue::Null,
_ => match hex::decode(reg.to_string()) {
Ok(bytes) => OwnedValue::Blob(Rc::new(bytes)),
Err(_) => OwnedValue::Null,
},
}
}

fn exec_unicode(reg: &OwnedValue) -> OwnedValue {
match reg {
OwnedValue::Text(_)
Expand Down Expand Up @@ -2304,7 +2324,7 @@ mod tests {
use super::{
exec_abs, exec_char, exec_hex, exec_if, exec_length, exec_like, exec_lower, exec_ltrim,
exec_max, exec_min, exec_nullif, exec_quote, exec_random, exec_round, exec_rtrim,
exec_sign, exec_substring, exec_trim, exec_typeof, exec_unicode, exec_upper, exec_zeroblob,
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,
};
Expand Down Expand Up @@ -2656,6 +2676,33 @@ mod tests {
assert_eq!(exec_hex(&input_float), expected_val);
}

#[test]
fn test_unhex() {
let input = OwnedValue::Text(Rc::new(String::from("6F")));
let expected = OwnedValue::Blob(Rc::new(vec![0x6f]));
assert_eq!(exec_unhex(&input, None), expected);

let input = OwnedValue::Text(Rc::new(String::from("6f")));
let expected = OwnedValue::Blob(Rc::new(vec![0x6f]));
assert_eq!(exec_unhex(&input, None), expected);

let input = OwnedValue::Text(Rc::new(String::from("611")));
let expected = OwnedValue::Null;
assert_eq!(exec_unhex(&input, None), expected);

let input = OwnedValue::Text(Rc::new(String::from("")));
let expected = OwnedValue::Blob(Rc::new(vec![]));
assert_eq!(exec_unhex(&input, None), expected);

let input = OwnedValue::Text(Rc::new(String::from("61x")));
let expected = OwnedValue::Null;
assert_eq!(exec_unhex(&input, None), expected);

let input = OwnedValue::Null;
let expected = OwnedValue::Null;
assert_eq!(exec_unhex(&input, None), expected);
}

#[test]
fn test_abs() {
let int_positive_reg = OwnedValue::Integer(10);
Expand Down
24 changes: 24 additions & 0 deletions testing/scalar-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,30 @@ do_execsql_test hex-null {
select hex(null)
} {}

do_execsql_test unhex-str-ab {
SELECT unhex('6162');
} {ab}

do_execsql_test unhex-int-ab {
SELECT unhex(6162);
} {ab}

do_execsql_test unhex-dot-uppercase {
SELECT unhex('2E');
} {.}

do_execsql_test unhex-dot-lowercase {
SELECT unhex('2e');
} {.}

do_execsql_test unhex-no-hex {
SELECT unhex('x');
} {}

do_execsql_test unhex-null {
SELECT unhex(NULL);
} {}

do_execsql_test trim {
SELECT trim(' Limbo ');
} {Limbo}
Expand Down

0 comments on commit 6fcd818

Please sign in to comment.