1#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2extern crate libsqlite3_sys as ffi;
3
4#[cfg(all(target_family = "wasm", target_os = "unknown"))]
5use sqlite_wasm_rs as ffi;
6
7use super::SqliteConnection;
8use crate::result::{DatabaseErrorKind, Error, QueryResult};
9use alloc::boxed::Box;
10use alloc::format;
11
12#[derive(#[automatically_derived]impl ::core::fmt::Debug for SqliteLimit {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_c_like_enum_write_str(f,
"Length SqlLength ColumnCount ExprDepth CompoundSelect VdbeOp FunctionArg Attached LikePatternLength VariableNumber TriggerDepth WorkerThreads",
match self {
SqliteLimit::Length => 0usize,
SqliteLimit::SqlLength => 7usize,
SqliteLimit::ColumnCount => 17usize,
SqliteLimit::ExprDepth => 29usize,
SqliteLimit::CompoundSelect => 39usize,
SqliteLimit::VdbeOp => 54usize,
SqliteLimit::FunctionArg => 61usize,
SqliteLimit::Attached => 73usize,
SqliteLimit::LikePatternLength => 82usize,
SqliteLimit::VariableNumber => 100usize,
SqliteLimit::TriggerDepth => 115usize,
SqliteLimit::WorkerThreads => 128usize,
})
}
}Debug, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for SqliteLimit {
}
#[automatically_derived]impl ::core::clone::Clone for SqliteLimit {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for SqliteLimit { }Copy, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
SqliteLimit {
}
#[automatically_derived]impl ::core::cmp::PartialEq for SqliteLimit {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for SqliteLimit { }Eq, #[automatically_derived]impl ::core::hash::Hash for SqliteLimit {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state)
}
}Hash)]
26#[non_exhaustive]
27pub enum SqliteLimit {
28 Length,
33
34 SqlLength,
39
40 ColumnCount,
47
48 ExprDepth,
55
56 CompoundSelect,
61
62 VdbeOp,
73
74 FunctionArg,
79
80 Attached,
85
86 LikePatternLength,
93
94 VariableNumber,
99
100 TriggerDepth,
105
106 WorkerThreads,
112}
113
114impl SqliteLimit {
115 pub const DEFAULT_LENGTH_LIMIT: u32 = 1_000_000_000;
117 pub const SAFE_LENGTH_LIMIT: u32 = 1_000_000;
119
120 pub const DEFAULT_SQL_LENGTH_LIMIT: u32 = 1_000_000_000;
122 pub const SAFE_SQL_LENGTH_LIMIT: u32 = 100_000;
124
125 pub const DEFAULT_COLUMN_COUNT_LIMIT: u32 = 2_000;
127 pub const SAFE_COLUMN_COUNT_LIMIT: u32 = 100;
129
130 pub const DEFAULT_EXPR_DEPTH_LIMIT: u32 = 1_000;
132 pub const SAFE_EXPR_DEPTH_LIMIT: u32 = 10;
134
135 pub const DEFAULT_COMPOUND_SELECT_LIMIT: u32 = 500;
137 pub const SAFE_COMPOUND_SELECT_LIMIT: u32 = 3;
139
140 pub const DEFAULT_VDBE_OP_LIMIT: u32 = 250_000_000;
142 pub const SAFE_VDBE_OP_LIMIT: u32 = 25_000;
144
145 pub const DEFAULT_FUNCTION_ARG_LIMIT: u32 = 127;
147 pub const SAFE_FUNCTION_ARG_LIMIT: u32 = 8;
149
150 pub const DEFAULT_ATTACHED_LIMIT: u32 = 10;
152 pub const SAFE_ATTACHED_LIMIT: u32 = 0;
154
155 pub const DEFAULT_LIKE_PATTERN_LENGTH_LIMIT: u32 = 50_000;
157 pub const SAFE_LIKE_PATTERN_LENGTH_LIMIT: u32 = 50;
159
160 pub const DEFAULT_VARIABLE_NUMBER_LIMIT: u32 = 32_766;
166 pub const SAFE_VARIABLE_NUMBER_LIMIT: u32 = 10;
168
169 pub const DEFAULT_TRIGGER_DEPTH_LIMIT: u32 = 1_000;
171 pub const SAFE_TRIGGER_DEPTH_LIMIT: u32 = 10;
173
174 pub const DEFAULT_WORKER_THREADS_LIMIT: u32 = 0;
176 pub const SAFE_WORKER_THREADS_LIMIT: u32 = 0;
179
180 pub(super) fn to_ffi(self) -> i32 {
182 match self {
183 SqliteLimit::Length => ffi::SQLITE_LIMIT_LENGTH,
184 SqliteLimit::SqlLength => ffi::SQLITE_LIMIT_SQL_LENGTH,
185 SqliteLimit::ColumnCount => ffi::SQLITE_LIMIT_COLUMN,
186 SqliteLimit::ExprDepth => ffi::SQLITE_LIMIT_EXPR_DEPTH,
187 SqliteLimit::CompoundSelect => ffi::SQLITE_LIMIT_COMPOUND_SELECT,
188 SqliteLimit::VdbeOp => ffi::SQLITE_LIMIT_VDBE_OP,
189 SqliteLimit::FunctionArg => ffi::SQLITE_LIMIT_FUNCTION_ARG,
190 SqliteLimit::Attached => ffi::SQLITE_LIMIT_ATTACHED,
191 SqliteLimit::LikePatternLength => ffi::SQLITE_LIMIT_LIKE_PATTERN_LENGTH,
192 SqliteLimit::VariableNumber => ffi::SQLITE_LIMIT_VARIABLE_NUMBER,
193 SqliteLimit::TriggerDepth => ffi::SQLITE_LIMIT_TRIGGER_DEPTH,
194 SqliteLimit::WorkerThreads => ffi::SQLITE_LIMIT_WORKER_THREADS,
195 }
196 }
197}
198
199impl SqliteConnection {
200 pub fn set_limit(&mut self, limit: SqliteLimit, value: u32) -> QueryResult<u32> {
228 let previous = self.raw_connection.set_limit(limit, value);
229 let applied = self.raw_connection.get_limit(limit);
230 if applied == value {
231 return Ok(previous);
232 }
233 self.raw_connection.set_limit(limit, previous);
234 Err(Error::DatabaseError(
235 DatabaseErrorKind::Unknown,
236 Box::new(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("SQLite caps the {0:?} limit at {1}, below the requested {2}",
limit, applied, value))
})format!(
237 "SQLite caps the {limit:?} limit at {applied}, below the requested {value}"
238 )),
239 ))
240 }
241
242 pub fn get_limit(&self, limit: SqliteLimit) -> u32 {
260 self.raw_connection.get_limit(limit)
261 }
262
263 pub fn set_recommended_security_limits(&mut self) -> QueryResult<()> {
310 self.set_limit(SqliteLimit::Length, SqliteLimit::SAFE_LENGTH_LIMIT)?;
311 self.set_limit(SqliteLimit::SqlLength, SqliteLimit::SAFE_SQL_LENGTH_LIMIT)?;
312 self.set_limit(
313 SqliteLimit::ColumnCount,
314 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
315 )?;
316 self.set_limit(SqliteLimit::ExprDepth, SqliteLimit::SAFE_EXPR_DEPTH_LIMIT)?;
317 self.set_limit(
318 SqliteLimit::CompoundSelect,
319 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
320 )?;
321 self.set_limit(SqliteLimit::VdbeOp, SqliteLimit::SAFE_VDBE_OP_LIMIT)?;
322 self.set_limit(
323 SqliteLimit::FunctionArg,
324 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
325 )?;
326 self.set_limit(SqliteLimit::Attached, SqliteLimit::SAFE_ATTACHED_LIMIT)?;
327 self.set_limit(
328 SqliteLimit::LikePatternLength,
329 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
330 )?;
331 self.set_limit(
332 SqliteLimit::VariableNumber,
333 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
334 )?;
335 self.set_limit(
336 SqliteLimit::TriggerDepth,
337 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
338 )?;
339 Ok(())
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346 use crate::prelude::*;
347
348 fn connection() -> SqliteConnection {
349 SqliteConnection::establish(":memory:").unwrap()
350 }
351
352 #[diesel_test_helper::test]
353 fn set_limit_returns_previous_value() {
354 let mut conn = connection();
355 let original = conn.get_limit(SqliteLimit::SqlLength);
356
357 assert_eq!(
360 conn.set_limit(SqliteLimit::SqlLength, 1024).unwrap(),
361 original
362 );
363 assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 2048).unwrap(), 1024);
364 assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 2048);
365 }
366
367 #[diesel_test_helper::test]
368 fn get_limit_does_not_mutate() {
369 let conn = connection();
370 let first = conn.get_limit(SqliteLimit::ExprDepth);
371 assert!(first > 0);
374 assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), first);
375 }
376
377 #[diesel_test_helper::test]
378 fn set_limit_enforces_length() {
379 let mut conn = connection();
380 conn.set_limit(SqliteLimit::Length, 100).unwrap();
381
382 assert!(
383 crate::sql_query("SELECT length(randomblob(50))")
384 .execute(&mut conn)
385 .is_ok()
386 );
387 if cfg!(not(miri)) {
388 assert!(
391 crate::sql_query("SELECT length(randomblob(500))")
392 .execute(&mut conn)
393 .is_err()
394 );
395 }
396 }
397
398 #[diesel_test_helper::test]
399 fn set_limit_enforces_column_count() {
400 let wide = format!(
403 "SELECT {}",
404 (1..=30)
405 .map(|i| i.to_string())
406 .collect::<Vec<_>>()
407 .join(", ")
408 );
409
410 let mut unconstrained = connection();
411 assert!(crate::sql_query(&wide).execute(&mut unconstrained).is_ok());
412
413 if cfg!(not(miri)) {
414 let mut conn = connection();
416 conn.set_limit(SqliteLimit::ColumnCount, 10).unwrap();
417 assert!(crate::sql_query(&wide).execute(&mut conn).is_err());
418 }
419 }
420
421 #[diesel_test_helper::test]
422 fn set_limit_enforces_expr_depth() {
423 let mut conn = connection();
424 conn.set_limit(SqliteLimit::ExprDepth, 5).unwrap();
425
426 assert!(crate::sql_query("SELECT 1+1").execute(&mut conn).is_ok());
427 if cfg!(not(miri)) {
428 let deep = format!("SELECT {}1", "1+".repeat(40));
431 assert!(crate::sql_query(&deep).execute(&mut conn).is_err());
432 }
433 }
434
435 #[diesel_test_helper::test]
436 fn set_limit_enforces_compound_select() {
437 let mut conn = connection();
438 conn.set_limit(SqliteLimit::CompoundSelect, 2).unwrap();
439
440 assert!(
441 crate::sql_query("SELECT 1 UNION SELECT 2")
442 .execute(&mut conn)
443 .is_ok()
444 );
445 if cfg!(not(miri)) {
446 assert!(
449 crate::sql_query(
450 "SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5"
451 )
452 .execute(&mut conn)
453 .is_err()
454 );
455 }
456 }
457
458 #[diesel_test_helper::test]
459 fn set_limit_enforces_vdbe_op() {
460 let heavy = "SELECT count(*) FROM sqlite_master a, sqlite_master b, sqlite_master c";
463
464 let mut unconstrained = connection();
465 assert!(crate::sql_query(heavy).execute(&mut unconstrained).is_ok());
466
467 if cfg!(not(miri)) {
468 let mut conn = connection();
470 conn.set_limit(SqliteLimit::VdbeOp, 5).unwrap();
471 assert!(crate::sql_query(heavy).execute(&mut conn).is_err());
472 }
473 }
474
475 #[diesel_test_helper::test]
476 fn set_limit_enforces_function_arg() {
477 let mut conn = connection();
478 conn.set_limit(SqliteLimit::FunctionArg, 3).unwrap();
479
480 assert!(
481 crate::sql_query("SELECT max(1, 2, 3)")
482 .execute(&mut conn)
483 .is_ok()
484 );
485 if cfg!(not(miri)) {
486 assert!(
489 crate::sql_query("SELECT max(1, 2, 3, 4, 5, 6, 7, 8)")
490 .execute(&mut conn)
491 .is_err()
492 );
493 }
494 }
495
496 #[cfg(not(miri))] #[diesel_test_helper::test]
498 fn set_limit_enforces_attached() {
499 let mut conn = connection();
500 conn.set_limit(SqliteLimit::Attached, 0).unwrap();
501
502 assert!(
504 crate::sql_query("ATTACH DATABASE ':memory:' AS aux_db")
505 .execute(&mut conn)
506 .is_err()
507 );
508 }
509
510 #[diesel_test_helper::test]
511 fn set_limit_enforces_variable_number() {
512 let mut conn = connection();
513 let limit = 10;
514
515 conn.set_limit(SqliteLimit::VariableNumber, 10).unwrap();
519 let at_limit = format!("SELECT ?{}", limit);
520 let mut at_limit_query = crate::sql_query(&at_limit).into_boxed();
521 for _ in 0..limit {
522 at_limit_query = at_limit_query.bind::<crate::sql_types::Integer, _>(1);
523 }
524 let past_limit = format!("SELECT ?{}", limit + 1);
525 let mut past_limit_query = crate::sql_query(&past_limit).into_boxed();
526 for _ in 0..(limit + 1) {
527 past_limit_query = past_limit_query.bind::<crate::sql_types::Integer, _>(1);
528 }
529
530 assert!(at_limit_query.execute(&mut conn).is_ok());
531 if cfg!(not(miri)) {
532 assert!(past_limit_query.execute(&mut conn).is_err());
534 }
535 }
536
537 #[diesel_test_helper::test]
538 fn set_limit_enforces_trigger_depth() {
539 use crate::connection::SimpleConnection;
540
541 let setup = "PRAGMA recursive_triggers = ON;\
543 CREATE TABLE recur (x INTEGER);\
544 CREATE TRIGGER recur_tr AFTER INSERT ON recur WHEN NEW.x < 100 \
545 BEGIN INSERT INTO recur VALUES (NEW.x + 1); END;";
546
547 let mut unconstrained = connection();
549 unconstrained.batch_execute(setup).unwrap();
550 assert!(
551 crate::sql_query("INSERT INTO recur VALUES (1)")
552 .execute(&mut unconstrained)
553 .is_ok()
554 );
555
556 let mut conn = connection();
559 conn.set_limit(SqliteLimit::TriggerDepth, 3).unwrap();
560 conn.batch_execute(setup).unwrap();
561 if cfg!(not(miri)) {
562 assert!(
564 crate::sql_query("INSERT INTO recur VALUES (1)")
565 .execute(&mut conn)
566 .is_err()
567 );
568 }
569 }
570
571 #[diesel_test_helper::test]
572 fn worker_threads_limit_has_no_runtime_error_path() {
573 let mut conn = connection();
578 conn.set_limit(SqliteLimit::WorkerThreads, 0).unwrap();
579 assert_eq!(conn.get_limit(SqliteLimit::WorkerThreads), 0);
580 assert!(crate::sql_query("SELECT 1").execute(&mut conn).is_ok());
581 }
582
583 #[cfg(not(miri))]
584 #[diesel_test_helper::test]
585 fn set_limit_enforces_sql_length() {
586 let mut conn = connection();
587 conn.set_limit(SqliteLimit::SqlLength, 20).unwrap();
588
589 let result =
591 crate::sql_query("SELECT * FROM sqlite_master WHERE type = 'table'").execute(&mut conn);
592 assert!(result.is_err());
593 }
594
595 #[diesel_test_helper::test]
596 fn set_limit_enforces_like_pattern_length() {
597 let mut conn = connection();
598 conn.set_limit(SqliteLimit::LikePatternLength, 100).unwrap();
599
600 assert!(
601 crate::sql_query("SELECT 'test' LIKE 'te%'")
602 .execute(&mut conn)
603 .is_ok()
604 );
605
606 if cfg!(not(miri)) {
608 let long_pattern = "%".repeat(200);
609 let query = format!("SELECT 'test' LIKE '{long_pattern}'");
610 assert!(crate::sql_query(&query).execute(&mut conn).is_err());
611 }
612 }
613
614 #[diesel_test_helper::test]
615 fn set_limit_rejects_values_above_compile_time_maximum() {
616 let mut conn = connection();
617 conn.set_limit(SqliteLimit::Length, 100).unwrap();
618 assert!(conn.set_limit(SqliteLimit::Length, u32::MAX).is_err());
620 assert_eq!(conn.get_limit(SqliteLimit::Length), 100);
621 }
622
623 #[diesel_test_helper::test]
624 fn set_recommended_security_limits_applies_documented_table() {
625 let mut conn = connection();
626 conn.set_recommended_security_limits().unwrap();
627
628 assert_eq!(conn.get_limit(SqliteLimit::Length), 1_000_000);
629 assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 100_000);
630 assert_eq!(conn.get_limit(SqliteLimit::ColumnCount), 100);
631 assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), 10);
632 assert_eq!(conn.get_limit(SqliteLimit::CompoundSelect), 3);
633 assert_eq!(conn.get_limit(SqliteLimit::VdbeOp), 25_000);
634 assert_eq!(conn.get_limit(SqliteLimit::FunctionArg), 8);
635 assert_eq!(conn.get_limit(SqliteLimit::Attached), 0);
636 assert_eq!(conn.get_limit(SqliteLimit::LikePatternLength), 50);
637 assert_eq!(conn.get_limit(SqliteLimit::VariableNumber), 10);
638 assert_eq!(conn.get_limit(SqliteLimit::TriggerDepth), 10);
639 }
640
641 #[diesel_test_helper::test]
642 fn safe_limit_constants_do_not_exceed_defaults() {
643 let pairs = [
649 (
650 SqliteLimit::SAFE_LENGTH_LIMIT,
651 SqliteLimit::DEFAULT_LENGTH_LIMIT,
652 ),
653 (
654 SqliteLimit::SAFE_SQL_LENGTH_LIMIT,
655 SqliteLimit::DEFAULT_SQL_LENGTH_LIMIT,
656 ),
657 (
658 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
659 SqliteLimit::DEFAULT_COLUMN_COUNT_LIMIT,
660 ),
661 (
662 SqliteLimit::SAFE_EXPR_DEPTH_LIMIT,
663 SqliteLimit::DEFAULT_EXPR_DEPTH_LIMIT,
664 ),
665 (
666 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
667 SqliteLimit::DEFAULT_COMPOUND_SELECT_LIMIT,
668 ),
669 (
670 SqliteLimit::SAFE_VDBE_OP_LIMIT,
671 SqliteLimit::DEFAULT_VDBE_OP_LIMIT,
672 ),
673 (
674 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
675 SqliteLimit::DEFAULT_FUNCTION_ARG_LIMIT,
676 ),
677 (
678 SqliteLimit::SAFE_ATTACHED_LIMIT,
679 SqliteLimit::DEFAULT_ATTACHED_LIMIT,
680 ),
681 (
682 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
683 SqliteLimit::DEFAULT_LIKE_PATTERN_LENGTH_LIMIT,
684 ),
685 (
686 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
687 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
688 ),
689 (
690 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
691 SqliteLimit::DEFAULT_TRIGGER_DEPTH_LIMIT,
692 ),
693 (
694 SqliteLimit::SAFE_WORKER_THREADS_LIMIT,
695 SqliteLimit::DEFAULT_WORKER_THREADS_LIMIT,
696 ),
697 ];
698 for (safe, default) in pairs {
699 assert!(
700 safe <= default,
701 "safe value {safe} exceeds default {default}"
702 );
703 }
704 }
705
706 #[diesel_test_helper::test]
707 fn safe_limit_constants_match_recommended_setter() {
708 let mut conn = connection();
709 conn.set_recommended_security_limits().unwrap();
710
711 assert_eq!(
712 conn.get_limit(SqliteLimit::Length),
713 SqliteLimit::SAFE_LENGTH_LIMIT
714 );
715 assert_eq!(
716 conn.get_limit(SqliteLimit::SqlLength),
717 SqliteLimit::SAFE_SQL_LENGTH_LIMIT
718 );
719 assert_eq!(
720 conn.get_limit(SqliteLimit::ColumnCount),
721 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT
722 );
723 assert_eq!(
724 conn.get_limit(SqliteLimit::ExprDepth),
725 SqliteLimit::SAFE_EXPR_DEPTH_LIMIT
726 );
727 assert_eq!(
728 conn.get_limit(SqliteLimit::CompoundSelect),
729 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT
730 );
731 assert_eq!(
732 conn.get_limit(SqliteLimit::VdbeOp),
733 SqliteLimit::SAFE_VDBE_OP_LIMIT
734 );
735 assert_eq!(
736 conn.get_limit(SqliteLimit::FunctionArg),
737 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT
738 );
739 assert_eq!(
740 conn.get_limit(SqliteLimit::Attached),
741 SqliteLimit::SAFE_ATTACHED_LIMIT
742 );
743 assert_eq!(
744 conn.get_limit(SqliteLimit::LikePatternLength),
745 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT
746 );
747 assert_eq!(
748 conn.get_limit(SqliteLimit::VariableNumber),
749 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT
750 );
751 assert_eq!(
752 conn.get_limit(SqliteLimit::TriggerDepth),
753 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT
754 );
755 assert_eq!(
758 conn.get_limit(SqliteLimit::WorkerThreads),
759 SqliteLimit::SAFE_WORKER_THREADS_LIMIT
760 );
761 }
762}