Add unhex(X) scalar function

This commit adds `unhex(X)` scalar function. Function with `unhex(X,Y)`
two arguments is not implemented yet.

Relates to issue #144
This commit is contained in:
Lauri Virtanen
2024-09-30 00:03:05 +03:00
parent b8dffbf7f9
commit adc6f9b6cd
5 changed files with 78 additions and 3 deletions

View File

@@ -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 | |

View File

@@ -77,6 +77,7 @@ pub enum ScalarFunc {
SqliteVersion,
UnixEpoch,
Hex,
Unhex,
}
impl Display for ScalarFunc {
@@ -112,6 +113,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(),
};
write!(f, "{}", str)
}
@@ -182,6 +184,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)),
_ => Err(()),
}
}

View File

@@ -1215,7 +1215,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!(

View File

@@ -1551,6 +1551,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();
}
@@ -2171,6 +2177,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(_)
@@ -2292,7 +2312,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_sign, exec_substring, exec_trim, exec_typeof, exec_unhex, exec_unicode, exec_upper,
execute_sqlite_version, get_new_rowid, AggContext, Cursor, CursorResult, LimboError,
OwnedRecord, OwnedValue, Result,
};
@@ -2644,6 +2664,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);

View File

@@ -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}