Change Value::Text to use a Cow<'static, str> instead of Vec<u8>

This commit is contained in:
pedrocarlo
2025-11-10 14:59:15 -03:00
parent c4d89662a8
commit 1db13889e3
25 changed files with 107 additions and 105 deletions

View File

@@ -12,7 +12,7 @@ impl From<Value> for turso_core::Value {
Value::Null => turso_core::Value::Null,
Value::Integer(n) => turso_core::Value::Integer(n),
Value::Real(n) => turso_core::Value::Float(n),
Value::Text(t) => turso_core::Value::from_text(&t),
Value::Text(t) => turso_core::Value::from_text(t),
Value::Blob(items) => turso_core::Value::from_blob(items),
}
}

View File

@@ -236,7 +236,7 @@ pub extern "system" fn Java_tech_turso_core_TursoStatement_bindText<'local>(
stmt.stmt.bind_at(
NonZero::new(position as usize).unwrap(),
Value::build_text(text.as_str()),
Value::build_text(text),
);
SQLITE_OK
}

View File

@@ -56,7 +56,7 @@ fn js_value_to_core(value: Either5<Null, i64, f64, String, Vec<u8>>) -> turso_co
Either5::A(_) => turso_core::Value::Null,
Either5::B(value) => turso_core::Value::Integer(value),
Either5::C(value) => turso_core::Value::Float(value),
Either5::D(value) => turso_core::Value::Text(turso_core::types::Text::new(&value)),
Either5::D(value) => turso_core::Value::Text(turso_core::types::Text::new(value)),
Either5::E(value) => turso_core::Value::Blob(value),
}
}

View File

@@ -128,7 +128,7 @@ impl From<Value> for turso_core::Value {
Value::Null => turso_core::Value::Null,
Value::Integer(n) => turso_core::Value::Integer(n),
Value::Real(n) => turso_core::Value::Float(n),
Value::Text(t) => turso_core::Value::from_text(&t),
Value::Text(t) => turso_core::Value::from_text(t),
Value::Blob(items) => turso_core::Value::from_blob(items),
}
}

View File

