Merge 'Add support for quote scalar function' from Jean Arhancet

Add support for quote scalar function. Related issue: #144

Closes #294
This commit is contained in:
Pekka Enberg
2024-08-18 15:53:09 +03:00
5 changed files with 66 additions and 4 deletions

View File

@@ -89,7 +89,7 @@ This document describes the SQLite compatibility status of Limbo:
| nullif(X,Y) | No | |
| octet_length(X) | No | |
| printf(FORMAT,...) | No | |
| quote(X) | No | |
| quote(X) | Yes | |
| random() | Yes | |
| randomblob(N) | No | |
| replace(X,Y,Z) | No | |

View File

@@ -61,6 +61,7 @@ pub enum ScalarFunc {
Date,
Time,
Unicode,
Quote,
}
impl ToString for ScalarFunc {
@@ -87,6 +88,7 @@ impl ToString for ScalarFunc {
ScalarFunc::Date => "date".to_string(),
ScalarFunc::Time => "time".to_string(),
ScalarFunc::Unicode => "unicode".to_string(),
ScalarFunc::Quote => "quote".to_string(),
}
}
}
@@ -130,6 +132,7 @@ impl Func {
"date" => Ok(Func::Scalar(ScalarFunc::Date)),
"time" => Ok(Func::Scalar(ScalarFunc::Time)),
"unicode" => Ok(Func::Scalar(ScalarFunc::Unicode)),
"quote" => Ok(Func::Scalar(ScalarFunc::Quote)),
"json" => Ok(Func::Json(JsonFunc::JSON)),
_ => Err(()),
}

View File

@@ -302,7 +302,8 @@ pub fn translate_expr(
| ScalarFunc::Lower
| ScalarFunc::Upper
| ScalarFunc::Length
| ScalarFunc::Unicode => {
| ScalarFunc::Unicode
| ScalarFunc::Quote => {
let args = if let Some(args) = args {
if args.len() != 1 {
crate::bail_parse_error!(

View File

@@ -1379,6 +1379,11 @@ impl Program {
state.registers[*dest] = exec_unicode(reg_value);
state.pc += 1;
}
Func::Scalar(ScalarFunc::Quote) => {
let reg_value = state.registers[*start_reg].borrow_mut();
state.registers[*dest] = exec_quote(reg_value);
state.pc += 1;
}
},
Insn::InitCoroutine {
yield_reg,
@@ -1662,6 +1667,28 @@ fn exec_random() -> OwnedValue {
OwnedValue::Integer(random_number)
}
fn exec_quote(value: &OwnedValue) -> OwnedValue {
match value {
OwnedValue::Null => OwnedValue::Text(OwnedValue::Null.to_string().into()),
OwnedValue::Integer(_) | OwnedValue::Float(_) => value.to_owned(),
OwnedValue::Blob(_) => todo!(),
OwnedValue::Text(s) => {
let mut quoted = String::with_capacity(s.len() + 2);
quoted.push('\'');
for c in s.chars() {
if c == '\0' {
break;
} else {
quoted.push(c);
}
}
quoted.push('\'');
OwnedValue::Text(Rc::new(quoted))
}
_ => OwnedValue::Null, // For unsupported types, return NULL
}
}
fn exec_char(values: Vec<OwnedValue>) -> OwnedValue {
let result: String = values
.iter()
@@ -1839,8 +1866,9 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
mod tests {
use super::{
exec_abs, exec_char, exec_if, exec_length, exec_like, exec_lower, exec_ltrim, exec_minmax,
exec_random, exec_round, exec_rtrim, exec_substring, exec_trim, exec_unicode, exec_upper,
get_new_rowid, Cursor, CursorResult, LimboError, OwnedRecord, OwnedValue, Result,
exec_quote, exec_random, exec_round, exec_rtrim, exec_substring, exec_trim, exec_unicode,
exec_upper, get_new_rowid, Cursor, CursorResult, LimboError, OwnedRecord, OwnedValue,
Result,
};
use mockall::{mock, predicate};
use rand::{rngs::mock::StepRng, thread_rng};
@@ -2003,6 +2031,21 @@ mod tests {
assert_eq!(exec_length(&expected_blob), expected_len);
}
#[test]
fn test_quote() {
let input = OwnedValue::Text(Rc::new(String::from("abc\0edf")));
let expected = OwnedValue::Text(Rc::new(String::from("'abc'")));
assert_eq!(exec_quote(&input), expected);
let input = OwnedValue::Integer(123);
let expected = OwnedValue::Integer(123);
assert_eq!(exec_quote(&input), expected);
let input = OwnedValue::Text(Rc::new(String::from("hello''world")));
let expected = OwnedValue::Text(Rc::new(String::from("'hello''world'")));
assert_eq!(exec_quote(&input), expected);
}
#[test]
fn test_unicode() {
assert_eq!(

View File

@@ -495,3 +495,18 @@ do_execsql_test unicode-null {
SELECT unicode(NULL);
} {}
do_execsql_test quote-string-embedded-nul {
SELECT quote(concat('abc', char(0), 'def'))
} {'abc'}
do_execsql_test quote-string {
SELECT quote('limbo')
} {'limbo'}
do_execsql_test quote-null {
SELECT quote(null)
} {NULL}
do_execsql_test quote-integer {
SELECT quote(123)
} {123}