mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-29 12:54:22 +01:00
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:
@@ -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 | |
|
||||
|
||||
@@ -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(()),
|
||||
}
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user