1use crate::connection::{DefaultLoadingMode, LoadConnection};
70use crate::deserialize::FromSqlRow;
71use crate::expression::QueryMetadata;
72use crate::query_builder::{AstPass, Query, QueryFragment, QueryId};
73use crate::result::{Error, QueryResult};
74use crate::sql_types::SqlType;
75use crate::sqlite::{AutoVacuumMode, Sqlite, SqliteConnection};
76use alloc::string::ToString;
77use alloc::vec::Vec;
78use core::marker::PhantomData;
79use core::num::NonZeroU32;
80
81pub trait Pragma: Sized {
83 const NAME: &'static str;
87 type Scope: PragmaScope;
89}
90
91pub trait PragmaScope: private::Sealed {}
93
94#[derive(#[automatically_derived]impl ::core::fmt::Debug for PerSchema {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match *self {}
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for PerSchema {
}
#[automatically_derived]impl ::core::clone::Clone for PerSchema {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for PerSchema { }Copy)]
96pub enum PerSchema {}
97
98#[derive(#[automatically_derived]impl ::core::fmt::Debug for PerConnection {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match *self {}
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for PerConnection {
}
#[automatically_derived]impl ::core::clone::Clone for PerConnection {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for PerConnection { }Copy)]
100pub enum PerConnection {}
101
102impl PragmaScope for PerSchema {}
103impl PragmaScope for PerConnection {}
104
105mod private {
106 use crate::query_builder::AstPass;
107 use crate::result::QueryResult;
108 use crate::sqlite::Sqlite;
109
110 pub trait Sealed {}
111 impl Sealed for super::PerSchema {}
112 impl Sealed for super::PerConnection {}
113
114 pub trait RenderArgument {
115 fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()>;
116 }
117}
118
119pub trait ReadPragma: Pragma {
121 type SqlType: SqlType;
123}
124
125pub trait WritePragma: Pragma {
129 type Argument<'a>: PragmaArgument;
131}
132
133pub trait PragmaArgument: private::RenderArgument {}
139
140#[derive(#[automatically_derived]impl ::core::fmt::Debug for PragmaKeyword {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "PragmaKeyword",
&&self.0)
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for PragmaKeyword {
}
#[automatically_derived]impl ::core::clone::Clone for PragmaKeyword {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<&'static str>;
*self
}
}Clone, #[automatically_derived]impl ::core::marker::Copy for PragmaKeyword { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
PragmaKeyword {
}
#[automatically_derived]impl ::core::cmp::PartialEq for PragmaKeyword {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for PragmaKeyword {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<&'static str>;
}
}Eq)]
189pub struct PragmaKeyword(&'static str);
190
191impl PragmaKeyword {
192 pub const fn new(keyword: &'static str) -> Self {
194 Self(keyword)
195 }
196}
197
198impl private::RenderArgument for PragmaKeyword {
199 fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
200 push_bare_word(out, "keyword", self.0)
201 }
202}
203
204impl PragmaArgument for PragmaKeyword {}
205
206#[derive(#[automatically_derived]impl<'a> ::core::fmt::Debug for PragmaText<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "PragmaText",
&&self.0)
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl<'a>
::core::clone::TrivialClone for PragmaText<'a> {
}
#[automatically_derived]impl<'a> ::core::clone::Clone for PragmaText<'a> {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<&'a str>;
*self
}
}Clone, #[automatically_derived]impl<'a> ::core::marker::Copy for PragmaText<'a> { }Copy, #[automatically_derived]impl<'a> ::core::marker::StructuralPartialEq for
PragmaText<'a> {
}
#[automatically_derived]impl<'a> ::core::cmp::PartialEq for PragmaText<'a> {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]impl<'a> ::core::cmp::Eq for PragmaText<'a> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<&'a str>;
}
}Eq)]
245pub struct PragmaText<'a>(&'a str);
246
247impl<'a> From<&'a str> for PragmaText<'a> {
248 fn from(text: &'a str) -> Self {
249 Self(text)
250 }
251}
252
253impl private::RenderArgument for PragmaText<'_> {
254 fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
255 out.push_sql("'");
256 for piece in self.0.split_inclusive('\'') {
257 out.push_sql(piece);
258 if piece.ends_with('\'') {
259 out.push_sql("'");
260 }
261 }
262 out.push_sql("'");
263 Ok(())
264 }
265}
266
267impl PragmaArgument for PragmaText<'_> {}
268
269macro_rules! integer_pragma_argument {
270 ($($ty:ty),*) => {$(
271 impl private::RenderArgument for $ty {
272 fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
273 out.push_sql(&i64::from(*self).to_string());
274 Ok(())
275 }
276 }
277
278 impl PragmaArgument for $ty {}
279 )*};
280}
281
282impl private::RenderArgument for i8 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for i8 {}
impl private::RenderArgument for i16 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for i16 {}
impl private::RenderArgument for i32 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for i32 {}
impl private::RenderArgument for i64 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for i64 {}
impl private::RenderArgument for u8 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for u8 {}
impl private::RenderArgument for u16 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for u16 {}
impl private::RenderArgument for u32 {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for u32 {}
impl private::RenderArgument for bool {
fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
out.push_sql(&i64::from(*self).to_string());
Ok(())
}
}
impl PragmaArgument for bool {}integer_pragma_argument!(i8, i16, i32, i64, u8, u16, u32, bool);
283
284pub trait SchemaPragma: Pragma<Scope = PerSchema> {
286 fn get<Row>(schema: Option<&str>, conn: &mut SqliteConnection) -> QueryResult<Row>
288 where
289 Self: ReadPragma,
290 Sqlite: QueryMetadata<Self::SqlType>,
291 Row: FromSqlRow<Self::SqlType, Sqlite>,
292 {
293 first_row::<Self, Row>(conn, Some(schema.unwrap_or("main")))
294 }
295
296 fn get_all<Row>(schema: Option<&str>, conn: &mut SqliteConnection) -> QueryResult<Vec<Row>>
298 where
299 Self: ReadPragma,
300 Sqlite: QueryMetadata<Self::SqlType>,
301 Row: FromSqlRow<Self::SqlType, Sqlite>,
302 {
303 all_rows::<Self, Row>(conn, Some(schema.unwrap_or("main")))
304 }
305
306 fn set<'a>(
308 argument: impl Into<Self::Argument<'a>>,
309 schema: Option<&str>,
310 conn: &mut SqliteConnection,
311 ) -> QueryResult<()>
312 where
313 Self: WritePragma,
314 {
315 assign::<Self>(conn, Some(schema.unwrap_or("main")), argument.into())
316 }
317}
318
319impl<P: Pragma<Scope = PerSchema>> SchemaPragma for P {}
320
321pub trait ConnectionPragma: Pragma<Scope = PerConnection> {
323 fn get<Row>(conn: &mut SqliteConnection) -> QueryResult<Row>
325 where
326 Self: ReadPragma,
327 Sqlite: QueryMetadata<Self::SqlType>,
328 Row: FromSqlRow<Self::SqlType, Sqlite>,
329 {
330 first_row::<Self, Row>(conn, None)
331 }
332
333 fn get_all<Row>(conn: &mut SqliteConnection) -> QueryResult<Vec<Row>>
335 where
336 Self: ReadPragma,
337 Sqlite: QueryMetadata<Self::SqlType>,
338 Row: FromSqlRow<Self::SqlType, Sqlite>,
339 {
340 all_rows::<Self, Row>(conn, None)
341 }
342
343 fn set<'a>(
345 argument: impl Into<Self::Argument<'a>>,
346 conn: &mut SqliteConnection,
347 ) -> QueryResult<()>
348 where
349 Self: WritePragma,
350 {
351 assign::<Self>(conn, None, argument.into())
352 }
353}
354
355impl<P: Pragma<Scope = PerConnection>> ConnectionPragma for P {}
356
357#[derive(#[automatically_derived]impl ::core::fmt::Debug for PageCount {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "PageCount")
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for PageCount {
}
#[automatically_derived]impl ::core::clone::Clone for PageCount {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for PageCount { }Copy)]
376pub struct PageCount;
377
378impl Pragma for PageCount {
379 const NAME: &'static str = "page_count";
380 type Scope = PerSchema;
381}
382
383impl ReadPragma for PageCount {
384 type SqlType = crate::sql_types::BigInt;
385}
386
387#[derive(#[automatically_derived]impl ::core::fmt::Debug for FreelistCount {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "FreelistCount")
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for FreelistCount {
}
#[automatically_derived]impl ::core::clone::Clone for FreelistCount {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for FreelistCount { }Copy)]
402pub struct FreelistCount;
403
404impl Pragma for FreelistCount {
405 const NAME: &'static str = "freelist_count";
406 type Scope = PerSchema;
407}
408
409impl ReadPragma for FreelistCount {
410 type SqlType = crate::sql_types::BigInt;
411}
412
413#[derive(#[automatically_derived]impl ::core::fmt::Debug for AutoVacuum {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "AutoVacuum")
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for AutoVacuum {
}
#[automatically_derived]impl ::core::clone::Clone for AutoVacuum {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for AutoVacuum { }Copy)]
434pub struct AutoVacuum;
435
436impl Pragma for AutoVacuum {
437 const NAME: &'static str = "auto_vacuum";
438 type Scope = PerSchema;
439}
440
441impl ReadPragma for AutoVacuum {
442 type SqlType = crate::sql_types::Integer;
443}
444
445impl WritePragma for AutoVacuum {
446 type Argument<'a> = AutoVacuumMode;
447}
448
449impl private::RenderArgument for AutoVacuumMode {
450 fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
451 out.push_sql(&(*self as i32).to_string());
453 Ok(())
454 }
455}
456
457impl PragmaArgument for AutoVacuumMode {}
458
459#[derive(#[automatically_derived]impl ::core::fmt::Debug for IncrementalVacuum {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "IncrementalVacuum")
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for IncrementalVacuum {
}
#[automatically_derived]impl ::core::clone::Clone for IncrementalVacuum {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for IncrementalVacuum { }Copy)]
479pub struct IncrementalVacuum;
480
481impl Pragma for IncrementalVacuum {
482 const NAME: &'static str = "incremental_vacuum";
483 type Scope = PerSchema;
484}
485
486impl WritePragma for IncrementalVacuum {
487 type Argument<'a> = Option<NonZeroU32>;
488}
489
490impl private::RenderArgument for Option<NonZeroU32> {
491 fn render(&self, out: &mut AstPass<'_, '_, Sqlite>) -> QueryResult<()> {
492 out.push_sql(&self.map_or(0, NonZeroU32::get).to_string());
493 Ok(())
494 }
495}
496
497impl PragmaArgument for Option<NonZeroU32> {}
498
499fn cursor<'conn, 'query, P>(
500 conn: &'conn mut SqliteConnection,
501 schema: Option<&'query str>,
502) -> QueryResult<<SqliteConnection as LoadConnection<DefaultLoadingMode>>::Cursor<'conn, 'query>>
503where
504 P: ReadPragma + 'query,
505 Sqlite: QueryMetadata<P::SqlType>,
506{
507 LoadConnection::<DefaultLoadingMode>::load(conn, PragmaQuery::<P>::new(schema))
508}
509
510fn first_row<P, Row>(conn: &mut SqliteConnection, schema: Option<&str>) -> QueryResult<Row>
511where
512 P: ReadPragma,
513 Sqlite: QueryMetadata<P::SqlType>,
514 Row: FromSqlRow<P::SqlType, Sqlite>,
515{
516 let mut cursor = cursor::<P>(conn, schema)?;
517 let row = cursor.next().ok_or(Error::NotFound)??;
518 Row::build_from_row(&row).map_err(Error::DeserializationError)
519}
520
521fn all_rows<P, Row>(conn: &mut SqliteConnection, schema: Option<&str>) -> QueryResult<Vec<Row>>
522where
523 P: ReadPragma,
524 Sqlite: QueryMetadata<P::SqlType>,
525 Row: FromSqlRow<P::SqlType, Sqlite>,
526{
527 cursor::<P>(conn, schema)?
528 .map(|row| Row::build_from_row(&row?).map_err(Error::DeserializationError))
529 .collect()
530}
531
532fn assign<P: WritePragma>(
533 conn: &mut SqliteConnection,
534 schema: Option<&str>,
535 argument: P::Argument<'_>,
536) -> QueryResult<()> {
537 use crate::connection::SimpleConnection;
538 use crate::query_builder::QueryBuilder;
539 use crate::sqlite::SqliteQueryBuilder;
540
541 let mut query = SqliteQueryBuilder::new();
544 PragmaAssignment::<P, _> {
545 schema,
546 argument,
547 pragma: PhantomData,
548 }
549 .to_sql(&mut query, &Sqlite)?;
550 conn.batch_execute(&query.finish())
551}
552
553#[derive(#[automatically_derived]impl<'a, P: ::core::fmt::Debug> ::core::fmt::Debug for
PragmaQuery<'a, P> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"PragmaQuery schema pragma", &self.schema, &&self.pragma)
}
}Debug)]
554struct PragmaQuery<'a, P> {
555 schema: Option<&'a str>,
556
557 pragma: PhantomData<P>,
558}
559
560impl<'a, P: Pragma> PragmaQuery<'a, P> {
561 fn new(schema: Option<&'a str>) -> Self {
562 Self {
563 schema,
564 pragma: PhantomData,
565 }
566 }
567}
568
569impl<P: Pragma> QueryFragment<Sqlite> for PragmaQuery<'_, P> {
570 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
571 push_pragma::<P>(&mut out, self.schema)
572 }
573}
574
575impl<P> QueryId for PragmaQuery<'_, P> {
577 type QueryId = ();
578
579 const HAS_STATIC_QUERY_ID: bool = false;
580}
581
582impl<P: ReadPragma> Query for PragmaQuery<'_, P> {
583 type SqlType = P::SqlType;
584}
585
586struct PragmaAssignment<'a, P, A> {
587 schema: Option<&'a str>,
588 argument: A,
589 pragma: PhantomData<P>,
590}
591
592impl<P: Pragma, A: PragmaArgument> QueryFragment<Sqlite> for PragmaAssignment<'_, P, A> {
593 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
594 push_pragma::<P>(&mut out, self.schema)?;
595 out.push_sql(" = ");
596 self.argument.render(&mut out)
597 }
598}
599
600fn push_pragma<P: Pragma>(
601 out: &mut AstPass<'_, '_, Sqlite>,
602 schema: Option<&str>,
603) -> QueryResult<()> {
604 out.push_sql("PRAGMA ");
605 if let Some(schema) = schema {
606 out.push_identifier(schema)?;
607 out.push_sql(".");
608 }
609 push_bare_word(out, "name", P::NAME)
610}
611
612fn push_bare_word(
613 out: &mut AstPass<'_, '_, Sqlite>,
614 kind: &str,
615 word: &'static str,
616) -> QueryResult<()> {
617 if word.is_empty()
618 || !word
619 .bytes()
620 .all(|byte| byte.is_ascii_alphanumeric() || byte == b'_')
621 {
622 return Err(Error::QueryBuilderError(
623 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is not a valid pragma {1}",
word, kind))
})alloc::format!("`{word}` is not a valid pragma {kind}").into(),
624 ));
625 }
626 out.push_sql(word);
627 Ok(())
628}