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
39pub struct InternalError {
140 pub(crate) class: ErrorClass,
141 pub(crate) origin: ErrorOrigin,
142
143 pub(crate) detail: Option<ErrorDetail>,
146}
147
148#[expect(
149 clippy::missing_const_for_fn,
150 reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
151)]
152impl InternalError {
153 #[must_use]
157 #[cold]
158 #[inline(never)]
159 pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
160 let detail = match (class, origin) {
161 (ErrorClass::Corruption, ErrorOrigin::Store) => {
162 Some(ErrorDetail::Store(StoreError::Corrupt))
163 }
164 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
165 Some(ErrorDetail::Store(StoreError::InvariantViolation))
166 }
167 _ => None,
168 };
169
170 Self {
171 class,
172 origin,
173 detail,
174 }
175 }
176
177 #[must_use]
179 pub const fn class(&self) -> ErrorClass {
180 self.class
181 }
182
183 #[must_use]
185 pub const fn origin(&self) -> ErrorOrigin {
186 self.origin
187 }
188
189 #[must_use]
191 pub const fn message(&self) -> &'static str {
192 compact_message_for(self.class, self.origin)
193 }
194
195 #[must_use]
197 pub const fn detail(&self) -> Option<&ErrorDetail> {
198 self.detail.as_ref()
199 }
200
201 #[must_use]
203 pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
204 match self.detail.as_ref() {
205 Some(ErrorDetail::Executor(detail)) => detail.constraint_diagnostic(),
206 Some(
207 ErrorDetail::Store(_)
208 | ErrorDetail::Query(_)
209 | ErrorDetail::Recovery(_)
210 | ErrorDetail::Serialize(_),
211 )
212 | None => None,
213 }
214 }
215
216 #[must_use]
218 pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
219 diagnostic_code::Diagnostic::new(
220 self.diagnostic_code(),
221 self.origin.diagnostic_origin(),
222 self.detail
223 .as_ref()
224 .and_then(ErrorDetail::diagnostic_detail),
225 )
226 }
227
228 #[must_use]
230 pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
231 self.detail.as_ref().map_or_else(
232 || self.class.diagnostic_code(self.origin),
233 ErrorDetail::diagnostic_code,
234 )
235 }
236
237 #[must_use]
239 pub fn into_message(self) -> String {
240 self.message().to_string()
241 }
242
243 #[cold]
245 #[inline(never)]
246 pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
247 Self::new(class, origin)
248 }
249
250 #[cold]
254 #[inline(never)]
255 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
256 Self::classified(self.class, origin)
257 }
258
259 #[cold]
261 #[inline(never)]
262 pub(crate) fn index_invariant() -> Self {
263 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
264 }
265
266 pub(crate) fn index_key_field_count_exceeds_max(
268 _index_name: &str,
269 _field_count: usize,
270 _max_fields: usize,
271 ) -> Self {
272 Self::index_invariant()
273 }
274
275 pub(crate) fn index_expression_source_type_mismatch(
277 _index_name: &str,
278 _expression: impl Sized,
279 _expected: impl Sized,
280 _source_label: &str,
281 ) -> Self {
282 Self::index_invariant()
283 }
284
285 #[cold]
288 #[inline(never)]
289 #[cfg(any(test, feature = "query"))]
290 pub(crate) fn planner_executor_invariant() -> Self {
291 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
292 }
293
294 #[cold]
297 #[inline(never)]
298 pub(crate) fn query_executor_invariant() -> Self {
299 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
300 }
301
302 #[cold]
305 #[inline(never)]
306 #[cfg(any(test, feature = "query"))]
307 pub(crate) fn cursor_executor_invariant() -> Self {
308 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
309 }
310
311 #[cold]
313 #[inline(never)]
314 pub(crate) fn executor_invariant() -> Self {
315 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
316 }
317
318 #[cold]
320 #[inline(never)]
321 pub(crate) fn executor_internal() -> Self {
322 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
323 }
324
325 #[cold]
327 #[inline(never)]
328 pub(crate) fn executor_unsupported() -> Self {
329 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
330 }
331
332 pub(crate) fn mutation_database_owned_field_explicit(
334 _entity_path: &str,
335 _field_name: &str,
336 ) -> Self {
337 Self {
338 class: ErrorClass::Unsupported,
339 origin: ErrorOrigin::Executor,
340 detail: Some(ErrorDetail::Executor(
341 ExecutorErrorDetail::MutationDatabaseOwnedFieldExplicit,
342 )),
343 }
344 }
345
346 #[must_use]
348 pub fn mutation_required_field_missing(_entity_path: &str, _field_names: &str) -> Self {
349 Self {
350 class: ErrorClass::Unsupported,
351 origin: ErrorOrigin::Executor,
352 detail: Some(ErrorDetail::Executor(
353 ExecutorErrorDetail::MutationRequiredFieldMissing,
354 )),
355 }
356 }
357
358 #[must_use]
360 pub(crate) fn mutation_managed_timestamp_regression() -> Self {
361 Self {
362 class: ErrorClass::InvariantViolation,
363 origin: ErrorOrigin::Executor,
364 detail: Some(ErrorDetail::Executor(
365 ExecutorErrorDetail::MutationManagedTimestampRegression,
366 )),
367 }
368 }
369
370 pub(crate) fn mutation_constraint_violation(diagnostic: ConstraintDiagnostic) -> Self {
372 Self {
373 class: ErrorClass::InvariantViolation,
374 origin: ErrorOrigin::Executor,
375 detail: Some(ErrorDetail::Executor(
376 ExecutorErrorDetail::ConstraintViolation {
377 diagnostic: Box::new(diagnostic),
378 },
379 )),
380 }
381 }
382
383 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
385 Self {
386 class: ErrorClass::Corruption,
387 origin: ErrorOrigin::Executor,
388 detail: Some(ErrorDetail::Executor(
389 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
390 )),
391 }
392 }
393
394 pub(crate) fn mutation_constraint_activation_write_blocked(
396 diagnostic: ConstraintDiagnostic,
397 ) -> Self {
398 Self {
399 class: ErrorClass::Conflict,
400 origin: ErrorOrigin::Executor,
401 detail: Some(ErrorDetail::Executor(
402 ExecutorErrorDetail::ConstraintActivationWriteBlocked {
403 diagnostic: Box::new(diagnostic),
404 },
405 )),
406 }
407 }
408
409 pub(crate) fn mutation_structural_field_unknown(_entity_path: &str, _field_name: &str) -> Self {
411 Self::executor_invariant()
412 }
413
414 #[cfg(any(test, feature = "query"))]
416 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
417 Self::query_executor_invariant()
418 }
419
420 #[cfg(any(test, feature = "query"))]
422 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
423 Self::query_executor_invariant()
424 }
425
426 #[cfg(any(test, feature = "query"))]
428 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
429 Self::query_executor_invariant()
430 }
431
432 #[cfg(any(test, feature = "query"))]
434 pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
435 Self::query_executor_invariant()
436 }
437
438 #[cfg(any(test, feature = "query"))]
440 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
441 Self::query_executor_invariant()
442 }
443
444 #[cfg(any(test, feature = "query"))]
446 pub(crate) fn index_range_limit_spec_required() -> Self {
447 Self::query_executor_invariant()
448 }
449
450 pub(crate) fn mutation_atomic_save_duplicate_key(_entity_path: &str, _key: impl Sized) -> Self {
452 Self {
453 class: ErrorClass::Conflict,
454 origin: ErrorOrigin::Executor,
455 detail: Some(ErrorDetail::Executor(
456 ExecutorErrorDetail::MutationBatchDuplicateKey,
457 )),
458 }
459 }
460
461 pub(crate) fn mutation_batch_empty() -> Self {
463 Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchEmpty)
464 }
465
466 pub(crate) fn mutation_batch_too_many_items() -> Self {
468 Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchTooManyItems)
469 }
470
471 pub(crate) fn mutation_batch_staged_bytes_exceeded() -> Self {
473 Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchStagedBytesExceeded)
474 }
475
476 pub(crate) fn mutation_batch_result_bytes_exceeded() -> Self {
478 Self::mutation_batch_unsupported(ExecutorErrorDetail::MutationBatchResultBytesExceeded)
479 }
480
481 pub(crate) fn mutation_batch_entity_mismatch() -> Self {
483 Self {
484 class: ErrorClass::Conflict,
485 origin: ErrorOrigin::Executor,
486 detail: Some(ErrorDetail::Executor(
487 ExecutorErrorDetail::MutationBatchEntityMismatch,
488 )),
489 }
490 }
491
492 fn mutation_batch_unsupported(detail: ExecutorErrorDetail) -> Self {
493 Self {
494 class: ErrorClass::Unsupported,
495 origin: ErrorOrigin::Executor,
496 detail: Some(ErrorDetail::Executor(detail)),
497 }
498 }
499
500 pub(crate) fn mutation_index_store_generation_changed(
502 _expected_generation: u64,
503 _observed_generation: u64,
504 ) -> Self {
505 Self::executor_invariant()
506 }
507
508 #[cold]
510 #[inline(never)]
511 #[cfg(any(test, feature = "query"))]
512 pub(crate) fn planner_invariant() -> Self {
513 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
514 }
515
516 #[cfg(any(test, feature = "query"))]
518 pub(crate) fn query_invalid_logical_plan() -> Self {
519 Self::planner_invariant()
520 }
521
522 pub(crate) fn store_invariant() -> Self {
524 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
525 }
526
527 #[cold]
529 #[inline(never)]
530 pub(crate) fn store_internal() -> Self {
531 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
532 }
533
534 pub(crate) fn commit_memory_id_unconfigured() -> Self {
536 Self::store_internal()
537 }
538
539 pub(crate) fn commit_store_uninitialized() -> Self {
541 Self::store_invariant()
542 }
543
544 pub(crate) fn commit_memory_id_mismatch(_cached_id: u8, _configured_id: u8) -> Self {
546 Self::store_internal()
547 }
548
549 pub(crate) fn commit_memory_stable_key_mismatch(
551 _cached_key: &str,
552 _configured_key: &str,
553 ) -> Self {
554 Self::store_internal()
555 }
556
557 pub(crate) fn database_incarnation_generation_failed() -> Self {
559 Self::store_internal()
560 }
561
562 pub(crate) fn database_incarnation_invalid() -> Self {
564 Self::store_corruption()
565 }
566
567 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
569 Self {
570 class: ErrorClass::IncompatiblePersistedFormat,
571 origin: ErrorOrigin::Recovery,
572 detail: Some(ErrorDetail::Recovery(
573 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
574 )),
575 }
576 }
577
578 pub(crate) fn recovery_malformed_database_format_marker(
580 reason: RecoveryFormatMarkerError,
581 ) -> Self {
582 Self {
583 class: ErrorClass::Corruption,
584 origin: ErrorOrigin::Recovery,
585 detail: Some(ErrorDetail::Recovery(
586 RecoveryErrorDetail::MalformedFormatMarker { reason },
587 )),
588 }
589 }
590
591 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
593 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
594 }
595
596 pub(crate) fn commit_control_memory_growth_failed() -> Self {
598 Self::store_internal()
599 }
600
601 #[cfg(not(test))]
603 pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
604 Self::store_internal()
605 }
606
607 pub(crate) fn recovery_effect_verification_failed() -> Self {
609 Self::store_corruption()
610 }
611
612 #[cold]
614 #[inline(never)]
615 pub(crate) fn index_internal() -> Self {
616 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
617 }
618
619 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
621 Self::index_internal()
622 }
623
624 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
626 Self::index_internal()
627 }
628
629 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
631 Self::index_internal()
632 }
633
634 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
636 Self::index_internal()
637 }
638
639 #[cfg(test)]
641 pub(crate) fn query_internal() -> Self {
642 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
643 }
644
645 #[cold]
647 #[inline(never)]
648 #[cfg(any(test, feature = "query"))]
649 pub(crate) fn query_unsupported() -> Self {
650 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
651 }
652
653 #[cold]
656 #[inline(never)]
657 #[cfg(any(test, feature = "query"))]
658 pub(crate) fn query_stale_accepted_schema_revision(
659 _expected_revision: u64,
660 _current_revision: Option<u64>,
661 ) -> Self {
662 Self {
663 class: ErrorClass::Conflict,
664 origin: ErrorOrigin::Query,
665 detail: Some(ErrorDetail::Query(QueryErrorDetail::StaleSchemaRevision)),
666 }
667 }
668
669 #[cold]
671 #[inline(never)]
672 #[cfg(feature = "sql")]
673 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
674 Self {
675 class: ErrorClass::Unsupported,
676 origin: ErrorOrigin::Query,
677 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
678 error,
679 })),
680 }
681 }
682
683 #[cold]
685 #[inline(never)]
686 #[cfg(any(test, feature = "query"))]
687 pub(crate) fn query_numeric_overflow() -> Self {
688 Self {
689 class: ErrorClass::Unsupported,
690 origin: ErrorOrigin::Query,
691 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
692 }
693 }
694
695 #[cold]
698 #[inline(never)]
699 #[cfg(any(test, feature = "query"))]
700 pub(crate) fn query_numeric_not_representable() -> Self {
701 Self {
702 class: ErrorClass::Unsupported,
703 origin: ErrorOrigin::Query,
704 detail: Some(ErrorDetail::Query(
705 QueryErrorDetail::NumericNotRepresentable,
706 )),
707 }
708 }
709
710 #[cold]
712 #[inline(never)]
713 pub(crate) fn serialize_internal() -> Self {
714 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
715 }
716
717 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
719 Self::persisted_row_encode_internal()
720 }
721
722 pub(crate) fn persisted_row_encode_internal() -> Self {
724 Self::serialize_internal()
725 }
726
727 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
729 Self::persisted_row_encode_internal()
730 }
731
732 #[cold]
734 #[inline(never)]
735 pub(crate) fn store_corruption() -> Self {
736 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
737 }
738
739 pub(crate) fn commit_corruption() -> Self {
741 Self::store_corruption()
742 }
743
744 pub(crate) fn commit_component_corruption() -> Self {
746 Self::commit_corruption()
747 }
748
749 pub(crate) fn commit_id_generation_failed() -> Self {
751 Self::store_internal()
752 }
753
754 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
756 Self::store_unsupported()
757 }
758
759 pub(crate) fn commit_component_length_invalid() -> Self {
761 Self::commit_corruption()
762 }
763
764 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
766 Self::commit_corruption()
767 }
768
769 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
771 Self::store_unsupported()
772 }
773
774 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
776 Self::store_unsupported()
777 }
778
779 pub(crate) fn startup_index_rebuild_invalid_data_key() -> Self {
781 Self::store_corruption()
782 }
783
784 #[cold]
786 #[inline(never)]
787 pub(crate) fn index_corruption() -> Self {
788 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
789 }
790
791 pub(crate) fn index_unique_validation_corruption() -> Self {
793 Self::index_plan_index_corruption()
794 }
795
796 pub(crate) fn structural_index_entry_corruption() -> Self {
798 Self::index_plan_index_corruption()
799 }
800
801 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
803 Self::index_invariant()
804 }
805
806 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
808 Self::index_plan_serialize_corruption()
809 }
810
811 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
813 Self::index_plan_serialize_corruption()
814 }
815
816 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
818 Self::index_plan_serialize_corruption()
819 }
820
821 pub(crate) fn index_unique_validation_row_required() -> Self {
823 Self::index_plan_store_corruption()
824 }
825
826 #[cfg(any(test, feature = "query"))]
828 pub(crate) fn index_only_predicate_component_required() -> Self {
829 Self::index_invariant()
830 }
831
832 #[cfg(any(test, feature = "query"))]
834 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
835 Self::index_invariant()
836 }
837
838 #[cfg(any(test, feature = "query"))]
840 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
841 Self::index_invariant()
842 }
843
844 #[cfg(any(test, feature = "query"))]
846 pub(crate) fn index_scan_key_corrupted_during(
847 _context: &'static str,
848 _err: impl Sized,
849 ) -> Self {
850 Self::index_corruption()
851 }
852
853 #[cfg(any(test, feature = "query"))]
855 pub(crate) fn index_projection_component_required(
856 _index_name: &str,
857 _component_index: usize,
858 ) -> Self {
859 Self::index_invariant()
860 }
861
862 #[cfg(any(test, feature = "query"))]
864 pub(crate) fn index_entry_decode_failed() -> Self {
865 Self::index_corruption()
866 }
867
868 pub(crate) fn serialize_corruption() -> Self {
870 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
871 }
872
873 pub(crate) fn persisted_row_decode_corruption() -> Self {
875 Self::serialize_corruption()
876 }
877
878 pub(crate) fn persisted_row_layout_outside_accepted_window() -> Self {
880 Self {
881 class: ErrorClass::Corruption,
882 origin: ErrorOrigin::Serialize,
883 detail: Some(ErrorDetail::Serialize(
884 SerializeErrorDetail::PersistedRowLayoutOutsideAcceptedWindow,
885 )),
886 }
887 }
888
889 pub(crate) fn persisted_row_slot_count_mismatch() -> Self {
891 Self {
892 class: ErrorClass::Corruption,
893 origin: ErrorOrigin::Serialize,
894 detail: Some(ErrorDetail::Serialize(
895 SerializeErrorDetail::PersistedRowSlotCountMismatch,
896 )),
897 }
898 }
899
900 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
902 Self::persisted_row_field_decode_corruption(field_name)
903 }
904
905 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
907 Self::persisted_row_decode_corruption()
908 }
909
910 pub(crate) fn persisted_row_field_kind_decode_failed(
912 field_name: &str,
913 _field_kind: impl fmt::Debug,
914 _detail: impl Sized,
915 ) -> Self {
916 Self::persisted_row_field_decode_corruption(field_name)
917 }
918
919 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
921 Self::persisted_row_field_decode_corruption(field_name)
922 }
923
924 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
926 Self::persisted_row_field_decode_corruption(field_name)
927 }
928
929 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
931 Self::persisted_row_field_decode_corruption(field_name)
932 }
933
934 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
936 Self::persisted_row_field_decode_corruption(field_name)
937 }
938
939 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
941 Self::persisted_row_field_decode_corruption(field_name)
942 }
943
944 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
946 Self::index_invariant()
947 }
948
949 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
951 _model_path: &str,
952 _slot: usize,
953 ) -> Self {
954 Self::index_invariant()
955 }
956
957 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
959 _data_key: impl fmt::Debug,
960 _detail: impl Sized,
961 ) -> Self {
962 Self::persisted_row_decode_corruption()
963 }
964
965 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
967 Self::persisted_row_decode_corruption()
968 }
969
970 pub(crate) fn persisted_row_key_mismatch() -> Self {
972 Self::store_corruption()
973 }
974
975 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
977 Self::persisted_row_field_decode_corruption(field_name)
978 }
979
980 pub(crate) fn reverse_index_ordinal_overflow(
982 _source_path: &str,
983 _field_name: &str,
984 _target_path: &str,
985 _detail: impl Sized,
986 ) -> Self {
987 Self::index_internal()
988 }
989
990 pub(crate) fn reverse_index_entry_corrupted(
992 _source_path: &str,
993 _field_name: &str,
994 _target_path: &str,
995 _index_key: impl fmt::Debug,
996 _detail: impl Sized,
997 ) -> Self {
998 Self::index_corruption()
999 }
1000
1001 pub(crate) fn relation_target_store_missing(
1003 _source_path: &str,
1004 _field_name: &str,
1005 _target_path: &str,
1006 _store_path: &str,
1007 _detail: impl Sized,
1008 ) -> Self {
1009 Self::executor_internal()
1010 }
1011
1012 pub(crate) fn relation_target_key_decode_failed(
1014 _context_label: &str,
1015 _source_path: &str,
1016 _field_name: &str,
1017 _target_path: &str,
1018 _detail: impl Sized,
1019 ) -> Self {
1020 Self::identity_corruption()
1021 }
1022
1023 pub(crate) fn relation_target_entity_mismatch(
1025 _context_label: &str,
1026 _source_path: &str,
1027 _field_name: &str,
1028 _target_path: &str,
1029 _target_entity_name: &str,
1030 _expected_tag: impl Sized,
1031 _actual_tag: impl Sized,
1032 ) -> Self {
1033 Self::store_corruption()
1034 }
1035
1036 pub(crate) fn relation_source_row_decode_failed(
1038 _source_path: &str,
1039 _field_name: &str,
1040 _target_path: &str,
1041 _detail: impl Sized,
1042 ) -> Self {
1043 Self::persisted_row_decode_corruption()
1044 }
1045
1046 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1048 _source_path: &str,
1049 _field_name: &str,
1050 _target_path: &str,
1051 ) -> Self {
1052 Self::persisted_row_decode_corruption()
1053 }
1054
1055 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1057 Self::persisted_row_decode_corruption()
1058 }
1059
1060 #[cfg(any(test, feature = "query"))]
1062 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1063 Self::index_corruption()
1064 }
1065
1066 #[cfg(any(test, feature = "query"))]
1068 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1069 Self::index_corruption()
1070 }
1071
1072 #[cfg(any(test, feature = "query"))]
1074 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1075 Self::index_corruption()
1076 }
1077
1078 #[cfg(any(test, feature = "query"))]
1080 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1081 Self::index_corruption()
1082 }
1083
1084 #[cfg(any(test, feature = "query"))]
1086 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1087 Self::index_corruption()
1088 }
1089
1090 #[cfg(any(test, feature = "query"))]
1092 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1093 Self::index_corruption()
1094 }
1095
1096 #[cfg(any(test, feature = "query"))]
1098 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1099 Self::index_corruption()
1100 }
1101
1102 #[cfg(any(test, feature = "query"))]
1104 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1105 Self::index_corruption()
1106 }
1107
1108 #[cfg(any(test, feature = "query"))]
1110 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1111 Self::index_corruption()
1112 }
1113
1114 pub(crate) fn identity_corruption() -> Self {
1116 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1117 }
1118
1119 pub(crate) fn identity_state_corruption() -> Self {
1121 Self::identity_corruption()
1122 }
1123
1124 pub(crate) fn identity_state_conflict() -> Self {
1126 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1127 }
1128
1129 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1131 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1132 }
1133
1134 pub(crate) fn identity_exhausted() -> Self {
1136 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1137 }
1138
1139 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1141 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1142 }
1143
1144 #[cold]
1146 #[inline(never)]
1147 pub(crate) fn store_unsupported() -> Self {
1148 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1149 }
1150
1151 pub(crate) fn schema_application_conflict() -> Self {
1153 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1154 }
1155
1156 #[cfg(any(test, feature = "query"))]
1158 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1159 Self {
1160 class: ErrorClass::Unsupported,
1161 origin: ErrorOrigin::Store,
1162 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1163 }
1164 }
1165
1166 #[cfg(feature = "sql")]
1168 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1169 Self {
1170 class: ErrorClass::Unsupported,
1171 origin: ErrorOrigin::Store,
1172 detail: Some(ErrorDetail::Store(
1173 StoreError::SchemaDdlRewriteRequiresMigration,
1174 )),
1175 }
1176 }
1177
1178 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1180 Self {
1181 class: ErrorClass::Unsupported,
1182 origin: ErrorOrigin::Store,
1183 detail: Some(ErrorDetail::Store(
1184 StoreError::JournalMutationRevisionExhausted,
1185 )),
1186 }
1187 }
1188
1189 pub(crate) fn schema_transition_budget_exceeded(
1191 resource: SchemaTransitionBudgetResource,
1192 ) -> Self {
1193 Self {
1194 class: ErrorClass::Unsupported,
1195 origin: ErrorOrigin::Store,
1196 detail: Some(ErrorDetail::Store(
1197 StoreError::SchemaTransitionBudgetExceeded { resource },
1198 )),
1199 }
1200 }
1201
1202 pub(crate) fn unsupported_entity_tag_in_data_store(
1204 _entity_tag: crate::types::EntityTag,
1205 ) -> Self {
1206 Self::store_unsupported()
1207 }
1208
1209 #[cfg(not(test))]
1211 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1212 Self::store_internal()
1213 }
1214
1215 pub(crate) fn index_unsupported() -> Self {
1217 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1218 }
1219
1220 pub(crate) fn index_component_exceeds_max_size() -> Self {
1222 Self::index_unsupported()
1223 }
1224
1225 pub(crate) fn serialize_unsupported() -> Self {
1227 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1228 }
1229
1230 #[cfg(any(test, feature = "query"))]
1232 pub(crate) fn cursor_invalid_continuation() -> Self {
1233 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1234 }
1235
1236 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1238 Self::new(
1239 ErrorClass::IncompatiblePersistedFormat,
1240 ErrorOrigin::Serialize,
1241 )
1242 }
1243
1244 #[cfg(feature = "sql")]
1247 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1248 Self {
1249 class: ErrorClass::Unsupported,
1250 origin: ErrorOrigin::Query,
1251 detail: Some(ErrorDetail::Query(
1252 QueryErrorDetail::UnsupportedSqlFeature { feature },
1253 )),
1254 }
1255 }
1256
1257 #[cfg(feature = "sql")]
1260 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1261 Self {
1262 class: ErrorClass::Unsupported,
1263 origin: ErrorOrigin::Query,
1264 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1265 }
1266 }
1267
1268 #[cfg(any(test, feature = "query"))]
1271 pub(crate) fn query_unsupported_projection(
1272 reason: diagnostic_code::QueryProjectionCode,
1273 ) -> Self {
1274 Self {
1275 class: ErrorClass::Unsupported,
1276 origin: ErrorOrigin::Query,
1277 detail: Some(ErrorDetail::Query(
1278 QueryErrorDetail::UnsupportedProjection { reason },
1279 )),
1280 }
1281 }
1282
1283 #[cfg(any(test, feature = "query"))]
1285 pub(crate) fn query_unknown_aggregate_target_field() -> Self {
1286 Self {
1287 class: ErrorClass::Unsupported,
1288 origin: ErrorOrigin::Query,
1289 detail: Some(ErrorDetail::Query(
1290 QueryErrorDetail::UnknownAggregateTargetField,
1291 )),
1292 }
1293 }
1294
1295 #[cfg(feature = "sql")]
1298 pub(crate) fn query_sql_surface_mismatch(
1299 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1300 ) -> Self {
1301 Self {
1302 class: ErrorClass::Unsupported,
1303 origin: ErrorOrigin::Query,
1304 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1305 mismatch,
1306 })),
1307 }
1308 }
1309
1310 pub(crate) fn query_sql_write_boundary(
1312 boundary: diagnostic_code::SqlWriteBoundaryCode,
1313 ) -> Self {
1314 Self {
1315 class: ErrorClass::Unsupported,
1316 origin: ErrorOrigin::Query,
1317 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1318 boundary,
1319 })),
1320 }
1321 }
1322
1323 pub fn store_not_found(_key: impl Sized) -> Self {
1324 Self {
1325 class: ErrorClass::NotFound,
1326 origin: ErrorOrigin::Store,
1327 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1328 }
1329 }
1330
1331 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1333 Self::store_unsupported()
1334 }
1335
1336 #[cold]
1338 #[inline(never)]
1339 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1340 Self::new(ErrorClass::Corruption, origin)
1341 }
1342
1343 #[cold]
1345 #[inline(never)]
1346 pub(crate) fn index_plan_index_corruption() -> Self {
1347 Self::index_plan_corruption(ErrorOrigin::Index)
1348 }
1349
1350 #[cold]
1352 #[inline(never)]
1353 pub(crate) fn index_plan_store_corruption() -> Self {
1354 Self::index_plan_corruption(ErrorOrigin::Store)
1355 }
1356
1357 #[cold]
1359 #[inline(never)]
1360 pub(crate) fn index_plan_serialize_corruption() -> Self {
1361 Self::index_plan_corruption(ErrorOrigin::Serialize)
1362 }
1363
1364 #[cfg(test)]
1366 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1367 Self::new(ErrorClass::InvariantViolation, origin)
1368 }
1369
1370 #[cfg(test)]
1372 pub(crate) fn index_plan_store_invariant() -> Self {
1373 Self::index_plan_invariant(ErrorOrigin::Store)
1374 }
1375
1376 pub(crate) fn index_conflict() -> Self {
1382 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1383 }
1384}
1385
1386impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1387 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1388 Self {
1389 class: ErrorClass::Unsupported,
1390 origin: ErrorOrigin::Query,
1391 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1392 reason,
1393 })),
1394 }
1395 }
1396}
1397
1398impl fmt::Debug for InternalError {
1399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1400 fmt_compact_diagnostic(
1401 f,
1402 self.diagnostic_code(),
1403 self.detail
1404 .as_ref()
1405 .and_then(ErrorDetail::diagnostic_detail),
1406 )
1407 }
1408}
1409
1410impl fmt::Display for InternalError {
1411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1412 f.write_str(self.message())
1413 }
1414}
1415
1416impl std::error::Error for InternalError {}
1417
1418#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1426pub enum ConstraintDiagnosticKind {
1427 Check,
1429
1430 NotNull,
1432
1433 Relation,
1435
1436 TargetedRule,
1438
1439 Unique,
1441}
1442
1443impl ConstraintDiagnosticKind {
1444 #[must_use]
1446 pub const fn as_str(self) -> &'static str {
1447 match self {
1448 Self::Check => "check",
1449 Self::NotNull => "not_null",
1450 Self::Relation => "relation",
1451 Self::TargetedRule => "targeted_rule",
1452 Self::Unique => "unique",
1453 }
1454 }
1455}
1456
1457#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1466pub enum ConstraintValuePathComponent {
1467 RootField { field_id: u32 },
1469
1470 RecordMember {
1472 composite_type_id: u32,
1473 member_id: u32,
1474 },
1475
1476 TupleElement {
1478 composite_type_id: u32,
1479 ordinal: u32,
1480 },
1481
1482 Newtype { composite_type_id: u32 },
1484
1485 EnumVariant { enum_type_id: u32, variant_id: u32 },
1487
1488 ListElement { index: u32 },
1490
1491 SetElement { index: u32 },
1493
1494 MapEntryKey { index: u32 },
1496
1497 MapEntryValue { index: u32 },
1499}
1500
1501impl fmt::Display for ConstraintValuePathComponent {
1502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1503 match self {
1504 Self::RootField { field_id } => write!(f, "field#{field_id}"),
1505 Self::RecordMember {
1506 composite_type_id,
1507 member_id,
1508 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
1509 Self::TupleElement {
1510 composite_type_id,
1511 ordinal,
1512 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
1513 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
1514 Self::EnumVariant {
1515 enum_type_id,
1516 variant_id,
1517 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
1518 Self::ListElement { index } => write!(f, "list[{index}]"),
1519 Self::SetElement { index } => write!(f, "set[{index}]"),
1520 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
1521 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
1522 }
1523 }
1524}
1525
1526#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1533pub struct ConstraintValuePath {
1534 components: Vec<ConstraintValuePathComponent>,
1535}
1536
1537impl ConstraintValuePath {
1538 #[must_use]
1540 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
1541 Self { components }
1542 }
1543
1544 #[must_use]
1546 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
1547 self.components.as_slice()
1548 }
1549}
1550
1551impl fmt::Display for ConstraintValuePath {
1552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1553 for (ordinal, component) in self.components.iter().enumerate() {
1554 if ordinal != 0 {
1555 f.write_str("/")?;
1556 }
1557 component.fmt(f)?;
1558 }
1559 Ok(())
1560 }
1561}
1562
1563#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
1571pub enum ConstraintDiagnosticContext {
1572 Integrity,
1574
1575 MigrationValidation,
1577
1578 WriteAdmission,
1580}
1581
1582impl ConstraintDiagnosticContext {
1583 #[must_use]
1585 pub const fn as_str(self) -> &'static str {
1586 match self {
1587 Self::Integrity => "integrity",
1588 Self::MigrationValidation => "migration_validation",
1589 Self::WriteAdmission => "write_admission",
1590 }
1591 }
1592}
1593
1594#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
1603pub struct ConstraintDiagnostic {
1604 constraint_id: u32,
1605 constraint_name: String,
1606 constraint_kind: ConstraintDiagnosticKind,
1607 entity: String,
1608 primary_key: Option<Vec<u8>>,
1609 field_paths: Vec<String>,
1610 value_path: Option<Box<ConstraintValuePath>>,
1611 context: ConstraintDiagnosticContext,
1612 error_code: u16,
1613}
1614
1615impl ConstraintDiagnostic {
1616 #[must_use]
1618 pub(crate) const fn write_violation(
1619 constraint_id: u32,
1620 constraint_name: String,
1621 constraint_kind: ConstraintDiagnosticKind,
1622 entity: String,
1623 primary_key: Option<Vec<u8>>,
1624 field_paths: Vec<String>,
1625 ) -> Self {
1626 Self {
1627 constraint_id,
1628 constraint_name,
1629 constraint_kind,
1630 entity,
1631 primary_key,
1632 field_paths,
1633 value_path: None,
1634 context: ConstraintDiagnosticContext::WriteAdmission,
1635 error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1636 }
1637 }
1638
1639 #[must_use]
1641 pub(crate) fn write_targeted_rule_violation(
1642 constraint_id: u32,
1643 constraint_name: String,
1644 entity: String,
1645 primary_key: Option<Vec<u8>>,
1646 field_paths: Vec<String>,
1647 value_path: ConstraintValuePath,
1648 ) -> Self {
1649 Self {
1650 constraint_id,
1651 constraint_name,
1652 constraint_kind: ConstraintDiagnosticKind::TargetedRule,
1653 entity,
1654 primary_key,
1655 field_paths,
1656 value_path: Some(Box::new(value_path)),
1657 context: ConstraintDiagnosticContext::WriteAdmission,
1658 error_code: diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_VIOLATION.raw(),
1659 }
1660 }
1661
1662 #[must_use]
1664 pub(crate) const fn write_activation_blocked(
1665 constraint_id: u32,
1666 constraint_name: String,
1667 constraint_kind: ConstraintDiagnosticKind,
1668 entity: String,
1669 primary_key: Option<Vec<u8>>,
1670 field_paths: Vec<String>,
1671 ) -> Self {
1672 Self {
1673 constraint_id,
1674 constraint_name,
1675 constraint_kind,
1676 entity,
1677 primary_key,
1678 field_paths,
1679 value_path: None,
1680 context: ConstraintDiagnosticContext::WriteAdmission,
1681 error_code:
1682 diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_CONSTRAINT_ACTIVATION_WRITE_BLOCKED
1683 .raw(),
1684 }
1685 }
1686
1687 #[must_use]
1689 pub(crate) const fn migration_validation(
1690 constraint_id: u32,
1691 constraint_name: String,
1692 constraint_kind: ConstraintDiagnosticKind,
1693 entity: String,
1694 primary_key: Vec<u8>,
1695 field_paths: Vec<String>,
1696 error_code: u16,
1697 ) -> Self {
1698 Self {
1699 constraint_id,
1700 constraint_name,
1701 constraint_kind,
1702 entity,
1703 primary_key: Some(primary_key),
1704 field_paths,
1705 value_path: None,
1706 context: ConstraintDiagnosticContext::MigrationValidation,
1707 error_code,
1708 }
1709 }
1710
1711 #[must_use]
1713 pub(crate) fn migration_targeted_rule_validation(
1714 constraint_id: u32,
1715 constraint_name: String,
1716 entity: String,
1717 primary_key: Vec<u8>,
1718 field_paths: Vec<String>,
1719 value_path: ConstraintValuePath,
1720 error_code: u16,
1721 ) -> Self {
1722 Self {
1723 constraint_id,
1724 constraint_name,
1725 constraint_kind: ConstraintDiagnosticKind::TargetedRule,
1726 entity,
1727 primary_key: Some(primary_key),
1728 field_paths,
1729 value_path: Some(Box::new(value_path)),
1730 context: ConstraintDiagnosticContext::MigrationValidation,
1731 error_code,
1732 }
1733 }
1734
1735 #[must_use]
1737 pub const fn constraint_id(&self) -> u32 {
1738 self.constraint_id
1739 }
1740
1741 #[must_use]
1743 pub const fn constraint_name(&self) -> &str {
1744 self.constraint_name.as_str()
1745 }
1746
1747 #[must_use]
1749 pub const fn constraint_kind(&self) -> ConstraintDiagnosticKind {
1750 self.constraint_kind
1751 }
1752
1753 #[must_use]
1755 pub const fn entity(&self) -> &str {
1756 self.entity.as_str()
1757 }
1758
1759 #[must_use]
1761 pub fn primary_key(&self) -> Option<&[u8]> {
1762 self.primary_key.as_deref()
1763 }
1764
1765 #[must_use]
1767 pub const fn field_paths(&self) -> &[String] {
1768 self.field_paths.as_slice()
1769 }
1770
1771 #[must_use]
1773 pub fn value_path(&self) -> Option<&ConstraintValuePath> {
1774 self.value_path.as_deref()
1775 }
1776
1777 #[must_use]
1779 pub const fn context(&self) -> ConstraintDiagnosticContext {
1780 self.context
1781 }
1782
1783 #[must_use]
1785 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
1786 diagnostic_code::ErrorCode::from_raw(self.error_code)
1787 }
1788
1789 #[must_use]
1791 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
1792 self.error_code().class()
1793 }
1794}
1795
1796pub enum ErrorDetail {
1804 Executor(ExecutorErrorDetail),
1806 Store(StoreError),
1807 Query(QueryErrorDetail),
1808 Recovery(RecoveryErrorDetail),
1809 Serialize(SerializeErrorDetail),
1811 }
1814
1815pub enum ExecutorErrorDetail {
1817 MutationRequiredFieldMissing,
1819 MutationManagedTimestampRegression,
1821 MutationDatabaseOwnedFieldExplicit,
1823 MutationBatchEmpty,
1825 MutationBatchTooManyItems,
1827 MutationBatchStagedBytesExceeded,
1829 MutationBatchResultBytesExceeded,
1831 MutationBatchEntityMismatch,
1833 MutationBatchDuplicateKey,
1835 ConstraintViolation {
1837 diagnostic: Box<ConstraintDiagnostic>,
1838 },
1839 AcceptedRowConstraintProgramCorrupt,
1841 ConstraintActivationWriteBlocked {
1843 diagnostic: Box<ConstraintDiagnostic>,
1844 },
1845}
1846
1847impl ExecutorErrorDetail {
1848 #[must_use]
1850 pub fn constraint_diagnostic(&self) -> Option<&ConstraintDiagnostic> {
1851 match self {
1852 Self::ConstraintActivationWriteBlocked { diagnostic }
1853 | Self::ConstraintViolation { diagnostic } => Some(diagnostic.as_ref()),
1854 Self::MutationRequiredFieldMissing
1855 | Self::MutationManagedTimestampRegression
1856 | Self::MutationDatabaseOwnedFieldExplicit
1857 | Self::MutationBatchEmpty
1858 | Self::MutationBatchTooManyItems
1859 | Self::MutationBatchStagedBytesExceeded
1860 | Self::MutationBatchResultBytesExceeded
1861 | Self::MutationBatchEntityMismatch
1862 | Self::MutationBatchDuplicateKey
1863 | Self::AcceptedRowConstraintProgramCorrupt => None,
1864 }
1865 }
1866}
1867
1868pub enum SerializeErrorDetail {
1870 PersistedRowLayoutOutsideAcceptedWindow,
1872
1873 PersistedRowSlotCountMismatch,
1875}
1876
1877pub enum RecoveryErrorDetail {
1884 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
1885
1886 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
1887}
1888
1889#[derive(Clone, Copy, Eq, PartialEq)]
1891pub enum RecoveryFormatMarkerError {
1892 Magic,
1893 Checksum,
1894 State,
1895}
1896
1897pub enum StoreError {
1905 NotFound,
1906
1907 Corrupt,
1908
1909 InvariantViolation,
1910
1911 SchemaDdlPublicationRaceLost,
1912
1913 SchemaDdlRewriteRequiresMigration,
1914
1915 SchemaRowLayoutVersionExhausted,
1916
1917 JournalMutationRevisionExhausted,
1918
1919 SchemaTransitionBudgetExceeded {
1920 resource: SchemaTransitionBudgetResource,
1921 },
1922
1923 SchemaGeneratedFieldAfterDdlField,
1925
1926 SchemaGeneratedConstraintActivationStale,
1928}
1929
1930pub enum QueryErrorDetail {
1937 NumericOverflow,
1938
1939 NumericNotRepresentable,
1940
1941 UnsupportedSqlFeature {
1942 feature: diagnostic_code::SqlFeatureCode,
1943 },
1944
1945 SqlLowering {
1946 reason: diagnostic_code::SqlLoweringCode,
1947 },
1948
1949 UnsupportedProjection {
1950 reason: diagnostic_code::QueryProjectionCode,
1951 },
1952
1953 UnknownAggregateTargetField,
1954
1955 ResultShapeMismatch {
1956 reason: diagnostic_code::QueryResultShapeCode,
1957 },
1958
1959 QueryReadAdmission {
1960 reason: diagnostic_code::QueryReadAdmissionCode,
1961 },
1962
1963 SqlSurfaceMismatch {
1964 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1965 },
1966
1967 SqlWriteBoundary {
1968 boundary: diagnostic_code::SqlWriteBoundaryCode,
1969 },
1970
1971 SchemaDdlAdmission {
1972 error: SchemaDdlAdmissionError,
1973 },
1974
1975 StaleSchemaRevision,
1976}
1977
1978impl fmt::Display for QueryErrorDetail {
1979 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1980 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
1981 }
1982}
1983
1984impl std::error::Error for QueryErrorDetail {}
1985
1986#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1994pub enum SchemaTransitionBudgetResource {
1995 DeletionKeys,
1997 ProjectionEntries,
1999 ProjectionWorkUnits,
2001 SourceRows,
2003 SourceRowBytes,
2005 StagedRawBytes,
2007}
2008
2009#[derive(Clone, Copy, Eq, PartialEq)]
2018pub enum SchemaDdlAdmissionError {
2019 MissingExpectedSchemaVersion,
2020
2021 MissingNextSchemaVersion,
2022
2023 StaleExpectedSchemaVersion,
2024
2025 InvalidExpectedSchemaVersion,
2026
2027 InvalidNextSchemaVersion,
2028
2029 AcceptedSchemaChangeWithoutVersionBump,
2030
2031 EmptyVersionBump,
2032
2033 VersionGap,
2034
2035 VersionRollback,
2036
2037 FingerprintMethodMismatch,
2038
2039 UnsupportedTransitionClass,
2040
2041 PhysicalRunnerMissing,
2042
2043 ValidationFailed,
2044
2045 PublicationRaceLost,
2046
2047 InvalidAddColumnDefault,
2048
2049 InvalidAlterColumnDefault,
2050
2051 RowLayoutVersionExhausted,
2052
2053 GeneratedIndexDropRejected,
2054
2055 SchemaRewriteRequiresMigration,
2056
2057 SchemaTransitionBudgetExceeded {
2058 resource: SchemaTransitionBudgetResource,
2059 },
2060
2061 GeneratedFieldDefaultChangeRejected,
2062
2063 GeneratedFieldNullabilityChangeRejected,
2064}
2065
2066impl fmt::Display for SchemaDdlAdmissionError {
2067 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2068 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2069 }
2070}
2071
2072impl std::error::Error for SchemaDdlAdmissionError {}
2073
2074impl fmt::Debug for ErrorDetail {
2075 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2076 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2077 }
2078}
2079
2080impl fmt::Debug for ExecutorErrorDetail {
2081 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2082 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2083 }
2084}
2085
2086impl fmt::Debug for StoreError {
2087 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2088 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2089 }
2090}
2091
2092impl fmt::Debug for QueryErrorDetail {
2093 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2094 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2095 }
2096}
2097
2098impl fmt::Debug for RecoveryErrorDetail {
2099 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2100 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2101 }
2102}
2103
2104impl fmt::Debug for SerializeErrorDetail {
2105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2106 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2107 }
2108}
2109
2110impl fmt::Debug for RecoveryFormatMarkerError {
2111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2112 fmt_compact_diagnostic(
2113 f,
2114 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2115 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2116 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2117 }),
2118 )
2119 }
2120}
2121
2122impl fmt::Debug for SchemaDdlAdmissionError {
2123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2124 fmt_compact_diagnostic(
2125 f,
2126 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2127 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2128 reason: self.diagnostic_code(),
2129 }),
2130 )
2131 }
2132}
2133
2134fn fmt_compact_diagnostic(
2135 f: &mut fmt::Formatter<'_>,
2136 code: diagnostic_code::DiagnosticCode,
2137 detail: Option<diagnostic_code::DiagnosticDetail>,
2138) -> fmt::Result {
2139 write!(
2140 f,
2141 "{}",
2142 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2143 )
2144}
2145
2146impl ErrorDetail {
2147 #[must_use]
2149 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2150 match self {
2151 Self::Executor(error) => error.diagnostic_code(),
2152 Self::Store(error) => error.diagnostic_code(),
2153 Self::Query(error) => error.diagnostic_code(),
2154 Self::Recovery(error) => error.diagnostic_code(),
2155 Self::Serialize(error) => error.diagnostic_code(),
2156 }
2157 }
2158
2159 #[must_use]
2161 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2162 match self {
2163 Self::Executor(error) => error.diagnostic_detail(),
2164 Self::Store(error) => error.diagnostic_detail(),
2165 Self::Query(error) => error.diagnostic_detail(),
2166 Self::Recovery(error) => error.diagnostic_detail(),
2167 Self::Serialize(error) => error.diagnostic_detail(),
2168 }
2169 }
2170}
2171
2172impl ExecutorErrorDetail {
2173 #[must_use]
2175 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2176 match self {
2177 Self::MutationRequiredFieldMissing
2178 | Self::MutationDatabaseOwnedFieldExplicit
2179 | Self::MutationBatchEmpty
2180 | Self::MutationBatchTooManyItems
2181 | Self::MutationBatchStagedBytesExceeded
2182 | Self::MutationBatchResultBytesExceeded => {
2183 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2184 }
2185 Self::MutationBatchEntityMismatch | Self::MutationBatchDuplicateKey => {
2186 diagnostic_code::DiagnosticCode::RuntimeConflict
2187 }
2188 Self::MutationManagedTimestampRegression => {
2189 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2190 }
2191 Self::ConstraintViolation { diagnostic }
2192 | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2193 diagnostic.error_code().diagnostic_code()
2194 }
2195 Self::AcceptedRowConstraintProgramCorrupt => {
2196 diagnostic_code::DiagnosticCode::RuntimeCorruption
2197 }
2198 }
2199 }
2200
2201 #[must_use]
2203 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2204 match self {
2205 Self::MutationRequiredFieldMissing => {
2206 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2207 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2208 })
2209 }
2210 Self::MutationDatabaseOwnedFieldExplicit => {
2211 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2212 boundary:
2213 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2214 })
2215 }
2216 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2217 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2218 }),
2219 Self::MutationBatchTooManyItems => {
2220 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2221 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2222 })
2223 }
2224 Self::MutationBatchStagedBytesExceeded => {
2225 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2226 boundary:
2227 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2228 })
2229 }
2230 Self::MutationBatchResultBytesExceeded => {
2231 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2232 boundary:
2233 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2234 })
2235 }
2236 Self::MutationBatchEntityMismatch => {
2237 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2238 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEntityMismatch,
2239 })
2240 }
2241 Self::MutationBatchDuplicateKey => {
2242 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2243 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2244 })
2245 }
2246 Self::MutationManagedTimestampRegression => {
2247 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2248 boundary:
2249 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2250 })
2251 }
2252 Self::ConstraintViolation { diagnostic }
2253 | Self::ConstraintActivationWriteBlocked { diagnostic } => {
2254 diagnostic.error_code().diagnostic_detail()
2255 }
2256 Self::AcceptedRowConstraintProgramCorrupt => {
2257 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2258 boundary:
2259 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2260 })
2261 }
2262 }
2263 }
2264}
2265
2266impl RecoveryErrorDetail {
2267 #[must_use]
2269 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2270 match self {
2271 Self::UnsupportedFormatVersion { .. } => {
2272 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2273 }
2274 Self::MalformedFormatMarker { .. } => {
2275 diagnostic_code::DiagnosticCode::RuntimeCorruption
2276 }
2277 }
2278 }
2279
2280 #[must_use]
2282 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2283 let kind = match self {
2284 Self::UnsupportedFormatVersion { .. } => {
2285 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2286 }
2287 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2288 };
2289
2290 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2291 }
2292}
2293
2294impl SerializeErrorDetail {
2295 #[must_use]
2297 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2298 match self {
2299 Self::PersistedRowLayoutOutsideAcceptedWindow | Self::PersistedRowSlotCountMismatch => {
2300 diagnostic_code::DiagnosticCode::RuntimeCorruption
2301 }
2302 }
2303 }
2304
2305 #[must_use]
2307 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2308 let boundary = match self {
2309 Self::PersistedRowLayoutOutsideAcceptedWindow => {
2310 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow
2311 }
2312 Self::PersistedRowSlotCountMismatch => {
2313 diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch
2314 }
2315 };
2316
2317 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary })
2318 }
2319}
2320
2321impl StoreError {
2322 #[must_use]
2324 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2325 match self {
2326 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2327 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2328 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2329 Self::SchemaDdlPublicationRaceLost
2330 | Self::SchemaDdlRewriteRequiresMigration
2331 | Self::SchemaRowLayoutVersionExhausted
2332 | Self::SchemaTransitionBudgetExceeded { .. } => {
2333 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2334 }
2335 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2336 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2337 }
2338 Self::SchemaGeneratedConstraintActivationStale => {
2339 diagnostic_code::DiagnosticCode::RuntimeConflict
2340 }
2341 }
2342 }
2343
2344 #[must_use]
2346 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2347 match self {
2348 Self::SchemaDdlPublicationRaceLost => {
2349 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2350 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2351 })
2352 }
2353 Self::SchemaDdlRewriteRequiresMigration => {
2354 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2355 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2356 })
2357 }
2358 Self::SchemaRowLayoutVersionExhausted => {
2359 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2360 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2361 })
2362 }
2363 Self::JournalMutationRevisionExhausted => {
2364 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2365 boundary:
2366 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2367 })
2368 }
2369 Self::SchemaTransitionBudgetExceeded { .. } => {
2370 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2371 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2372 })
2373 }
2374 Self::SchemaGeneratedFieldAfterDdlField => {
2375 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2376 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2377 })
2378 }
2379 Self::SchemaGeneratedConstraintActivationStale => {
2380 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2381 boundary:
2382 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2383 })
2384 }
2385 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2386 }
2387 }
2388}
2389
2390impl QueryErrorDetail {
2391 #[must_use]
2393 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2394 match self {
2395 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2396 Self::NumericNotRepresentable => {
2397 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2398 }
2399 Self::UnsupportedSqlFeature { .. } => {
2400 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2401 }
2402 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2403 Self::UnsupportedProjection { .. } => {
2404 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2405 }
2406 Self::UnknownAggregateTargetField => {
2407 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2408 }
2409 Self::ResultShapeMismatch { .. } => {
2410 diagnostic_code::DiagnosticCode::QueryResultShapeMismatch
2411 }
2412 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2413 Self::SqlSurfaceMismatch { .. } => {
2414 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2415 }
2416 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2417 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2418 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2419 }
2420 }
2421
2422 #[must_use]
2424 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2425 match self {
2426 Self::UnsupportedSqlFeature { feature } => {
2427 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2428 }
2429 Self::SqlLowering { reason } => {
2430 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2431 }
2432 Self::UnsupportedProjection { reason } => {
2433 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2434 }
2435 Self::ResultShapeMismatch { reason } => {
2436 Some(diagnostic_code::DiagnosticDetail::QueryResultShape { reason: *reason })
2437 }
2438 Self::QueryReadAdmission { reason } => {
2439 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2440 }
2441 Self::SqlSurfaceMismatch { mismatch } => {
2442 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2443 mismatch: *mismatch,
2444 })
2445 }
2446 Self::SqlWriteBoundary { boundary } => {
2447 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2448 boundary: *boundary,
2449 })
2450 }
2451 Self::SchemaDdlAdmission { error } => {
2452 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2453 reason: error.diagnostic_code(),
2454 })
2455 }
2456 Self::NumericOverflow
2457 | Self::NumericNotRepresentable
2458 | Self::UnknownAggregateTargetField
2459 | Self::StaleSchemaRevision => None,
2460 }
2461 }
2462}
2463
2464impl SchemaDdlAdmissionError {
2465 #[must_use]
2467 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2468 match self {
2469 Self::MissingExpectedSchemaVersion => {
2470 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2471 }
2472 Self::MissingNextSchemaVersion => {
2473 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2474 }
2475 Self::StaleExpectedSchemaVersion => {
2476 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2477 }
2478 Self::InvalidExpectedSchemaVersion => {
2479 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2480 }
2481 Self::InvalidNextSchemaVersion => {
2482 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2483 }
2484 Self::AcceptedSchemaChangeWithoutVersionBump => {
2485 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2486 }
2487 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2488 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2489 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2490 Self::FingerprintMethodMismatch => {
2491 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2492 }
2493 Self::UnsupportedTransitionClass => {
2494 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2495 }
2496 Self::PhysicalRunnerMissing => {
2497 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2498 }
2499 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2500 Self::PublicationRaceLost => {
2501 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2502 }
2503 Self::InvalidAddColumnDefault => {
2504 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2505 }
2506 Self::InvalidAlterColumnDefault => {
2507 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
2508 }
2509 Self::GeneratedIndexDropRejected => {
2510 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
2511 }
2512 Self::SchemaRewriteRequiresMigration => {
2513 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
2514 }
2515 Self::SchemaTransitionBudgetExceeded { .. } => {
2516 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
2517 }
2518 Self::GeneratedFieldDefaultChangeRejected => {
2519 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
2520 }
2521 Self::GeneratedFieldNullabilityChangeRejected => {
2522 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
2523 }
2524 Self::RowLayoutVersionExhausted => {
2525 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
2526 }
2527 }
2528 }
2529}
2530
2531#[repr(u8)]
2538#[derive(Clone, Copy, Eq, PartialEq)]
2539pub enum ErrorClass {
2540 Corruption,
2541 IncompatiblePersistedFormat,
2542 NotFound,
2543 Internal,
2544 Conflict,
2545 Unsupported,
2546 InvariantViolation,
2547}
2548
2549impl ErrorClass {
2550 #[must_use]
2552 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
2553 match self {
2554 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
2555 diagnostic_code::DiagnosticCode::StoreCorruption
2556 }
2557 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
2558 Self::IncompatiblePersistedFormat => {
2559 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2560 }
2561 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
2562 diagnostic_code::DiagnosticCode::StoreNotFound
2563 }
2564 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
2565 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
2566 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
2567 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
2568 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
2569 }
2570 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
2571 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
2572 diagnostic_code::DiagnosticCode::StoreInvariantViolation
2573 }
2574 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
2575 }
2576 }
2577}
2578
2579impl fmt::Debug for ErrorClass {
2580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2581 write!(f, "{}", *self as u8)
2582 }
2583}
2584
2585#[repr(u8)]
2592#[derive(Clone, Copy, Eq, PartialEq)]
2593pub enum ErrorOrigin {
2594 Serialize,
2595 Store,
2596 Index,
2597 Identity,
2598 Query,
2599 Planner,
2600 Cursor,
2601 Recovery,
2602 Response,
2603 Executor,
2604 Interface,
2605}
2606
2607impl ErrorOrigin {
2608 #[must_use]
2610 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
2611 match self {
2612 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
2613 Self::Store => diagnostic_code::ErrorOrigin::Store,
2614 Self::Index => diagnostic_code::ErrorOrigin::Index,
2615 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
2616 Self::Query => diagnostic_code::ErrorOrigin::Query,
2617 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
2618 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
2619 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
2620 Self::Response => diagnostic_code::ErrorOrigin::Response,
2621 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
2622 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
2623 }
2624 }
2625}
2626
2627impl fmt::Debug for ErrorOrigin {
2628 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2629 write!(f, "{}", *self as u8)
2630 }
2631}