1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::error::Error;
use crate::sqlite::connection::handle::ConnectionHandle;
use crate::sqlite::statement::StatementWorker;
use crate::{
common::StatementCache,
sqlite::{SqliteConnectOptions, SqliteConnection, SqliteError},
};
use libsqlite3_sys::{
sqlite3_busy_timeout, sqlite3_extended_result_codes, sqlite3_open_v2, SQLITE_OK,
SQLITE_OPEN_CREATE, SQLITE_OPEN_MEMORY, SQLITE_OPEN_NOMUTEX, SQLITE_OPEN_PRIVATECACHE,
SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE, SQLITE_OPEN_SHAREDCACHE,
};
use sqlx_rt::blocking;
use std::io;
use std::{
convert::TryFrom,
ptr::{null, null_mut},
};
pub(crate) async fn establish(options: &SqliteConnectOptions) -> Result<SqliteConnection, Error> {
let mut filename = options
.filename
.to_str()
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"filename passed to SQLite must be valid UTF-8",
)
})?
.to_owned();
filename.push('\0');
let mut flags = SQLITE_OPEN_NOMUTEX;
flags |= if options.read_only {
SQLITE_OPEN_READONLY
} else if options.create_if_missing {
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
} else {
SQLITE_OPEN_READWRITE
};
if options.in_memory {
flags |= SQLITE_OPEN_MEMORY;
}
flags |= if options.shared_cache {
SQLITE_OPEN_SHAREDCACHE
} else {
SQLITE_OPEN_PRIVATECACHE
};
let busy_timeout = options.busy_timeout;
let handle = blocking!({
let mut handle = null_mut();
let mut status = unsafe {
sqlite3_open_v2(
filename.as_bytes().as_ptr() as *const _,
&mut handle,
flags,
null(),
)
};
if handle.is_null() {
panic!("SQLite is unable to allocate memory to hold the sqlite3 object");
}
let handle = unsafe { ConnectionHandle::new(handle) };
if status != SQLITE_OK {
return Err(Error::Database(Box::new(SqliteError::new(handle.as_ptr()))));
}
unsafe {
sqlite3_extended_result_codes(handle.0.as_ptr(), 1);
}
let ms =
i32::try_from(busy_timeout.as_millis()).expect("Given busy timeout value is too big.");
status = unsafe { sqlite3_busy_timeout(handle.0.as_ptr(), ms) };
if status != SQLITE_OK {
return Err(Error::Database(Box::new(SqliteError::new(handle.as_ptr()))));
}
Ok(handle)
})?;
Ok(SqliteConnection {
handle,
worker: StatementWorker::new(),
statements: StatementCache::new(options.statement_cache_capacity),
statement: None,
transaction_depth: 0,
log_settings: options.log_settings.clone(),
})
}