mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 18:18:03 +00:00
Add support for sqlite_version
This commit is contained in:
parent
ac6dd71de6
commit
e9ba458514
7 changed files with 69 additions and 13 deletions
|
@ -103,7 +103,7 @@ This document describes the SQLite compatibility status of Limbo:
|
|||
| sqlite_compileoption_used(X) | No | |
|
||||
| sqlite_offset(X) | No | |
|
||||
| sqlite_source_id() | No | |
|
||||
| sqlite_version() | No | |
|
||||
| sqlite_version() | Yes | |
|
||||
| substr(X,Y,Z) | Yes | |
|
||||
| substr(X,Y) | Yes | |
|
||||
| substring(X,Y,Z) | Yes | |
|
||||
|
|
|
@ -73,6 +73,7 @@ pub enum ScalarFunc {
|
|||
Time,
|
||||
Unicode,
|
||||
Quote,
|
||||
SqliteVersion,
|
||||
UnixEpoch,
|
||||
}
|
||||
|
||||
|
@ -105,6 +106,7 @@ impl Display for ScalarFunc {
|
|||
ScalarFunc::Time => "time".to_string(),
|
||||
ScalarFunc::Unicode => "unicode".to_string(),
|
||||
ScalarFunc::Quote => "quote".to_string(),
|
||||
ScalarFunc::SqliteVersion => "sqlite_version".to_string(),
|
||||
ScalarFunc::UnixEpoch => "unixepoch".to_string(),
|
||||
};
|
||||
write!(f, "{}", str)
|
||||
|
@ -171,6 +173,7 @@ impl Func {
|
|||
"time" => Ok(Func::Scalar(ScalarFunc::Time)),
|
||||
"unicode" => Ok(Func::Scalar(ScalarFunc::Unicode)),
|
||||
"quote" => Ok(Func::Scalar(ScalarFunc::Quote)),
|
||||
"sqlite_version" => Ok(Func::Scalar(ScalarFunc::SqliteVersion)),
|
||||
"json" => Ok(Func::Json(JsonFunc::Json)),
|
||||
"unixepoch" => Ok(Func::Scalar(ScalarFunc::UnixEpoch)),
|
||||
_ => Err(()),
|
||||
|
|
10
core/lib.rs
10
core/lib.rs
|
@ -19,7 +19,7 @@ use log::trace;
|
|||
use schema::Schema;
|
||||
use sqlite3_parser::ast;
|
||||
use sqlite3_parser::{ast::Cmd, lexer::sql::Parser};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
#[cfg(feature = "fs")]
|
||||
use storage::database::FileStorage;
|
||||
|
@ -42,6 +42,8 @@ pub use storage::pager::Page;
|
|||
pub use storage::wal::Wal;
|
||||
pub use types::Value;
|
||||
|
||||
pub static DATABASE_VERSION: OnceLock<String> = OnceLock::new();
|
||||
|
||||
pub struct Database {
|
||||
pager: Rc<Pager>,
|
||||
schema: Rc<Schema>,
|
||||
|
@ -59,11 +61,15 @@ impl Database {
|
|||
}
|
||||
|
||||
pub fn open(
|
||||
io: Arc<dyn crate::io::IO>,
|
||||
io: Arc<dyn IO>,
|
||||
page_io: Rc<dyn DatabaseStorage>,
|
||||
wal: Rc<dyn Wal>,
|
||||
) -> Result<Database> {
|
||||
let db_header = Pager::begin_open(page_io.clone())?;
|
||||
DATABASE_VERSION.get_or_init(|| {
|
||||
let version = db_header.borrow().version_number.clone();
|
||||
version.to_string()
|
||||
});
|
||||
io.run_once()?;
|
||||
let pager = Rc::new(Pager::finish_open(
|
||||
db_header.clone(),
|
||||
|
|
|
@ -84,7 +84,7 @@ pub struct DatabaseHeader {
|
|||
application_id: u32,
|
||||
reserved: [u8; 20],
|
||||
version_valid_for: u32,
|
||||
version_number: u32,
|
||||
pub version_number: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
|
@ -1320,6 +1320,26 @@ pub fn translate_expr(
|
|||
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::SqliteVersion => {
|
||||
if args.is_some() {
|
||||
crate::bail_parse_error!("sqlite_version function with arguments");
|
||||
}
|
||||
|
||||
let output_register = program.alloc_register();
|
||||
program.emit_insn(Insn::Function {
|
||||
constant_mask: 0,
|
||||
start_reg: output_register,
|
||||
dest: output_register,
|
||||
func: func_ctx,
|
||||
});
|
||||
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: output_register,
|
||||
dst_reg: target_register,
|
||||
amount: 1,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -631,12 +631,18 @@ pub fn insn_to_str(
|
|||
*dest as i32,
|
||||
OwnedValue::Text(Rc::new(func.func.to_string())),
|
||||
0,
|
||||
format!(
|
||||
"r[{}]=func(r[{}..{}])",
|
||||
dest,
|
||||
start_reg,
|
||||
start_reg + func.arg_count - 1
|
||||
),
|
||||
if func.arg_count == 0 {
|
||||
format!("r[{}]=func()", dest)
|
||||
} else if *start_reg == *start_reg + func.arg_count - 1 {
|
||||
format!("r[{}]=func(r[{}])", dest, start_reg)
|
||||
} else {
|
||||
format!(
|
||||
"r[{}]=func(r[{}..{}])",
|
||||
dest,
|
||||
start_reg,
|
||||
start_reg + func.arg_count - 1
|
||||
)
|
||||
},
|
||||
),
|
||||
Insn::InitCoroutine {
|
||||
yield_reg,
|
||||
|
|
|
@ -31,7 +31,7 @@ use crate::schema::Table;
|
|||
use crate::storage::sqlite3_ondisk::DatabaseHeader;
|
||||
use crate::storage::{btree::BTreeCursor, pager::Pager};
|
||||
use crate::types::{AggContext, Cursor, CursorResult, OwnedRecord, OwnedValue, Record};
|
||||
use crate::Result;
|
||||
use crate::{Result, DATABASE_VERSION};
|
||||
|
||||
use datetime::{exec_date, exec_time, exec_unixepoch};
|
||||
|
||||
|
@ -1608,6 +1608,12 @@ impl Program {
|
|||
}
|
||||
}
|
||||
}
|
||||
ScalarFunc::SqliteVersion => {
|
||||
let version_integer: i64 =
|
||||
DATABASE_VERSION.get().unwrap().parse()?;
|
||||
let version = execute_sqlite_version(version_integer);
|
||||
state.registers[*dest] = OwnedValue::Text(Rc::new(version));
|
||||
}
|
||||
},
|
||||
crate::function::Func::Agg(_) => {
|
||||
unreachable!("Aggregate functions should not be handled here")
|
||||
|
@ -2212,13 +2218,21 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn execute_sqlite_version(version_integer: i64) -> String {
|
||||
let major = version_integer / 1_000_000;
|
||||
let minor = (version_integer % 1_000_000) / 1_000;
|
||||
let release = version_integer % 1_000;
|
||||
|
||||
format!("{}.{}.{}", major, minor, release)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
exec_abs, exec_char, exec_if, exec_length, exec_like, exec_lower, exec_ltrim, exec_minmax,
|
||||
exec_nullif, exec_quote, exec_random, exec_round, exec_rtrim, exec_sign, exec_substring,
|
||||
exec_trim, exec_unicode, exec_upper, get_new_rowid, Cursor, CursorResult, LimboError,
|
||||
OwnedRecord, OwnedValue, Result,
|
||||
exec_trim, exec_unicode, exec_upper, execute_sqlite_version, get_new_rowid, Cursor,
|
||||
CursorResult, LimboError, OwnedRecord, OwnedValue, Result,
|
||||
};
|
||||
use mockall::{mock, predicate};
|
||||
use rand::{rngs::mock::StepRng, thread_rng};
|
||||
|
@ -2813,4 +2827,11 @@ mod tests {
|
|||
let expected = Some(OwnedValue::Null);
|
||||
assert_eq!(exec_sign(&input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute_sqlite_version() {
|
||||
let version_integer = 3046001;
|
||||
let expected = "3.46.1";
|
||||
assert_eq!(execute_sqlite_version(version_integer), expected);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue