diesel/sqlite/connection/
limits.rs1#[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;
8
9#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SqliteLimit {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
SqliteLimit::Length => "Length",
SqliteLimit::SqlLength => "SqlLength",
SqliteLimit::ColumnCount => "ColumnCount",
SqliteLimit::ExprDepth => "ExprDepth",
SqliteLimit::CompoundSelect => "CompoundSelect",
SqliteLimit::VdbeOp => "VdbeOp",
SqliteLimit::FunctionArg => "FunctionArg",
SqliteLimit::Attached => "Attached",
SqliteLimit::LikePatternLength => "LikePatternLength",
SqliteLimit::VariableNumber => "VariableNumber",
SqliteLimit::TriggerDepth => "TriggerDepth",
SqliteLimit::WorkerThreads => "WorkerThreads",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SqliteLimit { }
#[automatically_derived]
impl ::core::clone::Clone for SqliteLimit {
#[inline]
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)]
23#[non_exhaustive]
24pub enum SqliteLimit {
25 Length,
30
31 SqlLength,
36
37 ColumnCount,
44
45 ExprDepth,
52
53 CompoundSelect,
58
59 VdbeOp,
70
71 FunctionArg,
76
77 Attached,
82
83 LikePatternLength,
90
91 VariableNumber,
96
97 TriggerDepth,
102
103 WorkerThreads,
109}
110
111impl SqliteLimit {
112 pub const DEFAULT_LENGTH_LIMIT: i32 = 1_000_000_000;
114 pub const SAFE_LENGTH_LIMIT: i32 = 1_000_000;
116
117 pub const DEFAULT_SQL_LENGTH_LIMIT: i32 = 1_000_000_000;
119 pub const SAFE_SQL_LENGTH_LIMIT: i32 = 100_000;
121
122 pub const DEFAULT_COLUMN_COUNT_LIMIT: i32 = 2_000;
124 pub const SAFE_COLUMN_COUNT_LIMIT: i32 = 100;
126
127 pub const DEFAULT_EXPR_DEPTH_LIMIT: i32 = 1_000;
129 pub const SAFE_EXPR_DEPTH_LIMIT: i32 = 10;
131
132 pub const DEFAULT_COMPOUND_SELECT_LIMIT: i32 = 500;
134 pub const SAFE_COMPOUND_SELECT_LIMIT: i32 = 3;
136
137 pub const DEFAULT_VDBE_OP_LIMIT: i32 = 250_000_000;
139 pub const SAFE_VDBE_OP_LIMIT: i32 = 25_000;
141
142 pub const DEFAULT_FUNCTION_ARG_LIMIT: i32 = 127;
144 pub const SAFE_FUNCTION_ARG_LIMIT: i32 = 8;
146
147 pub const DEFAULT_ATTACHED_LIMIT: i32 = 10;
149 pub const SAFE_ATTACHED_LIMIT: i32 = 0;
151
152 pub const DEFAULT_LIKE_PATTERN_LENGTH_LIMIT: i32 = 50_000;
154 pub const SAFE_LIKE_PATTERN_LENGTH_LIMIT: i32 = 50;
156
157 pub const DEFAULT_VARIABLE_NUMBER_LIMIT: i32 = 32_766;
163 pub const SAFE_VARIABLE_NUMBER_LIMIT: i32 = 10;
165
166 pub const DEFAULT_TRIGGER_DEPTH_LIMIT: i32 = 1_000;
168 pub const SAFE_TRIGGER_DEPTH_LIMIT: i32 = 10;
170
171 pub const DEFAULT_WORKER_THREADS_LIMIT: i32 = 0;
173 pub const SAFE_WORKER_THREADS_LIMIT: i32 = 0;
176
177 pub(super) fn to_ffi(self) -> i32 {
179 match self {
180 SqliteLimit::Length => ffi::SQLITE_LIMIT_LENGTH,
181 SqliteLimit::SqlLength => ffi::SQLITE_LIMIT_SQL_LENGTH,
182 SqliteLimit::ColumnCount => ffi::SQLITE_LIMIT_COLUMN,
183 SqliteLimit::ExprDepth => ffi::SQLITE_LIMIT_EXPR_DEPTH,
184 SqliteLimit::CompoundSelect => ffi::SQLITE_LIMIT_COMPOUND_SELECT,
185 SqliteLimit::VdbeOp => ffi::SQLITE_LIMIT_VDBE_OP,
186 SqliteLimit::FunctionArg => ffi::SQLITE_LIMIT_FUNCTION_ARG,
187 SqliteLimit::Attached => ffi::SQLITE_LIMIT_ATTACHED,
188 SqliteLimit::LikePatternLength => ffi::SQLITE_LIMIT_LIKE_PATTERN_LENGTH,
189 SqliteLimit::VariableNumber => ffi::SQLITE_LIMIT_VARIABLE_NUMBER,
190 SqliteLimit::TriggerDepth => ffi::SQLITE_LIMIT_TRIGGER_DEPTH,
191 SqliteLimit::WorkerThreads => ffi::SQLITE_LIMIT_WORKER_THREADS,
192 }
193 }
194}
195
196impl SqliteConnection {
197 pub fn set_limit(&mut self, limit: SqliteLimit, value: i32) -> i32 {
220 self.raw_connection.set_limit(limit, value)
221 }
222
223 pub fn get_limit(&self, limit: SqliteLimit) -> i32 {
241 self.raw_connection.get_limit(limit)
242 }
243
244 pub fn set_recommended_security_limits(&mut self) {
287 self.set_limit(SqliteLimit::Length, SqliteLimit::SAFE_LENGTH_LIMIT);
288 self.set_limit(SqliteLimit::SqlLength, SqliteLimit::SAFE_SQL_LENGTH_LIMIT);
289 self.set_limit(
290 SqliteLimit::ColumnCount,
291 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
292 );
293 self.set_limit(SqliteLimit::ExprDepth, SqliteLimit::SAFE_EXPR_DEPTH_LIMIT);
294 self.set_limit(
295 SqliteLimit::CompoundSelect,
296 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
297 );
298 self.set_limit(SqliteLimit::VdbeOp, SqliteLimit::SAFE_VDBE_OP_LIMIT);
299 self.set_limit(
300 SqliteLimit::FunctionArg,
301 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
302 );
303 self.set_limit(SqliteLimit::Attached, SqliteLimit::SAFE_ATTACHED_LIMIT);
304 self.set_limit(
305 SqliteLimit::LikePatternLength,
306 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
307 );
308 self.set_limit(
309 SqliteLimit::VariableNumber,
310 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
311 );
312 self.set_limit(
313 SqliteLimit::TriggerDepth,
314 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
315 );
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322 use crate::prelude::*;
323
324 fn connection() -> SqliteConnection {
325 SqliteConnection::establish(":memory:").unwrap()
326 }
327
328 #[diesel_test_helper::test]
329 fn set_limit_returns_previous_value() {
330 let mut conn = connection();
331 let original = conn.get_limit(SqliteLimit::SqlLength);
332
333 assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 1024), original);
336 assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 2048), 1024);
337 assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 2048);
338 }
339
340 #[diesel_test_helper::test]
341 fn get_limit_does_not_mutate() {
342 let conn = connection();
343 let first = conn.get_limit(SqliteLimit::ExprDepth);
344 assert!(first > 0);
347 assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), first);
348 }
349
350 #[diesel_test_helper::test]
351 fn set_limit_enforces_length() {
352 let mut conn = connection();
353 conn.set_limit(SqliteLimit::Length, 100);
354
355 assert!(
356 crate::sql_query("SELECT length(randomblob(50))")
357 .execute(&mut conn)
358 .is_ok()
359 );
360 if cfg!(not(miri)) {
361 assert!(
364 crate::sql_query("SELECT length(randomblob(500))")
365 .execute(&mut conn)
366 .is_err()
367 );
368 }
369 }
370
371 #[diesel_test_helper::test]
372 fn set_limit_enforces_column_count() {
373 let wide = format!(
376 "SELECT {}",
377 (1..=30)
378 .map(|i| i.to_string())
379 .collect::<Vec<_>>()
380 .join(", ")
381 );
382
383 let mut unconstrained = connection();
384 assert!(crate::sql_query(&wide).execute(&mut unconstrained).is_ok());
385
386 if cfg!(not(miri)) {
387 let mut conn = connection();
389 conn.set_limit(SqliteLimit::ColumnCount, 10);
390 assert!(crate::sql_query(&wide).execute(&mut conn).is_err());
391 }
392 }
393
394 #[diesel_test_helper::test]
395 fn set_limit_enforces_expr_depth() {
396 let mut conn = connection();
397 conn.set_limit(SqliteLimit::ExprDepth, 5);
398
399 assert!(crate::sql_query("SELECT 1+1").execute(&mut conn).is_ok());
400 if cfg!(not(miri)) {
401 let deep = format!("SELECT {}1", "1+".repeat(40));
404 assert!(crate::sql_query(&deep).execute(&mut conn).is_err());
405 }
406 }
407
408 #[diesel_test_helper::test]
409 fn set_limit_enforces_compound_select() {
410 let mut conn = connection();
411 conn.set_limit(SqliteLimit::CompoundSelect, 2);
412
413 assert!(
414 crate::sql_query("SELECT 1 UNION SELECT 2")
415 .execute(&mut conn)
416 .is_ok()
417 );
418 if cfg!(not(miri)) {
419 assert!(
422 crate::sql_query(
423 "SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5"
424 )
425 .execute(&mut conn)
426 .is_err()
427 );
428 }
429 }
430
431 #[diesel_test_helper::test]
432 fn set_limit_enforces_vdbe_op() {
433 let heavy = "SELECT count(*) FROM sqlite_master a, sqlite_master b, sqlite_master c";
436
437 let mut unconstrained = connection();
438 assert!(crate::sql_query(heavy).execute(&mut unconstrained).is_ok());
439
440 if cfg!(not(miri)) {
441 let mut conn = connection();
443 conn.set_limit(SqliteLimit::VdbeOp, 5);
444 assert!(crate::sql_query(heavy).execute(&mut conn).is_err());
445 }
446 }
447
448 #[diesel_test_helper::test]
449 fn set_limit_enforces_function_arg() {
450 let mut conn = connection();
451 conn.set_limit(SqliteLimit::FunctionArg, 3);
452
453 assert!(
454 crate::sql_query("SELECT max(1, 2, 3)")
455 .execute(&mut conn)
456 .is_ok()
457 );
458 if cfg!(not(miri)) {
459 assert!(
462 crate::sql_query("SELECT max(1, 2, 3, 4, 5, 6, 7, 8)")
463 .execute(&mut conn)
464 .is_err()
465 );
466 }
467 }
468
469 #[cfg(not(miri))] #[diesel_test_helper::test]
471 fn set_limit_enforces_attached() {
472 let mut conn = connection();
473 conn.set_limit(SqliteLimit::Attached, 0);
474
475 assert!(
477 crate::sql_query("ATTACH DATABASE ':memory:' AS aux_db")
478 .execute(&mut conn)
479 .is_err()
480 );
481 }
482
483 #[diesel_test_helper::test]
484 fn set_limit_enforces_variable_number() {
485 let mut conn = connection();
486 conn.set_limit(
490 SqliteLimit::VariableNumber,
491 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
492 );
493 let at_limit = format!("SELECT ?{}", SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT);
494 let past_limit = format!(
495 "SELECT ?{}",
496 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT as i64 + 1
497 );
498 assert!(crate::sql_query(&at_limit).execute(&mut conn).is_ok());
499 if cfg!(not(miri)) {
500 assert!(crate::sql_query(&past_limit).execute(&mut conn).is_err());
502 }
503 }
504
505 #[diesel_test_helper::test]
506 fn set_limit_enforces_trigger_depth() {
507 use crate::connection::SimpleConnection;
508
509 let setup = "PRAGMA recursive_triggers = ON;\
511 CREATE TABLE recur (x INTEGER);\
512 CREATE TRIGGER recur_tr AFTER INSERT ON recur WHEN NEW.x < 100 \
513 BEGIN INSERT INTO recur VALUES (NEW.x + 1); END;";
514
515 let mut unconstrained = connection();
517 unconstrained.batch_execute(setup).unwrap();
518 assert!(
519 crate::sql_query("INSERT INTO recur VALUES (1)")
520 .execute(&mut unconstrained)
521 .is_ok()
522 );
523
524 let mut conn = connection();
527 conn.set_limit(SqliteLimit::TriggerDepth, 3);
528 conn.batch_execute(setup).unwrap();
529 if cfg!(not(miri)) {
530 assert!(
532 crate::sql_query("INSERT INTO recur VALUES (1)")
533 .execute(&mut conn)
534 .is_err()
535 );
536 }
537 }
538
539 #[diesel_test_helper::test]
540 fn worker_threads_limit_has_no_runtime_error_path() {
541 let mut conn = connection();
546 conn.set_limit(SqliteLimit::WorkerThreads, 0);
547 assert_eq!(conn.get_limit(SqliteLimit::WorkerThreads), 0);
548 assert!(crate::sql_query("SELECT 1").execute(&mut conn).is_ok());
549 }
550
551 #[cfg(not(miri))]
552 #[diesel_test_helper::test]
553 fn set_limit_enforces_sql_length() {
554 let mut conn = connection();
555 conn.set_limit(SqliteLimit::SqlLength, 20);
556
557 let result =
559 crate::sql_query("SELECT * FROM sqlite_master WHERE type = 'table'").execute(&mut conn);
560 assert!(result.is_err());
561 }
562
563 #[diesel_test_helper::test]
564 fn set_limit_enforces_like_pattern_length() {
565 let mut conn = connection();
566 conn.set_limit(SqliteLimit::LikePatternLength, 100);
567
568 assert!(
569 crate::sql_query("SELECT 'test' LIKE 'te%'")
570 .execute(&mut conn)
571 .is_ok()
572 );
573
574 if cfg!(not(miri)) {
576 let long_pattern = "%".repeat(200);
577 let query = format!("SELECT 'test' LIKE '{long_pattern}'");
578 assert!(crate::sql_query(&query).execute(&mut conn).is_err());
579 }
580 }
581
582 #[diesel_test_helper::test]
583 fn set_limit_clamps_above_compile_time_maximum() {
584 let mut conn = connection();
585 conn.set_limit(SqliteLimit::Length, i32::MAX);
588 let clamped = conn.get_limit(SqliteLimit::Length);
589 assert!(clamped > 0 && clamped < i32::MAX);
590 }
591
592 #[diesel_test_helper::test]
593 fn set_recommended_security_limits_applies_documented_table() {
594 let mut conn = connection();
595 conn.set_recommended_security_limits();
596
597 assert_eq!(conn.get_limit(SqliteLimit::Length), 1_000_000);
598 assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 100_000);
599 assert_eq!(conn.get_limit(SqliteLimit::ColumnCount), 100);
600 assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), 10);
601 assert_eq!(conn.get_limit(SqliteLimit::CompoundSelect), 3);
602 assert_eq!(conn.get_limit(SqliteLimit::VdbeOp), 25_000);
603 assert_eq!(conn.get_limit(SqliteLimit::FunctionArg), 8);
604 assert_eq!(conn.get_limit(SqliteLimit::Attached), 0);
605 assert_eq!(conn.get_limit(SqliteLimit::LikePatternLength), 50);
606 assert_eq!(conn.get_limit(SqliteLimit::VariableNumber), 10);
607 assert_eq!(conn.get_limit(SqliteLimit::TriggerDepth), 10);
608 }
609
610 #[diesel_test_helper::test]
611 fn safe_limit_constants_do_not_exceed_defaults() {
612 let pairs = [
618 (
619 SqliteLimit::SAFE_LENGTH_LIMIT,
620 SqliteLimit::DEFAULT_LENGTH_LIMIT,
621 ),
622 (
623 SqliteLimit::SAFE_SQL_LENGTH_LIMIT,
624 SqliteLimit::DEFAULT_SQL_LENGTH_LIMIT,
625 ),
626 (
627 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
628 SqliteLimit::DEFAULT_COLUMN_COUNT_LIMIT,
629 ),
630 (
631 SqliteLimit::SAFE_EXPR_DEPTH_LIMIT,
632 SqliteLimit::DEFAULT_EXPR_DEPTH_LIMIT,
633 ),
634 (
635 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
636 SqliteLimit::DEFAULT_COMPOUND_SELECT_LIMIT,
637 ),
638 (
639 SqliteLimit::SAFE_VDBE_OP_LIMIT,
640 SqliteLimit::DEFAULT_VDBE_OP_LIMIT,
641 ),
642 (
643 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
644 SqliteLimit::DEFAULT_FUNCTION_ARG_LIMIT,
645 ),
646 (
647 SqliteLimit::SAFE_ATTACHED_LIMIT,
648 SqliteLimit::DEFAULT_ATTACHED_LIMIT,
649 ),
650 (
651 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
652 SqliteLimit::DEFAULT_LIKE_PATTERN_LENGTH_LIMIT,
653 ),
654 (
655 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
656 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
657 ),
658 (
659 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
660 SqliteLimit::DEFAULT_TRIGGER_DEPTH_LIMIT,
661 ),
662 (
663 SqliteLimit::SAFE_WORKER_THREADS_LIMIT,
664 SqliteLimit::DEFAULT_WORKER_THREADS_LIMIT,
665 ),
666 ];
667 for (safe, default) in pairs {
668 assert!(
669 safe <= default,
670 "safe value {safe} exceeds default {default}"
671 );
672 }
673 }
674
675 #[diesel_test_helper::test]
676 fn safe_limit_constants_match_recommended_setter() {
677 let mut conn = connection();
678 conn.set_recommended_security_limits();
679
680 assert_eq!(
681 conn.get_limit(SqliteLimit::Length),
682 SqliteLimit::SAFE_LENGTH_LIMIT
683 );
684 assert_eq!(
685 conn.get_limit(SqliteLimit::SqlLength),
686 SqliteLimit::SAFE_SQL_LENGTH_LIMIT
687 );
688 assert_eq!(
689 conn.get_limit(SqliteLimit::ColumnCount),
690 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT
691 );
692 assert_eq!(
693 conn.get_limit(SqliteLimit::ExprDepth),
694 SqliteLimit::SAFE_EXPR_DEPTH_LIMIT
695 );
696 assert_eq!(
697 conn.get_limit(SqliteLimit::CompoundSelect),
698 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT
699 );
700 assert_eq!(
701 conn.get_limit(SqliteLimit::VdbeOp),
702 SqliteLimit::SAFE_VDBE_OP_LIMIT
703 );
704 assert_eq!(
705 conn.get_limit(SqliteLimit::FunctionArg),
706 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT
707 );
708 assert_eq!(
709 conn.get_limit(SqliteLimit::Attached),
710 SqliteLimit::SAFE_ATTACHED_LIMIT
711 );
712 assert_eq!(
713 conn.get_limit(SqliteLimit::LikePatternLength),
714 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT
715 );
716 assert_eq!(
717 conn.get_limit(SqliteLimit::VariableNumber),
718 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT
719 );
720 assert_eq!(
721 conn.get_limit(SqliteLimit::TriggerDepth),
722 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT
723 );
724 assert_eq!(
727 conn.get_limit(SqliteLimit::WorkerThreads),
728 SqliteLimit::SAFE_WORKER_THREADS_LIMIT
729 );
730 }
731}