Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions crates/core/src/db/datastore/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use super::system_tables::SystemTable;
use enum_as_inner::EnumAsInner;
use spacetimedb_lib::buffer::DecodeError;
use spacetimedb_lib::{
db::{
error::LibError,
raw_def::{v9::RawSql, RawIndexDefV8},
},
AlgebraicType, AlgebraicValue, ProductValue,
};
use spacetimedb_primitives::{ColId, ColList, IndexId, SequenceId, TableId};
use spacetimedb_sats::{product_value::InvalidFieldError, satn::Satn};
use spacetimedb_snapshot::SnapshotError;
use spacetimedb_table::{
bflatn_to, read_column,
table::{self, ReadViaBsatnError, UniqueConstraintViolation},
};
use thiserror::Error;

#[derive(Error, Debug, EnumAsInner)]
pub enum DatastoreError {
#[error("LibError: {0}")]
Lib(#[from] LibError),
#[error("TableError: {0}")]
Table(#[from] TableError),
#[error("IndexError: {0}")]
Index(#[from] IndexError),
#[error("SequenceError: {0}")]
Sequence(#[from] SequenceError),
#[error(transparent)]
// Box the inner [`SnapshotError`] to keep Clippy quiet about large `Err` variants.
Snapshot(#[from] Box<SnapshotError>),
// TODO(cloutiertyler): should this be a TableError? I couldn't get it to compile
#[error("Error reading a value from a table through BSATN: {0}")]
ReadViaBsatnError(#[from] ReadViaBsatnError),
#[error(transparent)]
Other(#[from] anyhow::Error),
}

#[derive(Error, Debug, EnumAsInner)]
pub enum TableError {
#[error("Table with name `{0}` start with 'st_' and that is reserved for internal system tables.")]
System(Box<str>),
#[error("Table with name `{0}` already exists.")]
Exist(String),
#[error("Table with name `{0}` not found.")]
NotFound(String),
#[error("Table with ID `{1}` not found in `{0}`.")]
IdNotFound(SystemTable, u32),
#[error("Sql `{1}` not found in `{0}`.")]
RawSqlNotFound(SystemTable, RawSql),
#[error("Table with ID `{0}` not found in `TxState`.")]
IdNotFoundState(TableId),
#[error("Column `{0}.{1}` is missing a name")]
ColumnWithoutName(String, ColId),
#[error("schema_for_table: Table has invalid schema: {0} Err: {1}")]
InvalidSchema(TableId, LibError),
#[error("Row has invalid row type for table: {0} Err: {1}", table_id, row.to_satn())]
RowInvalidType { table_id: TableId, row: ProductValue },
#[error("failed to decode row in table")]
RowDecodeError(DecodeError),
#[error("Column with name `{0}` already exists")]
DuplicateColumnName(String),
#[error("Column `{0}` not found")]
ColumnNotFound(ColId),
#[error(
"DecodeError for field `{0}.{1}`, expect `{2}` but found `{3}`",
table,
field,
expect,
found
)]
DecodeField {
table: String,
field: Box<str>,
expect: String,
found: String,
},
#[error(transparent)]
Bflatn(#[from] bflatn_to::Error),
#[error(transparent)]
Duplicate(#[from] table::DuplicateError),
#[error(transparent)]
ReadColTypeError(#[from] read_column::TypeError),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum IndexError {
#[error("Index not found: {0:?}")]
NotFound(IndexId),
#[error("Column not found: {0:?}")]
ColumnNotFound(RawIndexDefV8),
#[error(transparent)]
UniqueConstraintViolation(#[from] UniqueConstraintViolation),
#[error("Attempt to define a index with more than 1 auto_inc column: Table: {0:?}, Columns: {1:?}")]
OneAutoInc(TableId, Vec<String>),
#[error("Could not decode arguments to index scan")]
Decode(DecodeError),
#[error("Index was not unique: {0:?}")]
NotUnique(IndexId),
#[error("Key {1:?} was not found in index {0:?}")]
KeyNotFound(IndexId, AlgebraicValue),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum SequenceError {
#[error("Sequence with name `{0}` already exists.")]
Exist(String),
#[error("Sequence `{0}`: The increment is 0, and this means the sequence can't advance.")]
IncrementIsZero(String),
#[error("Sequence `{0}`: The min_value {1} must < max_value {2}.")]
MinMax(String, i128, i128),
#[error("Sequence `{0}`: The start value {1} must be >= min_value {2}.")]
MinStart(String, i128, i128),
#[error("Sequence `{0}`: The start value {1} must be <= min_value {2}.")]
MaxStart(String, i128, i128),
#[error("Sequence `{0}` failed to decode value from Sled (not a u128).")]
SequenceValue(String),
#[error("Sequence ID `{0}` not found.")]
NotFound(SequenceId),
#[error("Sequence applied to a non-integer field. Column `{col}` is of type {{found.to_sats()}}.")]
NotInteger { col: String, found: AlgebraicType },
#[error("Sequence ID `{0}` still had no values left after allocation.")]
UnableToAllocate(SequenceId),
#[error("Autoinc constraint on table {0:?} spans more than one column: {1:?}")]
MultiColumnAutoInc(TableId, ColList),
}

impl From<InvalidFieldError> for DatastoreError {
fn from(value: InvalidFieldError) -> Self {
LibError::from(value).into()
}
}

impl From<spacetimedb_table::read_column::TypeError> for DatastoreError {
fn from(err: spacetimedb_table::read_column::TypeError) -> Self {
TableError::from(err).into()
}
}

impl From<table::InsertError> for DatastoreError {
fn from(err: table::InsertError) -> Self {
match err {
table::InsertError::Duplicate(e) => TableError::from(e).into(),
table::InsertError::Bflatn(e) => TableError::from(e).into(),
table::InsertError::IndexError(e) => IndexError::from(e).into(),
}
}
}

impl From<bflatn_to::Error> for DatastoreError {
fn from(err: bflatn_to::Error) -> Self {
Self::Table(err.into())
}
}

impl From<SnapshotError> for DatastoreError {
fn from(e: SnapshotError) -> Self {
DatastoreError::Snapshot(Box::new(e))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use super::{
use crate::{
db::{
datastore::{
error::{IndexError, TableError},
system_tables::{
system_tables, StColumnRow, StConstraintData, StConstraintRow, StIndexRow, StSequenceRow,
StTableFields, StTableRow, SystemTable, ST_CLIENT_ID, ST_CLIENT_IDX, ST_COLUMN_ID, ST_COLUMN_IDX,
Expand All @@ -21,7 +22,6 @@ use crate::{
},
db_metrics::DB_METRICS,
},
error::{IndexError, TableError},
execution_context::ExecutionContext,
};
use anyhow::anyhow;
Expand Down
18 changes: 9 additions & 9 deletions crates/core/src/db/datastore/locking_tx_datastore/datastore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::{
tx_state::TxState,
};
use crate::db::datastore::{
error::{DatastoreError, TableError},
locking_tx_datastore::state_view::{IterByColRangeMutTx, IterMutTx, IterTx},
traits::{InsertFlags, UpdateFlags},
};
Expand All @@ -25,7 +26,6 @@ use crate::{
},
db_metrics::DB_METRICS,
},
error::{DBError, TableError},
execution_context::ExecutionContext,
};
use anyhow::{anyhow, Context};
Expand All @@ -47,7 +47,7 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use thiserror::Error;

pub type Result<T> = std::result::Result<T, DBError>;
pub type Result<T> = std::result::Result<T, DatastoreError>;

/// Struct contains various database states, each protected by
/// their own lock. To avoid deadlocks, it is crucial to acquire these locks
Expand Down Expand Up @@ -634,7 +634,7 @@ impl MutTxDatastore for Locking {
.map(|row| {
let ptr = row.pointer();
let row = StModuleRow::try_from(row)?;
Ok::<_, DBError>((ptr, row))
Ok::<_, DatastoreError>((ptr, row))
})
.transpose()?;
match old {
Expand Down Expand Up @@ -893,7 +893,7 @@ pub enum ReplayError {
#[error(transparent)]
Decode(#[from] bsatn::DecodeError),
#[error(transparent)]
Db(#[from] DBError),
Db(#[from] DatastoreError),
#[error(transparent)]
Any(#[from] anyhow::Error),
}
Expand Down Expand Up @@ -1137,6 +1137,7 @@ fn metadata_from_row(row: RowRef<'_>) -> Result<Metadata> {
#[cfg(test)]
mod tests {
use super::*;
use crate::db::datastore::error::IndexError;
use crate::db::datastore::locking_tx_datastore::tx_state::PendingSchemaChange;
use crate::db::datastore::system_tables::{
system_tables, StColumnRow, StConstraintData, StConstraintFields, StConstraintRow, StIndexAlgorithm,
Expand All @@ -1148,7 +1149,6 @@ mod tests {
};
use crate::db::datastore::traits::{IsolationLevel, MutTx};
use crate::db::datastore::Result;
use crate::error::{DBError, IndexError};
use bsatn::to_vec;
use core::{fmt, mem};
use itertools::Itertools;
Expand Down Expand Up @@ -2034,7 +2034,7 @@ mod tests {
insert(&datastore, &mut tx, table_id, &row)?;
let result = insert(&datastore, &mut tx, table_id, &row);
match result {
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
_ => panic!("Expected an unique constraint violation error."),
}
#[rustfmt::skip]
Expand All @@ -2051,7 +2051,7 @@ mod tests {
let mut tx = begin_mut_tx(&datastore);
let result = insert(&datastore, &mut tx, table_id, &row);
match result {
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
_ => panic!("Expected an unique constraint violation error."),
}
#[rustfmt::skip]
Expand Down Expand Up @@ -2139,7 +2139,7 @@ mod tests {
let row = u32_str_u32(0, "Bar", 18); // 0 will be ignored.
let result = insert(&datastore, &mut tx, table_id, &row);
match result {
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
e => panic!("Expected an unique constraint violation error but got {e:?}."),
}
#[rustfmt::skip]
Expand All @@ -2164,7 +2164,7 @@ mod tests {
let row = u32_str_u32(0, "Bar", 18); // 0 will be ignored.
let result = insert(&datastore, &mut tx, table_id, &row);
match result {
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
_ => panic!("Expected an unique constraint violation error."),
}
#[rustfmt::skip]
Expand Down
20 changes: 10 additions & 10 deletions crates/core/src/db/datastore/locking_tx_datastore/mut_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ use super::{
tx_state::{IndexIdMap, PendingSchemaChange, TxState, TxTableForInsertion},
SharedMutexGuard, SharedWriteGuard,
};
use crate::db::datastore::system_tables::{
with_sys_table_buf, StClientFields, StClientRow, StColumnFields, StColumnRow, StConstraintFields, StConstraintRow,
StFields as _, StIndexFields, StIndexRow, StRowLevelSecurityFields, StRowLevelSecurityRow, StScheduledFields,
StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, ST_CLIENT_ID,
ST_COLUMN_ID, ST_CONSTRAINT_ID, ST_INDEX_ID, ST_ROW_LEVEL_SECURITY_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID,
ST_TABLE_ID,
};
use crate::db::datastore::traits::{InsertFlags, RowTypeForTable, TxData, UpdateFlags};
use crate::execution_context::Workload;
use crate::{
use crate::db::datastore::{
error::{IndexError, SequenceError, TableError},
execution_context::ExecutionContext,
system_tables::{
with_sys_table_buf, StClientFields, StClientRow, StColumnFields, StColumnRow, StConstraintFields,
StConstraintRow, StFields as _, StIndexFields, StIndexRow, StRowLevelSecurityFields, StRowLevelSecurityRow,
StScheduledFields, StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable,
ST_CLIENT_ID, ST_COLUMN_ID, ST_CONSTRAINT_ID, ST_INDEX_ID, ST_ROW_LEVEL_SECURITY_ID, ST_SCHEDULED_ID,
ST_SEQUENCE_ID, ST_TABLE_ID,
},
};
use crate::execution_context::ExecutionContext;
use crate::execution_context::Workload;
use core::ops::RangeBounds;
use core::{cell::RefCell, mem};
use core::{iter, ops::Bound};
Expand Down
12 changes: 5 additions & 7 deletions crates/core/src/db/datastore/locking_tx_datastore/state_view.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use super::mut_tx::{FilterDeleted, IndexScanRanged};
use super::{committed_state::CommittedState, datastore::Result, tx_state::TxState};
use crate::{
db::datastore::system_tables::{
StColumnFields, StColumnRow, StConstraintFields, StConstraintRow, StIndexFields, StIndexRow, StScheduledFields,
StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, ST_COLUMN_ID,
ST_CONSTRAINT_ID, ST_INDEX_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID, ST_TABLE_ID,
},
error::TableError,
use crate::db::datastore::error::TableError;
use crate::db::datastore::system_tables::{
StColumnFields, StColumnRow, StConstraintFields, StConstraintRow, StIndexFields, StIndexRow, StScheduledFields,
StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, ST_COLUMN_ID,
ST_CONSTRAINT_ID, ST_INDEX_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID, ST_TABLE_ID,
};
use core::ops::RangeBounds;
use spacetimedb_primitives::{ColList, TableId};
Expand Down
5 changes: 3 additions & 2 deletions crates/core/src/db/datastore/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pub mod error;
pub mod locking_tx_datastore;
pub mod system_tables;
pub mod traits;

use crate::error::DBError;
use error::DatastoreError;

pub type Result<T> = core::result::Result<T, DBError>;
pub type Result<T> = core::result::Result<T, DatastoreError>;
Loading
Loading