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