#[cfg(test)]
mod tests;
use candid::CandidType;
use icydb_diagnostic_code as diagnostic_code;
use serde::Deserialize;
use std::fmt;
pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
match origin {
ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
COMPACT_QUERY_DIAGNOSTIC_MESSAGE
}
ErrorOrigin::Cursor
| ErrorOrigin::Recovery
| ErrorOrigin::Executor
| ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct MutationDiagnosticContext {
entity_tag: u64,
operation: diagnostic_code::DiagnosticMutationOperation,
batch_position: Option<u32>,
}
impl MutationDiagnosticContext {
#[must_use]
pub(crate) const fn new(
entity_tag: u64,
operation: diagnostic_code::DiagnosticMutationOperation,
batch_position: u32,
) -> Self {
Self {
entity_tag,
operation,
batch_position: Some(batch_position),
}
}
#[must_use]
pub(crate) const fn operation_only(
entity_tag: u64,
operation: diagnostic_code::DiagnosticMutationOperation,
) -> Self {
Self {
entity_tag,
operation,
batch_position: None,
}
}
fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
let mut facts = Vec::with_capacity(
2 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
);
facts.push((
diagnostic_code::DiagnosticFactTag::EntityTag,
self.entity_tag,
));
if let Some(field_id) = field_id {
facts.push((
diagnostic_code::DiagnosticFactTag::FieldId,
u64::from(field_id),
));
}
facts.push((
diagnostic_code::DiagnosticFactTag::MutationOperation,
self.operation.raw(),
));
if let Some(batch_position) = self.batch_position {
facts.push((
diagnostic_code::DiagnosticFactTag::BatchPosition,
u64::from(batch_position),
));
}
facts
}
#[must_use]
pub(crate) const fn entity_tag(self) -> u64 {
self.entity_tag
}
fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
facts.push((
diagnostic_code::DiagnosticFactTag::MutationOperation,
self.operation.raw(),
));
if let Some(batch_position) = self.batch_position {
facts.push((
diagnostic_code::DiagnosticFactTag::BatchPosition,
u64::from(batch_position),
));
}
}
}
pub struct DiagnosticFactDetail {
diagnostic: diagnostic_code::Diagnostic,
facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
}
pub struct InternalError {
pub(crate) class: ErrorClass,
pub(crate) origin: ErrorOrigin,
pub(crate) detail: Option<ErrorDetail>,
}
#[expect(
clippy::missing_const_for_fn,
reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
)]
impl InternalError {
#[must_use]
#[cold]
#[inline(never)]
pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
let detail = match (class, origin) {
(ErrorClass::Corruption, ErrorOrigin::Store) => {
Some(ErrorDetail::Store(StoreError::Corrupt))
}
(ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
Some(ErrorDetail::Store(StoreError::InvariantViolation))
}
_ => None,
};
Self {
class,
origin,
detail,
}
}
#[must_use]
pub const fn class(&self) -> ErrorClass {
self.class
}
#[must_use]
pub const fn origin(&self) -> ErrorOrigin {
self.origin
}
#[must_use]
pub const fn message(&self) -> &'static str {
compact_message_for(self.class, self.origin)
}
#[must_use]
pub const fn detail(&self) -> Option<&ErrorDetail> {
self.detail.as_ref()
}
#[must_use]
pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
diagnostic_code::Diagnostic::new(
self.diagnostic_code(),
self.origin.diagnostic_origin(),
self.detail
.as_ref()
.and_then(ErrorDetail::diagnostic_detail),
)
}
#[must_use]
#[cold]
#[inline(never)]
pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
self.detail
.as_ref()
.map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
}
#[must_use]
pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
self.detail.as_ref().map_or_else(
|| self.class.diagnostic_code(self.origin),
ErrorDetail::diagnostic_code,
)
}
#[must_use]
pub fn into_message(self) -> String {
self.message().to_string()
}
#[cold]
#[inline(never)]
pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
Self::new(class, origin)
}
#[cold]
#[inline(never)]
fn with_diagnostic_facts(
class: ErrorClass,
origin: ErrorOrigin,
detail: Option<diagnostic_code::DiagnosticDetail>,
facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
) -> Self {
let code = match detail {
Some(detail) => detail.diagnostic_code(),
None => class.diagnostic_code(origin),
};
Self {
class,
origin,
detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
DiagnosticFactDetail {
diagnostic: diagnostic_code::Diagnostic::new(
code,
origin.diagnostic_origin(),
detail,
),
facts,
},
))),
}
}
#[cold]
#[inline(never)]
fn mutation_boundary_with_facts(
class: ErrorClass,
boundary: diagnostic_code::RuntimeBoundaryCode,
facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
) -> Self {
Self::with_diagnostic_facts(
class,
ErrorOrigin::Executor,
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
facts,
)
}
#[cold]
#[inline(never)]
pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
match self.detail {
Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
self.class,
origin,
detail.diagnostic.detail().copied(),
detail.facts,
),
_ => Self::classified(self.class, origin),
}
}
#[cold]
#[inline(never)]
pub(crate) fn index_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
}
pub(crate) fn index_key_field_count_exceeds_max(
entity_tag: u64,
physical_generation: u64,
field_count: usize,
max_fields: usize,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::InvariantViolation,
ErrorOrigin::Index,
None,
vec![
(diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
(
diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
physical_generation,
),
(
diagnostic_code::DiagnosticFactTag::ComponentKind,
diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
),
(
diagnostic_code::DiagnosticFactTag::ActualArity,
field_count as u64,
),
(
diagnostic_code::DiagnosticFactTag::Maximum,
max_fields as u64,
),
],
)
}
pub(crate) fn index_expression_source_type_mismatch(
_index_name: &str,
_expression: impl Sized,
_expected: impl Sized,
_source_label: &str,
) -> Self {
Self::index_invariant()
}
#[cold]
#[inline(never)]
pub(crate) fn planner_executor_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
}
#[cold]
#[inline(never)]
pub(crate) fn query_executor_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
}
#[cold]
#[inline(never)]
pub(crate) fn cursor_executor_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
}
#[cold]
#[inline(never)]
pub(crate) fn executor_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
}
#[cold]
#[inline(never)]
pub(crate) fn executor_internal() -> Self {
Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
}
#[cold]
#[inline(never)]
pub(crate) fn executor_unsupported() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_database_owned_field_explicit(
context: MutationDiagnosticContext,
field_id: u32,
) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Unsupported,
diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
context.facts(Some(field_id)),
)
}
#[must_use]
#[cold]
#[inline(never)]
pub(crate) fn mutation_required_field_missing(
context: MutationDiagnosticContext,
field_id: u32,
) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Unsupported,
diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
context.facts(Some(field_id)),
)
}
#[must_use]
#[cold]
#[inline(never)]
pub(crate) fn mutation_managed_timestamp_regression(
context: MutationDiagnosticContext,
) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::InvariantViolation,
diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
context.facts(None),
)
}
pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::InvariantViolation,
diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
context.facts(),
)
}
pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
Self {
class: ErrorClass::Corruption,
origin: ErrorOrigin::Executor,
detail: Some(ErrorDetail::Executor(
ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
)),
}
}
pub(crate) fn mutation_constraint_activation_write_blocked(
context: AcceptedConstraintFactContext,
) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Conflict,
diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
context.facts(),
)
}
pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
Self::executor_invariant()
}
pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
Self::query_executor_invariant()
}
pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
Self::query_executor_invariant()
}
pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
Self::query_executor_invariant()
}
pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
Self::query_executor_invariant()
}
pub(crate) fn secondary_index_prefix_spec_required() -> Self {
Self::query_executor_invariant()
}
pub(crate) fn index_range_limit_spec_required() -> Self {
Self::query_executor_invariant()
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_atomic_save_duplicate_key(
entity_tag: u64,
first_position: u32,
duplicate_position: u32,
) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Conflict,
diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
vec![
(diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
(
diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
u64::from(first_position),
),
(
diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
u64::from(duplicate_position),
),
],
)
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_batch_empty() -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Unsupported,
diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
)
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Unsupported,
diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
vec![
(
diagnostic_code::DiagnosticFactTag::ActualCount,
actual_count as u64,
),
(diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
],
)
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_batch_staged_bytes_exceeded(
actual_bytes: Option<usize>,
limit: usize,
) -> Self {
let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
if let Some(actual_bytes) = actual_bytes {
facts.push((
diagnostic_code::DiagnosticFactTag::ActualLength,
actual_bytes as u64,
));
}
facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
Self::mutation_boundary_with_facts(
ErrorClass::Unsupported,
diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
facts,
)
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Unsupported,
diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
vec![
(
diagnostic_code::DiagnosticFactTag::ActualLength,
actual_bytes as u64,
),
(diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
],
)
}
#[cold]
#[inline(never)]
pub(crate) fn mutation_batch_entity_mismatch(
batch_position: u32,
expected_entity_tag: u64,
actual_entity_tag: u64,
) -> Self {
Self::mutation_boundary_with_facts(
ErrorClass::Conflict,
diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
vec![
(
diagnostic_code::DiagnosticFactTag::BatchPosition,
u64::from(batch_position),
),
(
diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
expected_entity_tag,
),
(
diagnostic_code::DiagnosticFactTag::ActualEntityTag,
actual_entity_tag,
),
],
)
}
pub(crate) fn mutation_index_store_generation_changed(
_expected_generation: u64,
_observed_generation: u64,
) -> Self {
Self::executor_invariant()
}
#[cold]
#[inline(never)]
pub(crate) fn planner_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
}
pub(crate) fn query_invalid_logical_plan() -> Self {
Self::planner_invariant()
}
pub(crate) fn store_invariant() -> Self {
Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
}
#[cold]
#[inline(never)]
pub(crate) fn store_internal() -> Self {
Self::new(ErrorClass::Internal, ErrorOrigin::Store)
}
pub(crate) fn commit_memory_id_unconfigured() -> Self {
Self::store_internal()
}
pub(crate) fn commit_store_uninitialized() -> Self {
Self::store_invariant()
}
pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Internal,
ErrorOrigin::Store,
None,
vec![
(
diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
u64::from(cached_id),
),
(
diagnostic_code::DiagnosticFactTag::ActualMemoryId,
u64::from(configured_id),
),
],
)
}
pub(crate) fn commit_memory_stable_key_mismatch(
_cached_key: &str,
_configured_key: &str,
) -> Self {
Self::store_internal()
}
pub(crate) fn database_incarnation_generation_failed() -> Self {
Self::store_internal()
}
pub(crate) fn database_incarnation_invalid() -> Self {
Self::store_corruption()
}
pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
Self {
class: ErrorClass::IncompatiblePersistedFormat,
origin: ErrorOrigin::Recovery,
detail: Some(ErrorDetail::Recovery(
RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
)),
}
}
pub(crate) fn recovery_malformed_database_format_marker(
reason: RecoveryFormatMarkerError,
) -> Self {
Self {
class: ErrorClass::Corruption,
origin: ErrorOrigin::Recovery,
detail: Some(ErrorDetail::Recovery(
RecoveryErrorDetail::MalformedFormatMarker { reason },
)),
}
}
pub(crate) fn recovery_database_format_control_unavailable() -> Self {
Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
}
pub(crate) fn commit_control_memory_growth_failed() -> Self {
Self::store_internal()
}
#[cfg(not(test))]
pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
Self::store_internal()
}
pub(crate) fn recovery_effect_verification_failed() -> Self {
Self::store_corruption()
}
#[cold]
#[inline(never)]
pub(crate) fn index_internal() -> Self {
Self::new(ErrorClass::Internal, ErrorOrigin::Index)
}
pub(crate) fn structural_index_removal_entity_key_required() -> Self {
Self::index_internal()
}
pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
Self::index_internal()
}
pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
Self::index_internal()
}
pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
Self::index_internal()
}
#[cfg(test)]
pub(crate) fn query_internal() -> Self {
Self::new(ErrorClass::Internal, ErrorOrigin::Query)
}
#[cold]
#[inline(never)]
pub(crate) fn query_unsupported() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
}
#[cold]
#[inline(never)]
pub(crate) fn query_stale_accepted_schema_revision(
expected_revision: u64,
current_revision: Option<u64>,
) -> Self {
let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
facts.push((
diagnostic_code::DiagnosticFactTag::ExpectedRevision,
expected_revision,
));
if let Some(current_revision) = current_revision {
facts.push((
diagnostic_code::DiagnosticFactTag::CurrentRevision,
current_revision,
));
}
Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
}
#[cold]
#[inline(never)]
#[cfg(feature = "sql")]
pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
error,
})),
}
}
#[cold]
#[inline(never)]
pub(crate) fn query_numeric_overflow() -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
}
}
#[cold]
#[inline(never)]
pub(crate) fn query_numeric_not_representable() -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(
QueryErrorDetail::NumericNotRepresentable,
)),
}
}
#[cold]
#[inline(never)]
pub(crate) fn serialize_internal() -> Self {
Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
}
pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
Self::persisted_row_encode_internal()
}
pub(crate) fn persisted_row_encode_internal() -> Self {
Self::serialize_internal()
}
pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
Self::persisted_row_encode_internal()
}
#[cold]
#[inline(never)]
pub(crate) fn store_corruption() -> Self {
Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
}
pub(crate) fn commit_corruption() -> Self {
Self::store_corruption()
}
pub(crate) fn commit_component_corruption() -> Self {
Self::commit_corruption()
}
pub(crate) fn commit_id_generation_failed() -> Self {
Self::store_internal()
}
pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
Self::store_unsupported()
}
pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Corruption,
ErrorOrigin::Store,
None,
vec![
(
diagnostic_code::DiagnosticFactTag::ComponentKind,
diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
),
(
diagnostic_code::DiagnosticFactTag::ActualLength,
actual_length as u64,
),
(diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
],
)
}
pub(crate) fn commit_marker_exceeds_max_size() -> Self {
Self::commit_corruption()
}
pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
Self::store_unsupported()
}
pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
Self::store_unsupported()
}
pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
Self::store_corruption()
}
#[cold]
#[inline(never)]
pub(crate) fn index_corruption() -> Self {
Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
}
pub(crate) fn index_unique_validation_corruption() -> Self {
Self::index_plan_index_corruption()
}
pub(crate) fn structural_index_entry_corruption() -> Self {
Self::index_plan_index_corruption()
}
pub(crate) fn index_unique_validation_entity_key_required() -> Self {
Self::index_invariant()
}
pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
Self::index_plan_serialize_corruption()
}
pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
Self::index_plan_serialize_corruption()
}
pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
Self::index_plan_serialize_corruption()
}
pub(crate) fn index_unique_validation_row_required() -> Self {
Self::index_plan_store_corruption()
}
pub(crate) fn index_only_predicate_component_required() -> Self {
Self::index_invariant()
}
pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
Self::index_invariant()
}
pub(crate) fn index_scan_continuation_advancement_required() -> Self {
Self::index_invariant()
}
pub(crate) fn index_scan_key_corrupted_during(
_context: &'static str,
_err: impl Sized,
) -> Self {
Self::index_corruption()
}
pub(crate) fn index_projection_component_required(
_index_name: &str,
_component_index: usize,
) -> Self {
Self::index_invariant()
}
pub(crate) fn index_entry_decode_failed() -> Self {
Self::index_corruption()
}
pub(crate) fn serialize_corruption() -> Self {
Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
}
pub(crate) fn persisted_row_decode_corruption() -> Self {
Self::serialize_corruption()
}
pub(crate) fn persisted_row_layout_outside_accepted_window(
row_layout: u32,
history_floor: u32,
current_layout: u32,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Corruption,
ErrorOrigin::Serialize,
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
}),
vec![
(
diagnostic_code::DiagnosticFactTag::RowLayout,
u64::from(row_layout),
),
(
diagnostic_code::DiagnosticFactTag::HistoryFloor,
u64::from(history_floor),
),
(
diagnostic_code::DiagnosticFactTag::CurrentLayout,
u64::from(current_layout),
),
],
)
}
pub(crate) fn persisted_row_slot_count_mismatch(
row_layout: u32,
expected_slot_count: usize,
actual_slot_count: usize,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Corruption,
ErrorOrigin::Serialize,
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
}),
vec![
(
diagnostic_code::DiagnosticFactTag::RowLayout,
u64::from(row_layout),
),
(
diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
expected_slot_count as u64,
),
(
diagnostic_code::DiagnosticFactTag::ActualSlotCount,
actual_slot_count as u64,
),
],
)
}
pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
Self::persisted_row_decode_corruption()
}
pub(crate) fn persisted_row_field_kind_decode_failed(
field_name: &str,
_field_kind: impl fmt::Debug,
_detail: impl Sized,
) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
Self::index_invariant()
}
pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
_model_path: &str,
_slot: usize,
) -> Self {
Self::index_invariant()
}
pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
_data_key: impl fmt::Debug,
_detail: impl Sized,
) -> Self {
Self::persisted_row_decode_corruption()
}
pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
Self::persisted_row_decode_corruption()
}
pub(crate) fn persisted_row_key_mismatch() -> Self {
Self::store_corruption()
}
pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
Self::persisted_row_field_decode_corruption(field_name)
}
pub(crate) fn reverse_index_ordinal_overflow(
_source_path: &str,
_field_name: &str,
_target_path: &str,
_detail: impl Sized,
) -> Self {
Self::index_internal()
}
pub(crate) fn reverse_index_entry_corrupted(
_source_path: &str,
_field_name: &str,
_target_path: &str,
_index_key: impl fmt::Debug,
_detail: impl Sized,
) -> Self {
Self::index_corruption()
}
pub(crate) fn relation_target_store_missing(
_source_path: &str,
_field_name: &str,
_target_path: &str,
_store_path: &str,
_detail: impl Sized,
) -> Self {
Self::executor_internal()
}
pub(crate) fn relation_target_primary_key_arity_mismatch(
expected_arity: usize,
actual_arity: usize,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Internal,
ErrorOrigin::Executor,
None,
vec![
(
diagnostic_code::DiagnosticFactTag::ComponentKind,
diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
),
(
diagnostic_code::DiagnosticFactTag::ExpectedArity,
expected_arity as u64,
),
(
diagnostic_code::DiagnosticFactTag::ActualArity,
actual_arity as u64,
),
],
)
}
pub(crate) fn relation_target_key_decode_failed(
_context_label: &str,
_source_path: &str,
_field_name: &str,
_target_path: &str,
_detail: impl Sized,
) -> Self {
Self::identity_corruption()
}
pub(crate) fn relation_target_entity_mismatch(
_context_label: &str,
_source_path: &str,
_field_name: &str,
_target_path: &str,
_target_entity_name: &str,
expected_tag: u64,
actual_tag: u64,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Corruption,
ErrorOrigin::Store,
None,
vec![
(
diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
expected_tag,
),
(
diagnostic_code::DiagnosticFactTag::ActualEntityTag,
actual_tag,
),
],
)
}
pub(crate) fn relation_source_row_decode_failed(
_source_path: &str,
_field_name: &str,
_target_path: &str,
_detail: impl Sized,
) -> Self {
Self::persisted_row_decode_corruption()
}
pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
_source_path: &str,
_field_name: &str,
_target_path: &str,
) -> Self {
Self::persisted_row_decode_corruption()
}
pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
Self::persisted_row_decode_corruption()
}
pub(crate) fn bytes_covering_component_payload_empty() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
Self::index_corruption()
}
pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
Self::index_corruption()
}
pub(crate) fn identity_corruption() -> Self {
Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
}
pub(crate) fn identity_state_corruption() -> Self {
Self::identity_corruption()
}
pub(crate) fn identity_state_conflict() -> Self {
Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
}
pub(crate) fn identity_state_capacity_exhausted() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
}
pub(crate) fn identity_exhausted() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
}
pub(crate) fn identity_candidate_count_exhausted() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
}
#[cold]
#[inline(never)]
pub(crate) fn store_unsupported() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
}
pub(crate) fn schema_application_conflict() -> Self {
Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
}
pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
let class = match reason.diagnostic_code() {
diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
_ => ErrorClass::Internal,
};
Self {
class,
origin: ErrorOrigin::Store,
detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
}
}
pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Store,
detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
}
}
#[cfg(feature = "sql")]
pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Store,
detail: Some(ErrorDetail::Store(
StoreError::SchemaDdlRewriteRequiresMigration,
)),
}
}
pub(crate) fn journal_mutation_revision_exhausted() -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Store,
detail: Some(ErrorDetail::Store(
StoreError::JournalMutationRevisionExhausted,
)),
}
}
pub(crate) fn schema_transition_budget_exceeded(
resource: SchemaTransitionBudgetResource,
) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Store,
detail: Some(ErrorDetail::Store(
StoreError::SchemaTransitionBudgetExceeded { resource },
)),
}
}
pub(crate) fn unsupported_entity_tag_in_data_store(
_entity_tag: crate::types::EntityTag,
) -> Self {
Self::store_unsupported()
}
#[cfg(not(test))]
pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
Self::store_internal()
}
pub(crate) fn index_unsupported() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
}
pub(crate) fn index_component_exceeds_max_size_at(
entity_tag: u64,
physical_generation: u64,
component_index: usize,
actual_length: usize,
limit: usize,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Unsupported,
ErrorOrigin::Index,
None,
vec![
(diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
(
diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
physical_generation,
),
(
diagnostic_code::DiagnosticFactTag::ComponentIndex,
component_index as u64,
),
(
diagnostic_code::DiagnosticFactTag::ComponentKind,
diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
),
(
diagnostic_code::DiagnosticFactTag::ActualLength,
actual_length as u64,
),
(diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
],
)
}
pub(crate) fn index_component_exceeds_max_size() -> Self {
Self::index_unsupported()
}
pub(crate) fn serialize_unsupported() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
}
pub(crate) fn cursor_invalid_continuation() -> Self {
Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
}
pub(crate) fn serialize_incompatible_persisted_format() -> Self {
Self::new(
ErrorClass::IncompatiblePersistedFormat,
ErrorOrigin::Serialize,
)
}
#[cfg(feature = "sql")]
pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(
QueryErrorDetail::UnsupportedSqlFeature { feature },
)),
}
}
#[cfg(feature = "sql")]
pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
}
}
#[cfg(feature = "sql")]
pub(crate) fn query_sql_lowering_with_facts(
reason: diagnostic_code::SqlLoweringCode,
facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Unsupported,
ErrorOrigin::Query,
Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
facts,
)
}
pub(crate) fn query_unsupported_projection(
reason: diagnostic_code::QueryProjectionCode,
) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(
QueryErrorDetail::UnsupportedProjection { reason },
)),
}
}
pub(crate) fn query_unknown_aggregate_target_field() -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(
QueryErrorDetail::UnknownAggregateTargetField,
)),
}
}
#[cfg(feature = "sql")]
pub(crate) fn query_sql_surface_mismatch(
mismatch: diagnostic_code::SqlSurfaceMismatchCode,
) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
mismatch,
})),
}
}
pub(crate) fn query_sql_write_boundary(
boundary: diagnostic_code::SqlWriteBoundaryCode,
) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
boundary,
})),
}
}
pub(crate) fn query_sql_write_boundary_with_facts(
boundary: diagnostic_code::SqlWriteBoundaryCode,
facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
) -> Self {
Self::with_diagnostic_facts(
ErrorClass::Unsupported,
ErrorOrigin::Query,
Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
facts,
)
}
pub fn store_not_found(_key: impl Sized) -> Self {
Self {
class: ErrorClass::NotFound,
origin: ErrorOrigin::Store,
detail: Some(ErrorDetail::Store(StoreError::NotFound)),
}
}
pub fn unsupported_entity_path(_path: impl Sized) -> Self {
Self::store_unsupported()
}
#[cold]
#[inline(never)]
pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
Self::new(ErrorClass::Corruption, origin)
}
#[cold]
#[inline(never)]
pub(crate) fn index_plan_index_corruption() -> Self {
Self::index_plan_corruption(ErrorOrigin::Index)
}
#[cold]
#[inline(never)]
pub(crate) fn index_plan_store_corruption() -> Self {
Self::index_plan_corruption(ErrorOrigin::Store)
}
#[cold]
#[inline(never)]
pub(crate) fn index_plan_serialize_corruption() -> Self {
Self::index_plan_corruption(ErrorOrigin::Serialize)
}
#[cfg(test)]
pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
Self::new(ErrorClass::InvariantViolation, origin)
}
#[cfg(test)]
pub(crate) fn index_plan_store_invariant() -> Self {
Self::index_plan_invariant(ErrorOrigin::Store)
}
pub(crate) fn index_conflict() -> Self {
Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
}
}
impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
Self {
class: ErrorClass::Unsupported,
origin: ErrorOrigin::Query,
detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
reason,
})),
}
}
}
impl fmt::Debug for InternalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(
f,
self.diagnostic_code(),
self.detail
.as_ref()
.and_then(ErrorDetail::diagnostic_detail),
)
}
}
impl fmt::Display for InternalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.message())
}
}
impl std::error::Error for InternalError {}
#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
pub enum ConstraintValuePathComponent {
RootField { field_id: u32 },
RecordMember {
composite_type_id: u32,
member_id: u32,
},
TupleElement {
composite_type_id: u32,
ordinal: u32,
},
Newtype { composite_type_id: u32 },
EnumVariant { enum_type_id: u32, variant_id: u32 },
ListElement { index: u32 },
SetElement { index: u32 },
MapEntryKey { index: u32 },
MapEntryValue { index: u32 },
}
impl fmt::Display for ConstraintValuePathComponent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RootField { field_id } => write!(f, "field#{field_id}"),
Self::RecordMember {
composite_type_id,
member_id,
} => write!(f, "record#{composite_type_id}.member#{member_id}"),
Self::TupleElement {
composite_type_id,
ordinal,
} => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
Self::EnumVariant {
enum_type_id,
variant_id,
} => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
Self::ListElement { index } => write!(f, "list[{index}]"),
Self::SetElement { index } => write!(f, "set[{index}]"),
Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
}
}
}
#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
pub struct ConstraintValuePath {
components: Vec<ConstraintValuePathComponent>,
}
impl ConstraintValuePath {
#[must_use]
pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
Self { components }
}
#[must_use]
pub const fn components(&self) -> &[ConstraintValuePathComponent] {
self.components.as_slice()
}
}
impl fmt::Display for ConstraintValuePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (ordinal, component) in self.components.iter().enumerate() {
if ordinal != 0 {
f.write_str("/")?;
}
component.fmt(f)?;
}
Ok(())
}
}
#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
pub struct ConstraintValidationFindingOutput {
accepted_schema_fingerprint: [u8; 16],
entity_tag: u64,
constraint_id: u32,
primary_key: Vec<u8>,
field_ids: Vec<u32>,
value_path: Option<ConstraintValuePath>,
error_code: u16,
}
impl ConstraintValidationFindingOutput {
#[must_use]
pub(crate) const fn new(
accepted_schema_fingerprint: [u8; 16],
entity_tag: u64,
constraint_id: u32,
primary_key: Vec<u8>,
field_ids: Vec<u32>,
value_path: Option<ConstraintValuePath>,
error_code: u16,
) -> Self {
Self {
accepted_schema_fingerprint,
entity_tag,
constraint_id,
primary_key,
field_ids,
value_path,
error_code,
}
}
#[must_use]
pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
self.accepted_schema_fingerprint
}
#[must_use]
pub const fn entity_tag(&self) -> u64 {
self.entity_tag
}
#[must_use]
pub const fn constraint_id(&self) -> u32 {
self.constraint_id
}
#[must_use]
pub const fn primary_key(&self) -> &[u8] {
self.primary_key.as_slice()
}
#[must_use]
pub const fn field_ids(&self) -> &[u32] {
self.field_ids.as_slice()
}
#[must_use]
pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
self.value_path.as_ref()
}
#[must_use]
pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
diagnostic_code::ErrorCode::from_raw(self.error_code)
}
#[must_use]
pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
self.error_code().class()
}
}
#[derive(Clone)]
pub(crate) struct AcceptedConstraintFactContext {
fingerprint_method: u8,
accepted_schema_fingerprint: [u8; 16],
entity_tag: u64,
constraint_id: u32,
constraint_kind: diagnostic_code::DiagnosticConstraintKind,
mutation: Option<MutationDiagnosticContext>,
value_path: Option<ConstraintValuePath>,
}
impl AcceptedConstraintFactContext {
#[must_use]
pub(crate) fn write_admission(
fingerprint_method: u8,
accepted_schema_fingerprint: [u8; 16],
entity_tag: u64,
constraint_id: u32,
constraint_kind: diagnostic_code::DiagnosticConstraintKind,
mutation: Option<MutationDiagnosticContext>,
value_path: Option<ConstraintValuePath>,
) -> Self {
debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
Self {
fingerprint_method,
accepted_schema_fingerprint,
entity_tag,
constraint_id,
constraint_kind,
mutation,
value_path,
}
}
fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
let high = u64::from_be_bytes([
self.accepted_schema_fingerprint[0],
self.accepted_schema_fingerprint[1],
self.accepted_schema_fingerprint[2],
self.accepted_schema_fingerprint[3],
self.accepted_schema_fingerprint[4],
self.accepted_schema_fingerprint[5],
self.accepted_schema_fingerprint[6],
self.accepted_schema_fingerprint[7],
]);
let low = u64::from_be_bytes([
self.accepted_schema_fingerprint[8],
self.accepted_schema_fingerprint[9],
self.accepted_schema_fingerprint[10],
self.accepted_schema_fingerprint[11],
self.accepted_schema_fingerprint[12],
self.accepted_schema_fingerprint[13],
self.accepted_schema_fingerprint[14],
self.accepted_schema_fingerprint[15],
]);
let path_len = self
.value_path
.as_ref()
.map_or(0, |path| path.components().len());
let mutation_fact_count = self.mutation.map_or(0, |mutation| {
1 + usize::from(mutation.batch_position.is_some())
});
let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
facts.push((
diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
u64::from(self.fingerprint_method),
));
facts.push((
diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
high,
));
facts.push((
diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
low,
));
facts.push((
diagnostic_code::DiagnosticFactTag::EntityTag,
self.entity_tag,
));
facts.push((
diagnostic_code::DiagnosticFactTag::ConstraintId,
u64::from(self.constraint_id),
));
facts.push((
diagnostic_code::DiagnosticFactTag::ConstraintKind,
self.constraint_kind.raw(),
));
facts.push((
diagnostic_code::DiagnosticFactTag::ConstraintContext,
diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
));
if let Some(mutation) = self.mutation {
mutation.append_operation_facts(&mut facts);
}
if let Some(path) = self.value_path {
for component in path.components {
facts.push(constraint_value_path_fact(component));
}
}
debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
facts
}
}
fn constraint_value_path_fact(
component: ConstraintValuePathComponent,
) -> (diagnostic_code::DiagnosticFactTag, u64) {
use diagnostic_code::DiagnosticFactTag;
match component {
ConstraintValuePathComponent::RootField { field_id } => {
(DiagnosticFactTag::RootField, u64::from(field_id))
}
ConstraintValuePathComponent::RecordMember {
composite_type_id,
member_id,
} => (
DiagnosticFactTag::RecordMember,
diagnostic_code::pack_u32_pair(composite_type_id, member_id),
),
ConstraintValuePathComponent::TupleElement {
composite_type_id,
ordinal,
} => (
DiagnosticFactTag::TupleElement,
diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
),
ConstraintValuePathComponent::Newtype { composite_type_id } => {
(DiagnosticFactTag::Newtype, u64::from(composite_type_id))
}
ConstraintValuePathComponent::EnumVariant {
enum_type_id,
variant_id,
} => (
DiagnosticFactTag::EnumVariant,
diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
),
ConstraintValuePathComponent::ListElement { index } => {
(DiagnosticFactTag::ListElement, u64::from(index))
}
ConstraintValuePathComponent::SetElement { index } => {
(DiagnosticFactTag::SetElement, u64::from(index))
}
ConstraintValuePathComponent::MapEntryKey { index } => {
(DiagnosticFactTag::MapEntryKey, u64::from(index))
}
ConstraintValuePathComponent::MapEntryValue { index } => {
(DiagnosticFactTag::MapEntryValue, u64::from(index))
}
}
}
pub enum ErrorDetail {
DiagnosticFacts(Box<DiagnosticFactDetail>),
Executor(ExecutorErrorDetail),
Store(StoreError),
Query(QueryErrorDetail),
Recovery(RecoveryErrorDetail),
}
pub enum ExecutorErrorDetail {
MutationRequiredFieldMissing,
MutationManagedTimestampRegression,
MutationDatabaseOwnedFieldExplicit,
MutationBatchEmpty,
MutationBatchTooManyItems,
MutationBatchStagedBytesExceeded,
MutationBatchResultBytesExceeded,
MutationBatchEntityMismatch,
MutationBatchDuplicateKey,
AcceptedRowConstraintProgramCorrupt,
}
pub enum RecoveryErrorDetail {
UnsupportedFormatVersion { found: Option<u16>, required: u16 },
MalformedFormatMarker { reason: RecoveryFormatMarkerError },
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum RecoveryFormatMarkerError {
Magic,
Checksum,
State,
}
impl RecoveryFormatMarkerError {
const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
match self {
Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
}
}
}
pub enum StoreError {
NotFound,
Corrupt,
InvariantViolation,
SchemaDdlPublicationRaceLost,
SchemaDdlRewriteRequiresMigration,
SchemaMigration {
reason: diagnostic_code::SchemaMigrationCode,
},
SchemaRowLayoutVersionExhausted,
JournalMutationRevisionExhausted,
SchemaTransitionBudgetExceeded {
resource: SchemaTransitionBudgetResource,
},
SchemaGeneratedFieldAfterDdlField,
SchemaGeneratedConstraintActivationStale,
}
pub enum QueryErrorDetail {
NumericOverflow,
NumericNotRepresentable,
UnsupportedSqlFeature {
feature: diagnostic_code::SqlFeatureCode,
},
SqlLowering {
reason: diagnostic_code::SqlLoweringCode,
},
UnsupportedProjection {
reason: diagnostic_code::QueryProjectionCode,
},
UnknownAggregateTargetField,
ResultShapeMismatch {
reason: diagnostic_code::QueryResultShapeCode,
},
QueryReadAdmission {
reason: diagnostic_code::QueryReadAdmissionCode,
},
SqlSurfaceMismatch {
mismatch: diagnostic_code::SqlSurfaceMismatchCode,
},
SqlWriteBoundary {
boundary: diagnostic_code::SqlWriteBoundaryCode,
},
SchemaDdlAdmission {
error: SchemaDdlAdmissionError,
},
StaleSchemaRevision,
}
impl fmt::Display for QueryErrorDetail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
}
}
impl std::error::Error for QueryErrorDetail {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SchemaTransitionBudgetResource {
DeletionKeys,
ProjectionEntries,
ProjectionWorkUnits,
SourceRows,
SourceRowBytes,
StagedRawBytes,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum SchemaDdlAdmissionError {
MissingExpectedSchemaVersion,
MissingNextSchemaVersion,
StaleExpectedSchemaVersion,
InvalidExpectedSchemaVersion,
InvalidNextSchemaVersion,
AcceptedSchemaChangeWithoutVersionBump,
EmptyVersionBump,
VersionGap,
VersionRollback,
FingerprintMethodMismatch,
UnsupportedTransitionClass,
PhysicalRunnerMissing,
ValidationFailed,
PublicationRaceLost,
InvalidAddColumnDefault,
InvalidAlterColumnDefault,
RowLayoutVersionExhausted,
GeneratedIndexDropRejected,
SchemaRewriteRequiresMigration,
SchemaTransitionBudgetExceeded {
resource: SchemaTransitionBudgetResource,
},
GeneratedFieldDefaultChangeRejected,
GeneratedFieldNullabilityChangeRejected,
}
impl fmt::Display for SchemaDdlAdmissionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
}
}
impl std::error::Error for SchemaDdlAdmissionError {}
impl fmt::Debug for ErrorDetail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
}
}
impl fmt::Debug for ExecutorErrorDetail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
}
}
impl fmt::Debug for StoreError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
}
}
impl fmt::Debug for QueryErrorDetail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
}
}
impl fmt::Debug for RecoveryErrorDetail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
}
}
impl fmt::Debug for RecoveryFormatMarkerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(
f,
diagnostic_code::DiagnosticCode::RuntimeCorruption,
Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
kind: diagnostic_code::RuntimeErrorKind::Corruption,
}),
)
}
}
impl fmt::Debug for SchemaDdlAdmissionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_compact_diagnostic(
f,
diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
reason: self.diagnostic_code(),
}),
)
}
}
fn fmt_compact_diagnostic(
f: &mut fmt::Formatter<'_>,
code: diagnostic_code::DiagnosticCode,
detail: Option<diagnostic_code::DiagnosticDetail>,
) -> fmt::Result {
write!(
f,
"{}",
diagnostic_code::ErrorCode::from_parts(code, detail).raw()
)
}
impl ErrorDetail {
#[must_use]
pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
match self {
Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
Self::Executor(error) => error.diagnostic_code(),
Self::Store(error) => error.diagnostic_code(),
Self::Query(error) => error.diagnostic_code(),
Self::Recovery(error) => error.diagnostic_code(),
}
}
#[must_use]
pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
match self {
Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
Self::Executor(error) => error.diagnostic_detail(),
Self::Store(error) => error.diagnostic_detail(),
Self::Query(error) => error.diagnostic_detail(),
Self::Recovery(error) => error.diagnostic_detail(),
}
}
#[must_use]
#[cold]
#[inline(never)]
pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
match self {
Self::DiagnosticFacts(detail) => detail.facts.clone(),
Self::Executor(error) => error.diagnostic_facts(),
Self::Query(error) => error.diagnostic_facts(),
Self::Recovery(error) => error.diagnostic_facts(),
Self::Store(_) => Vec::new(),
}
}
}
impl ExecutorErrorDetail {
#[must_use]
pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
match self {
Self::MutationRequiredFieldMissing
| Self::MutationDatabaseOwnedFieldExplicit
| Self::MutationBatchEmpty
| Self::MutationBatchTooManyItems
| Self::MutationBatchStagedBytesExceeded
| Self::MutationBatchResultBytesExceeded => {
diagnostic_code::DiagnosticCode::RuntimeUnsupported
}
Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
diagnostic_code::DiagnosticCode::RuntimeConflict
}
Self::MutationManagedTimestampRegression => {
diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
}
Self::AcceptedRowConstraintProgramCorrupt => {
diagnostic_code::DiagnosticCode::RuntimeCorruption
}
}
}
#[must_use]
pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
match self {
Self::MutationRequiredFieldMissing => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
})
}
Self::MutationDatabaseOwnedFieldExplicit => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
})
}
Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
}),
Self::MutationBatchTooManyItems => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
})
}
Self::MutationBatchStagedBytesExceeded => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
})
}
Self::MutationBatchResultBytesExceeded => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
})
}
Self::MutationBatchEntityMismatch => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
})
}
Self::MutationBatchDuplicateKey => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
})
}
Self::MutationManagedTimestampRegression => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
})
}
Self::AcceptedRowConstraintProgramCorrupt => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
})
}
}
}
#[must_use]
#[cold]
#[inline(never)]
pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
Vec::new()
}
}
impl RecoveryErrorDetail {
#[must_use]
pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
match self {
Self::UnsupportedFormatVersion { .. } => {
diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
}
Self::MalformedFormatMarker { .. } => {
diagnostic_code::DiagnosticCode::RuntimeCorruption
}
}
}
#[must_use]
pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
let kind = match self {
Self::UnsupportedFormatVersion { .. } => {
diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
}
Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
};
Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
}
#[must_use]
pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
match self {
Self::UnsupportedFormatVersion { found, required } => {
let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
facts.push((
diagnostic_code::DiagnosticFactTag::ExpectedVersion,
u64::from(*required),
));
if let Some(found) = found {
facts.push((
diagnostic_code::DiagnosticFactTag::ActualVersion,
u64::from(*found),
));
}
facts
}
Self::MalformedFormatMarker { reason } => vec![(
diagnostic_code::DiagnosticFactTag::DecodeReason,
reason.diagnostic_decode_reason().raw(),
)],
}
}
}
impl StoreError {
#[must_use]
pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
match self {
Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
Self::SchemaDdlPublicationRaceLost
| Self::SchemaDdlRewriteRequiresMigration
| Self::SchemaRowLayoutVersionExhausted
| Self::SchemaTransitionBudgetExceeded { .. } => {
diagnostic_code::DiagnosticCode::SchemaDdlAdmission
}
Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
diagnostic_code::DiagnosticCode::RuntimeUnsupported
}
Self::SchemaGeneratedConstraintActivationStale => {
diagnostic_code::DiagnosticCode::RuntimeConflict
}
Self::SchemaMigration { reason } => reason.diagnostic_code(),
}
}
#[must_use]
pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
match self {
Self::SchemaDdlPublicationRaceLost => {
Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
})
}
Self::SchemaDdlRewriteRequiresMigration => {
Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
})
}
Self::SchemaMigration { reason } => {
Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
}
Self::SchemaRowLayoutVersionExhausted => {
Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
})
}
Self::JournalMutationRevisionExhausted => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
})
}
Self::SchemaTransitionBudgetExceeded { .. } => {
Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
})
}
Self::SchemaGeneratedFieldAfterDdlField => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
})
}
Self::SchemaGeneratedConstraintActivationStale => {
Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
boundary:
diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
})
}
Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
}
}
}
impl QueryErrorDetail {
#[must_use]
pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
match self {
Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
Self::NumericNotRepresentable => {
diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
}
Self::UnsupportedSqlFeature { .. } => {
diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
}
Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
Self::UnsupportedProjection { .. } => {
diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
}
Self::UnknownAggregateTargetField => {
diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
}
Self::ResultShapeMismatch { .. } => {
diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
}
Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
Self::SqlSurfaceMismatch { .. } => {
diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
}
Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
}
}
#[must_use]
pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
match self {
Self::UnsupportedSqlFeature { feature } => {
Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
}
Self::SqlLowering { reason } => {
Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
}
Self::UnsupportedProjection { reason } => {
Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
}
Self::ResultShapeMismatch { reason } => {
Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
}
Self::QueryReadAdmission { reason } => {
Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
}
Self::SqlSurfaceMismatch { mismatch } => {
Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
mismatch: *mismatch,
})
}
Self::SqlWriteBoundary { boundary } => {
Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
boundary: *boundary,
})
}
Self::SchemaDdlAdmission { error } => {
Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
reason: error.diagnostic_code(),
})
}
Self::NumericOverflow
| Self::NumericNotRepresentable
| Self::UnknownAggregateTargetField
| Self::StaleSchemaRevision => None,
}
}
#[must_use]
#[cold]
#[inline(never)]
pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
Vec::new()
}
}
impl SchemaDdlAdmissionError {
#[must_use]
pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
match self {
Self::MissingExpectedSchemaVersion => {
diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
}
Self::MissingNextSchemaVersion => {
diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
}
Self::StaleExpectedSchemaVersion => {
diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
}
Self::InvalidExpectedSchemaVersion => {
diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
}
Self::InvalidNextSchemaVersion => {
diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
}
Self::AcceptedSchemaChangeWithoutVersionBump => {
diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
}
Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
Self::FingerprintMethodMismatch => {
diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
}
Self::UnsupportedTransitionClass => {
diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
}
Self::PhysicalRunnerMissing => {
diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
}
Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
Self::PublicationRaceLost => {
diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
}
Self::InvalidAddColumnDefault => {
diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
}
Self::InvalidAlterColumnDefault => {
diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
}
Self::GeneratedIndexDropRejected => {
diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
}
Self::SchemaRewriteRequiresMigration => {
diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
}
Self::SchemaTransitionBudgetExceeded { .. } => {
diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
}
Self::GeneratedFieldDefaultChangeRejected => {
diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
}
Self::GeneratedFieldNullabilityChangeRejected => {
diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
}
Self::RowLayoutVersionExhausted => {
diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
}
}
}
}
#[repr(u8)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum ErrorClass {
Corruption,
IncompatiblePersistedFormat,
NotFound,
Internal,
Conflict,
Unsupported,
InvariantViolation,
}
impl ErrorClass {
#[must_use]
pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
match self {
Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
diagnostic_code::DiagnosticCode::StoreCorruption
}
Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
Self::IncompatiblePersistedFormat => {
diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
}
Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
diagnostic_code::DiagnosticCode::StoreNotFound
}
Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
}
Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
diagnostic_code::DiagnosticCode::StoreInvariantViolation
}
Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
}
}
}
impl fmt::Debug for ErrorClass {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", *self as u8)
}
}
#[repr(u8)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum ErrorOrigin {
Serialize,
Store,
Index,
Identity,
Query,
Planner,
Cursor,
Recovery,
Response,
Executor,
Interface,
}
impl ErrorOrigin {
#[must_use]
pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
match self {
Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
Self::Store => diagnostic_code::ErrorOrigin::Store,
Self::Index => diagnostic_code::ErrorOrigin::Index,
Self::Identity => diagnostic_code::ErrorOrigin::Identity,
Self::Query => diagnostic_code::ErrorOrigin::Query,
Self::Planner => diagnostic_code::ErrorOrigin::Planner,
Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
Self::Response => diagnostic_code::ErrorOrigin::Response,
Self::Executor => diagnostic_code::ErrorOrigin::Executor,
Self::Interface => diagnostic_code::ErrorOrigin::Interface,
}
}
}
impl fmt::Debug for ErrorOrigin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", *self as u8)
}
}