mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 00:45:37 +01:00
Merge 'Add query only pragma' from bit-aloo
This PR adds support for the PRAGMA `query_only` pragma, which enables or disables write operations on a database connection. It allows applications to mark the connection as read-only at runtime. Reviewed-by: Preston Thorpe <preston@turso.tech> Closes #2498
This commit is contained in:
@@ -150,7 +150,7 @@ Turso aims to be fully compatible with SQLite, with opt-in features not supporte
|
||||
| PRAGMA page_size | Yes | |
|
||||
| PRAGMA parser_trace | No | |
|
||||
| PRAGMA pragma_list | Yes | |
|
||||
| PRAGMA query_only | No | |
|
||||
| PRAGMA query_only | Yes | |
|
||||
| PRAGMA quick_check | No | |
|
||||
| PRAGMA read_uncommitted | No | |
|
||||
| PRAGMA recursive_triggers | No | |
|
||||
|
||||
10
core/lib.rs
10
core/lib.rs
@@ -371,6 +371,7 @@ impl Database {
|
||||
capture_data_changes: RefCell::new(CaptureDataChangesMode::Off),
|
||||
closed: Cell::new(false),
|
||||
attached_databases: RefCell::new(DatabaseCatalog::new()),
|
||||
query_only: Cell::new(false),
|
||||
});
|
||||
let builtin_syms = self.builtin_syms.borrow();
|
||||
// add built-in extensions symbols to the connection to prevent having to load each time
|
||||
@@ -726,6 +727,7 @@ pub struct Connection {
|
||||
closed: Cell<bool>,
|
||||
/// Attached databases
|
||||
attached_databases: RefCell<DatabaseCatalog>,
|
||||
query_only: Cell<bool>,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
@@ -1738,6 +1740,14 @@ impl Connection {
|
||||
self.pager.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn get_query_only(&self) -> bool {
|
||||
self.query_only.get()
|
||||
}
|
||||
|
||||
pub fn set_query_only(&self, value: bool) {
|
||||
self.query_only.set(value);
|
||||
}
|
||||
|
||||
#[cfg(feature = "fs")]
|
||||
/// Copy the current Database and write out to a new file.
|
||||
/// TODO: sqlite3 instead essentially does the equivalent of
|
||||
|
||||
@@ -98,6 +98,10 @@ pub fn pragma_for(pragma: &PragmaName) -> Pragma {
|
||||
PragmaFlags::NeedSchema | PragmaFlags::Result0 | PragmaFlags::SchemaReq,
|
||||
&["mode", "table"],
|
||||
),
|
||||
QueryOnly => Pragma::new(
|
||||
PragmaFlags::Result0 | PragmaFlags::NoColumns1,
|
||||
&["query_only"],
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,10 @@ pub fn translate_inner(
|
||||
| ast::Stmt::Insert(..)
|
||||
);
|
||||
|
||||
if is_write && connection.get_query_only() {
|
||||
bail_parse_error!("Cannot execute write statement in query_only mode")
|
||||
}
|
||||
|
||||
let is_select = matches!(stmt, ast::Stmt::Select { .. });
|
||||
|
||||
let mut program = match stmt {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use chrono::Datelike;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use turso_sqlite3_parser::ast::{self, ColumnDefinition, Expr};
|
||||
use turso_sqlite3_parser::ast::{self, ColumnDefinition, Expr, Literal, Name};
|
||||
use turso_sqlite3_parser::ast::{PragmaName, QualifiedName};
|
||||
|
||||
use crate::pragma::pragma_for;
|
||||
@@ -292,6 +292,14 @@ fn update_pragma(
|
||||
Ok((program, TransactionMode::Write))
|
||||
}
|
||||
PragmaName::DatabaseList => unreachable!("database_list cannot be set"),
|
||||
PragmaName::QueryOnly => query_pragma(
|
||||
PragmaName::QueryOnly,
|
||||
schema,
|
||||
Some(value),
|
||||
pager,
|
||||
connection,
|
||||
program,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,6 +535,33 @@ fn query_pragma(
|
||||
program.add_pragma_result_column(pragma.columns[1].to_string());
|
||||
Ok((program, TransactionMode::Read))
|
||||
}
|
||||
PragmaName::QueryOnly => {
|
||||
if let Some(value_expr) = value {
|
||||
let is_query_only = match value_expr {
|
||||
ast::Expr::Literal(Literal::Numeric(i)) => i.parse::<i64>().unwrap() != 0,
|
||||
ast::Expr::Literal(Literal::String(ref s))
|
||||
| ast::Expr::Name(Name::Ident(ref s)) => {
|
||||
let s = s.to_lowercase();
|
||||
s == "1" || s == "on" || s == "true"
|
||||
}
|
||||
_ => {
|
||||
return Err(LimboError::ParseError(format!(
|
||||
"Invalid value for PRAGMA query_only: {value_expr:?}"
|
||||
)));
|
||||
}
|
||||
};
|
||||
connection.set_query_only(is_query_only);
|
||||
return Ok((program, TransactionMode::None));
|
||||
};
|
||||
|
||||
let register = program.alloc_register();
|
||||
let is_query_only = connection.get_query_only();
|
||||
program.emit_int(is_query_only as i64, register);
|
||||
program.emit_result_row(register, 1);
|
||||
program.add_pragma_result_column(pragma.to_string());
|
||||
|
||||
Ok((program, TransactionMode::None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1816,6 +1816,8 @@ pub enum PragmaName {
|
||||
PageCount,
|
||||
/// Return the page size of the database in bytes.
|
||||
PageSize,
|
||||
/// make connection query only
|
||||
QueryOnly,
|
||||
/// Returns schema version of the database file.
|
||||
SchemaVersion,
|
||||
/// returns information about the columns of a table
|
||||
|
||||
Reference in New Issue
Block a user