From 62efbde66178c33da14733ea6fbf7b9577ff8e4f Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Thu, 30 Jan 2025 20:42:41 -0500 Subject: [PATCH 1/2] use strum package to simplify PragmaName enum management The pragma list will only grow. The strum crate can be used to: * automatically convert to string from enum * automatically convert to enum from string * implement an iterator over all elements of the enum --- core/translate/mod.rs | 2 +- vendored/sqlite3-parser/Cargo.toml | 2 ++ vendored/sqlite3-parser/src/parser/ast/mod.rs | 19 ++++--------------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/core/translate/mod.rs b/core/translate/mod.rs index 1f40c3f02..04e0e3af2 100644 --- a/core/translate/mod.rs +++ b/core/translate/mod.rs @@ -548,7 +548,7 @@ fn translate_pragma( let pragma = match PragmaName::from_str(&name.name.0) { Ok(pragma) => pragma, - Err(()) => bail_parse_error!("Not a valid pragma name"), + Err(_) => bail_parse_error!("Not a valid pragma name"), }; match body { diff --git a/vendored/sqlite3-parser/Cargo.toml b/vendored/sqlite3-parser/Cargo.toml index 9b8513f74..b446e9ba4 100644 --- a/vendored/sqlite3-parser/Cargo.toml +++ b/vendored/sqlite3-parser/Cargo.toml @@ -32,6 +32,8 @@ bitflags = "2.0" uncased = "0.9.10" indexmap = "2.0" miette = "7.4.0" +strum = { version = "0.26", features = ["derive"] } +strum_macros = "0.26" [dev-dependencies] env_logger = { version = "0.11", default-features = false } diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index f46f38e85..93bf05bee 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -7,6 +7,8 @@ use std::num::ParseIntError; use std::ops::Deref; use std::str::{self, Bytes, FromStr}; +use strum_macros::{EnumIter, EnumString}; + use fmt::{ToTokens, TokenStream}; use indexmap::{IndexMap, IndexSet}; @@ -1585,7 +1587,8 @@ pub type PragmaValue = Expr; // TODO /// `PRAGMA` value // https://sqlite.org/pragma.html -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, EnumIter, EnumString, strum::Display)] +#[strum(serialize_all = "snake_case")] pub enum PragmaName { /// `cache_size` pragma CacheSize, @@ -1597,20 +1600,6 @@ pub enum PragmaName { TableInfo, } -impl FromStr for PragmaName { - type Err = (); - - fn from_str(input: &str) -> Result { - match input { - "cache_size" => Ok(PragmaName::CacheSize), - "wal_checkpoint" => Ok(PragmaName::WalCheckpoint), - "journal_mode" => Ok(PragmaName::JournalMode), - "table_info" => Ok(PragmaName::TableInfo), - _ => Err(()), - } - } -} - /// `CREATE TRIGGER` time #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum TriggerTime { From a7cc367c1ffb82df5a801b235cdc1df6f9c7d64b Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Thu, 30 Jan 2025 21:05:31 -0500 Subject: [PATCH 2/2] implement pragma pragma_list List all available pragmas (Except pragma_list) --- COMPAT.md | 2 +- Cargo.lock | 25 +++++++++++++++++++++++++ core/Cargo.toml | 1 + core/translate/mod.rs | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/COMPAT.md b/COMPAT.md index fb2da2d79..905de6c77 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -138,7 +138,7 @@ The current status of Limbo is: | PRAGMA page_count | No | | | PRAGMA page_size | No | | | PRAGMA parser_trace | No | | -| PRAGMA pragma_list | No | | +| PRAGMA pragma_list | Yes | | | PRAGMA query_only | No | | | PRAGMA quick_check | No | | | PRAGMA read_uncommitted | No | | diff --git a/Cargo.lock b/Cargo.lock index af303d953..23a263f9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1588,6 +1588,7 @@ dependencies = [ "serde", "sieve-cache", "sqlite3-parser", + "strum", "tempfile", "thiserror 1.0.69", ] @@ -2704,6 +2705,8 @@ dependencies = [ "phf", "phf_codegen", "phf_shared", + "strum", + "strum_macros", "uncased", ] @@ -2731,6 +2734,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.96", +] + [[package]] name = "supports-color" version = "3.0.2" diff --git a/core/Cargo.toml b/core/Cargo.toml index 347602f57..d2172af34 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -66,6 +66,7 @@ limbo_vector = { path = "../extensions/vector", optional = true, features = ["st limbo_regexp = { path = "../extensions/regexp", optional = true, features = ["static"] } limbo_percentile = { path = "../extensions/percentile", optional = true, features = ["static"] } miette = "7.4.0" +strum = "0.26" [build-dependencies] chrono = "0.4.38" diff --git a/core/translate/mod.rs b/core/translate/mod.rs index 04e0e3af2..c0190942b 100644 --- a/core/translate/mod.rs +++ b/core/translate/mod.rs @@ -29,6 +29,7 @@ use crate::storage::wal::CheckpointMode; use crate::translate::delete::translate_delete; use crate::util::{normalize_ident, PRIMARY_KEY_AUTOMATIC_INDEX_NAME_PREFIX}; use crate::vdbe::builder::CursorType; +use crate::vdbe::BranchOffset; use crate::vdbe::{builder::ProgramBuilder, insn::Insn, Program}; use crate::{bail_parse_error, Connection, LimboError, Result, SymbolTable}; use insert::translate_insert; @@ -38,6 +39,7 @@ use std::cell::RefCell; use std::fmt::Display; use std::rc::{Rc, Weak}; use std::str::FromStr; +use strum::IntoEnumIterator; /// Translate SQL statement into bytecode program. pub fn translate( @@ -531,6 +533,36 @@ enum PrimaryKeyDefinitionType<'a> { Composite, } +fn list_pragmas( + program: &mut ProgramBuilder, + init_label: BranchOffset, + start_offset: BranchOffset, +) { + let mut pragma_strings: Vec = PragmaName::iter().map(|x| x.to_string()).collect(); + pragma_strings.sort(); + + let register = program.alloc_register(); + for pragma in &pragma_strings { + program.emit_insn(Insn::String8 { + value: pragma.to_string(), + dest: register, + }); + program.emit_insn(Insn::ResultRow { + start_reg: register, + count: 1, + }); + } + program.emit_insn(Insn::Halt { + err_code: 0, + description: String::new(), + }); + program.resolve_label(init_label, program.offset()); + program.emit_constant_insns(); + program.emit_insn(Insn::Goto { + target_pc: start_offset, + }); +} + fn translate_pragma( program: &mut ProgramBuilder, schema: &Schema, @@ -546,6 +578,11 @@ fn translate_pragma( let start_offset = program.offset(); let mut write = false; + if name.name.0.to_lowercase() == "pragma_list" { + list_pragmas(program, init_label, start_offset); + return Ok(()); + } + let pragma = match PragmaName::from_str(&name.name.0) { Ok(pragma) => pragma, Err(_) => bail_parse_error!("Not a valid pragma name"),