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