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]
2103 pub const fn field_ids(&self) -> &[u32] {
2104 self.field_ids.as_slice()
2105 }
2106
2107 #[must_use]
2109 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2110 self.value_path.as_ref()
2111 }
2112
2113 #[must_use]
2115 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2116 diagnostic_code::ErrorCode::from_raw(self.error_code)
2117 }
2118
2119 #[must_use]
2121 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2122 self.error_code().class()
2123 }
2124}
2125
2126#[derive(Clone)]
2128pub(crate) struct AcceptedConstraintFactContext {
2129 fingerprint_method: u8,
2130 accepted_schema_fingerprint: [u8; 16],
2131 entity_tag: u64,
2132 constraint_id: u32,
2133 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2134 mutation: Option<MutationDiagnosticContext>,
2135 value_path: Option<ConstraintValuePath>,
2136}
2137
2138impl AcceptedConstraintFactContext {
2139 #[must_use]
2140 pub(crate) fn write_admission(
2141 fingerprint_method: u8,
2142 accepted_schema_fingerprint: [u8; 16],
2143 entity_tag: u64,
2144 constraint_id: u32,
2145 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2146 mutation: Option<MutationDiagnosticContext>,
2147 value_path: Option<ConstraintValuePath>,
2148 ) -> Self {
2149 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2150 Self {
2151 fingerprint_method,
2152 accepted_schema_fingerprint,
2153 entity_tag,
2154 constraint_id,
2155 constraint_kind,
2156 mutation,
2157 value_path,
2158 }
2159 }
2160
2161 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2162 let path_len = self
2163 .value_path
2164 .as_ref()
2165 .map_or(0, |path| path.components().len());
2166 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2167 1 + usize::from(mutation.batch_position.is_some())
2168 });
2169 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2170 append_accepted_schema_facts(
2171 &mut facts,
2172 self.fingerprint_method,
2173 self.accepted_schema_fingerprint,
2174 );
2175 facts.push((
2176 diagnostic_code::DiagnosticFactTag::EntityTag,
2177 self.entity_tag,
2178 ));
2179 facts.push((
2180 diagnostic_code::DiagnosticFactTag::ConstraintId,
2181 u64::from(self.constraint_id),
2182 ));
2183 facts.push((
2184 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2185 self.constraint_kind.raw(),
2186 ));
2187 facts.push((
2188 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2189 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2190 ));
2191 if let Some(mutation) = self.mutation {
2192 mutation.append_operation_facts(&mut facts);
2193 }
2194 if let Some(path) = self.value_path {
2195 for component in path.components {
2196 facts.push(constraint_value_path_fact(component));
2197 }
2198 }
2199 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2200 facts
2201 }
2202}
2203
2204fn append_accepted_schema_facts(
2206 facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2207 method: u8,
2208 fingerprint: [u8; 16],
2209) {
2210 facts.extend([
2211 (
2212 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2213 u64::from(method),
2214 ),
2215 (
2216 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2217 u64::from_be_bytes([
2218 fingerprint[0],
2219 fingerprint[1],
2220 fingerprint[2],
2221 fingerprint[3],
2222 fingerprint[4],
2223 fingerprint[5],
2224 fingerprint[6],
2225 fingerprint[7],
2226 ]),
2227 ),
2228 (
2229 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2230 u64::from_be_bytes([
2231 fingerprint[8],
2232 fingerprint[9],
2233 fingerprint[10],
2234 fingerprint[11],
2235 fingerprint[12],
2236 fingerprint[13],
2237 fingerprint[14],
2238 fingerprint[15],
2239 ]),
2240 ),
2241 ]);
2242}
2243
2244fn constraint_value_path_fact(
2245 component: ConstraintValuePathComponent,
2246) -> (diagnostic_code::DiagnosticFactTag, u64) {
2247 use diagnostic_code::DiagnosticFactTag;
2248 match component {
2249 ConstraintValuePathComponent::RootField { field_id } => {
2250 (DiagnosticFactTag::RootField, u64::from(field_id))
2251 }
2252 ConstraintValuePathComponent::RecordMember {
2253 composite_type_id,
2254 member_id,
2255 } => (
2256 DiagnosticFactTag::RecordMember,
2257 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2258 ),
2259 ConstraintValuePathComponent::TupleElement {
2260 composite_type_id,
2261 ordinal,
2262 } => (
2263 DiagnosticFactTag::TupleElement,
2264 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2265 ),
2266 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2267 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2268 }
2269 ConstraintValuePathComponent::EnumVariant {
2270 enum_type_id,
2271 variant_id,
2272 } => (
2273 DiagnosticFactTag::EnumVariant,
2274 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2275 ),
2276 ConstraintValuePathComponent::ListElement { index } => {
2277 (DiagnosticFactTag::ListElement, u64::from(index))
2278 }
2279 ConstraintValuePathComponent::SetElement { index } => {
2280 (DiagnosticFactTag::SetElement, u64::from(index))
2281 }
2282 ConstraintValuePathComponent::MapEntryKey { index } => {
2283 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2284 }
2285 ConstraintValuePathComponent::MapEntryValue { index } => {
2286 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2287 }
2288 }
2289}
2290
2291pub enum ErrorDetail {
2299 DiagnosticFacts(Box<DiagnosticFactDetail>),
2301 Executor(ExecutorErrorDetail),
2303 Store(StoreError),
2304 Query(QueryErrorDetail),
2305 Recovery(RecoveryErrorDetail),
2306 }
2309
2310pub enum ExecutorErrorDetail {
2312 MutationRequiredFieldMissing,
2314 MutationManagedTimestampRegression,
2316 MutationDatabaseOwnedFieldExplicit,
2318 MutationBatchEmpty,
2320 MutationBatchTooManyItems,
2322 MutationBatchStagedBytesExceeded,
2324 MutationBatchResultBytesExceeded,
2326 MutationBatchStoreMismatch,
2328 MutationBatchTooManyEntities,
2330 MutationBatchDuplicateKey,
2332 AcceptedRowConstraintProgramCorrupt,
2334}
2335
2336pub enum RecoveryErrorDetail {
2343 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2344
2345 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2346}
2347
2348#[derive(Clone, Copy, Eq, PartialEq)]
2350pub enum RecoveryFormatMarkerError {
2351 Magic,
2352 Checksum,
2353 State,
2354}
2355
2356impl RecoveryFormatMarkerError {
2357 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2358 match self {
2359 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2360 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2361 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2362 }
2363 }
2364}
2365
2366pub enum StoreError {
2374 NotFound,
2375
2376 Corrupt,
2377
2378 InvariantViolation,
2379
2380 SchemaDdlPublicationRaceLost,
2381
2382 SchemaDdlRewriteRequiresMigration,
2383
2384 SchemaMigration {
2385 reason: diagnostic_code::SchemaMigrationCode,
2386 },
2387
2388 SchemaRowLayoutVersionExhausted,
2389
2390 JournalMutationRevisionExhausted,
2391
2392 SchemaTransitionBudgetExceeded {
2393 resource: SchemaTransitionBudgetResource,
2394 },
2395
2396 SchemaGeneratedFieldAfterDdlField,
2398
2399 SchemaGeneratedConstraintActivationStale,
2401}
2402
2403pub enum QueryErrorDetail {
2410 ExactCountMetadataUnavailable,
2412
2413 NumericOverflow,
2414
2415 NumericNotRepresentable,
2416
2417 UnsupportedSqlFeature {
2418 feature: diagnostic_code::SqlFeatureCode,
2419 },
2420
2421 SqlLowering {
2422 reason: diagnostic_code::SqlLoweringCode,
2423 },
2424
2425 UnsupportedProjection {
2426 reason: diagnostic_code::QueryProjectionCode,
2427 },
2428
2429 UnknownAggregateTargetField,
2430
2431 QueryReadAdmission {
2432 reason: diagnostic_code::QueryReadAdmissionCode,
2433 },
2434
2435 SqlSurfaceMismatch {
2436 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2437 },
2438
2439 SqlWriteBoundary {
2440 boundary: diagnostic_code::SqlWriteBoundaryCode,
2441 },
2442
2443 SchemaDdlAdmission {
2444 error: SchemaDdlAdmissionError,
2445 },
2446
2447 StaleSchemaRevision,
2448}
2449
2450impl fmt::Display for QueryErrorDetail {
2451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2452 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2453 }
2454}
2455
2456impl std::error::Error for QueryErrorDetail {}
2457
2458#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2466pub enum SchemaTransitionBudgetResource {
2467 DeletionKeys,
2469 ProjectionEntries,
2471 ProjectionWorkUnits,
2473 SourceRows,
2475 SourceRowBytes,
2477 StagedRawBytes,
2479}
2480
2481#[derive(Clone, Copy, Eq, PartialEq)]
2490pub enum SchemaDdlAdmissionError {
2491 MissingExpectedSchemaVersion,
2492
2493 MissingNextSchemaVersion,
2494
2495 StaleExpectedSchemaVersion,
2496
2497 InvalidExpectedSchemaVersion,
2498
2499 InvalidNextSchemaVersion,
2500
2501 AcceptedSchemaChangeWithoutVersionBump,
2502
2503 EmptyVersionBump,
2504
2505 VersionGap,
2506
2507 VersionRollback,
2508
2509 FingerprintMethodMismatch,
2510
2511 UnsupportedTransitionClass,
2512
2513 PhysicalRunnerMissing,
2514
2515 ValidationFailed,
2516
2517 PublicationRaceLost,
2518
2519 InvalidAddColumnDefault,
2520
2521 InvalidAlterColumnDefault,
2522
2523 RowLayoutVersionExhausted,
2524
2525 GeneratedIndexDropRejected,
2526
2527 SchemaRewriteRequiresMigration,
2528
2529 SchemaTransitionBudgetExceeded {
2530 resource: SchemaTransitionBudgetResource,
2531 },
2532
2533 GeneratedFieldDefaultChangeRejected,
2534
2535 GeneratedFieldNullabilityChangeRejected,
2536}
2537
2538impl fmt::Display for SchemaDdlAdmissionError {
2539 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2540 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2541 }
2542}
2543
2544impl std::error::Error for SchemaDdlAdmissionError {}
2545
2546impl fmt::Debug for ErrorDetail {
2547 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2548 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2549 }
2550}
2551
2552impl fmt::Debug for ExecutorErrorDetail {
2553 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2554 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2555 }
2556}
2557
2558impl fmt::Debug for StoreError {
2559 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2560 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2561 }
2562}
2563
2564impl fmt::Debug for QueryErrorDetail {
2565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2566 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2567 }
2568}
2569
2570impl fmt::Debug for RecoveryErrorDetail {
2571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2572 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2573 }
2574}
2575
2576impl fmt::Debug for RecoveryFormatMarkerError {
2577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2578 fmt_compact_diagnostic(
2579 f,
2580 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2581 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2582 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2583 }),
2584 )
2585 }
2586}
2587
2588impl fmt::Debug for SchemaDdlAdmissionError {
2589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2590 fmt_compact_diagnostic(
2591 f,
2592 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2593 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2594 reason: self.diagnostic_code(),
2595 }),
2596 )
2597 }
2598}
2599
2600fn fmt_compact_diagnostic(
2601 f: &mut fmt::Formatter<'_>,
2602 code: diagnostic_code::DiagnosticCode,
2603 detail: Option<diagnostic_code::DiagnosticDetail>,
2604) -> fmt::Result {
2605 write!(
2606 f,
2607 "{}",
2608 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2609 )
2610}
2611
2612impl ErrorDetail {
2613 #[must_use]
2615 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2616 match self {
2617 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2618 Self::Executor(error) => error.diagnostic_code(),
2619 Self::Store(error) => error.diagnostic_code(),
2620 Self::Query(error) => error.diagnostic_code(),
2621 Self::Recovery(error) => error.diagnostic_code(),
2622 }
2623 }
2624
2625 #[must_use]
2627 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2628 match self {
2629 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2630 Self::Executor(error) => error.diagnostic_detail(),
2631 Self::Store(error) => error.diagnostic_detail(),
2632 Self::Query(error) => error.diagnostic_detail(),
2633 Self::Recovery(error) => error.diagnostic_detail(),
2634 }
2635 }
2636
2637 #[must_use]
2639 #[cold]
2640 #[inline(never)]
2641 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2642 match self {
2643 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2644 Self::Executor(error) => error.diagnostic_facts(),
2645 Self::Query(error) => error.diagnostic_facts(),
2646 Self::Recovery(error) => error.diagnostic_facts(),
2647 Self::Store(_) => Vec::new(),
2648 }
2649 }
2650}
2651
2652impl ExecutorErrorDetail {
2653 #[must_use]
2655 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2656 match self {
2657 Self::MutationRequiredFieldMissing
2658 | Self::MutationDatabaseOwnedFieldExplicit
2659 | Self::MutationBatchEmpty
2660 | Self::MutationBatchTooManyItems
2661 | Self::MutationBatchTooManyEntities
2662 | Self::MutationBatchStagedBytesExceeded
2663 | Self::MutationBatchResultBytesExceeded => {
2664 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2665 }
2666 Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2667 diagnostic_code::DiagnosticCode::RuntimeConflict
2668 }
2669 Self::MutationManagedTimestampRegression => {
2670 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2671 }
2672 Self::AcceptedRowConstraintProgramCorrupt => {
2673 diagnostic_code::DiagnosticCode::RuntimeCorruption
2674 }
2675 }
2676 }
2677
2678 #[must_use]
2680 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2681 match self {
2682 Self::MutationRequiredFieldMissing => {
2683 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2684 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2685 })
2686 }
2687 Self::MutationDatabaseOwnedFieldExplicit => {
2688 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2689 boundary:
2690 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2691 })
2692 }
2693 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2694 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2695 }),
2696 Self::MutationBatchTooManyItems => {
2697 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2698 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2699 })
2700 }
2701 Self::MutationBatchStagedBytesExceeded => {
2702 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2703 boundary:
2704 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2705 })
2706 }
2707 Self::MutationBatchResultBytesExceeded => {
2708 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2709 boundary:
2710 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2711 })
2712 }
2713 Self::MutationBatchStoreMismatch => {
2714 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2715 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2716 })
2717 }
2718 Self::MutationBatchTooManyEntities => {
2719 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2720 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2721 })
2722 }
2723 Self::MutationBatchDuplicateKey => {
2724 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2725 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2726 })
2727 }
2728 Self::MutationManagedTimestampRegression => {
2729 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2730 boundary:
2731 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2732 })
2733 }
2734 Self::AcceptedRowConstraintProgramCorrupt => {
2735 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2736 boundary:
2737 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2738 })
2739 }
2740 }
2741 }
2742
2743 #[must_use]
2745 #[cold]
2746 #[inline(never)]
2747 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2748 Vec::new()
2749 }
2750}
2751
2752impl RecoveryErrorDetail {
2753 #[must_use]
2755 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2756 match self {
2757 Self::UnsupportedFormatVersion { .. } => {
2758 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2759 }
2760 Self::MalformedFormatMarker { .. } => {
2761 diagnostic_code::DiagnosticCode::RuntimeCorruption
2762 }
2763 }
2764 }
2765
2766 #[must_use]
2768 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2769 let kind = match self {
2770 Self::UnsupportedFormatVersion { .. } => {
2771 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2772 }
2773 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2774 };
2775
2776 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2777 }
2778
2779 #[must_use]
2781 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2782 match self {
2783 Self::UnsupportedFormatVersion { found, required } => {
2784 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2785 facts.push((
2786 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2787 u64::from(*required),
2788 ));
2789 if let Some(found) = found {
2790 facts.push((
2791 diagnostic_code::DiagnosticFactTag::ActualVersion,
2792 u64::from(*found),
2793 ));
2794 }
2795 facts
2796 }
2797 Self::MalformedFormatMarker { reason } => vec![(
2798 diagnostic_code::DiagnosticFactTag::DecodeReason,
2799 reason.diagnostic_decode_reason().raw(),
2800 )],
2801 }
2802 }
2803}
2804
2805impl StoreError {
2806 #[must_use]
2808 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2809 match self {
2810 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2811 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2812 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2813 Self::SchemaDdlPublicationRaceLost
2814 | Self::SchemaDdlRewriteRequiresMigration
2815 | Self::SchemaRowLayoutVersionExhausted
2816 | Self::SchemaTransitionBudgetExceeded { .. } => {
2817 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2818 }
2819 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2820 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2821 }
2822 Self::SchemaGeneratedConstraintActivationStale => {
2823 diagnostic_code::DiagnosticCode::RuntimeConflict
2824 }
2825 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2826 }
2827 }
2828
2829 #[must_use]
2831 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2832 match self {
2833 Self::SchemaDdlPublicationRaceLost => {
2834 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2835 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2836 })
2837 }
2838 Self::SchemaDdlRewriteRequiresMigration => {
2839 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2840 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2841 })
2842 }
2843 Self::SchemaMigration { reason } => {
2844 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2845 }
2846 Self::SchemaRowLayoutVersionExhausted => {
2847 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2848 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2849 })
2850 }
2851 Self::JournalMutationRevisionExhausted => {
2852 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2853 boundary:
2854 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2855 })
2856 }
2857 Self::SchemaTransitionBudgetExceeded { .. } => {
2858 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2859 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2860 })
2861 }
2862 Self::SchemaGeneratedFieldAfterDdlField => {
2863 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2864 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2865 })
2866 }
2867 Self::SchemaGeneratedConstraintActivationStale => {
2868 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2869 boundary:
2870 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2871 })
2872 }
2873 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2874 }
2875 }
2876}
2877
2878impl QueryErrorDetail {
2879 #[must_use]
2881 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2882 match self {
2883 Self::ExactCountMetadataUnavailable => {
2884 diagnostic_code::DiagnosticCode::QueryExactCountMetadataUnavailable
2885 }
2886 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2887 Self::NumericNotRepresentable => {
2888 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2889 }
2890 Self::UnsupportedSqlFeature { .. } => {
2891 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2892 }
2893 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2894 Self::UnsupportedProjection { .. } => {
2895 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2896 }
2897 Self::UnknownAggregateTargetField => {
2898 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2899 }
2900 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2901 Self::SqlSurfaceMismatch { .. } => {
2902 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2903 }
2904 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2905 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2906 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2907 }
2908 }
2909
2910 #[must_use]
2912 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2913 match self {
2914 Self::UnsupportedSqlFeature { feature } => {
2915 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2916 }
2917 Self::SqlLowering { reason } => {
2918 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2919 }
2920 Self::UnsupportedProjection { reason } => {
2921 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2922 }
2923 Self::QueryReadAdmission { reason } => {
2924 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2925 }
2926 Self::SqlSurfaceMismatch { mismatch } => {
2927 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2928 mismatch: *mismatch,
2929 })
2930 }
2931 Self::SqlWriteBoundary { boundary } => {
2932 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2933 boundary: *boundary,
2934 })
2935 }
2936 Self::SchemaDdlAdmission { error } => {
2937 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2938 reason: error.diagnostic_code(),
2939 })
2940 }
2941 Self::ExactCountMetadataUnavailable
2942 | Self::NumericOverflow
2943 | Self::NumericNotRepresentable
2944 | Self::UnknownAggregateTargetField
2945 | Self::StaleSchemaRevision => None,
2946 }
2947 }
2948
2949 #[must_use]
2951 #[cold]
2952 #[inline(never)]
2953 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2954 Vec::new()
2955 }
2956}
2957
2958impl SchemaDdlAdmissionError {
2959 #[must_use]
2961 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2962 match self {
2963 Self::MissingExpectedSchemaVersion => {
2964 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2965 }
2966 Self::MissingNextSchemaVersion => {
2967 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2968 }
2969 Self::StaleExpectedSchemaVersion => {
2970 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2971 }
2972 Self::InvalidExpectedSchemaVersion => {
2973 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2974 }
2975 Self::InvalidNextSchemaVersion => {
2976 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
2977 }
2978 Self::AcceptedSchemaChangeWithoutVersionBump => {
2979 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
2980 }
2981 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
2982 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
2983 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
2984 Self::FingerprintMethodMismatch => {
2985 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
2986 }
2987 Self::UnsupportedTransitionClass => {
2988 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
2989 }
2990 Self::PhysicalRunnerMissing => {
2991 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
2992 }
2993 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
2994 Self::PublicationRaceLost => {
2995 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
2996 }
2997 Self::InvalidAddColumnDefault => {
2998 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
2999 }
3000 Self::InvalidAlterColumnDefault => {
3001 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3002 }
3003 Self::GeneratedIndexDropRejected => {
3004 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3005 }
3006 Self::SchemaRewriteRequiresMigration => {
3007 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3008 }
3009 Self::SchemaTransitionBudgetExceeded { .. } => {
3010 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3011 }
3012 Self::GeneratedFieldDefaultChangeRejected => {
3013 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3014 }
3015 Self::GeneratedFieldNullabilityChangeRejected => {
3016 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3017 }
3018 Self::RowLayoutVersionExhausted => {
3019 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3020 }
3021 }
3022 }
3023}
3024
3025#[repr(u8)]
3032#[derive(Clone, Copy, Eq, PartialEq)]
3033pub enum ErrorClass {
3034 Corruption,
3035 IncompatiblePersistedFormat,
3036 NotFound,
3037 Internal,
3038 Conflict,
3039 Unsupported,
3040 InvariantViolation,
3041}
3042
3043impl ErrorClass {
3044 #[must_use]
3046 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3047 match self {
3048 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3049 diagnostic_code::DiagnosticCode::StoreCorruption
3050 }
3051 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3052 Self::IncompatiblePersistedFormat => {
3053 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3054 }
3055 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3056 diagnostic_code::DiagnosticCode::StoreNotFound
3057 }
3058 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3059 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3060 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3061 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3062 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3063 }
3064 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3065 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3066 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3067 }
3068 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3069 }
3070 }
3071}
3072
3073impl fmt::Debug for ErrorClass {
3074 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3075 write!(f, "{}", *self as u8)
3076 }
3077}
3078
3079#[repr(u8)]
3086#[derive(Clone, Copy, Eq, PartialEq)]
3087pub enum ErrorOrigin {
3088 Serialize,
3089 Store,
3090 Index,
3091 Identity,
3092 Query,
3093 Planner,
3094 Cursor,
3095 Recovery,
3096 Response,
3097 Executor,
3098 Interface,
3099}
3100
3101impl ErrorOrigin {
3102 #[must_use]
3104 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3105 match self {
3106 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3107 Self::Store => diagnostic_code::ErrorOrigin::Store,
3108 Self::Index => diagnostic_code::ErrorOrigin::Index,
3109 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3110 Self::Query => diagnostic_code::ErrorOrigin::Query,
3111 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3112 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3113 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3114 Self::Response => diagnostic_code::ErrorOrigin::Response,
3115 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3116 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3117 }
3118 }
3119}
3120
3121impl fmt::Debug for ErrorOrigin {
3122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3123 write!(f, "{}", *self as u8)
3124 }
3125}