1#[cfg(test)]
9mod tests;
10
11use candid::CandidType;
12use icydb_diagnostic_code as diagnostic_code;
13use serde::Deserialize;
14use std::fmt;
15
16pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
17const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
18const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
19const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
20const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
21const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
22
23const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
24 match origin {
25 ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
26 ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
27 ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
28 ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
29 ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
30 COMPACT_QUERY_DIAGNOSTIC_MESSAGE
31 }
32 ErrorOrigin::Cursor
33 | ErrorOrigin::Recovery
34 | ErrorOrigin::Executor
35 | ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
36 }
37}
38
39#[derive(Clone, Copy, Debug)]
134pub(crate) struct MutationDiagnosticContext {
135 entity_tag: u64,
136 operation: diagnostic_code::DiagnosticMutationOperation,
137 batch_position: Option<u32>,
138}
139
140impl MutationDiagnosticContext {
141 #[must_use]
143 pub(crate) const fn new(
144 entity_tag: u64,
145 operation: diagnostic_code::DiagnosticMutationOperation,
146 batch_position: u32,
147 ) -> Self {
148 Self {
149 entity_tag,
150 operation,
151 batch_position: Some(batch_position),
152 }
153 }
154
155 #[must_use]
157 pub(crate) const fn operation_only(
158 entity_tag: u64,
159 operation: diagnostic_code::DiagnosticMutationOperation,
160 ) -> Self {
161 Self {
162 entity_tag,
163 operation,
164 batch_position: None,
165 }
166 }
167
168 fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
169 let mut facts = Vec::with_capacity(
170 2 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
171 );
172 facts.push((
173 diagnostic_code::DiagnosticFactTag::EntityTag,
174 self.entity_tag,
175 ));
176 if let Some(field_id) = field_id {
177 facts.push((
178 diagnostic_code::DiagnosticFactTag::FieldId,
179 u64::from(field_id),
180 ));
181 }
182 facts.push((
183 diagnostic_code::DiagnosticFactTag::MutationOperation,
184 self.operation.raw(),
185 ));
186 if let Some(batch_position) = self.batch_position {
187 facts.push((
188 diagnostic_code::DiagnosticFactTag::BatchPosition,
189 u64::from(batch_position),
190 ));
191 }
192 facts
193 }
194
195 #[must_use]
196 pub(crate) const fn entity_tag(self) -> u64 {
197 self.entity_tag
198 }
199
200 fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
201 facts.push((
202 diagnostic_code::DiagnosticFactTag::MutationOperation,
203 self.operation.raw(),
204 ));
205 if let Some(batch_position) = self.batch_position {
206 facts.push((
207 diagnostic_code::DiagnosticFactTag::BatchPosition,
208 u64::from(batch_position),
209 ));
210 }
211 }
212}
213
214pub struct DiagnosticFactDetail {
216 diagnostic: diagnostic_code::Diagnostic,
217 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
218}
219
220pub struct InternalError {
228 pub(crate) class: ErrorClass,
229 pub(crate) origin: ErrorOrigin,
230
231 pub(crate) detail: Option<ErrorDetail>,
234}
235
236#[expect(
237 clippy::missing_const_for_fn,
238 reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
239)]
240impl InternalError {
241 #[must_use]
245 #[cold]
246 #[inline(never)]
247 pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
248 let detail = match (class, origin) {
249 (ErrorClass::Corruption, ErrorOrigin::Store) => {
250 Some(ErrorDetail::Store(StoreError::Corrupt))
251 }
252 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
253 Some(ErrorDetail::Store(StoreError::InvariantViolation))
254 }
255 _ => None,
256 };
257
258 Self {
259 class,
260 origin,
261 detail,
262 }
263 }
264
265 #[must_use]
267 pub const fn class(&self) -> ErrorClass {
268 self.class
269 }
270
271 #[must_use]
273 pub const fn origin(&self) -> ErrorOrigin {
274 self.origin
275 }
276
277 #[must_use]
279 pub const fn message(&self) -> &'static str {
280 compact_message_for(self.class, self.origin)
281 }
282
283 #[must_use]
285 pub const fn detail(&self) -> Option<&ErrorDetail> {
286 self.detail.as_ref()
287 }
288
289 #[must_use]
291 pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
292 diagnostic_code::Diagnostic::new(
293 self.diagnostic_code(),
294 self.origin.diagnostic_origin(),
295 self.detail
296 .as_ref()
297 .and_then(ErrorDetail::diagnostic_detail),
298 )
299 }
300
301 #[must_use]
303 #[cold]
304 #[inline(never)]
305 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
306 self.detail
307 .as_ref()
308 .map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
309 }
310
311 #[must_use]
313 pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
314 self.detail.as_ref().map_or_else(
315 || self.class.diagnostic_code(self.origin),
316 ErrorDetail::diagnostic_code,
317 )
318 }
319
320 #[must_use]
322 pub fn into_message(self) -> String {
323 self.message().to_string()
324 }
325
326 #[cold]
328 #[inline(never)]
329 pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
330 Self::new(class, origin)
331 }
332
333 #[cold]
334 #[inline(never)]
335 fn with_diagnostic_facts(
336 class: ErrorClass,
337 origin: ErrorOrigin,
338 detail: Option<diagnostic_code::DiagnosticDetail>,
339 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
340 ) -> Self {
341 let code = match detail {
342 Some(detail) => detail.diagnostic_code(),
343 None => class.diagnostic_code(origin),
344 };
345 let diagnostic = diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), detail);
346 if diagnostic_code::validate_known_diagnostic_fact_schema(
347 diagnostic.error_code(),
348 facts.as_slice(),
349 )
350 .is_err()
351 {
352 return Self::new(ErrorClass::InvariantViolation, origin);
353 }
354 Self {
355 class,
356 origin,
357 detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
358 DiagnosticFactDetail { diagnostic, facts },
359 ))),
360 }
361 }
362
363 #[cold]
364 #[inline(never)]
365 fn mutation_boundary_with_facts(
366 class: ErrorClass,
367 boundary: diagnostic_code::RuntimeBoundaryCode,
368 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
369 ) -> Self {
370 Self::with_diagnostic_facts(
371 class,
372 ErrorOrigin::Executor,
373 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
374 facts,
375 )
376 }
377
378 #[cold]
379 #[inline(never)]
380 fn exact_key_batch_boundary_with_facts(
381 boundary: diagnostic_code::RuntimeBoundaryCode,
382 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
383 ) -> Self {
384 Self::with_diagnostic_facts(
385 ErrorClass::Unsupported,
386 ErrorOrigin::Query,
387 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
388 facts,
389 )
390 }
391
392 pub(crate) fn sql_query_entity_not_found() -> Self {
394 Self::with_diagnostic_facts(
395 ErrorClass::NotFound,
396 ErrorOrigin::Interface,
397 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
398 boundary: diagnostic_code::RuntimeBoundaryCode::SqlQueryEntityNotFound,
399 }),
400 Vec::new(),
401 )
402 }
403
404 #[cold]
406 #[inline(never)]
407 pub(crate) fn execution_budget_exceeded(
408 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
409 limit: u64,
410 observed: u64,
411 scope: diagnostic_code::DiagnosticExecutionBudgetScope,
412 lane: diagnostic_code::DiagnosticExecutionLane,
413 normalized_shape_fingerprint_prefix: u64,
414 ) -> Self {
415 Self::with_diagnostic_facts(
416 ErrorClass::Unsupported,
417 ErrorOrigin::Executor,
418 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
419 boundary: diagnostic_code::RuntimeBoundaryCode::ExecutionBudgetExceeded,
420 }),
421 vec![
422 (
423 diagnostic_code::DiagnosticFactTag::BudgetResource,
424 resource.raw(),
425 ),
426 (diagnostic_code::DiagnosticFactTag::Limit, limit),
427 (diagnostic_code::DiagnosticFactTag::Actual, observed),
428 (
429 diagnostic_code::DiagnosticFactTag::ExecutionBudgetScope,
430 scope.raw(),
431 ),
432 (
433 diagnostic_code::DiagnosticFactTag::ExecutionLane,
434 lane.raw(),
435 ),
436 (
437 diagnostic_code::DiagnosticFactTag::QueryShapeFingerprintPrefix,
438 normalized_shape_fingerprint_prefix,
439 ),
440 ],
441 )
442 }
443
444 #[cold]
446 #[inline(never)]
447 pub(crate) fn page_unit_too_large(
448 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
449 limit: u64,
450 attempted: u64,
451 ) -> Self {
452 Self::with_diagnostic_facts(
453 ErrorClass::Unsupported,
454 ErrorOrigin::Executor,
455 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
456 boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
457 }),
458 vec![
459 (
460 diagnostic_code::DiagnosticFactTag::BudgetResource,
461 resource.raw(),
462 ),
463 (diagnostic_code::DiagnosticFactTag::Limit, limit),
464 (diagnostic_code::DiagnosticFactTag::Actual, attempted),
465 ],
466 )
467 }
468
469 #[cold]
474 #[inline(never)]
475 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
476 match self.detail {
477 Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
478 self.class,
479 origin,
480 detail.diagnostic.detail().copied(),
481 detail.facts,
482 ),
483 _ => Self::classified(self.class, origin),
484 }
485 }
486
487 #[cold]
489 #[inline(never)]
490 pub(crate) fn index_invariant() -> Self {
491 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
492 }
493
494 pub(crate) fn index_key_field_count_exceeds_max(
496 entity_tag: u64,
497 physical_generation: u64,
498 field_count: usize,
499 max_fields: usize,
500 ) -> Self {
501 Self::with_diagnostic_facts(
502 ErrorClass::InvariantViolation,
503 ErrorOrigin::Index,
504 None,
505 vec![
506 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
507 (
508 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
509 physical_generation,
510 ),
511 (
512 diagnostic_code::DiagnosticFactTag::ComponentKind,
513 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
514 ),
515 (
516 diagnostic_code::DiagnosticFactTag::ActualArity,
517 field_count as u64,
518 ),
519 (
520 diagnostic_code::DiagnosticFactTag::Maximum,
521 max_fields as u64,
522 ),
523 ],
524 )
525 }
526
527 pub(crate) fn index_expression_source_type_mismatch(
529 _index_name: &str,
530 _expression: impl Sized,
531 _expected: impl Sized,
532 _source_label: &str,
533 ) -> Self {
534 Self::index_invariant()
535 }
536
537 #[cold]
540 #[inline(never)]
541 pub(crate) fn planner_executor_invariant() -> Self {
542 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
543 }
544
545 #[cold]
548 #[inline(never)]
549 pub(crate) fn query_executor_invariant() -> Self {
550 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
551 }
552
553 #[cold]
556 #[inline(never)]
557 pub(crate) fn cursor_executor_invariant() -> Self {
558 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
559 }
560
561 #[cold]
563 #[inline(never)]
564 pub(crate) fn executor_invariant() -> Self {
565 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
566 }
567
568 #[cold]
570 #[inline(never)]
571 pub(crate) fn executor_internal() -> Self {
572 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
573 }
574
575 #[cold]
577 #[inline(never)]
578 pub(crate) fn executor_unsupported() -> Self {
579 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
580 }
581
582 #[cold]
584 #[inline(never)]
585 pub(crate) fn mutation_database_owned_field_explicit(
586 context: MutationDiagnosticContext,
587 field_id: u32,
588 ) -> Self {
589 Self::mutation_boundary_with_facts(
590 ErrorClass::Unsupported,
591 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
592 context.facts(Some(field_id)),
593 )
594 }
595
596 #[must_use]
598 #[cold]
599 #[inline(never)]
600 pub(crate) fn mutation_required_field_missing(
601 context: MutationDiagnosticContext,
602 field_id: u32,
603 ) -> Self {
604 Self::mutation_boundary_with_facts(
605 ErrorClass::Unsupported,
606 diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
607 context.facts(Some(field_id)),
608 )
609 }
610
611 #[must_use]
613 #[cold]
614 #[inline(never)]
615 pub(crate) fn mutation_managed_timestamp_regression(
616 context: MutationDiagnosticContext,
617 ) -> Self {
618 Self::mutation_boundary_with_facts(
619 ErrorClass::InvariantViolation,
620 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
621 context.facts(None),
622 )
623 }
624
625 pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
627 Self::mutation_boundary_with_facts(
628 ErrorClass::InvariantViolation,
629 diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
630 context.facts(),
631 )
632 }
633
634 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
636 Self {
637 class: ErrorClass::Corruption,
638 origin: ErrorOrigin::Executor,
639 detail: Some(ErrorDetail::Executor(
640 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
641 )),
642 }
643 }
644
645 pub(crate) fn mutation_constraint_activation_write_blocked(
647 context: AcceptedConstraintFactContext,
648 ) -> Self {
649 Self::mutation_boundary_with_facts(
650 ErrorClass::Conflict,
651 diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
652 context.facts(),
653 )
654 }
655
656 pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
658 Self::executor_invariant()
659 }
660
661 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
663 Self::query_executor_invariant()
664 }
665
666 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
668 Self::query_executor_invariant()
669 }
670
671 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
673 Self::query_executor_invariant()
674 }
675
676 pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
678 Self::query_executor_invariant()
679 }
680
681 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
683 Self::query_executor_invariant()
684 }
685
686 pub(crate) fn index_range_limit_spec_required() -> Self {
688 Self::query_executor_invariant()
689 }
690
691 #[cold]
693 #[inline(never)]
694 pub(crate) fn mutation_atomic_save_duplicate_key(
695 entity_tag: u64,
696 first_position: u32,
697 duplicate_position: u32,
698 ) -> Self {
699 Self::mutation_boundary_with_facts(
700 ErrorClass::Conflict,
701 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
702 vec![
703 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
704 (
705 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
706 u64::from(first_position),
707 ),
708 (
709 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
710 u64::from(duplicate_position),
711 ),
712 ],
713 )
714 }
715
716 #[cold]
718 #[inline(never)]
719 pub(crate) fn mutation_batch_empty() -> Self {
720 Self::mutation_boundary_with_facts(
721 ErrorClass::Unsupported,
722 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
723 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
724 )
725 }
726
727 #[cold]
729 #[inline(never)]
730 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
731 Self::mutation_boundary_with_facts(
732 ErrorClass::Unsupported,
733 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
734 vec![
735 (
736 diagnostic_code::DiagnosticFactTag::ActualCount,
737 actual_count as u64,
738 ),
739 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
740 ],
741 )
742 }
743
744 #[cold]
746 #[inline(never)]
747 pub(crate) fn mutation_batch_staged_bytes_exceeded(
748 actual_bytes: Option<usize>,
749 limit: usize,
750 ) -> Self {
751 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
752 if let Some(actual_bytes) = actual_bytes {
753 facts.push((
754 diagnostic_code::DiagnosticFactTag::ActualLength,
755 actual_bytes as u64,
756 ));
757 }
758 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
759 Self::mutation_boundary_with_facts(
760 ErrorClass::Unsupported,
761 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
762 facts,
763 )
764 }
765
766 #[cold]
768 #[inline(never)]
769 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
770 Self::mutation_boundary_with_facts(
771 ErrorClass::Unsupported,
772 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
773 vec![
774 (
775 diagnostic_code::DiagnosticFactTag::ActualLength,
776 actual_bytes as u64,
777 ),
778 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
779 ],
780 )
781 }
782
783 #[cold]
785 #[inline(never)]
786 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
787 Self::exact_key_batch_boundary_with_facts(
788 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
789 vec![
790 (
791 diagnostic_code::DiagnosticFactTag::ActualCount,
792 actual_count as u64,
793 ),
794 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
795 ],
796 )
797 }
798
799 #[cold]
801 #[inline(never)]
802 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
803 Self::exact_key_batch_bytes_exceeded(
804 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
805 actual_bytes,
806 limit,
807 )
808 }
809
810 #[cold]
812 #[inline(never)]
813 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
814 Self::exact_key_batch_bytes_exceeded(
815 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
816 actual_bytes,
817 limit,
818 )
819 }
820
821 #[cold]
823 #[inline(never)]
824 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
825 Self::exact_key_batch_bytes_exceeded(
826 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
827 actual_bytes,
828 limit,
829 )
830 }
831
832 #[cold]
833 #[inline(never)]
834 fn exact_key_batch_bytes_exceeded(
835 boundary: diagnostic_code::RuntimeBoundaryCode,
836 actual_bytes: usize,
837 limit: usize,
838 ) -> Self {
839 Self::exact_key_batch_boundary_with_facts(
840 boundary,
841 vec![
842 (
843 diagnostic_code::DiagnosticFactTag::ActualLength,
844 actual_bytes as u64,
845 ),
846 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
847 ],
848 )
849 }
850
851 #[cold]
853 #[inline(never)]
854 pub(crate) fn mutation_batch_entity_mismatch(
855 batch_position: u32,
856 expected_entity_tag: u64,
857 actual_entity_tag: u64,
858 ) -> Self {
859 Self::mutation_boundary_with_facts(
860 ErrorClass::Conflict,
861 diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
862 vec![
863 (
864 diagnostic_code::DiagnosticFactTag::BatchPosition,
865 u64::from(batch_position),
866 ),
867 (
868 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
869 expected_entity_tag,
870 ),
871 (
872 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
873 actual_entity_tag,
874 ),
875 ],
876 )
877 }
878
879 pub(crate) fn mutation_index_store_generation_changed(
881 _expected_generation: u64,
882 _observed_generation: u64,
883 ) -> Self {
884 Self::executor_invariant()
885 }
886
887 #[cold]
889 #[inline(never)]
890 pub(crate) fn planner_invariant() -> Self {
891 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
892 }
893
894 pub(crate) fn query_invalid_logical_plan() -> Self {
896 Self::planner_invariant()
897 }
898
899 pub(crate) fn store_invariant() -> Self {
901 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
902 }
903
904 #[cold]
906 #[inline(never)]
907 pub(crate) fn store_internal() -> Self {
908 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
909 }
910
911 pub(crate) fn commit_memory_id_unconfigured() -> Self {
913 Self::store_internal()
914 }
915
916 pub(crate) fn commit_store_uninitialized() -> Self {
918 Self::store_invariant()
919 }
920
921 pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
923 Self::with_diagnostic_facts(
924 ErrorClass::Internal,
925 ErrorOrigin::Store,
926 None,
927 vec![
928 (
929 diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
930 u64::from(cached_id),
931 ),
932 (
933 diagnostic_code::DiagnosticFactTag::ActualMemoryId,
934 u64::from(configured_id),
935 ),
936 ],
937 )
938 }
939
940 pub(crate) fn commit_memory_stable_key_mismatch(
942 _cached_key: &str,
943 _configured_key: &str,
944 ) -> Self {
945 Self::store_internal()
946 }
947
948 pub(crate) fn database_incarnation_generation_failed() -> Self {
950 Self::store_internal()
951 }
952
953 pub(crate) fn database_incarnation_invalid() -> Self {
955 Self::store_corruption()
956 }
957
958 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
960 Self {
961 class: ErrorClass::IncompatiblePersistedFormat,
962 origin: ErrorOrigin::Recovery,
963 detail: Some(ErrorDetail::Recovery(
964 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
965 )),
966 }
967 }
968
969 pub(crate) fn recovery_malformed_database_format_marker(
971 reason: RecoveryFormatMarkerError,
972 ) -> Self {
973 Self {
974 class: ErrorClass::Corruption,
975 origin: ErrorOrigin::Recovery,
976 detail: Some(ErrorDetail::Recovery(
977 RecoveryErrorDetail::MalformedFormatMarker { reason },
978 )),
979 }
980 }
981
982 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
984 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
985 }
986
987 pub(crate) fn recovery_pending() -> Self {
989 Self::with_diagnostic_facts(
990 ErrorClass::Conflict,
991 ErrorOrigin::Recovery,
992 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
993 boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
994 }),
995 Vec::new(),
996 )
997 }
998
999 pub(crate) fn startup_control_corruption() -> Self {
1001 Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1002 }
1003
1004 pub(crate) fn commit_control_memory_growth_failed() -> Self {
1006 Self::store_internal()
1007 }
1008
1009 #[cfg(not(test))]
1011 pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1012 Self::store_internal()
1013 }
1014
1015 pub(crate) fn recovery_effect_verification_failed() -> Self {
1017 Self::store_corruption()
1018 }
1019
1020 #[cold]
1022 #[inline(never)]
1023 pub(crate) fn index_internal() -> Self {
1024 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1025 }
1026
1027 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1029 Self::index_internal()
1030 }
1031
1032 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1034 Self::index_internal()
1035 }
1036
1037 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1039 Self::index_internal()
1040 }
1041
1042 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1044 Self::index_internal()
1045 }
1046
1047 #[cfg(test)]
1049 pub(crate) fn query_internal() -> Self {
1050 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1051 }
1052
1053 #[cold]
1055 #[inline(never)]
1056 pub(crate) fn query_unsupported() -> Self {
1057 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1058 }
1059
1060 #[cold]
1063 #[inline(never)]
1064 pub(crate) fn query_stale_accepted_schema_revision(
1065 expected_revision: u64,
1066 current_revision: Option<u64>,
1067 ) -> Self {
1068 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1069 facts.push((
1070 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1071 expected_revision,
1072 ));
1073 if let Some(current_revision) = current_revision {
1074 facts.push((
1075 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1076 current_revision,
1077 ));
1078 }
1079 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1080 }
1081
1082 #[cold]
1084 #[inline(never)]
1085 #[cfg(feature = "sql")]
1086 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1087 Self {
1088 class: ErrorClass::Unsupported,
1089 origin: ErrorOrigin::Query,
1090 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1091 error,
1092 })),
1093 }
1094 }
1095
1096 #[cold]
1098 #[inline(never)]
1099 pub(crate) fn query_numeric_overflow() -> Self {
1100 Self {
1101 class: ErrorClass::Unsupported,
1102 origin: ErrorOrigin::Query,
1103 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1104 }
1105 }
1106
1107 #[cold]
1110 #[inline(never)]
1111 pub(crate) fn query_numeric_not_representable() -> Self {
1112 Self {
1113 class: ErrorClass::Unsupported,
1114 origin: ErrorOrigin::Query,
1115 detail: Some(ErrorDetail::Query(
1116 QueryErrorDetail::NumericNotRepresentable,
1117 )),
1118 }
1119 }
1120
1121 #[cold]
1123 #[inline(never)]
1124 pub(crate) fn serialize_internal() -> Self {
1125 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1126 }
1127
1128 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1130 Self::persisted_row_encode_internal()
1131 }
1132
1133 pub(crate) fn persisted_row_encode_internal() -> Self {
1135 Self::serialize_internal()
1136 }
1137
1138 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1140 Self::persisted_row_encode_internal()
1141 }
1142
1143 #[cold]
1145 #[inline(never)]
1146 pub(crate) fn store_corruption() -> Self {
1147 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1148 }
1149
1150 pub(crate) fn commit_corruption() -> Self {
1152 Self::store_corruption()
1153 }
1154
1155 pub(crate) fn commit_component_corruption() -> Self {
1157 Self::commit_corruption()
1158 }
1159
1160 pub(crate) fn commit_id_generation_failed() -> Self {
1162 Self::store_internal()
1163 }
1164
1165 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1167 Self::store_unsupported()
1168 }
1169
1170 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1172 Self::with_diagnostic_facts(
1173 ErrorClass::Corruption,
1174 ErrorOrigin::Store,
1175 None,
1176 vec![
1177 (
1178 diagnostic_code::DiagnosticFactTag::ComponentKind,
1179 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1180 ),
1181 (
1182 diagnostic_code::DiagnosticFactTag::ActualLength,
1183 actual_length as u64,
1184 ),
1185 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1186 ],
1187 )
1188 }
1189
1190 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1192 Self::commit_corruption()
1193 }
1194
1195 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1197 Self::store_unsupported()
1198 }
1199
1200 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1202 Self::store_unsupported()
1203 }
1204
1205 #[cold]
1207 #[inline(never)]
1208 pub(crate) fn index_corruption() -> Self {
1209 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1210 }
1211
1212 pub(crate) fn index_unique_validation_corruption() -> Self {
1214 Self::index_plan_index_corruption()
1215 }
1216
1217 pub(crate) fn structural_index_entry_corruption() -> Self {
1219 Self::index_plan_index_corruption()
1220 }
1221
1222 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1224 Self::index_invariant()
1225 }
1226
1227 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1229 Self::index_plan_serialize_corruption()
1230 }
1231
1232 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1234 Self::index_plan_serialize_corruption()
1235 }
1236
1237 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1239 Self::index_plan_serialize_corruption()
1240 }
1241
1242 pub(crate) fn index_unique_validation_row_required() -> Self {
1244 Self::index_plan_store_corruption()
1245 }
1246
1247 pub(crate) fn index_only_predicate_component_required() -> Self {
1249 Self::index_invariant()
1250 }
1251
1252 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1254 Self::index_invariant()
1255 }
1256
1257 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1259 Self::index_invariant()
1260 }
1261
1262 pub(crate) fn index_scan_key_corrupted_during(
1264 _context: &'static str,
1265 _err: impl Sized,
1266 ) -> Self {
1267 Self::index_corruption()
1268 }
1269
1270 pub(crate) fn index_projection_component_required(
1272 _index_name: &str,
1273 _component_index: usize,
1274 ) -> Self {
1275 Self::index_invariant()
1276 }
1277
1278 pub(crate) fn index_entry_decode_failed() -> Self {
1280 Self::index_corruption()
1281 }
1282
1283 pub(crate) fn serialize_corruption() -> Self {
1285 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1286 }
1287
1288 pub(crate) fn persisted_row_decode_corruption() -> Self {
1290 Self::serialize_corruption()
1291 }
1292
1293 pub(crate) fn persisted_row_layout_outside_accepted_window(
1295 row_layout: u32,
1296 history_floor: u32,
1297 current_layout: u32,
1298 ) -> Self {
1299 Self::with_diagnostic_facts(
1300 ErrorClass::Corruption,
1301 ErrorOrigin::Serialize,
1302 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1303 boundary:
1304 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1305 }),
1306 vec![
1307 (
1308 diagnostic_code::DiagnosticFactTag::RowLayout,
1309 u64::from(row_layout),
1310 ),
1311 (
1312 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1313 u64::from(history_floor),
1314 ),
1315 (
1316 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1317 u64::from(current_layout),
1318 ),
1319 ],
1320 )
1321 }
1322
1323 pub(crate) fn persisted_row_slot_count_mismatch(
1325 row_layout: u32,
1326 expected_slot_count: usize,
1327 actual_slot_count: usize,
1328 ) -> Self {
1329 Self::with_diagnostic_facts(
1330 ErrorClass::Corruption,
1331 ErrorOrigin::Serialize,
1332 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1333 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1334 }),
1335 vec![
1336 (
1337 diagnostic_code::DiagnosticFactTag::RowLayout,
1338 u64::from(row_layout),
1339 ),
1340 (
1341 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1342 expected_slot_count as u64,
1343 ),
1344 (
1345 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1346 actual_slot_count as u64,
1347 ),
1348 ],
1349 )
1350 }
1351
1352 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1354 Self::persisted_row_field_decode_corruption(field_name)
1355 }
1356
1357 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1359 Self::persisted_row_decode_corruption()
1360 }
1361
1362 pub(crate) fn persisted_row_field_kind_decode_failed(
1364 field_name: &str,
1365 _field_kind: impl fmt::Debug,
1366 _detail: impl Sized,
1367 ) -> Self {
1368 Self::persisted_row_field_decode_corruption(field_name)
1369 }
1370
1371 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1373 Self::persisted_row_field_decode_corruption(field_name)
1374 }
1375
1376 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1378 Self::persisted_row_field_decode_corruption(field_name)
1379 }
1380
1381 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1383 Self::persisted_row_field_decode_corruption(field_name)
1384 }
1385
1386 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1388 Self::persisted_row_field_decode_corruption(field_name)
1389 }
1390
1391 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1393 Self::persisted_row_field_decode_corruption(field_name)
1394 }
1395
1396 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1398 Self::index_invariant()
1399 }
1400
1401 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1403 _model_path: &str,
1404 _slot: usize,
1405 ) -> Self {
1406 Self::index_invariant()
1407 }
1408
1409 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1411 _data_key: impl fmt::Debug,
1412 _detail: impl Sized,
1413 ) -> Self {
1414 Self::persisted_row_decode_corruption()
1415 }
1416
1417 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1419 Self::persisted_row_decode_corruption()
1420 }
1421
1422 pub(crate) fn persisted_row_key_mismatch() -> Self {
1424 Self::store_corruption()
1425 }
1426
1427 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1429 Self::persisted_row_field_decode_corruption(field_name)
1430 }
1431
1432 pub(crate) fn reverse_index_ordinal_overflow(
1434 _source_path: &str,
1435 _field_name: &str,
1436 _target_path: &str,
1437 _detail: impl Sized,
1438 ) -> Self {
1439 Self::index_internal()
1440 }
1441
1442 pub(crate) fn reverse_index_entry_corrupted(
1444 _source_path: &str,
1445 _field_name: &str,
1446 _target_path: &str,
1447 _index_key: impl fmt::Debug,
1448 _detail: impl Sized,
1449 ) -> Self {
1450 Self::index_corruption()
1451 }
1452
1453 pub(crate) fn relation_target_store_missing(
1455 _source_path: &str,
1456 _field_name: &str,
1457 _target_path: &str,
1458 _store_path: &str,
1459 _detail: impl Sized,
1460 ) -> Self {
1461 Self::executor_internal()
1462 }
1463
1464 pub(crate) fn relation_target_primary_key_arity_mismatch(
1466 expected_arity: usize,
1467 actual_arity: usize,
1468 ) -> Self {
1469 Self::with_diagnostic_facts(
1470 ErrorClass::Internal,
1471 ErrorOrigin::Executor,
1472 None,
1473 vec![
1474 (
1475 diagnostic_code::DiagnosticFactTag::ComponentKind,
1476 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1477 ),
1478 (
1479 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1480 expected_arity as u64,
1481 ),
1482 (
1483 diagnostic_code::DiagnosticFactTag::ActualArity,
1484 actual_arity as u64,
1485 ),
1486 ],
1487 )
1488 }
1489
1490 pub(crate) fn relation_target_key_decode_failed(
1492 _context_label: &str,
1493 _source_path: &str,
1494 _field_name: &str,
1495 _target_path: &str,
1496 _detail: impl Sized,
1497 ) -> Self {
1498 Self::identity_corruption()
1499 }
1500
1501 pub(crate) fn relation_target_entity_mismatch(
1503 _context_label: &str,
1504 _source_path: &str,
1505 _field_name: &str,
1506 _target_path: &str,
1507 _target_entity_name: &str,
1508 expected_tag: u64,
1509 actual_tag: u64,
1510 ) -> Self {
1511 Self::with_diagnostic_facts(
1512 ErrorClass::Corruption,
1513 ErrorOrigin::Store,
1514 None,
1515 vec![
1516 (
1517 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1518 expected_tag,
1519 ),
1520 (
1521 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1522 actual_tag,
1523 ),
1524 ],
1525 )
1526 }
1527
1528 pub(crate) fn relation_source_row_decode_failed(
1530 _source_path: &str,
1531 _field_name: &str,
1532 _target_path: &str,
1533 _detail: impl Sized,
1534 ) -> Self {
1535 Self::persisted_row_decode_corruption()
1536 }
1537
1538 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1540 _source_path: &str,
1541 _field_name: &str,
1542 _target_path: &str,
1543 ) -> Self {
1544 Self::persisted_row_decode_corruption()
1545 }
1546
1547 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1549 Self::persisted_row_decode_corruption()
1550 }
1551
1552 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1554 Self::index_corruption()
1555 }
1556
1557 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1559 Self::index_corruption()
1560 }
1561
1562 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1564 Self::index_corruption()
1565 }
1566
1567 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1569 Self::index_corruption()
1570 }
1571
1572 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1574 Self::index_corruption()
1575 }
1576
1577 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1579 Self::index_corruption()
1580 }
1581
1582 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1584 Self::index_corruption()
1585 }
1586
1587 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1589 Self::index_corruption()
1590 }
1591
1592 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1594 Self::index_corruption()
1595 }
1596
1597 pub(crate) fn identity_corruption() -> Self {
1599 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1600 }
1601
1602 pub(crate) fn identity_state_corruption() -> Self {
1604 Self::identity_corruption()
1605 }
1606
1607 pub(crate) fn identity_state_conflict() -> Self {
1609 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1610 }
1611
1612 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1614 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1615 }
1616
1617 pub(crate) fn identity_exhausted() -> Self {
1619 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1620 }
1621
1622 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1624 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1625 }
1626
1627 #[cold]
1629 #[inline(never)]
1630 pub(crate) fn store_unsupported() -> Self {
1631 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1632 }
1633
1634 pub(crate) fn schema_application_conflict() -> Self {
1636 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1637 }
1638
1639 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1641 let class = match reason.diagnostic_code() {
1642 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1643 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1644 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1645 _ => ErrorClass::Internal,
1646 };
1647 Self {
1648 class,
1649 origin: ErrorOrigin::Store,
1650 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1651 }
1652 }
1653
1654 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1656 Self {
1657 class: ErrorClass::Unsupported,
1658 origin: ErrorOrigin::Store,
1659 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1660 }
1661 }
1662
1663 #[cfg(feature = "sql")]
1665 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1666 Self {
1667 class: ErrorClass::Unsupported,
1668 origin: ErrorOrigin::Store,
1669 detail: Some(ErrorDetail::Store(
1670 StoreError::SchemaDdlRewriteRequiresMigration,
1671 )),
1672 }
1673 }
1674
1675 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1677 Self {
1678 class: ErrorClass::Unsupported,
1679 origin: ErrorOrigin::Store,
1680 detail: Some(ErrorDetail::Store(
1681 StoreError::JournalMutationRevisionExhausted,
1682 )),
1683 }
1684 }
1685
1686 pub(crate) fn schema_transition_budget_exceeded(
1688 resource: SchemaTransitionBudgetResource,
1689 ) -> Self {
1690 Self {
1691 class: ErrorClass::Unsupported,
1692 origin: ErrorOrigin::Store,
1693 detail: Some(ErrorDetail::Store(
1694 StoreError::SchemaTransitionBudgetExceeded { resource },
1695 )),
1696 }
1697 }
1698
1699 pub(crate) fn unsupported_entity_tag_in_data_store(
1701 _entity_tag: crate::types::EntityTag,
1702 ) -> Self {
1703 Self::store_unsupported()
1704 }
1705
1706 #[cfg(not(test))]
1708 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1709 Self::store_internal()
1710 }
1711
1712 pub(crate) fn index_unsupported() -> Self {
1714 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1715 }
1716
1717 pub(crate) fn index_component_exceeds_max_size_at(
1719 entity_tag: u64,
1720 physical_generation: u64,
1721 component_index: usize,
1722 actual_length: usize,
1723 limit: usize,
1724 ) -> Self {
1725 Self::with_diagnostic_facts(
1726 ErrorClass::Unsupported,
1727 ErrorOrigin::Index,
1728 None,
1729 vec![
1730 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1731 (
1732 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1733 physical_generation,
1734 ),
1735 (
1736 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1737 component_index as u64,
1738 ),
1739 (
1740 diagnostic_code::DiagnosticFactTag::ComponentKind,
1741 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1742 ),
1743 (
1744 diagnostic_code::DiagnosticFactTag::ActualLength,
1745 actual_length as u64,
1746 ),
1747 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1748 ],
1749 )
1750 }
1751
1752 pub(crate) fn index_component_exceeds_max_size() -> Self {
1755 Self::index_unsupported()
1756 }
1757
1758 pub(crate) fn serialize_unsupported() -> Self {
1760 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1761 }
1762
1763 pub(crate) fn cursor_invalid_continuation() -> Self {
1765 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1766 }
1767
1768 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1770 Self::new(
1771 ErrorClass::IncompatiblePersistedFormat,
1772 ErrorOrigin::Serialize,
1773 )
1774 }
1775
1776 #[cfg(feature = "sql")]
1779 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1780 Self {
1781 class: ErrorClass::Unsupported,
1782 origin: ErrorOrigin::Query,
1783 detail: Some(ErrorDetail::Query(
1784 QueryErrorDetail::UnsupportedSqlFeature { feature },
1785 )),
1786 }
1787 }
1788
1789 #[cfg(feature = "sql")]
1792 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1793 Self {
1794 class: ErrorClass::Unsupported,
1795 origin: ErrorOrigin::Query,
1796 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1797 }
1798 }
1799
1800 #[cfg(feature = "sql")]
1802 pub(crate) fn query_sql_lowering_with_facts(
1803 reason: diagnostic_code::SqlLoweringCode,
1804 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1805 ) -> Self {
1806 Self::with_diagnostic_facts(
1807 ErrorClass::Unsupported,
1808 ErrorOrigin::Query,
1809 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1810 facts,
1811 )
1812 }
1813
1814 pub(crate) fn query_unsupported_projection(
1817 reason: diagnostic_code::QueryProjectionCode,
1818 ) -> Self {
1819 Self {
1820 class: ErrorClass::Unsupported,
1821 origin: ErrorOrigin::Query,
1822 detail: Some(ErrorDetail::Query(
1823 QueryErrorDetail::UnsupportedProjection { reason },
1824 )),
1825 }
1826 }
1827
1828 pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1830 Self {
1831 class: ErrorClass::Unsupported,
1832 origin: ErrorOrigin::Query,
1833 detail: Some(ErrorDetail::Query(
1834 QueryErrorDetail::UnknownAggregateTargetField,
1835 )),
1836 }
1837 }
1838
1839 #[cfg(feature = "sql")]
1842 pub(crate) fn query_sql_surface_mismatch(
1843 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1844 ) -> Self {
1845 Self {
1846 class: ErrorClass::Unsupported,
1847 origin: ErrorOrigin::Query,
1848 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1849 mismatch,
1850 })),
1851 }
1852 }
1853
1854 pub(crate) fn query_sql_write_boundary(
1856 boundary: diagnostic_code::SqlWriteBoundaryCode,
1857 ) -> Self {
1858 Self {
1859 class: ErrorClass::Unsupported,
1860 origin: ErrorOrigin::Query,
1861 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1862 boundary,
1863 })),
1864 }
1865 }
1866
1867 pub(crate) fn query_sql_write_boundary_with_facts(
1869 boundary: diagnostic_code::SqlWriteBoundaryCode,
1870 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1871 ) -> Self {
1872 Self::with_diagnostic_facts(
1873 ErrorClass::Unsupported,
1874 ErrorOrigin::Query,
1875 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1876 facts,
1877 )
1878 }
1879
1880 pub fn store_not_found(_key: impl Sized) -> Self {
1881 Self {
1882 class: ErrorClass::NotFound,
1883 origin: ErrorOrigin::Store,
1884 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1885 }
1886 }
1887
1888 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1890 Self::store_unsupported()
1891 }
1892
1893 #[cold]
1895 #[inline(never)]
1896 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1897 Self::new(ErrorClass::Corruption, origin)
1898 }
1899
1900 #[cold]
1902 #[inline(never)]
1903 pub(crate) fn index_plan_index_corruption() -> Self {
1904 Self::index_plan_corruption(ErrorOrigin::Index)
1905 }
1906
1907 #[cold]
1909 #[inline(never)]
1910 pub(crate) fn index_plan_store_corruption() -> Self {
1911 Self::index_plan_corruption(ErrorOrigin::Store)
1912 }
1913
1914 #[cold]
1916 #[inline(never)]
1917 pub(crate) fn index_plan_serialize_corruption() -> Self {
1918 Self::index_plan_corruption(ErrorOrigin::Serialize)
1919 }
1920
1921 #[cfg(test)]
1923 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1924 Self::new(ErrorClass::InvariantViolation, origin)
1925 }
1926
1927 #[cfg(test)]
1929 pub(crate) fn index_plan_store_invariant() -> Self {
1930 Self::index_plan_invariant(ErrorOrigin::Store)
1931 }
1932
1933 pub(crate) fn index_conflict() -> Self {
1939 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1940 }
1941}
1942
1943impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1944 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1945 Self {
1946 class: ErrorClass::Unsupported,
1947 origin: ErrorOrigin::Query,
1948 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1949 reason,
1950 })),
1951 }
1952 }
1953}
1954
1955impl fmt::Debug for InternalError {
1956 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1957 fmt_compact_diagnostic(
1958 f,
1959 self.diagnostic_code(),
1960 self.detail
1961 .as_ref()
1962 .and_then(ErrorDetail::diagnostic_detail),
1963 )
1964 }
1965}
1966
1967impl fmt::Display for InternalError {
1968 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1969 f.write_str(self.message())
1970 }
1971}
1972
1973impl std::error::Error for InternalError {}
1974
1975#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1984pub enum ConstraintValuePathComponent {
1985 RootField { field_id: u32 },
1987
1988 RecordMember {
1990 composite_type_id: u32,
1991 member_id: u32,
1992 },
1993
1994 TupleElement {
1996 composite_type_id: u32,
1997 ordinal: u32,
1998 },
1999
2000 Newtype { composite_type_id: u32 },
2002
2003 EnumVariant { enum_type_id: u32, variant_id: u32 },
2005
2006 ListElement { index: u32 },
2008
2009 SetElement { index: u32 },
2011
2012 MapEntryKey { index: u32 },
2014
2015 MapEntryValue { index: u32 },
2017}
2018
2019impl fmt::Display for ConstraintValuePathComponent {
2020 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021 match self {
2022 Self::RootField { field_id } => write!(f, "field#{field_id}"),
2023 Self::RecordMember {
2024 composite_type_id,
2025 member_id,
2026 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2027 Self::TupleElement {
2028 composite_type_id,
2029 ordinal,
2030 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2031 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2032 Self::EnumVariant {
2033 enum_type_id,
2034 variant_id,
2035 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2036 Self::ListElement { index } => write!(f, "list[{index}]"),
2037 Self::SetElement { index } => write!(f, "set[{index}]"),
2038 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2039 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2040 }
2041 }
2042}
2043
2044#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2051pub struct ConstraintValuePath {
2052 components: Vec<ConstraintValuePathComponent>,
2053}
2054
2055impl ConstraintValuePath {
2056 #[must_use]
2058 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2059 Self { components }
2060 }
2061
2062 #[must_use]
2064 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2065 self.components.as_slice()
2066 }
2067}
2068
2069impl fmt::Display for ConstraintValuePath {
2070 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2071 for (ordinal, component) in self.components.iter().enumerate() {
2072 if ordinal != 0 {
2073 f.write_str("/")?;
2074 }
2075 component.fmt(f)?;
2076 }
2077 Ok(())
2078 }
2079}
2080
2081#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2090pub struct ConstraintValidationFindingOutput {
2091 accepted_schema_fingerprint: [u8; 16],
2092 entity_tag: u64,
2093 constraint_id: u32,
2094 primary_key: Vec<u8>,
2095 field_ids: Vec<u32>,
2096 value_path: Option<ConstraintValuePath>,
2097 error_code: u16,
2098}
2099
2100impl ConstraintValidationFindingOutput {
2101 #[must_use]
2103 pub(crate) const fn new(
2104 accepted_schema_fingerprint: [u8; 16],
2105 entity_tag: u64,
2106 constraint_id: u32,
2107 primary_key: Vec<u8>,
2108 field_ids: Vec<u32>,
2109 value_path: Option<ConstraintValuePath>,
2110 error_code: u16,
2111 ) -> Self {
2112 Self {
2113 accepted_schema_fingerprint,
2114 entity_tag,
2115 constraint_id,
2116 primary_key,
2117 field_ids,
2118 value_path,
2119 error_code,
2120 }
2121 }
2122
2123 #[must_use]
2125 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2126 self.accepted_schema_fingerprint
2127 }
2128
2129 #[must_use]
2131 pub const fn entity_tag(&self) -> u64 {
2132 self.entity_tag
2133 }
2134
2135 #[must_use]
2137 pub const fn constraint_id(&self) -> u32 {
2138 self.constraint_id
2139 }
2140
2141 #[must_use]
2143 pub const fn primary_key(&self) -> &[u8] {
2144 self.primary_key.as_slice()
2145 }
2146
2147 #[must_use]
2149 pub const fn field_ids(&self) -> &[u32] {
2150 self.field_ids.as_slice()
2151 }
2152
2153 #[must_use]
2155 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2156 self.value_path.as_ref()
2157 }
2158
2159 #[must_use]
2161 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2162 diagnostic_code::ErrorCode::from_raw(self.error_code)
2163 }
2164
2165 #[must_use]
2167 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2168 self.error_code().class()
2169 }
2170}
2171
2172#[derive(Clone)]
2174pub(crate) struct AcceptedConstraintFactContext {
2175 fingerprint_method: u8,
2176 accepted_schema_fingerprint: [u8; 16],
2177 entity_tag: u64,
2178 constraint_id: u32,
2179 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2180 mutation: Option<MutationDiagnosticContext>,
2181 value_path: Option<ConstraintValuePath>,
2182}
2183
2184impl AcceptedConstraintFactContext {
2185 #[must_use]
2186 pub(crate) fn write_admission(
2187 fingerprint_method: u8,
2188 accepted_schema_fingerprint: [u8; 16],
2189 entity_tag: u64,
2190 constraint_id: u32,
2191 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2192 mutation: Option<MutationDiagnosticContext>,
2193 value_path: Option<ConstraintValuePath>,
2194 ) -> Self {
2195 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2196 Self {
2197 fingerprint_method,
2198 accepted_schema_fingerprint,
2199 entity_tag,
2200 constraint_id,
2201 constraint_kind,
2202 mutation,
2203 value_path,
2204 }
2205 }
2206
2207 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2208 let high = u64::from_be_bytes([
2209 self.accepted_schema_fingerprint[0],
2210 self.accepted_schema_fingerprint[1],
2211 self.accepted_schema_fingerprint[2],
2212 self.accepted_schema_fingerprint[3],
2213 self.accepted_schema_fingerprint[4],
2214 self.accepted_schema_fingerprint[5],
2215 self.accepted_schema_fingerprint[6],
2216 self.accepted_schema_fingerprint[7],
2217 ]);
2218 let low = u64::from_be_bytes([
2219 self.accepted_schema_fingerprint[8],
2220 self.accepted_schema_fingerprint[9],
2221 self.accepted_schema_fingerprint[10],
2222 self.accepted_schema_fingerprint[11],
2223 self.accepted_schema_fingerprint[12],
2224 self.accepted_schema_fingerprint[13],
2225 self.accepted_schema_fingerprint[14],
2226 self.accepted_schema_fingerprint[15],
2227 ]);
2228 let path_len = self
2229 .value_path
2230 .as_ref()
2231 .map_or(0, |path| path.components().len());
2232 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2233 1 + usize::from(mutation.batch_position.is_some())
2234 });
2235 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2236 facts.push((
2237 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2238 u64::from(self.fingerprint_method),
2239 ));
2240 facts.push((
2241 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2242 high,
2243 ));
2244 facts.push((
2245 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2246 low,
2247 ));
2248 facts.push((
2249 diagnostic_code::DiagnosticFactTag::EntityTag,
2250 self.entity_tag,
2251 ));
2252 facts.push((
2253 diagnostic_code::DiagnosticFactTag::ConstraintId,
2254 u64::from(self.constraint_id),
2255 ));
2256 facts.push((
2257 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2258 self.constraint_kind.raw(),
2259 ));
2260 facts.push((
2261 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2262 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2263 ));
2264 if let Some(mutation) = self.mutation {
2265 mutation.append_operation_facts(&mut facts);
2266 }
2267 if let Some(path) = self.value_path {
2268 for component in path.components {
2269 facts.push(constraint_value_path_fact(component));
2270 }
2271 }
2272 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2273 facts
2274 }
2275}
2276
2277fn constraint_value_path_fact(
2278 component: ConstraintValuePathComponent,
2279) -> (diagnostic_code::DiagnosticFactTag, u64) {
2280 use diagnostic_code::DiagnosticFactTag;
2281 match component {
2282 ConstraintValuePathComponent::RootField { field_id } => {
2283 (DiagnosticFactTag::RootField, u64::from(field_id))
2284 }
2285 ConstraintValuePathComponent::RecordMember {
2286 composite_type_id,
2287 member_id,
2288 } => (
2289 DiagnosticFactTag::RecordMember,
2290 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2291 ),
2292 ConstraintValuePathComponent::TupleElement {
2293 composite_type_id,
2294 ordinal,
2295 } => (
2296 DiagnosticFactTag::TupleElement,
2297 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2298 ),
2299 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2300 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2301 }
2302 ConstraintValuePathComponent::EnumVariant {
2303 enum_type_id,
2304 variant_id,
2305 } => (
2306 DiagnosticFactTag::EnumVariant,
2307 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2308 ),
2309 ConstraintValuePathComponent::ListElement { index } => {
2310 (DiagnosticFactTag::ListElement, u64::from(index))
2311 }
2312 ConstraintValuePathComponent::SetElement { index } => {
2313 (DiagnosticFactTag::SetElement, u64::from(index))
2314 }
2315 ConstraintValuePathComponent::MapEntryKey { index } => {
2316 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2317 }
2318 ConstraintValuePathComponent::MapEntryValue { index } => {
2319 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2320 }
2321 }
2322}
2323
2324pub enum ErrorDetail {
2332 DiagnosticFacts(Box<DiagnosticFactDetail>),
2334 Executor(ExecutorErrorDetail),
2336 Store(StoreError),
2337 Query(QueryErrorDetail),
2338 Recovery(RecoveryErrorDetail),
2339 }
2342
2343pub enum ExecutorErrorDetail {
2345 MutationRequiredFieldMissing,
2347 MutationManagedTimestampRegression,
2349 MutationDatabaseOwnedFieldExplicit,
2351 MutationBatchEmpty,
2353 MutationBatchTooManyItems,
2355 MutationBatchStagedBytesExceeded,
2357 MutationBatchResultBytesExceeded,
2359 MutationBatchEntityMismatch,
2361 MutationBatchDuplicateKey,
2363 AcceptedRowConstraintProgramCorrupt,
2365}
2366
2367pub enum RecoveryErrorDetail {
2374 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2375
2376 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2377}
2378
2379#[derive(Clone, Copy, Eq, PartialEq)]
2381pub enum RecoveryFormatMarkerError {
2382 Magic,
2383 Checksum,
2384 State,
2385}
2386
2387impl RecoveryFormatMarkerError {
2388 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2389 match self {
2390 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2391 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2392 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2393 }
2394 }
2395}
2396
2397pub enum StoreError {
2405 NotFound,
2406
2407 Corrupt,
2408
2409 InvariantViolation,
2410
2411 SchemaDdlPublicationRaceLost,
2412
2413 SchemaDdlRewriteRequiresMigration,
2414
2415 SchemaMigration {
2416 reason: diagnostic_code::SchemaMigrationCode,
2417 },
2418
2419 SchemaRowLayoutVersionExhausted,
2420
2421 JournalMutationRevisionExhausted,
2422
2423 SchemaTransitionBudgetExceeded {
2424 resource: SchemaTransitionBudgetResource,
2425 },
2426
2427 SchemaGeneratedFieldAfterDdlField,
2429
2430 SchemaGeneratedConstraintActivationStale,
2432}
2433
2434pub enum QueryErrorDetail {
2441 NumericOverflow,
2442
2443 NumericNotRepresentable,
2444
2445 UnsupportedSqlFeature {
2446 feature: diagnostic_code::SqlFeatureCode,
2447 },
2448
2449 SqlLowering {
2450 reason: diagnostic_code::SqlLoweringCode,
2451 },
2452
2453 UnsupportedProjection {
2454 reason: diagnostic_code::QueryProjectionCode,
2455 },
2456
2457 UnknownAggregateTargetField,
2458
2459 ResultShapeMismatch {
2460 reason: diagnostic_code::QueryResultShapeCode,
2461 },
2462
2463 QueryReadAdmission {
2464 reason: diagnostic_code::QueryReadAdmissionCode,
2465 },
2466
2467 SqlSurfaceMismatch {
2468 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2469 },
2470
2471 SqlWriteBoundary {
2472 boundary: diagnostic_code::SqlWriteBoundaryCode,
2473 },
2474
2475 SchemaDdlAdmission {
2476 error: SchemaDdlAdmissionError,
2477 },
2478
2479 StaleSchemaRevision,
2480}
2481
2482impl fmt::Display for QueryErrorDetail {
2483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2484 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2485 }
2486}
2487
2488impl std::error::Error for QueryErrorDetail {}
2489
2490#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2498pub enum SchemaTransitionBudgetResource {
2499 DeletionKeys,
2501 ProjectionEntries,
2503 ProjectionWorkUnits,
2505 SourceRows,
2507 SourceRowBytes,
2509 StagedRawBytes,
2511}
2512
2513#[derive(Clone, Copy, Eq, PartialEq)]
2522pub enum SchemaDdlAdmissionError {
2523 MissingExpectedSchemaVersion,
2524
2525 MissingNextSchemaVersion,
2526
2527 StaleExpectedSchemaVersion,
2528
2529 InvalidExpectedSchemaVersion,
2530
2531 InvalidNextSchemaVersion,
2532
2533 AcceptedSchemaChangeWithoutVersionBump,
2534
2535 EmptyVersionBump,
2536
2537 VersionGap,
2538
2539 VersionRollback,
2540
2541 FingerprintMethodMismatch,
2542
2543 UnsupportedTransitionClass,
2544
2545 PhysicalRunnerMissing,
2546
2547 ValidationFailed,
2548
2549 PublicationRaceLost,
2550
2551 InvalidAddColumnDefault,
2552
2553 InvalidAlterColumnDefault,
2554
2555 RowLayoutVersionExhausted,
2556
2557 GeneratedIndexDropRejected,
2558
2559 SchemaRewriteRequiresMigration,
2560
2561 SchemaTransitionBudgetExceeded {
2562 resource: SchemaTransitionBudgetResource,
2563 },
2564
2565 GeneratedFieldDefaultChangeRejected,
2566
2567 GeneratedFieldNullabilityChangeRejected,
2568}
2569
2570impl fmt::Display for SchemaDdlAdmissionError {
2571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2572 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2573 }
2574}
2575
2576impl std::error::Error for SchemaDdlAdmissionError {}
2577
2578impl fmt::Debug for ErrorDetail {
2579 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2580 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2581 }
2582}
2583
2584impl fmt::Debug for ExecutorErrorDetail {
2585 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2586 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2587 }
2588}
2589
2590impl fmt::Debug for StoreError {
2591 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2592 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2593 }
2594}
2595
2596impl fmt::Debug for QueryErrorDetail {
2597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2598 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2599 }
2600}
2601
2602impl fmt::Debug for RecoveryErrorDetail {
2603 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2604 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2605 }
2606}
2607
2608impl fmt::Debug for RecoveryFormatMarkerError {
2609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2610 fmt_compact_diagnostic(
2611 f,
2612 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2613 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2614 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2615 }),
2616 )
2617 }
2618}
2619
2620impl fmt::Debug for SchemaDdlAdmissionError {
2621 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2622 fmt_compact_diagnostic(
2623 f,
2624 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2625 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2626 reason: self.diagnostic_code(),
2627 }),
2628 )
2629 }
2630}
2631
2632fn fmt_compact_diagnostic(
2633 f: &mut fmt::Formatter<'_>,
2634 code: diagnostic_code::DiagnosticCode,
2635 detail: Option<diagnostic_code::DiagnosticDetail>,
2636) -> fmt::Result {
2637 write!(
2638 f,
2639 "{}",
2640 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2641 )
2642}
2643
2644impl ErrorDetail {
2645 #[must_use]
2647 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2648 match self {
2649 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2650 Self::Executor(error) => error.diagnostic_code(),
2651 Self::Store(error) => error.diagnostic_code(),
2652 Self::Query(error) => error.diagnostic_code(),
2653 Self::Recovery(error) => error.diagnostic_code(),
2654 }
2655 }
2656
2657 #[must_use]
2659 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2660 match self {
2661 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2662 Self::Executor(error) => error.diagnostic_detail(),
2663 Self::Store(error) => error.diagnostic_detail(),
2664 Self::Query(error) => error.diagnostic_detail(),
2665 Self::Recovery(error) => error.diagnostic_detail(),
2666 }
2667 }
2668
2669 #[must_use]
2671 #[cold]
2672 #[inline(never)]
2673 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2674 match self {
2675 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2676 Self::Executor(error) => error.diagnostic_facts(),
2677 Self::Query(error) => error.diagnostic_facts(),
2678 Self::Recovery(error) => error.diagnostic_facts(),
2679 Self::Store(_) => Vec::new(),
2680 }
2681 }
2682}
2683
2684impl ExecutorErrorDetail {
2685 #[must_use]
2687 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2688 match self {
2689 Self::MutationRequiredFieldMissing
2690 | Self::MutationDatabaseOwnedFieldExplicit
2691 | Self::MutationBatchEmpty
2692 | Self::MutationBatchTooManyItems
2693 | Self::MutationBatchStagedBytesExceeded
2694 | Self::MutationBatchResultBytesExceeded => {
2695 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2696 }
2697 Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2698 diagnostic_code::DiagnosticCode::RuntimeConflict
2699 }
2700 Self::MutationManagedTimestampRegression => {
2701 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2702 }
2703 Self::AcceptedRowConstraintProgramCorrupt => {
2704 diagnostic_code::DiagnosticCode::RuntimeCorruption
2705 }
2706 }
2707 }
2708
2709 #[must_use]
2711 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2712 match self {
2713 Self::MutationRequiredFieldMissing => {
2714 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2715 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2716 })
2717 }
2718 Self::MutationDatabaseOwnedFieldExplicit => {
2719 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2720 boundary:
2721 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2722 })
2723 }
2724 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2725 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2726 }),
2727 Self::MutationBatchTooManyItems => {
2728 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2729 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2730 })
2731 }
2732 Self::MutationBatchStagedBytesExceeded => {
2733 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2734 boundary:
2735 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2736 })
2737 }
2738 Self::MutationBatchResultBytesExceeded => {
2739 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2740 boundary:
2741 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2742 })
2743 }
2744 Self::MutationBatchEntityMismatch => {
2745 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2746 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2747 })
2748 }
2749 Self::MutationBatchDuplicateKey => {
2750 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2751 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2752 })
2753 }
2754 Self::MutationManagedTimestampRegression => {
2755 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2756 boundary:
2757 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2758 })
2759 }
2760 Self::AcceptedRowConstraintProgramCorrupt => {
2761 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2762 boundary:
2763 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2764 })
2765 }
2766 }
2767 }
2768
2769 #[must_use]
2771 #[cold]
2772 #[inline(never)]
2773 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2774 Vec::new()
2775 }
2776}
2777
2778impl RecoveryErrorDetail {
2779 #[must_use]
2781 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2782 match self {
2783 Self::UnsupportedFormatVersion { .. } => {
2784 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2785 }
2786 Self::MalformedFormatMarker { .. } => {
2787 diagnostic_code::DiagnosticCode::RuntimeCorruption
2788 }
2789 }
2790 }
2791
2792 #[must_use]
2794 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2795 let kind = match self {
2796 Self::UnsupportedFormatVersion { .. } => {
2797 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2798 }
2799 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2800 };
2801
2802 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2803 }
2804
2805 #[must_use]
2807 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2808 match self {
2809 Self::UnsupportedFormatVersion { found, required } => {
2810 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2811 facts.push((
2812 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2813 u64::from(*required),
2814 ));
2815 if let Some(found) = found {
2816 facts.push((
2817 diagnostic_code::DiagnosticFactTag::ActualVersion,
2818 u64::from(*found),
2819 ));
2820 }
2821 facts
2822 }
2823 Self::MalformedFormatMarker { reason } => vec![(
2824 diagnostic_code::DiagnosticFactTag::DecodeReason,
2825 reason.diagnostic_decode_reason().raw(),
2826 )],
2827 }
2828 }
2829}
2830
2831impl StoreError {
2832 #[must_use]
2834 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2835 match self {
2836 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2837 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2838 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2839 Self::SchemaDdlPublicationRaceLost
2840 | Self::SchemaDdlRewriteRequiresMigration
2841 | Self::SchemaRowLayoutVersionExhausted
2842 | Self::SchemaTransitionBudgetExceeded { .. } => {
2843 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2844 }
2845 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2846 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2847 }
2848 Self::SchemaGeneratedConstraintActivationStale => {
2849 diagnostic_code::DiagnosticCode::RuntimeConflict
2850 }
2851 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2852 }
2853 }
2854
2855 #[must_use]
2857 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2858 match self {
2859 Self::SchemaDdlPublicationRaceLost => {
2860 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2861 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2862 })
2863 }
2864 Self::SchemaDdlRewriteRequiresMigration => {
2865 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2866 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2867 })
2868 }
2869 Self::SchemaMigration { reason } => {
2870 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2871 }
2872 Self::SchemaRowLayoutVersionExhausted => {
2873 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2874 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2875 })
2876 }
2877 Self::JournalMutationRevisionExhausted => {
2878 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2879 boundary:
2880 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2881 })
2882 }
2883 Self::SchemaTransitionBudgetExceeded { .. } => {
2884 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2885 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2886 })
2887 }
2888 Self::SchemaGeneratedFieldAfterDdlField => {
2889 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2890 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2891 })
2892 }
2893 Self::SchemaGeneratedConstraintActivationStale => {
2894 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2895 boundary:
2896 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2897 })
2898 }
2899 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2900 }
2901 }
2902}
2903
2904impl QueryErrorDetail {
2905 #[must_use]
2907 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2908 match self {
2909 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2910 Self::NumericNotRepresentable => {
2911 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2912 }
2913 Self::UnsupportedSqlFeature { .. } => {
2914 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2915 }
2916 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2917 Self::UnsupportedProjection { .. } => {
2918 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2919 }
2920 Self::UnknownAggregateTargetField => {
2921 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2922 }
2923 Self::ResultShapeMismatch { .. } => {
2924 diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2925 }
2926 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2927 Self::SqlSurfaceMismatch { .. } => {
2928 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2929 }
2930 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2931 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2932 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2933 }
2934 }
2935
2936 #[must_use]
2938 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2939 match self {
2940 Self::UnsupportedSqlFeature { feature } => {
2941 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2942 }
2943 Self::SqlLowering { reason } => {
2944 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2945 }
2946 Self::UnsupportedProjection { reason } => {
2947 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2948 }
2949 Self::ResultShapeMismatch { reason } => {
2950 Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2951 }
2952 Self::QueryReadAdmission { reason } => {
2953 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2954 }
2955 Self::SqlSurfaceMismatch { mismatch } => {
2956 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2957 mismatch: *mismatch,
2958 })
2959 }
2960 Self::SqlWriteBoundary { boundary } => {
2961 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2962 boundary: *boundary,
2963 })
2964 }
2965 Self::SchemaDdlAdmission { error } => {
2966 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2967 reason: error.diagnostic_code(),
2968 })
2969 }
2970 Self::NumericOverflow
2971 | Self::NumericNotRepresentable
2972 | Self::UnknownAggregateTargetField
2973 | Self::StaleSchemaRevision => None,
2974 }
2975 }
2976
2977 #[must_use]
2979 #[cold]
2980 #[inline(never)]
2981 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2982 Vec::new()
2983 }
2984}
2985
2986impl SchemaDdlAdmissionError {
2987 #[must_use]
2989 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2990 match self {
2991 Self::MissingExpectedSchemaVersion => {
2992 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2993 }
2994 Self::MissingNextSchemaVersion => {
2995 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2996 }
2997 Self::StaleExpectedSchemaVersion => {
2998 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2999 }
3000 Self::InvalidExpectedSchemaVersion => {
3001 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3002 }
3003 Self::InvalidNextSchemaVersion => {
3004 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3005 }
3006 Self::AcceptedSchemaChangeWithoutVersionBump => {
3007 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3008 }
3009 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3010 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3011 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3012 Self::FingerprintMethodMismatch => {
3013 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3014 }
3015 Self::UnsupportedTransitionClass => {
3016 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3017 }
3018 Self::PhysicalRunnerMissing => {
3019 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3020 }
3021 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3022 Self::PublicationRaceLost => {
3023 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3024 }
3025 Self::InvalidAddColumnDefault => {
3026 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3027 }
3028 Self::InvalidAlterColumnDefault => {
3029 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3030 }
3031 Self::GeneratedIndexDropRejected => {
3032 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3033 }
3034 Self::SchemaRewriteRequiresMigration => {
3035 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3036 }
3037 Self::SchemaTransitionBudgetExceeded { .. } => {
3038 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3039 }
3040 Self::GeneratedFieldDefaultChangeRejected => {
3041 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3042 }
3043 Self::GeneratedFieldNullabilityChangeRejected => {
3044 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3045 }
3046 Self::RowLayoutVersionExhausted => {
3047 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3048 }
3049 }
3050 }
3051}
3052
3053#[repr(u8)]
3060#[derive(Clone, Copy, Eq, PartialEq)]
3061pub enum ErrorClass {
3062 Corruption,
3063 IncompatiblePersistedFormat,
3064 NotFound,
3065 Internal,
3066 Conflict,
3067 Unsupported,
3068 InvariantViolation,
3069}
3070
3071impl ErrorClass {
3072 #[must_use]
3074 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3075 match self {
3076 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3077 diagnostic_code::DiagnosticCode::StoreCorruption
3078 }
3079 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3080 Self::IncompatiblePersistedFormat => {
3081 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3082 }
3083 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3084 diagnostic_code::DiagnosticCode::StoreNotFound
3085 }
3086 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3087 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3088 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3089 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3090 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3091 }
3092 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3093 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3094 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3095 }
3096 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3097 }
3098 }
3099}
3100
3101impl fmt::Debug for ErrorClass {
3102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3103 write!(f, "{}", *self as u8)
3104 }
3105}
3106
3107#[repr(u8)]
3114#[derive(Clone, Copy, Eq, PartialEq)]
3115pub enum ErrorOrigin {
3116 Serialize,
3117 Store,
3118 Index,
3119 Identity,
3120 Query,
3121 Planner,
3122 Cursor,
3123 Recovery,
3124 Response,
3125 Executor,
3126 Interface,
3127}
3128
3129impl ErrorOrigin {
3130 #[must_use]
3132 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3133 match self {
3134 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3135 Self::Store => diagnostic_code::ErrorOrigin::Store,
3136 Self::Index => diagnostic_code::ErrorOrigin::Index,
3137 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3138 Self::Query => diagnostic_code::ErrorOrigin::Query,
3139 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3140 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3141 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3142 Self::Response => diagnostic_code::ErrorOrigin::Response,
3143 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3144 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3145 }
3146 }
3147}
3148
3149impl fmt::Debug for ErrorOrigin {
3150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3151 write!(f, "{}", *self as u8)
3152 }
3153}