mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-02 09:12:16 +00:00
Add support for sqlite_version() scalar function
This commit is contained in:
parent
9f1ce53d18
commit
6b40acabbc
7 changed files with 60 additions and 6 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 | |
|
||||
|
|
|
@ -65,6 +65,7 @@ pub enum ScalarFunc {
|
|||
Time,
|
||||
Unicode,
|
||||
Quote,
|
||||
SqliteVersion,
|
||||
UnixEpoch,
|
||||
}
|
||||
|
||||
|
@ -96,6 +97,7 @@ impl ToString 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(),
|
||||
}
|
||||
}
|
||||
|
@ -160,6 +162,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(()),
|
||||
|
|
|
@ -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>,
|
||||
|
@ -64,6 +66,10 @@ impl Database {
|
|||
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)]
|
||||
|
|
|
@ -1311,6 +1311,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
@ -1574,6 +1574,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")
|
||||
|
@ -2150,13 +2156,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};
|
||||
|
@ -2751,4 +2765,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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -430,3 +430,7 @@ do_execsql_test sign-text-non-numeric {
|
|||
do_execsql_test sign-null {
|
||||
SELECT sign(NULL);
|
||||
} {}
|
||||
|
||||
do_execsql_test sqlite_version {
|
||||
SELECT sqlite_version();
|
||||
} {3.46.1}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue