Skip to content

Commit 6c74c53

Browse files
authored
Merge 'Kill unwrap() calls in VDBE module' from Pekka Enberg
Reviewed-by: Jussi Saurio <[email protected]> Closes #4014
2 parents 6638119 + 5716424 commit 6c74c53

File tree

8 files changed

+220
-115
lines changed

8 files changed

+220
-115
lines changed

core/vdbe/builder.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,10 @@ impl ProgramBuilder {
365365
) -> crate::Result<usize> {
366366
tracing::debug!("alloc cursor: {:?} {:?}", key, index.index_method.is_some());
367367
let module = index.index_method.as_ref();
368-
if module.is_some_and(|m| !m.definition().backing_btree) {
369-
let module = module.unwrap().clone();
370-
return Ok(self._alloc_cursor_id(key, CursorType::IndexMethod(module)));
368+
if let Some(m) = module {
369+
if !m.definition().backing_btree {
370+
return Ok(self._alloc_cursor_id(key, CursorType::IndexMethod(m.clone())));
371+
}
371372
}
372373
Ok(self._alloc_cursor_id(key, CursorType::BTreeIndex(index.clone())))
373374
}
@@ -544,11 +545,11 @@ impl ProgramBuilder {
544545
});
545546
for resolved_offset in self.label_to_resolved_offset.iter_mut() {
546547
if let Some((old_offset, target)) = resolved_offset {
547-
let new_offset = self
548-
.insns
549-
.iter()
550-
.position(|(_, index)| *old_offset == *index as u32)
551-
.unwrap() as u32;
548+
let new_offset =
549+
self.insns
550+
.iter()
551+
.position(|(_, index)| *old_offset == *index as u32)
552+
.expect("instruction offset must exist") as u32;
552553
*resolved_offset = Some((new_offset, *target));
553554
}
554555
}
@@ -1064,7 +1065,7 @@ impl ProgramBuilder {
10641065
}
10651066

10661067
pub fn emit_column_or_rowid(&mut self, cursor_id: CursorID, column: usize, out: usize) {
1067-
let (_, cursor_type) = self.cursor_ref.get(cursor_id).unwrap();
1068+
let (_, cursor_type) = self.cursor_ref.get(cursor_id).expect("cursor_id is valid");
10681069
if let CursorType::BTreeTable(btree) = cursor_type {
10691070
let column_def = btree
10701071
.columns
@@ -1084,7 +1085,7 @@ impl ProgramBuilder {
10841085
}
10851086

10861087
fn emit_column(&mut self, cursor_id: CursorID, column: usize, out: usize) {
1087-
let (_, cursor_type) = self.cursor_ref.get(cursor_id).unwrap();
1088+
let (_, cursor_type) = self.cursor_ref.get(cursor_id).expect("cursor_id is valid");
10881089

10891090
use crate::translate::expr::sanitize_string;
10901091

@@ -1114,9 +1115,10 @@ impl ProgramBuilder {
11141115
.chunks_exact(2)
11151116
.map(|pair| {
11161117
// We assume that sqlite3-parser has already validated that
1117-
// the input is valid hex string, thus unwrap is safe.
1118-
let hex_byte = std::str::from_utf8(pair).unwrap();
1119-
u8::from_str_radix(hex_byte, 16).unwrap()
1118+
// the input is valid hex string, thus expect is safe.
1119+
let hex_byte =
1120+
std::str::from_utf8(pair).expect("parser validated hex string");
1121+
u8::from_str_radix(hex_byte, 16).expect("parser validated hex digit")
11201122
})
11211123
.collect(),
11221124
),

core/vdbe/execute.rs

Lines changed: 145 additions & 61 deletions
Large diffs are not rendered by default.

core/vdbe/explain.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ pub fn insn_to_row(
561561
name
562562
}
563563
CursorType::BTreeIndex(index) => {
564-
let name = &index.columns.get(*column).unwrap().name;
564+
let name = &index.columns.get(*column).expect("column index out of bounds").name;
565565
Some(name)
566566
}
567567
CursorType::MaterializedView(table, _) => {
@@ -571,7 +571,7 @@ pub fn insn_to_row(
571571
CursorType::Pseudo(_) => None,
572572
CursorType::Sorter => None,
573573
CursorType::IndexMethod(..) => None,
574-
CursorType::VirtualTable(v) => v.columns.get(*column).unwrap().name.as_ref(),
574+
CursorType::VirtualTable(v) => v.columns.get(*column).expect("column index out of bounds").name.as_ref(),
575575
};
576576
(
577577
"Column",
@@ -1017,8 +1017,8 @@ pub fn insn_to_row(
10171017
SortOrder::Asc => "",
10181018
SortOrder::Desc => "-",
10191019
};
1020-
if collation.is_some() {
1021-
format!("{sign}{}", collation.unwrap())
1020+
if let Some(coll) = collation {
1021+
format!("{sign}{coll}")
10221022
} else {
10231023
format!("{sign}B")
10241024
}

core/vdbe/insn.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,9 @@ const fn get_insn_virtual_table() -> [InsnFunction; InsnVariants::COUNT] {
12761276

12771277
let mut insn = 0;
12781278
while insn < InsnVariants::COUNT {
1279-
result[insn] = InsnVariants::from_repr(insn as u8).unwrap().to_function();
1279+
result[insn] = InsnVariants::from_repr(insn as u8)
1280+
.expect("insn index should be valid within COUNT")
1281+
.to_function();
12801282
insn += 1;
12811283
}
12821284

core/vdbe/likeop.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn construct_like_regex_with_escape(pattern: &str, escape: char) -> Regex {
6060
.case_insensitive(true)
6161
.dot_matches_new_line(true)
6262
.build()
63-
.unwrap()
63+
.expect("constructed LIKE regex pattern should be valid")
6464
}
6565

6666
// Implements GLOB pattern matching. Caches the constructed regex if a cache is provided
@@ -173,7 +173,8 @@ fn construct_glob_regex(pattern: &str) -> Result<Regex, LimboError> {
173173
regex_pattern.push('$');
174174

175175
if bracket_closed {
176-
Ok(Regex::new(&regex_pattern).unwrap())
176+
Regex::new(&regex_pattern)
177+
.map_err(|e| LimboError::InternalError(format!("invalid GLOB regex pattern: {e}")))
177178
} else {
178179
Err(LimboError::Constraint(
179180
"blob pattern is not closed".to_string(),

core/vdbe/mod.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ impl Program {
997997
.connection
998998
.view_transaction_states
999999
.get(view_name)
1000-
.unwrap()
1000+
.expect("view should have transaction state")
10011001
.get_table_deltas();
10021002

10031003
let schema = self.connection.schema.read();
@@ -1067,7 +1067,7 @@ impl Program {
10671067
let Some(tx_id) = conn.get_mv_tx_id() else {
10681068
return Ok(IOResult::Done(()));
10691069
};
1070-
let state_machine = mv_store.commit_tx(tx_id, &conn).unwrap();
1070+
let state_machine = mv_store.commit_tx(tx_id, &conn)?;
10711071
program_state.commit_state = CommitState::CommitingMvcc { state_machine };
10721072
}
10731073
let CommitState::CommitingMvcc { state_machine } = &mut program_state.commit_state
@@ -1314,7 +1314,12 @@ impl<'a> FromValueRow<'a> for &'a Value {
13141314

13151315
impl Row {
13161316
pub fn get<'a, T: FromValueRow<'a> + 'a>(&'a self, idx: usize) -> Result<T> {
1317-
let value = unsafe { self.values.add(idx).as_ref().unwrap() };
1317+
let value = unsafe {
1318+
self.values
1319+
.add(idx)
1320+
.as_ref()
1321+
.expect("row value pointer should be valid")
1322+
};
13181323
let value = match value {
13191324
Register::Value(value) => value,
13201325
_ => unreachable!("a row should be formed of values only"),
@@ -1323,7 +1328,12 @@ impl Row {
13231328
}
13241329

13251330
pub fn get_value(&self, idx: usize) -> &Value {
1326-
let value = unsafe { self.values.add(idx).as_ref().unwrap() };
1331+
let value = unsafe {
1332+
self.values
1333+
.add(idx)
1334+
.as_ref()
1335+
.expect("row value pointer should be valid")
1336+
};
13271337
match value {
13281338
Register::Value(value) => value,
13291339
_ => unreachable!("a row should be formed of values only"),

core/vdbe/sorter.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use turso_parser::ast::SortOrder;
22

3+
use parking_lot::RwLock;
34
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd, Reverse};
45
use std::collections::BinaryHeap;
56
use std::rc::Rc;
6-
use std::sync::{atomic, Arc, RwLock};
7+
use std::sync::{atomic, Arc};
78
use tempfile;
89

910
use crate::types::IOCompletions;
@@ -158,10 +159,7 @@ impl Sorter {
158159
SortState::InitHeap => {
159160
turso_assert!(
160161
!self.chunks.iter().any(|chunk| {
161-
matches!(
162-
*chunk.io_state.read().unwrap(),
163-
SortedChunkIOState::WaitingForWrite
164-
)
162+
matches!(*chunk.io_state.read(), SortedChunkIOState::WaitingForWrite)
165163
}),
166164
"chunks should been written"
167165
);
@@ -255,7 +253,7 @@ impl Sorter {
255253
// Make sure all chunks read at least one record into their buffer.
256254
turso_assert!(
257255
!self.chunks.iter().any(|chunk| matches!(
258-
*chunk.io_state.read().unwrap(),
256+
*chunk.io_state.read(),
259257
SortedChunkIOState::WaitingForRead
260258
)),
261259
"chunks should have been read"
@@ -332,11 +330,12 @@ impl Sorter {
332330
None => {
333331
let temp_dir = tempfile::tempdir()?;
334332
let chunk_file_path = temp_dir.as_ref().join("chunk_file");
335-
let chunk_file = self.io.open_file(
336-
chunk_file_path.to_str().unwrap(),
337-
OpenFlags::Create,
338-
false,
339-
)?;
333+
let chunk_file_path_str = chunk_file_path.to_str().ok_or_else(|| {
334+
LimboError::InternalError("temp file path is not valid UTF-8".to_string())
335+
})?;
336+
let chunk_file =
337+
self.io
338+
.open_file(chunk_file_path_str, OpenFlags::Create, false)?;
340339
self.temp_file = Some(TempFile {
341340
_temp_dir: temp_dir,
342341
file: chunk_file.clone(),
@@ -438,7 +437,7 @@ impl SortedChunk {
438437
}
439438

440439
if self.records.is_empty() {
441-
let mut buffer_ref = self.buffer.write().unwrap();
440+
let mut buffer_ref = self.buffer.write();
442441
let buffer = buffer_ref.as_mut_slice();
443442
let mut buffer_offset = 0;
444443
while buffer_offset < buffer_len {
@@ -449,8 +448,7 @@ impl SortedChunk {
449448
(record_size as usize, bytes_read)
450449
}
451450
Err(LimboError::Corrupt(_))
452-
if *self.io_state.read().unwrap()
453-
!= SortedChunkIOState::ReadEOF =>
451+
if *self.io_state.read() != SortedChunkIOState::ReadEOF =>
454452
{
455453
// Failed to decode a partial varint.
456454
break;
@@ -460,7 +458,7 @@ impl SortedChunk {
460458
}
461459
};
462460
if record_size > buffer_len - (buffer_offset + bytes_read) {
463-
if *self.io_state.read().unwrap() == SortedChunkIOState::ReadEOF {
461+
if *self.io_state.read() == SortedChunkIOState::ReadEOF {
464462
crate::bail_corrupt_error!("Incomplete record");
465463
}
466464
break;
@@ -489,13 +487,13 @@ impl SortedChunk {
489487
self.next_state = NextState::Finish;
490488
// This check is done to see if we need to read more from the chunk before popping the record
491489
if self.records.len() == 1
492-
&& *self.io_state.read().unwrap() != SortedChunkIOState::ReadEOF
490+
&& *self.io_state.read() != SortedChunkIOState::ReadEOF
493491
{
494492
// We've consumed the last record. Read more payload into the buffer.
495493
if self.chunk_size - self.total_bytes_read.load(atomic::Ordering::SeqCst)
496494
== 0
497495
{
498-
*self.io_state.write().unwrap() = SortedChunkIOState::ReadEOF;
496+
*self.io_state.write() = SortedChunkIOState::ReadEOF;
499497
} else {
500498
let c = self.read()?;
501499
if !c.succeeded() {
@@ -513,9 +511,9 @@ impl SortedChunk {
513511
}
514512

515513
fn read(&mut self) -> Result<Completion> {
516-
*self.io_state.write().unwrap() = SortedChunkIOState::WaitingForRead;
514+
*self.io_state.write() = SortedChunkIOState::WaitingForRead;
517515

518-
let read_buffer_size = self.buffer.read().unwrap().len() - self.buffer_len();
516+
let read_buffer_size = self.buffer.read().len() - self.buffer_len();
519517
let read_buffer_size = read_buffer_size
520518
.min(self.chunk_size - self.total_bytes_read.load(atomic::Ordering::SeqCst));
521519

@@ -535,12 +533,12 @@ impl SortedChunk {
535533

536534
let bytes_read = bytes_read as usize;
537535
if bytes_read == 0 {
538-
*chunk_io_state_copy.write().unwrap() = SortedChunkIOState::ReadEOF;
536+
*chunk_io_state_copy.write() = SortedChunkIOState::ReadEOF;
539537
return;
540538
}
541-
*chunk_io_state_copy.write().unwrap() = SortedChunkIOState::ReadComplete;
539+
*chunk_io_state_copy.write() = SortedChunkIOState::ReadComplete;
542540

543-
let mut stored_buf_ref = stored_buffer_copy.write().unwrap();
541+
let mut stored_buf_ref = stored_buffer_copy.write();
544542
let stored_buf = stored_buf_ref.as_mut_slice();
545543
let mut stored_buf_len = stored_buffer_len_copy.load(atomic::Ordering::SeqCst);
546544

@@ -566,8 +564,8 @@ impl SortedChunk {
566564
record_size_lengths: Vec<usize>,
567565
chunk_size: usize,
568566
) -> Result<Completion> {
569-
assert!(*self.io_state.read().unwrap() == SortedChunkIOState::None);
570-
*self.io_state.write().unwrap() = SortedChunkIOState::WaitingForWrite;
567+
assert!(*self.io_state.read() == SortedChunkIOState::None);
568+
*self.io_state.write() = SortedChunkIOState::WaitingForWrite;
571569
self.chunk_size = chunk_size;
572570

573571
let buffer = Buffer::new_temporary(self.chunk_size);
@@ -592,7 +590,7 @@ impl SortedChunk {
592590
let Ok(bytes_written) = res else {
593591
return;
594592
};
595-
*chunk_io_state_copy.write().unwrap() = SortedChunkIOState::WriteComplete;
593+
*chunk_io_state_copy.write() = SortedChunkIOState::WriteComplete;
596594
let buf_len = buffer_ref_copy.len();
597595
if bytes_written < buf_len as i32 {
598596
tracing::error!("wrote({bytes_written}) less than expected({buf_len})");
@@ -684,7 +682,9 @@ impl Ord for SortableImmutableRecord {
684682
// SAFETY: these were checked to be valid UTF-8 on construction.
685683
&left, &right,
686684
),
687-
_ => this_key_value.partial_cmp(&other_key_value).unwrap(),
685+
_ => this_key_value
686+
.partial_cmp(&other_key_value)
687+
.expect("sorter values of the same column should be comparable"),
688688
};
689689
if !cmp.is_eq() {
690690
return match column_order {

core/vdbe/value.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ impl Value {
205205

206206
// Convert the word to lowercase for consistent lookups
207207
let word = word.to_lowercase();
208-
let first_letter = word.chars().next().unwrap();
208+
let first_letter = word
209+
.chars()
210+
.next()
211+
.expect("word should not be empty after validation");
209212

210213
// Remove all occurrences of 'h' and 'w' except the first letter
211214
let code: String = word
@@ -559,7 +562,7 @@ impl Value {
559562
}
560563

561564
let f: f64 = crate::numeric::str_to_f64(format!("{f:.precision$}"))
562-
.unwrap()
565+
.expect("formatted float should always parse successfully")
563566
.into();
564567

565568
Value::Float(f)
@@ -987,7 +990,10 @@ impl Value {
987990
return Value::Null;
988991
}
989992

990-
let separator = match registers.next().unwrap() {
993+
let separator = match registers
994+
.next()
995+
.expect("registers should have at least one element after length check")
996+
{
991997
Value::Null | Value::Blob(_) => return Value::Null,
992998
v => format!("{v}"),
993999
};
@@ -1040,7 +1046,7 @@ pub fn construct_like_regex(pattern: &str) -> Regex {
10401046
.case_insensitive(true)
10411047
.dot_matches_new_line(true)
10421048
.build()
1043-
.unwrap()
1049+
.expect("constructed LIKE regex pattern should be valid")
10441050
}
10451051

10461052
#[cfg(test)]

0 commit comments

Comments
 (0)