@@ -1722,7 +1722,7 @@ impl Limbo {
Value::Float(f) => write!(out, "{f}").map(|_| ()),
Value::Text(s) => {
out.write_all(b"'")?;
let bytes = &s.value;
let bytes = s.value.as_bytes();
let mut i = 0;
while i < bytes.len() {
let b = bytes[i];

View File

@@ -250,7 +250,7 @@ impl AggFunc {
}
}
pub fn to_string(&self) -> &str {
pub fn as_str(&self) -> &'static str {
match self {
Self::Avg => "avg",
Self::Count0 => "count",
@@ -617,7 +617,7 @@ pub enum Func {
impl Display for Func {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Agg(agg_func) => write!(f, "{}", agg_func.to_string()),
Self::Agg(agg_func) => write!(f, "{}", agg_func.as_str()),
Self::Scalar(scalar_func) => write!(f, "{scalar_func}"),
Self::Math(math_func) => write!(f, "{math_func}"),
Self::Vector(vector_func) => write!(f, "{vector_func}"),

View File

@@ -96,14 +96,14 @@ fn modify_dt(dt: &mut NaiveDateTime, mods: &[Register], output_type: DateTimeOut
fn format_dt(dt: NaiveDateTime, output_type: DateTimeOutput, subsec: bool) -> Value {
match output_type {
DateTimeOutput::Date => Value::from_text(dt.format("%Y-%m-%d").to_string().as_str()),
DateTimeOutput::Date => Value::from_text(dt.format("%Y-%m-%d").to_string()),
DateTimeOutput::Time => {
let t = if subsec {
dt.format("%H:%M:%S%.3f").to_string()
} else {
dt.format("%H:%M:%S").to_string()
};
Value::from_text(t.as_str())
Value::from_text(t)
}
DateTimeOutput::DateTime => {
let t = if subsec && dt.nanosecond() != 0 {
@@ -111,11 +111,9 @@ fn format_dt(dt: NaiveDateTime, output_type: DateTimeOutput, subsec: bool) -> Va
} else {
dt.format("%Y-%m-%d %H:%M:%S").to_string()
};
Value::from_text(t.as_str())
}
DateTimeOutput::StrfTime(format_str) => {
Value::from_text(strftime_format(&dt, &format_str).as_str())
Value::from_text(t)
}
DateTimeOutput::StrfTime(format_str) => Value::from_text(strftime_format(&dt, &format_str)),
DateTimeOutput::JuliaDay => Value::Float(to_julian_day_exact(&dt)),
}
}
@@ -832,7 +830,7 @@ mod tests {
let test_date_str = "2024-07-21";
let next_date_str = "2024-07-22";
let test_cases = vec![
let test_cases: Vec<(Value, &str)> = vec![
// Format 1: YYYY-MM-DD (no timezone applicable)
(Value::build_text("2024-07-21"), test_date_str),
// Format 2: YYYY-MM-DD HH:MM
@@ -936,7 +934,7 @@ mod tests {
let result = exec_date(&[Register::Value(input.clone())]);
assert_eq!(
result,
Value::build_text(expected),
Value::build_text(expected.to_string()),
"Failed for input: {input:?}"
);
}
@@ -1428,7 +1426,7 @@ mod tests {
}
fn text(value: &str) -> Register {
Register::Value(Value::build_text(value))
Register::Value(Value::build_text(value.to_string()))
}
fn format(dt: NaiveDateTime) -> String {

View File

@@ -257,7 +257,7 @@ mod tests {
use super::*;
fn text(value: &str) -> Register {
Register::Value(Value::build_text(value))
Register::Value(Value::build_text(value.to_string()))
}
fn integer(value: i64) -> Register {

View File

@@ -271,7 +271,7 @@ impl CompiledExpression {
}
}
Literal::String(s) => {
let cleaned = s.trim_matches('\'').trim_matches('"');
let cleaned = s.trim_matches('\'').trim_matches('"').to_string();
Value::Text(Text::new(cleaned))
}
Literal::Null => Value::Null,

View File

@@ -691,7 +691,7 @@ mod tests {
i,
vec![
Value::Integer(i),
Value::Text(Text::new(&category)),
Value::Text(Text::new(category)),
Value::Integer(i * 10),
],
);
@@ -4442,7 +4442,7 @@ mod tests {
.iter()
.map(|(row, _)| {
let category = match &row.values[0] {
Value::Text(s) => String::from_utf8(s.value.clone()).unwrap(),
Value::Text(s) => s.value.clone().into_owned(),
_ => panic!("Expected text for category"),
};
let value = match &row.values[1] {

View File

@@ -173,7 +173,7 @@ mod tests {
// Helper function to create test Value and Jsonb from JSON string
fn create_test_pair(json_str: &str) -> (Value, Jsonb) {
// Create Value as text representation of JSON
let key = Value::build_text(json_str);
let key = Value::build_text(json_str.to_string());
// Create Jsonb from the same JSON string
let value = Jsonb::from_str(json_str).unwrap();

View File

@@ -53,10 +53,7 @@ pub fn get_json(json_value: &Value, indent: Option<&str>) -> crate::Result<Value
Value::Blob(b) => {
let jsonbin = Jsonb::new(b.len(), Some(b));
jsonbin.element_type()?;
Ok(Value::Text(Text {
value: jsonbin.to_string().into_bytes(),
subtype: TextSubtype::Json,
}))
Ok(Value::Text(Text::json(jsonbin.to_string())))
}
Value::Null => Ok(Value::Null),
_ => {
@@ -480,15 +477,9 @@ pub fn json_string_to_db_type(
if matches!(flag, OutputVariant::ElementType) {
json_string.remove(json_string.len() - 1);
json_string.remove(0);
Ok(Value::Text(Text {
value: json_string.into_bytes(),
subtype: TextSubtype::Json,
}))
Ok(Value::Text(Text::json(json_string)))
} else {
Ok(Value::Text(Text {
value: json_string.into_bytes(),
subtype: TextSubtype::Text,
}))
Ok(Value::Text(Text::new(json_string)))
}
}
ElementType::FLOAT5 | ElementType::FLOAT => Ok(Value::Float(

View File

@@ -231,7 +231,13 @@ impl InternalVirtualTableCursor for JsonEachCursor {
}
if args.len() == 2 && matches!(self.traversal_mode, JsonTraversalMode::Tree) {
if let Value::Text(ref text) = args[1] {
if !text.value.is_empty() && text.value.windows(3).any(|chars| chars == b"[#-") {
if !text.value.is_empty()
&& text
.value
.as_bytes()
.windows(3)
.any(|chars| chars == b"[#-")
{
return Err(LimboError::InvalidArgument(
"Json paths with negative indices in json_tree are not supported yet"
.to_owned(),
@@ -495,7 +501,7 @@ mod columns {
fn key_representation(&self) -> Value {
match self {
Key::Integer(ref i) => Value::Integer(*i),
Key::String(ref s) => Value::Text(Text::new(&s.to_owned().replace("\\\"", "\""))),
Key::String(ref s) => Value::Text(Text::new(s.to_owned().replace("\\\"", "\""))),
Key::None => Value::Null,
}
}
@@ -572,7 +578,7 @@ mod columns {
| jsonb::ElementType::TEXTRAW => {
let s = value.to_string();
let s = (s[1..s.len() - 1]).to_string();
Ok(Value::Text(Text::new(&s)))
Ok(Value::Text(Text::new(s)))
}
jsonb::ElementType::ARRAY => Ok(Value::Null),
jsonb::ElementType::OBJECT => Ok(Value::Null),
@@ -599,11 +605,11 @@ mod columns {
}
pub(super) fn fullkey(&self) -> Value {
Value::Text(Text::new(&self.fullkey))
Value::Text(Text::new(self.fullkey.clone()))
}
pub(super) fn path(&self) -> Value {
Value::Text(Text::new(&self.innermost_container_path))
Value::Text(Text::new(self.innermost_container_path.clone()))
}
pub(super) fn parent(&self) -> Value {

View File

@@ -104,7 +104,7 @@ impl MvccTestDbNoConn {
}
pub(crate) fn generate_simple_string_row(table_id: MVTableId, id: i64, data: &str) -> Row {
let record = ImmutableRecord::from_values(&[Value::Text(Text::new(data))], 1);
let record = ImmutableRecord::from_values(&[Value::Text(Text::new(data.to_string()))], 1);
Row {
id: RowID {
table_id,
@@ -116,7 +116,7 @@ pub(crate) fn generate_simple_string_row(table_id: MVTableId, id: i64, data: &st
}
pub(crate) fn generate_simple_string_record(data: &str) -> ImmutableRecord {
ImmutableRecord::from_values(&[Value::Text(Text::new(data))], 1)
ImmutableRecord::from_values(&[Value::Text(Text::new(data.to_string()))], 1)
}
#[test]
@@ -740,7 +740,7 @@ fn setup_test_db() -> (MvccTestDb, u64) {
for (row_id, data) in test_rows.iter() {
let id = RowID::new(table_id, *row_id);
let record = ImmutableRecord::from_values(&[Value::Text(Text::new(data))], 1);
let record = ImmutableRecord::from_values(&[Value::Text(Text::new(data.to_string()))], 1);
let row = Row::new(id, record.as_blob().to_vec(), 1);
db.mvcc_store.insert(tx_id, row).unwrap();
}
@@ -765,7 +765,7 @@ fn setup_lazy_db(initial_keys: &[i64]) -> (MvccTestDb, u64) {
for i in initial_keys {
let id = RowID::new(table_id.into(), *i);
let data = format!("row{i}");
let record = ImmutableRecord::from_values(&[Value::Text(Text::new(&data))], 1);
let record = ImmutableRecord::from_values(&[Value::Text(Text::new(data))], 1);
let row = Row::new(id, record.as_blob().to_vec(), 1);
db.mvcc_store.insert(tx_id, row).unwrap();
}

View File

@@ -316,7 +316,7 @@ impl PragmaVirtualTableCursor {
0 => self
.arg
.as_ref()
.map_or(Value::Null, |arg| Value::from_text(arg)),
.map_or(Value::Null, |arg| Value::from_text(arg.to_string())),
_ => Value::Null,
};
Ok(value)

View File

@@ -10292,10 +10292,7 @@ mod tests {
for (i, huge_text) in huge_texts.iter().enumerate().take(iterations) {
let mut cursor = BTreeCursor::new_table(pager.clone(), root_page, num_columns);
tracing::info!("INSERT INTO t VALUES ({});", i,);
let regs = &[Register::Value(Value::Text(Text {
value: huge_text.as_bytes().to_vec(),
subtype: crate::types::TextSubtype::Text,
}))];
let regs = &[Register::Value(Value::Text(Text::new(huge_text.clone())))];
let value = ImmutableRecord::from_registers(regs, regs.len());
tracing::trace!("before insert {}", i);
tracing::debug!(

View File

@@ -241,7 +241,7 @@ fn link_with_window(
original_expr: expr.clone(),
});
} else {
crate::bail_parse_error!("misuse of window function: {}()", func.to_string());
crate::bail_parse_error!("misuse of window function: {}()", func.as_str());
}
Ok(())
}

View File

@@ -18,7 +18,7 @@ use crate::vdbe::sorter::Sorter;
use crate::vdbe::Register;
use crate::vtab::VirtualTableCursor;
use crate::{Completion, CompletionError, Result, IO};
use std::borrow::Borrow;
use std::borrow::{Borrow, Cow};
use std::fmt::{Debug, Display};
use std::ops::Deref;
use std::task::Waker;
@@ -63,7 +63,7 @@ pub enum TextSubtype {
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Text {
pub value: Vec<u8>,
pub value: Cow<'static, str>,
pub subtype: TextSubtype,
}
@@ -74,22 +74,22 @@ impl Display for Text {
}
impl Text {
pub fn new(value: &str) -> Self {
pub fn new(value: impl Into<Cow<'static, str>>) -> Self {
Self {
value: value.as_bytes().to_vec(),
value: value.into(),
subtype: TextSubtype::Text,
}
}
#[cfg(feature = "json")]
pub fn json(value: String) -> Self {
Self {
value: value.into_bytes(),
value: value.into(),
subtype: TextSubtype::Json,
}
}
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.value.as_ref()) }
&self.value
}
}
@@ -133,8 +133,9 @@ pub trait Extendable<T> {
impl<T: AnyText> Extendable<T> for Text {
#[inline(always)]
fn do_extend(&mut self, other: &T) {
self.value.clear();
self.value.extend_from_slice(other.as_ref().as_bytes());
let value = self.value.to_mut();
value.clear();
value.push_str(other.as_ref());
self.subtype = other.subtype();
}
}
@@ -188,7 +189,7 @@ impl AsRef<str> for Text {
impl From<&str> for Text {
fn from(value: &str) -> Self {
Text {
value: value.as_bytes().to_vec(),
value: value.to_owned().into(),
subtype: TextSubtype::Text,
}
}
@@ -197,7 +198,7 @@ impl From<&str> for Text {
impl From<String> for Text {
fn from(value: String) -> Self {
Text {
value: value.into_bytes(),
value: Cow::from(value),
subtype: TextSubtype::Text,
}
}
@@ -205,7 +206,7 @@ impl From<String> for Text {
impl From<Text> for String {
fn from(value: Text) -> Self {
String::from_utf8(value.value).unwrap()
value.value.into_owned()
}
}
@@ -359,7 +360,7 @@ impl Value {
Value::Integer(v) => ValueRef::Integer(*v),
Value::Float(v) => ValueRef::Float(*v),
Value::Text(v) => ValueRef::Text(TextRef {
value: &v.value,
value: v.value.as_bytes(),
subtype: v.subtype,
}),
Value::Blob(v) => ValueRef::Blob(v.as_slice()),
@@ -367,8 +368,8 @@ impl Value {
}
// A helper function that makes building a text Value easier.
pub fn build_text(text: impl AsRef<str>) -> Self {
Self::Text(Text::new(text.as_ref()))
pub fn build_text(text: impl Into<Cow<'static, str>>) -> Self {
Self::Text(Text::new(text))
}
pub fn to_blob(&self) -> Option<&[u8]> {
@@ -424,7 +425,7 @@ impl Value {
}
}
pub fn from_text(text: &str) -> Self {
pub fn from_text(text: impl Into<Cow<'static, str>>) -> Self {
Value::Text(Text::new(text))
}
@@ -453,7 +454,7 @@ impl Value {
}
}
Value::Float(f) => out.extend_from_slice(&f.to_be_bytes()),
Value::Text(t) => out.extend_from_slice(&t.value),
Value::Text(t) => out.extend_from_slice(t.value.as_bytes()),
Value::Blob(b) => out.extend_from_slice(b),
};
}
@@ -535,7 +536,7 @@ impl Value {
if v.is_json() {
return Ok(Value::Text(Text::json(text.to_string())));
}
Ok(Value::build_text(text))
Ok(Value::build_text(text.to_string()))
}
ExtValueType::Blob => {
let Some(blob) = v.to_blob() else {
@@ -828,26 +829,26 @@ impl std::ops::AddAssign for Value {
*float_left += float_right;
}
(Self::Text(string_left), Self::Text(string_right)) => {
string_left.value.extend_from_slice(&string_right.value);
string_left.value.to_mut().push_str(&string_right.value);
string_left.subtype = TextSubtype::Text;
}
(Self::Text(string_left), Self::Integer(int_right)) => {
let string_right = int_right.to_string();
string_left.value.extend_from_slice(string_right.as_bytes());
string_left.value.to_mut().push_str(&string_right);
string_left.subtype = TextSubtype::Text;
}
(Self::Integer(int_left), Self::Text(string_right)) => {
let string_left = int_left.to_string();
*self = Self::build_text(&(string_left + string_right.as_str()));
*self = Self::build_text(string_left + string_right.as_str());
}
(Self::Text(string_left), Self::Float(float_right)) => {
let string_right = Self::Float(float_right).to_string();
string_left.value.extend_from_slice(string_right.as_bytes());
string_left.value.to_mut().push_str(&string_right);
string_left.subtype = TextSubtype::Text;
}
(Self::Float(float_left), Self::Text(string_right)) => {
let string_left = Self::Float(*float_left).to_string();
*self = Self::build_text(&(string_left + string_right.as_str()));
*self = Self::build_text(string_left + string_right.as_str());
}
(_, Self::Null) => {}
(Self::Null, rhs) => *self = rhs,
@@ -1132,7 +1133,7 @@ impl ImmutableRecord {
}
Value::Float(f) => writer.extend_from_slice(&f.to_be_bytes()),
Value::Text(t) => {
writer.extend_from_slice(&t.value);
writer.extend_from_slice(t.value.as_bytes());
}
Value::Blob(b) => {
writer.extend_from_slice(b);
@@ -1544,7 +1545,7 @@ impl<'a> ValueRef<'a> {
ValueRef::Integer(i) => Value::Integer(*i),
ValueRef::Float(f) => Value::Float(*f),
ValueRef::Text(text) => Value::Text(Text {
value: text.value.to_vec(),
value: text.as_str().to_string().into(),
subtype: text.subtype,
}),
ValueRef::Blob(b) => Value::Blob(b.to_vec()),
@@ -2394,7 +2395,7 @@ impl Record {
}
}
Value::Float(f) => buf.extend_from_slice(&f.to_be_bytes()),
Value::Text(t) => buf.extend_from_slice(&t.value),
Value::Text(t) => buf.extend_from_slice(t.value.as_bytes()),
Value::Blob(b) => buf.extend_from_slice(b),
};
}

View File

@@ -1743,8 +1743,9 @@ pub fn op_column(
// SAFETY: We know the text is valid UTF-8 because we only accept valid UTF-8 and the serial type is TEXT.
let text =
unsafe { std::str::from_utf8_unchecked(buf) };
state.registers[*dest] =
Register::Value(Value::Text(Text::new(text)));
state.registers[*dest] = Register::Value(Value::Text(
Text::new(text.to_string()),
));
}
}
}
@@ -2678,7 +2679,7 @@ pub fn op_string8(
mv_store: Option<&Arc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
load_insn!(String8 { value, dest }, insn);
state.registers[*dest] = Register::Value(Value::build_text(value));
state.registers[*dest] = Register::Value(Value::build_text(value.clone()));
state.pc += 1;
Ok(InsnFunctionStepResult::Step)
}

View File

@@ -484,7 +484,7 @@ pub fn insn_to_row(
*db as i32,
0,
0,
Value::build_text(table_name),
Value::build_text(table_name.clone()),
0,
"".to_string(),
),
@@ -659,7 +659,7 @@ pub fn insn_to_row(
*err_code as i32,
0,
0,
Value::build_text(description),
Value::build_text(description.clone()),
0,
"".to_string(),
),
@@ -672,7 +672,7 @@ pub fn insn_to_row(
*err_code as i32,
0,
*target_reg as i32,
Value::build_text(description),
Value::build_text(description.clone()),
0,
"".to_string(),
),
@@ -750,7 +750,7 @@ pub fn insn_to_row(
0,
*dest as i32,
0,
Value::build_text(value),
Value::build_text(value.clone()),
0,
format!("r[{dest}]='{value}'"),
),
@@ -963,7 +963,7 @@ pub fn insn_to_row(
0,
*col as i32,
*acc_reg as i32,
Value::build_text(func.to_string()),
Value::build_text(func.as_str()),
0,
format!("accum=r[{}] step(r[{}])", *acc_reg, *col),
),
@@ -972,7 +972,7 @@ pub fn insn_to_row(
0,
*register as i32,
0,
Value::build_text(func.to_string()),
Value::build_text(func.as_str()),
0,
format!("accum=r[{}]", *register),
),
@@ -981,7 +981,7 @@ pub fn insn_to_row(
0,
*acc_reg as i32,
*dest_reg as i32,
Value::build_text(func.to_string()),
Value::build_text(func.as_str()),
0,
format!("accum=r[{}] dest=r[{}]", *acc_reg, *dest_reg),
),
@@ -1157,7 +1157,7 @@ pub fn insn_to_row(
*cursor as i32,
*record_reg as i32,
*key_reg as i32,
Value::build_text(table_name),
Value::build_text(table_name.clone()),
flag.0 as u16,
format!("intkey=r[{key_reg}] data=r[{record_reg}]"),
),
@@ -1166,7 +1166,7 @@ pub fn insn_to_row(
*cursor_id as i32,
0,
0,
Value::build_text(table_name),
Value::build_text(table_name.clone()),
0,
"".to_string(),
),
@@ -1364,7 +1364,7 @@ pub fn insn_to_row(
*db as i32,
0,
0,
Value::build_text(table_name),
Value::build_text(table_name.clone()),
0,
format!("DROP TABLE {table_name}"),
),
@@ -1373,7 +1373,7 @@ pub fn insn_to_row(
*db as i32,
0,
0,
Value::build_text(view_name),
Value::build_text(view_name.clone()),
0,
format!("DROP VIEW {view_name}"),
),
@@ -1792,7 +1792,7 @@ pub fn insn_to_row(
*db as i32,
*dest as i32,
0,
Value::build_text(new_mode.as_ref().unwrap_or(&String::new())),
Value::build_text(new_mode.clone().unwrap_or(String::new())),
0,
format!("r[{dest}]=journal_mode(db[{db}]{})",
new_mode.as_ref().map_or(String::new(), |m| format!(",'{m}'"))),
@@ -1802,7 +1802,7 @@ pub fn insn_to_row(
reg.unwrap_or(0) as i32,
0,
0,
Value::build_text(collation.to_string().as_str()),
Value::build_text(collation.to_string()),
0,
format!("collation={collation}"),
),
@@ -1820,7 +1820,7 @@ pub fn insn_to_row(
*p1 as i32,
p2.as_ref().map(|p| *p).unwrap_or(0) as i32,
0,
Value::build_text(detail.as_str()),
Value::build_text(detail.clone()),
0,
String::new(),
),

View File

@@ -666,7 +666,7 @@ impl Program {
state.registers[4] = Register::Value(Value::Integer(p3 as i64));
state.registers[5] = Register::Value(p4);
state.registers[6] = Register::Value(Value::Integer(p5 as i64));
state.registers[7] = Register::Value(Value::from_text(&comment));
state.registers[7] = Register::Value(Value::from_text(comment));
state.result_row = Some(Row {
values: &state.registers[0] as *const Register,
count: EXPLAIN_COLUMNS.len(),
@@ -712,7 +712,7 @@ impl Program {
state.registers[1] =
Register::Value(Value::Integer(p2.as_ref().map(|p| *p).unwrap_or(0) as i64));
state.registers[2] = Register::Value(Value::Integer(0));
state.registers[3] = Register::Value(Value::from_text(detail.as_str()));
state.registers[3] = Register::Value(Value::from_text(detail.clone()));
state.result_row = Some(Row {
values: &state.registers[0] as *const Register,
count: EXPLAIN_QUERY_PLAN_COLUMNS.len(),

View File

@@ -425,7 +425,7 @@ impl Value {
end_byte_idx = ceil_char_boundary(s, end_byte_idx + 1);
end -= 1;
}
Value::build_text(&s[start_byte_idx..end_byte_idx])
Value::build_text(s[start_byte_idx..end_byte_idx].to_string())
} else {
Value::Null
}
@@ -570,9 +570,11 @@ impl Value {
(Value::Text(_) | Value::Integer(_) | Value::Float(_), Some(pattern)) => {
let pattern_chars: Vec<char> = pattern.to_string().chars().collect();
let text = self.to_string();
Value::build_text(trim_type.trim(&text, &pattern_chars))
Value::build_text(trim_type.trim(&text, &pattern_chars).to_string())
}
(Value::Text(t), None) => {
Value::build_text(trim_type.trim(t.as_str(), &[' ']).to_string())
}
(Value::Text(t), None) => Value::build_text(trim_type.trim(t.as_str(), &[' '])),
(reg, _) => reg.to_owned(),
}
}
@@ -900,9 +902,9 @@ impl Value {
pub fn exec_concat(&self, rhs: &Value) -> Value {
if let (Value::Blob(lhs), Value::Blob(rhs)) = (self, rhs) {
return Value::build_text(String::from_utf8_lossy(
&[lhs.as_slice(), rhs.as_slice()].concat(),
));
return Value::build_text(
String::from_utf8_lossy(&[lhs.as_slice(), rhs.as_slice()].concat()).into_owned(),
);
}
let Some(lhs) = self.cast_text() else {

View File

@@ -1019,7 +1019,7 @@ pub unsafe extern "C" fn sqlite3_bind_text(
};
if ptr_val == transient_ptr {
let val = Value::from_text(&str_value);
let val = Value::from_text(str_value);
stmt_ref
.stmt
.bind_at(NonZero::new_unchecked(idx as usize), val);

View File

@@ -514,7 +514,10 @@ pub async fn has_table<Ctx>(
) -> Result<bool> {
let mut stmt =
conn.prepare("SELECT COUNT(*) FROM sqlite_schema WHERE type = 'table' AND name = ?")?;
stmt.bind_at(1.try_into().unwrap(), Value::Text(Text::new(table_name)));
stmt.bind_at(
1.try_into().unwrap(),
Value::Text(Text::new(table_name.to_string())),
);
let count = match run_stmt_expect_one_row(coro, &mut stmt).await? {
Some(row) => row[0]
@@ -557,7 +560,7 @@ pub async fn update_last_change_id<Ctx>(
let mut select_stmt = conn.prepare(TURSO_SYNC_SELECT_LAST_CHANGE_ID)?;
select_stmt.bind_at(
1.try_into().unwrap(),
turso_core::Value::Text(turso_core::types::Text::new(client_id)),
turso_core::Value::Text(turso_core::types::Text::new(client_id.to_string())),
);
let row = run_stmt_expect_one_row(coro, &mut select_stmt).await?;
tracing::info!("update_last_change_id(client_id={client_id}): selected client row if any");
@@ -568,7 +571,7 @@ pub async fn update_last_change_id<Ctx>(
update_stmt.bind_at(2.try_into().unwrap(), turso_core::Value::Integer(change_id));
update_stmt.bind_at(
3.try_into().unwrap(),
turso_core::Value::Text(turso_core::types::Text::new(client_id)),
turso_core::Value::Text(turso_core::types::Text::new(client_id.to_string())),
);
run_stmt_ignore_rows(coro, &mut update_stmt).await?;
tracing::info!("update_last_change_id(client_id={client_id}): updated row for the client");
@@ -576,7 +579,7 @@ pub async fn update_last_change_id<Ctx>(
let mut update_stmt = conn.prepare(TURSO_SYNC_INSERT_LAST_CHANGE_ID)?;
update_stmt.bind_at(
1.try_into().unwrap(),
turso_core::Value::Text(turso_core::types::Text::new(client_id)),
turso_core::Value::Text(turso_core::types::Text::new(client_id.to_string())),
);
update_stmt.bind_at(2.try_into().unwrap(), turso_core::Value::Integer(pull_gen));
update_stmt.bind_at(3.try_into().unwrap(), turso_core::Value::Integer(change_id));
@@ -603,7 +606,10 @@ pub async fn read_last_change_id<Ctx>(
Err(err) => return Err(err.into()),
};
select_last_change_id_stmt.bind_at(1.try_into().unwrap(), Value::Text(Text::new(client_id)));
select_last_change_id_stmt.bind_at(
1.try_into().unwrap(),
Value::Text(Text::new(client_id.to_string())),
);
match run_stmt_expect_one_row(coro, &mut select_last_change_id_stmt).await? {
Some(row) => {

View File

@@ -67,7 +67,7 @@ fn record<const N: usize>(values: [Value; N]) -> Vec<u8> {
Value::Null => turso_core::Value::Null,
Value::Integer(x) => turso_core::Value::Integer(x),
Value::Real(x) => turso_core::Value::Float(x),
Value::Text(x) => turso_core::Value::Text(turso_core::types::Text::new(&x)),
Value::Text(x) => turso_core::Value::Text(turso_core::types::Text::new(x)),
Value::Blob(x) => turso_core::Value::Blob(x),
})
.collect::<Vec<_>>();