#[cfg(not(feature = "std"))]
use crate::prelude::*;
use crate::values::SQLiteValue;
use drizzle_core::{SQL, ToSQL};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AutoVacuum {
None,
Full,
Incremental,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JournalMode {
Delete,
Truncate,
Persist,
Memory,
Wal,
Off,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Synchronous {
Off,
Normal,
Full,
Extra,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TempStore {
Default,
File,
Memory,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LockingMode {
Normal,
Exclusive,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SecureDelete {
Off,
On,
Fast,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Encoding {
Utf8,
Utf16Le,
Utf16Be,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CacheSpill {
Enabled(bool),
Pages(i32),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WalCheckpointMode {
Passive,
Full,
Restart,
Truncate,
Noop,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WritableSchema {
Enabled(bool),
Reset,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Pragma {
ApplicationId(i32),
AutoVacuum(AutoVacuum),
CacheSize(i32),
ForeignKeys(bool),
JournalMode(JournalMode),
WalAutocheckpoint(i32),
Synchronous(Synchronous),
TempStore(TempStore),
LockingMode(LockingMode),
SecureDelete(SecureDelete),
UserVersion(i32),
Encoding(Encoding),
PageSize(i32),
MmapSize(i64),
RecursiveTriggers(bool),
AnalysisLimit(i32),
AutomaticIndex(bool),
BusyTimeout(i32),
CacheSpill(CacheSpill),
CaseSensitiveLike(bool),
CellSizeCheck(bool),
CheckpointFullFsync(bool),
CountChanges(bool),
DataStoreDirectory(&'static str),
DefaultCacheSize(i32),
DeferForeignKeys(bool),
EmptyResultCallbacks(bool),
FullColumnNames(bool),
FullFsync(bool),
HardHeapLimit(i64),
IgnoreCheckConstraints(bool),
JournalSizeLimit(i64),
LegacyAlterTable(bool),
LegacyFileFormat,
MaxPageCount(i32),
QueryOnly(bool),
ReadUncommitted(bool),
ReverseUnorderedSelects(bool),
SchemaVersion(i32),
ShortColumnNames(bool),
SoftHeapLimit(i64),
TempStoreDirectory(&'static str),
Threads(i32),
TrustedSchema(bool),
WritableSchema(WritableSchema),
ParserTrace(bool),
VdbeAddoptrace(bool),
VdbeDebug(bool),
VdbeListing(bool),
VdbeTrace(bool),
CollationList,
CompileOptions,
DatabaseList,
FunctionList,
TableList,
TableXInfo(&'static str),
ModuleList,
DataVersion,
FreelistCount,
PageCount,
PragmaList,
Stats,
IncrementalVacuum(Option<i32>),
ShrinkMemory,
WalCheckpoint(Option<WalCheckpointMode>),
IntegrityCheck(Option<&'static str>),
QuickCheck(Option<&'static str>),
Optimize(Option<u32>),
ForeignKeyCheck(Option<&'static str>),
TableInfo(&'static str),
IndexList(&'static str),
IndexInfo(&'static str),
IndexXInfo(&'static str),
ForeignKeyList(&'static str),
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for AutoVacuum {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::None => SQL::raw("NONE"),
Self::Full => SQL::raw("FULL"),
Self::Incremental => SQL::raw("INCREMENTAL"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for JournalMode {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Delete => SQL::raw("DELETE"),
Self::Truncate => SQL::raw("TRUNCATE"),
Self::Persist => SQL::raw("PERSIST"),
Self::Memory => SQL::raw("MEMORY"),
Self::Wal => SQL::raw("WAL"),
Self::Off => SQL::raw("OFF"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for Synchronous {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Off => SQL::raw("OFF"),
Self::Normal => SQL::raw("NORMAL"),
Self::Full => SQL::raw("FULL"),
Self::Extra => SQL::raw("EXTRA"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for TempStore {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Default => SQL::raw("DEFAULT"),
Self::File => SQL::raw("FILE"),
Self::Memory => SQL::raw("MEMORY"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for LockingMode {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Normal => SQL::raw("NORMAL"),
Self::Exclusive => SQL::raw("EXCLUSIVE"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for SecureDelete {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Off => SQL::raw("OFF"),
Self::On => SQL::raw("ON"),
Self::Fast => SQL::raw("FAST"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for Encoding {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Utf8 => SQL::raw("UTF-8"),
Self::Utf16Le => SQL::raw("UTF-16LE"),
Self::Utf16Be => SQL::raw("UTF-16BE"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for CacheSpill {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Enabled(enabled) => SQL::raw(if *enabled { "ON" } else { "OFF" }),
Self::Pages(pages) => SQL::raw(format!("{pages}")),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for WalCheckpointMode {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Passive => SQL::raw("PASSIVE"),
Self::Full => SQL::raw("FULL"),
Self::Restart => SQL::raw("RESTART"),
Self::Truncate => SQL::raw("TRUNCATE"),
Self::Noop => SQL::raw("NOOP"),
}
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for WritableSchema {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
match self {
Self::Enabled(enabled) => SQL::raw(if *enabled { "ON" } else { "OFF" }),
Self::Reset => SQL::raw("RESET"),
}
}
}
fn bool_pragma<'a>(name: &str, enabled: bool) -> SQL<'a, SQLiteValue<'a>> {
let suffix = if enabled { "ON" } else { "OFF" };
SQL::raw(format!("PRAGMA {name} = {suffix}"))
}
fn utility_pragma<'a>(pragma: &Pragma) -> Option<SQL<'a, SQLiteValue<'a>>> {
match pragma {
Pragma::IncrementalVacuum(pages) => Some(pages.as_ref().map_or_else(
|| SQL::raw("PRAGMA incremental_vacuum"),
|count| SQL::raw(format!("PRAGMA incremental_vacuum({count})")),
)),
Pragma::ShrinkMemory => Some(SQL::raw("PRAGMA shrink_memory")),
Pragma::WalCheckpoint(mode) => Some(mode.as_ref().map_or_else(
|| SQL::raw("PRAGMA wal_checkpoint"),
|m| SQL::raw("PRAGMA wal_checkpoint = ").append(m.to_sql()),
)),
Pragma::IntegrityCheck(table) => Some(table.as_ref().map_or_else(
|| SQL::raw("PRAGMA integrity_check"),
|t| SQL::raw(format!("PRAGMA integrity_check({t})")),
)),
Pragma::QuickCheck(table) => Some(table.as_ref().map_or_else(
|| SQL::raw("PRAGMA quick_check"),
|t| SQL::raw(format!("PRAGMA quick_check({t})")),
)),
Pragma::Optimize(mask) => Some(mask.as_ref().map_or_else(
|| SQL::raw("PRAGMA optimize"),
|m| SQL::raw(format!("PRAGMA optimize({m})")),
)),
Pragma::ForeignKeyCheck(table) => Some(table.as_ref().map_or_else(
|| SQL::raw("PRAGMA foreign_key_check"),
|t| SQL::raw(format!("PRAGMA foreign_key_check({t})")),
)),
_ => None,
}
}
impl<'a> ToSQL<'a, SQLiteValue<'a>> for Pragma {
fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
if let Some(sql) = utility_pragma(self) {
return sql;
}
match self {
Self::ApplicationId(id) => SQL::raw(format!("PRAGMA application_id = {id}")),
Self::AutoVacuum(mode) => SQL::raw("PRAGMA auto_vacuum = ").append(mode.to_sql()),
Self::CacheSize(size) => SQL::raw(format!("PRAGMA cache_size = {size}")),
Self::ForeignKeys(enabled) => bool_pragma("foreign_keys", *enabled),
Self::JournalMode(mode) => SQL::raw("PRAGMA journal_mode = ").append(mode.to_sql()),
Self::Synchronous(mode) => SQL::raw("PRAGMA synchronous = ").append(mode.to_sql()),
Self::WalAutocheckpoint(pages) => {
SQL::raw(format!("PRAGMA wal_autocheckpoint = {pages}"))
}
Self::TempStore(store) => SQL::raw("PRAGMA temp_store = ").append(store.to_sql()),
Self::LockingMode(mode) => SQL::raw("PRAGMA locking_mode = ").append(mode.to_sql()),
Self::SecureDelete(mode) => SQL::raw("PRAGMA secure_delete = ").append(mode.to_sql()),
Self::UserVersion(version) => SQL::raw(format!("PRAGMA user_version = {version}")),
Self::Encoding(encoding) => SQL::raw("PRAGMA encoding = ").append(encoding.to_sql()),
Self::PageSize(size) => SQL::raw(format!("PRAGMA page_size = {size}")),
Self::MmapSize(size) => SQL::raw(format!("PRAGMA mmap_size = {size}")),
Self::RecursiveTriggers(enabled) => bool_pragma("recursive_triggers", *enabled),
Self::AnalysisLimit(limit) => SQL::raw(format!("PRAGMA analysis_limit = {limit}")),
Self::AutomaticIndex(enabled) => bool_pragma("automatic_index", *enabled),
Self::BusyTimeout(timeout) => SQL::raw(format!("PRAGMA busy_timeout = {timeout}")),
Self::CacheSpill(setting) => SQL::raw("PRAGMA cache_spill = ").append(setting.to_sql()),
Self::CaseSensitiveLike(enabled) => bool_pragma("case_sensitive_like", *enabled),
Self::CellSizeCheck(enabled) => bool_pragma("cell_size_check", *enabled),
Self::CheckpointFullFsync(enabled) => bool_pragma("checkpoint_fullfsync", *enabled),
Self::CountChanges(enabled) => bool_pragma("count_changes", *enabled),
Self::DataStoreDirectory(directory) => {
SQL::raw(format!("PRAGMA data_store_directory = '{directory}'"))
}
Self::DefaultCacheSize(size) => SQL::raw(format!("PRAGMA default_cache_size = {size}")),
Self::DeferForeignKeys(enabled) => bool_pragma("defer_foreign_keys", *enabled),
Self::EmptyResultCallbacks(enabled) => bool_pragma("empty_result_callbacks", *enabled),
Self::FullColumnNames(enabled) => bool_pragma("full_column_names", *enabled),
Self::FullFsync(enabled) => bool_pragma("fullfsync", *enabled),
Self::HardHeapLimit(limit) => SQL::raw(format!("PRAGMA hard_heap_limit = {limit}")),
Self::IgnoreCheckConstraints(enabled) => {
bool_pragma("ignore_check_constraints", *enabled)
}
Self::JournalSizeLimit(limit) => {
SQL::raw(format!("PRAGMA journal_size_limit = {limit}"))
}
Self::LegacyAlterTable(enabled) => bool_pragma("legacy_alter_table", *enabled),
Self::LegacyFileFormat => SQL::raw("PRAGMA legacy_file_format"),
Self::MaxPageCount(count) => SQL::raw(format!("PRAGMA max_page_count = {count}")),
Self::QueryOnly(enabled) => bool_pragma("query_only", *enabled),
Self::ReadUncommitted(enabled) => bool_pragma("read_uncommitted", *enabled),
Self::ReverseUnorderedSelects(enabled) => {
bool_pragma("reverse_unordered_selects", *enabled)
}
Self::SchemaVersion(version) => SQL::raw(format!("PRAGMA schema_version = {version}")),
Self::ShortColumnNames(enabled) => bool_pragma("short_column_names", *enabled),
Self::SoftHeapLimit(limit) => SQL::raw(format!("PRAGMA soft_heap_limit = {limit}")),
Self::TempStoreDirectory(directory) => {
SQL::raw(format!("PRAGMA temp_store_directory = '{directory}'"))
}
Self::Threads(threads) => SQL::raw(format!("PRAGMA threads = {threads}")),
Self::TrustedSchema(enabled) => bool_pragma("trusted_schema", *enabled),
Self::WritableSchema(mode) => {
SQL::raw("PRAGMA writable_schema = ").append(mode.to_sql())
}
Self::ParserTrace(enabled) => bool_pragma("parser_trace", *enabled),
Self::VdbeAddoptrace(enabled) => bool_pragma("vdbe_addoptrace", *enabled),
Self::VdbeDebug(enabled) => bool_pragma("vdbe_debug", *enabled),
Self::VdbeListing(enabled) => bool_pragma("vdbe_listing", *enabled),
Self::VdbeTrace(enabled) => bool_pragma("vdbe_trace", *enabled),
Self::CollationList => SQL::raw("PRAGMA collation_list"),
Self::CompileOptions => SQL::raw("PRAGMA compile_options"),
Self::DatabaseList => SQL::raw("PRAGMA database_list"),
Self::FunctionList => SQL::raw("PRAGMA function_list"),
Self::TableList => SQL::raw("PRAGMA table_list"),
Self::TableXInfo(table) => SQL::raw(format!("PRAGMA table_xinfo({table})")),
Self::ModuleList => SQL::raw("PRAGMA module_list"),
Self::DataVersion => SQL::raw("PRAGMA data_version"),
Self::FreelistCount => SQL::raw("PRAGMA freelist_count"),
Self::PageCount => SQL::raw("PRAGMA page_count"),
Self::PragmaList => SQL::raw("PRAGMA pragma_list"),
Self::Stats => SQL::raw("PRAGMA stats"),
Self::IncrementalVacuum(_)
| Self::ShrinkMemory
| Self::WalCheckpoint(_)
| Self::IntegrityCheck(_)
| Self::QuickCheck(_)
| Self::Optimize(_)
| Self::ForeignKeyCheck(_) => unreachable!("routed via utility_pragma"),
Self::TableInfo(table) => SQL::raw(format!("PRAGMA table_info({table})")),
Self::IndexList(table) => SQL::raw(format!("PRAGMA index_list({table})")),
Self::IndexInfo(index) => SQL::raw(format!("PRAGMA index_info({index})")),
Self::IndexXInfo(index) => SQL::raw(format!("PRAGMA index_xinfo({index})")),
Self::ForeignKeyList(table) => SQL::raw(format!("PRAGMA foreign_key_list({table})")),
}
}
}
impl Pragma {
#[must_use]
pub fn query(pragma_name: &str) -> SQL<'static, SQLiteValue<'static>> {
SQL::raw(format!("PRAGMA {pragma_name}"))
}
#[must_use]
pub const fn foreign_keys(enabled: bool) -> Self {
Self::ForeignKeys(enabled)
}
#[must_use]
pub const fn journal_mode(mode: JournalMode) -> Self {
Self::JournalMode(mode)
}
#[must_use]
pub const fn wal_autocheckpoint(pages: i32) -> Self {
Self::WalAutocheckpoint(pages)
}
#[must_use]
pub const fn table_info(table: &'static str) -> Self {
Self::TableInfo(table)
}
#[must_use]
pub const fn index_list(table: &'static str) -> Self {
Self::IndexList(table)
}
#[must_use]
pub const fn foreign_key_list(table: &'static str) -> Self {
Self::ForeignKeyList(table)
}
#[must_use]
pub const fn integrity_check(table: Option<&'static str>) -> Self {
Self::IntegrityCheck(table)
}
#[must_use]
pub const fn foreign_key_check(table: Option<&'static str>) -> Self {
Self::ForeignKeyCheck(table)
}
#[must_use]
pub const fn table_xinfo(table: &'static str) -> Self {
Self::TableXInfo(table)
}
#[must_use]
pub const fn encoding(encoding: Encoding) -> Self {
Self::Encoding(encoding)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_query_pragma_helper() {
assert_eq!(Pragma::query("foreign_keys").sql(), "PRAGMA foreign_keys");
assert_eq!(Pragma::query("custom_pragma").sql(), "PRAGMA custom_pragma");
}
#[test]
fn test_convenience_constructor_integration() {
assert_eq!(
Pragma::foreign_keys(true).to_sql().sql(),
Pragma::ForeignKeys(true).to_sql().sql()
);
assert_eq!(
Pragma::table_info("users").to_sql().sql(),
Pragma::TableInfo("users").to_sql().sql()
);
assert_eq!(
Pragma::encoding(Encoding::Utf8).to_sql().sql(),
Pragma::Encoding(Encoding::Utf8).to_sql().sql()
);
}
}