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 pub(crate) fn with_grouped_limit(
453 self,
454 resource: diagnostic_code::DiagnosticGroupBudgetResource,
455 ) -> Self {
456 let diagnostic = self.diagnostic();
457 if diagnostic.error_code()
458 != diagnostic_code::ErrorCode::RUNTIME_BOUNDARY_EXECUTION_BUDGET_EXCEEDED
459 {
460 return self;
461 }
462 let mut facts = self.diagnostic_facts();
463 facts.push((
464 diagnostic_code::DiagnosticFactTag::GroupedLimit,
465 resource.raw(),
466 ));
467 Self::with_diagnostic_facts(self.class, self.origin, diagnostic.detail().copied(), facts)
468 }
469
470 #[cold]
472 #[inline(never)]
473 pub(crate) fn relation_budget_exceeded(
474 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
475 limit: u64,
476 observed: u64,
477 ) -> Self {
478 Self::execution_budget_exceeded(
479 resource,
480 limit,
481 observed,
482 diagnostic_code::DiagnosticExecutionBudgetScope::Execution,
483 diagnostic_code::DiagnosticExecutionLane::Mutation,
484 0,
485 )
486 }
487
488 #[cold]
490 #[inline(never)]
491 pub(crate) fn page_unit_too_large(
492 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
493 limit: u64,
494 attempted: u64,
495 ) -> Self {
496 Self::with_diagnostic_facts(
497 ErrorClass::Unsupported,
498 ErrorOrigin::Executor,
499 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
500 boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
501 }),
502 vec![
503 (
504 diagnostic_code::DiagnosticFactTag::BudgetResource,
505 resource.raw(),
506 ),
507 (diagnostic_code::DiagnosticFactTag::Limit, limit),
508 (diagnostic_code::DiagnosticFactTag::Actual, attempted),
509 ],
510 )
511 }
512
513 #[cold]
519 #[inline(never)]
520 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
521 match self.detail {
522 Some(ErrorDetail::DiagnosticFacts(mut detail)) => {
523 let leaf = detail.diagnostic.detail().copied();
524 let code = leaf.map_or_else(
525 || self.class.diagnostic_code(origin),
526 diagnostic_code::DiagnosticDetail::diagnostic_code,
527 );
528 let diagnostic =
529 diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), leaf);
530 if diagnostic_code::validate_known_diagnostic_fact_schema(
533 diagnostic.error_code(),
534 &detail.facts,
535 )
536 .is_err()
537 {
538 return Self::classified(self.class, origin);
539 }
540 detail.diagnostic = diagnostic;
541
542 Self {
543 class: self.class,
544 origin,
545 detail: Some(ErrorDetail::DiagnosticFacts(detail)),
546 }
547 }
548 _ => Self::classified(self.class, origin),
549 }
550 }
551
552 #[cold]
554 #[inline(never)]
555 pub(crate) fn index_invariant() -> Self {
556 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
557 }
558
559 pub(crate) fn index_key_field_count_exceeds_max(
561 entity_tag: u64,
562 physical_generation: u64,
563 field_count: usize,
564 max_fields: usize,
565 ) -> Self {
566 Self::with_diagnostic_facts(
567 ErrorClass::InvariantViolation,
568 ErrorOrigin::Index,
569 None,
570 vec![
571 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
572 (
573 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
574 physical_generation,
575 ),
576 (
577 diagnostic_code::DiagnosticFactTag::ComponentKind,
578 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
579 ),
580 (
581 diagnostic_code::DiagnosticFactTag::ActualArity,
582 field_count as u64,
583 ),
584 (
585 diagnostic_code::DiagnosticFactTag::Maximum,
586 max_fields as u64,
587 ),
588 ],
589 )
590 }
591
592 #[cold]
595 #[inline(never)]
596 pub(crate) fn planner_executor_invariant() -> Self {
597 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
598 }
599
600 #[cold]
603 #[inline(never)]
604 pub(crate) fn query_executor_invariant() -> Self {
605 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
606 }
607
608 #[cold]
611 #[inline(never)]
612 pub(crate) fn cursor_executor_invariant() -> Self {
613 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
614 }
615
616 #[cold]
618 #[inline(never)]
619 pub(crate) fn executor_invariant() -> Self {
620 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
621 }
622
623 #[cold]
625 #[inline(never)]
626 pub(crate) fn executor_internal() -> Self {
627 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
628 }
629
630 #[cold]
632 #[inline(never)]
633 pub(crate) fn executor_unsupported() -> Self {
634 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
635 }
636
637 #[cold]
639 #[inline(never)]
640 pub(crate) fn mutation_database_owned_field_explicit(
641 context: MutationDiagnosticContext,
642 field_id: u32,
643 ) -> Self {
644 Self::mutation_boundary_with_facts(
645 ErrorClass::Unsupported,
646 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
647 context.facts(Some(field_id)),
648 )
649 }
650
651 #[must_use]
653 #[cold]
654 #[inline(never)]
655 pub(crate) fn mutation_required_field_missing(
656 context: MutationDiagnosticContext,
657 field_id: u32,
658 ) -> Self {
659 Self::mutation_boundary_with_facts(
660 ErrorClass::Unsupported,
661 diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
662 context.facts(Some(field_id)),
663 )
664 }
665
666 #[must_use]
668 #[cold]
669 #[inline(never)]
670 pub(crate) fn mutation_managed_timestamp_regression(
671 context: MutationDiagnosticContext,
672 ) -> Self {
673 Self::mutation_boundary_with_facts(
674 ErrorClass::InvariantViolation,
675 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
676 context.facts(None),
677 )
678 }
679
680 pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
682 Self::mutation_boundary_with_facts(
683 ErrorClass::InvariantViolation,
684 diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
685 context.facts(),
686 )
687 }
688
689 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
691 Self {
692 class: ErrorClass::Corruption,
693 origin: ErrorOrigin::Executor,
694 detail: Some(ErrorDetail::Executor(
695 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
696 )),
697 }
698 }
699
700 pub(crate) fn mutation_constraint_activation_write_blocked(
702 context: AcceptedConstraintFactContext,
703 ) -> Self {
704 Self::mutation_boundary_with_facts(
705 ErrorClass::Conflict,
706 diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
707 context.facts(),
708 )
709 }
710
711 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
713 Self::query_executor_invariant()
714 }
715
716 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
718 Self::query_executor_invariant()
719 }
720
721 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
723 Self::query_executor_invariant()
724 }
725
726 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
728 Self::query_executor_invariant()
729 }
730
731 pub(crate) fn index_range_limit_spec_required() -> Self {
733 Self::query_executor_invariant()
734 }
735
736 #[cold]
738 #[inline(never)]
739 pub(crate) fn mutation_atomic_save_duplicate_key(
740 entity_tag: u64,
741 first_position: u32,
742 duplicate_position: u32,
743 ) -> Self {
744 Self::mutation_boundary_with_facts(
745 ErrorClass::Conflict,
746 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
747 vec![
748 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
749 (
750 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
751 u64::from(first_position),
752 ),
753 (
754 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
755 u64::from(duplicate_position),
756 ),
757 ],
758 )
759 }
760
761 #[cold]
763 #[inline(never)]
764 pub(crate) fn mutation_batch_empty() -> Self {
765 Self::mutation_boundary_with_facts(
766 ErrorClass::Unsupported,
767 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
768 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
769 )
770 }
771
772 #[cold]
774 #[inline(never)]
775 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
776 Self::mutation_boundary_with_facts(
777 ErrorClass::Unsupported,
778 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
779 vec![
780 (
781 diagnostic_code::DiagnosticFactTag::ActualCount,
782 actual_count as u64,
783 ),
784 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
785 ],
786 )
787 }
788
789 #[cold]
791 #[inline(never)]
792 pub(crate) fn mutation_batch_staged_bytes_exceeded(
793 actual_bytes: Option<usize>,
794 limit: usize,
795 ) -> Self {
796 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
797 if let Some(actual_bytes) = actual_bytes {
798 facts.push((
799 diagnostic_code::DiagnosticFactTag::ActualLength,
800 actual_bytes as u64,
801 ));
802 }
803 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
804 Self::mutation_boundary_with_facts(
805 ErrorClass::Unsupported,
806 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
807 facts,
808 )
809 }
810
811 #[cold]
813 #[inline(never)]
814 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
815 Self::mutation_boundary_with_facts(
816 ErrorClass::Unsupported,
817 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
818 vec![
819 (
820 diagnostic_code::DiagnosticFactTag::ActualLength,
821 actual_bytes as u64,
822 ),
823 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
824 ],
825 )
826 }
827
828 #[cold]
830 #[inline(never)]
831 pub(crate) fn mutation_batch_commit_work_exceeded(
832 actual_units: Option<usize>,
833 limit: usize,
834 ) -> Self {
835 let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
836 if let Some(actual_units) = actual_units {
837 facts.push((
838 diagnostic_code::DiagnosticFactTag::ActualCount,
839 actual_units as u64,
840 ));
841 }
842 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
843 Self::mutation_boundary_with_facts(
844 ErrorClass::Unsupported,
845 diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
846 facts,
847 )
848 }
849
850 pub(crate) fn convergence_backlog_pressure(
852 resource: diagnostic_code::DiagnosticBacklogResource,
853 current: u64,
854 proposed: u64,
855 limit: u64,
856 ) -> Self {
857 Self::mutation_boundary_with_facts(
858 ErrorClass::Conflict,
859 diagnostic_code::RuntimeBoundaryCode::ConvergenceBacklogPressure,
860 vec![
861 (
862 diagnostic_code::DiagnosticFactTag::BacklogResource,
863 resource.raw(),
864 ),
865 (diagnostic_code::DiagnosticFactTag::CurrentCount, current),
866 (diagnostic_code::DiagnosticFactTag::ProposedCount, proposed),
867 (diagnostic_code::DiagnosticFactTag::Limit, limit),
868 ],
869 )
870 }
871
872 #[cold]
874 #[inline(never)]
875 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
876 Self::exact_key_batch_boundary_with_facts(
877 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
878 vec![
879 (
880 diagnostic_code::DiagnosticFactTag::ActualCount,
881 actual_count as u64,
882 ),
883 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
884 ],
885 )
886 }
887
888 #[cold]
890 #[inline(never)]
891 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
892 Self::exact_key_batch_bytes_exceeded(
893 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
894 actual_bytes,
895 limit,
896 )
897 }
898
899 #[cold]
901 #[inline(never)]
902 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
903 Self::exact_key_batch_bytes_exceeded(
904 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
905 actual_bytes,
906 limit,
907 )
908 }
909
910 #[cold]
912 #[inline(never)]
913 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
914 Self::exact_key_batch_bytes_exceeded(
915 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
916 actual_bytes,
917 limit,
918 )
919 }
920
921 #[cold]
922 #[inline(never)]
923 fn exact_key_batch_bytes_exceeded(
924 boundary: diagnostic_code::RuntimeBoundaryCode,
925 actual_bytes: usize,
926 limit: usize,
927 ) -> Self {
928 Self::exact_key_batch_boundary_with_facts(
929 boundary,
930 vec![
931 (
932 diagnostic_code::DiagnosticFactTag::ActualLength,
933 actual_bytes as u64,
934 ),
935 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
936 ],
937 )
938 }
939
940 #[cold]
942 #[inline(never)]
943 pub(crate) fn mutation_batch_store_mismatch(
944 batch_position: u32,
945 expected_entity_tag: u64,
946 actual_entity_tag: u64,
947 ) -> Self {
948 Self::mutation_boundary_with_facts(
949 ErrorClass::Conflict,
950 diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
951 vec![
952 (
953 diagnostic_code::DiagnosticFactTag::BatchPosition,
954 u64::from(batch_position),
955 ),
956 (
957 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
958 expected_entity_tag,
959 ),
960 (
961 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
962 actual_entity_tag,
963 ),
964 ],
965 )
966 }
967
968 #[cold]
970 #[inline(never)]
971 pub(crate) fn mutation_batch_too_many_entities(actual_count: usize, limit: usize) -> Self {
972 Self::mutation_boundary_with_facts(
973 ErrorClass::Unsupported,
974 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
975 vec![
976 (
977 diagnostic_code::DiagnosticFactTag::ActualCount,
978 actual_count as u64,
979 ),
980 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
981 ],
982 )
983 }
984
985 #[cold]
987 #[inline(never)]
988 pub(crate) fn planner_invariant() -> Self {
989 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
990 }
991
992 pub(crate) fn query_invalid_logical_plan() -> Self {
994 Self::planner_invariant()
995 }
996
997 pub(crate) fn store_invariant() -> Self {
999 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
1000 }
1001
1002 #[cold]
1004 #[inline(never)]
1005 pub(crate) fn store_internal() -> Self {
1006 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
1007 }
1008
1009 pub(crate) fn commit_memory_id_unconfigured() -> Self {
1011 Self::store_internal()
1012 }
1013
1014 pub(crate) fn commit_store_uninitialized() -> Self {
1016 Self::store_invariant()
1017 }
1018
1019 pub(crate) fn database_incarnation_generation_failed() -> Self {
1021 Self::store_internal()
1022 }
1023
1024 pub(crate) fn database_incarnation_invalid() -> Self {
1026 Self::store_corruption()
1027 }
1028
1029 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
1031 Self {
1032 class: ErrorClass::IncompatiblePersistedFormat,
1033 origin: ErrorOrigin::Recovery,
1034 detail: Some(ErrorDetail::Recovery(
1035 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
1036 )),
1037 }
1038 }
1039
1040 pub(crate) fn recovery_malformed_database_format_marker(
1042 reason: RecoveryFormatMarkerError,
1043 ) -> Self {
1044 Self {
1045 class: ErrorClass::Corruption,
1046 origin: ErrorOrigin::Recovery,
1047 detail: Some(ErrorDetail::Recovery(
1048 RecoveryErrorDetail::MalformedFormatMarker { reason },
1049 )),
1050 }
1051 }
1052
1053 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1055 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1056 }
1057
1058 pub(crate) fn recovery_pending() -> Self {
1060 Self::with_diagnostic_facts(
1061 ErrorClass::Conflict,
1062 ErrorOrigin::Recovery,
1063 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1064 boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1065 }),
1066 Vec::new(),
1067 )
1068 }
1069
1070 pub(crate) fn startup_control_corruption() -> Self {
1072 Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1073 }
1074
1075 pub(crate) fn commit_control_memory_growth_failed() -> Self {
1077 Self::store_internal()
1078 }
1079
1080 pub(crate) fn recovery_effect_verification_failed() -> Self {
1082 Self::store_corruption()
1083 }
1084
1085 #[cold]
1087 #[inline(never)]
1088 pub(crate) fn index_internal() -> Self {
1089 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1090 }
1091
1092 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1094 Self::index_internal()
1095 }
1096
1097 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1099 Self::index_internal()
1100 }
1101
1102 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1104 Self::index_internal()
1105 }
1106
1107 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1109 Self::index_internal()
1110 }
1111
1112 #[cfg(test)]
1114 pub(crate) fn query_internal() -> Self {
1115 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1116 }
1117
1118 #[cold]
1120 #[inline(never)]
1121 pub(crate) fn query_unsupported() -> Self {
1122 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1123 }
1124
1125 #[cold]
1127 #[inline(never)]
1128 pub(crate) fn query_exact_count_metadata_unavailable() -> Self {
1129 Self {
1130 class: ErrorClass::Unsupported,
1131 origin: ErrorOrigin::Query,
1132 detail: Some(ErrorDetail::Query(
1133 QueryErrorDetail::ExactCountMetadataUnavailable,
1134 )),
1135 }
1136 }
1137
1138 pub(crate) fn query_explain_output_exceeded(limit: u64, observed: u64) -> Self {
1141 Self::with_diagnostic_facts(
1142 ErrorClass::Unsupported,
1143 ErrorOrigin::Query,
1144 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1145 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainOutputExceeded,
1146 }),
1147 vec![
1148 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1149 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1150 ],
1151 )
1152 }
1153
1154 pub(crate) fn query_explain_depth_exceeded(limit: u64, observed: u64) -> Self {
1157 Self::with_diagnostic_facts(
1158 ErrorClass::Unsupported,
1159 ErrorOrigin::Query,
1160 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1161 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainDepthExceeded,
1162 }),
1163 vec![
1164 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1165 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1166 ],
1167 )
1168 }
1169
1170 #[cold]
1173 #[inline(never)]
1174 pub(crate) fn query_stale_accepted_schema_revision(
1175 expected_revision: u64,
1176 current_revision: Option<u64>,
1177 ) -> Self {
1178 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1179 facts.push((
1180 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1181 expected_revision,
1182 ));
1183 if let Some(current_revision) = current_revision {
1184 facts.push((
1185 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1186 current_revision,
1187 ));
1188 }
1189 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1190 }
1191
1192 #[cold]
1194 #[inline(never)]
1195 #[cfg(feature = "sql")]
1196 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1197 Self {
1198 class: ErrorClass::Unsupported,
1199 origin: ErrorOrigin::Query,
1200 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1201 error,
1202 })),
1203 }
1204 }
1205
1206 #[cold]
1208 #[inline(never)]
1209 pub(crate) fn query_numeric_overflow() -> Self {
1210 Self {
1211 class: ErrorClass::Unsupported,
1212 origin: ErrorOrigin::Query,
1213 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1214 }
1215 }
1216
1217 #[cold]
1220 #[inline(never)]
1221 pub(crate) fn query_numeric_not_representable() -> Self {
1222 Self {
1223 class: ErrorClass::Unsupported,
1224 origin: ErrorOrigin::Query,
1225 detail: Some(ErrorDetail::Query(
1226 QueryErrorDetail::NumericNotRepresentable,
1227 )),
1228 }
1229 }
1230
1231 #[cold]
1233 #[inline(never)]
1234 pub(crate) fn serialize_internal() -> Self {
1235 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1236 }
1237
1238 pub(crate) fn persisted_row_encode_internal() -> Self {
1240 Self::serialize_internal()
1241 }
1242
1243 pub(crate) fn persisted_row_size_limit_exceeded(actual_length: usize, limit: usize) -> Self {
1245 Self::with_diagnostic_facts(
1246 ErrorClass::Unsupported,
1247 ErrorOrigin::Serialize,
1248 None,
1249 vec![
1250 (
1251 diagnostic_code::DiagnosticFactTag::ActualLength,
1252 actual_length as u64,
1253 ),
1254 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1255 ],
1256 )
1257 }
1258
1259 #[cold]
1261 #[inline(never)]
1262 pub(crate) fn store_corruption() -> Self {
1263 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1264 }
1265
1266 pub(crate) fn commit_corruption() -> Self {
1268 Self::store_corruption()
1269 }
1270
1271 pub(crate) fn commit_component_corruption() -> Self {
1273 Self::commit_corruption()
1274 }
1275
1276 pub(crate) fn commit_id_generation_failed() -> Self {
1278 Self::store_internal()
1279 }
1280
1281 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1283 Self::store_unsupported()
1284 }
1285
1286 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1288 Self::with_diagnostic_facts(
1289 ErrorClass::Corruption,
1290 ErrorOrigin::Store,
1291 None,
1292 vec![
1293 (
1294 diagnostic_code::DiagnosticFactTag::ComponentKind,
1295 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1296 ),
1297 (
1298 diagnostic_code::DiagnosticFactTag::ActualLength,
1299 actual_length as u64,
1300 ),
1301 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1302 ],
1303 )
1304 }
1305
1306 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1308 Self::commit_corruption()
1309 }
1310
1311 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1313 Self::store_unsupported()
1314 }
1315
1316 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1318 Self::store_unsupported()
1319 }
1320
1321 #[cold]
1323 #[inline(never)]
1324 pub(crate) fn index_corruption() -> Self {
1325 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1326 }
1327
1328 pub(crate) fn index_unique_validation_corruption() -> Self {
1330 Self::index_plan_index_corruption()
1331 }
1332
1333 pub(crate) fn structural_index_entry_corruption() -> Self {
1335 Self::index_plan_index_corruption()
1336 }
1337
1338 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1340 Self::index_invariant()
1341 }
1342
1343 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1345 Self::index_plan_serialize_corruption()
1346 }
1347
1348 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1350 Self::index_plan_serialize_corruption()
1351 }
1352
1353 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1355 Self::index_plan_serialize_corruption()
1356 }
1357
1358 pub(crate) fn index_unique_validation_row_required() -> Self {
1360 Self::index_plan_store_corruption()
1361 }
1362
1363 pub(crate) fn index_only_predicate_component_required() -> Self {
1365 Self::index_invariant()
1366 }
1367
1368 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1370 Self::index_invariant()
1371 }
1372
1373 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1375 Self::index_invariant()
1376 }
1377
1378 pub(crate) fn index_entry_decode_failed() -> Self {
1380 Self::index_corruption()
1381 }
1382
1383 pub(crate) fn serialize_corruption() -> Self {
1385 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1386 }
1387
1388 pub(crate) fn persisted_row_decode_corruption() -> Self {
1390 Self::serialize_corruption()
1391 }
1392
1393 pub(crate) fn persisted_row_layout_outside_accepted_window(
1395 row_layout: u32,
1396 history_floor: u32,
1397 current_layout: u32,
1398 ) -> Self {
1399 Self::with_diagnostic_facts(
1400 ErrorClass::Corruption,
1401 ErrorOrigin::Serialize,
1402 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1403 boundary:
1404 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1405 }),
1406 vec![
1407 (
1408 diagnostic_code::DiagnosticFactTag::RowLayout,
1409 u64::from(row_layout),
1410 ),
1411 (
1412 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1413 u64::from(history_floor),
1414 ),
1415 (
1416 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1417 u64::from(current_layout),
1418 ),
1419 ],
1420 )
1421 }
1422
1423 pub(crate) fn persisted_row_slot_count_mismatch(
1425 row_layout: u32,
1426 expected_slot_count: usize,
1427 actual_slot_count: usize,
1428 ) -> Self {
1429 Self::with_diagnostic_facts(
1430 ErrorClass::Corruption,
1431 ErrorOrigin::Serialize,
1432 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1433 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1434 }),
1435 vec![
1436 (
1437 diagnostic_code::DiagnosticFactTag::RowLayout,
1438 u64::from(row_layout),
1439 ),
1440 (
1441 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1442 expected_slot_count as u64,
1443 ),
1444 (
1445 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1446 actual_slot_count as u64,
1447 ),
1448 ],
1449 )
1450 }
1451
1452 pub(crate) fn persisted_row_key_mismatch() -> Self {
1454 Self::store_corruption()
1455 }
1456
1457 pub(crate) fn with_relation_identity(self, entity_tag: u64, relation_id: u32) -> Self {
1459 if self.diagnostic().error_code() != diagnostic_code::ErrorCode::RUNTIME_INTERNAL {
1460 return self;
1461 }
1462 let mut facts = vec![
1463 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1464 (
1465 diagnostic_code::DiagnosticFactTag::RelationId,
1466 u64::from(relation_id),
1467 ),
1468 ];
1469 facts.extend(self.diagnostic_facts());
1470 Self::with_diagnostic_facts(self.class, self.origin, None, facts)
1471 }
1472
1473 pub(crate) fn relation_target_primary_key_arity_mismatch(
1475 expected_arity: usize,
1476 actual_arity: usize,
1477 ) -> Self {
1478 Self::with_diagnostic_facts(
1479 ErrorClass::Internal,
1480 ErrorOrigin::Executor,
1481 None,
1482 vec![
1483 (
1484 diagnostic_code::DiagnosticFactTag::ComponentKind,
1485 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1486 ),
1487 (
1488 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1489 expected_arity as u64,
1490 ),
1491 (
1492 diagnostic_code::DiagnosticFactTag::ActualArity,
1493 actual_arity as u64,
1494 ),
1495 ],
1496 )
1497 }
1498
1499 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1501 Self::index_corruption()
1502 }
1503
1504 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1506 Self::index_corruption()
1507 }
1508
1509 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1511 Self::index_corruption()
1512 }
1513
1514 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1516 Self::index_corruption()
1517 }
1518
1519 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1521 Self::index_corruption()
1522 }
1523
1524 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1526 Self::index_corruption()
1527 }
1528
1529 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1531 Self::index_corruption()
1532 }
1533
1534 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1536 Self::index_corruption()
1537 }
1538
1539 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1541 Self::index_corruption()
1542 }
1543
1544 pub(crate) fn identity_corruption() -> Self {
1546 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1547 }
1548
1549 pub(crate) fn identity_state_corruption() -> Self {
1551 Self::identity_corruption()
1552 }
1553
1554 pub(crate) fn identity_state_conflict() -> Self {
1556 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1557 }
1558
1559 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1561 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1562 }
1563
1564 pub(crate) fn identity_exhausted() -> Self {
1566 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1567 }
1568
1569 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1571 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1572 }
1573
1574 #[cold]
1576 #[inline(never)]
1577 pub(crate) fn store_unsupported() -> Self {
1578 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1579 }
1580
1581 pub(crate) fn schema_application_conflict() -> Self {
1583 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1584 }
1585
1586 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1588 let class = match reason.diagnostic_code() {
1589 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1590 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1591 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1592 _ => ErrorClass::Internal,
1593 };
1594 Self {
1595 class,
1596 origin: ErrorOrigin::Store,
1597 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1598 }
1599 }
1600
1601 pub(crate) fn schema_ddl_publication_race_lost() -> Self {
1603 Self {
1604 class: ErrorClass::Unsupported,
1605 origin: ErrorOrigin::Store,
1606 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1607 }
1608 }
1609
1610 #[cfg(feature = "sql")]
1612 pub(crate) fn schema_ddl_rewrite_requires_migration() -> Self {
1613 Self {
1614 class: ErrorClass::Unsupported,
1615 origin: ErrorOrigin::Store,
1616 detail: Some(ErrorDetail::Store(
1617 StoreError::SchemaDdlRewriteRequiresMigration,
1618 )),
1619 }
1620 }
1621
1622 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1624 Self {
1625 class: ErrorClass::Unsupported,
1626 origin: ErrorOrigin::Store,
1627 detail: Some(ErrorDetail::Store(
1628 StoreError::JournalMutationRevisionExhausted,
1629 )),
1630 }
1631 }
1632
1633 pub(crate) fn schema_transition_budget_exceeded(
1635 resource: SchemaTransitionBudgetResource,
1636 ) -> Self {
1637 Self {
1638 class: ErrorClass::Unsupported,
1639 origin: ErrorOrigin::Store,
1640 detail: Some(ErrorDetail::Store(
1641 StoreError::SchemaTransitionBudgetExceeded { resource },
1642 )),
1643 }
1644 }
1645
1646 pub(crate) fn schema_validation_page_budget_exceeded(
1648 actual_tag: diagnostic_code::DiagnosticFactTag,
1649 limit: u64,
1650 actual: u64,
1651 ) -> Self {
1652 Self::with_diagnostic_facts(
1653 ErrorClass::Unsupported,
1654 ErrorOrigin::Query,
1655 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
1656 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
1657 }),
1658 vec![
1659 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1660 (actual_tag, actual),
1661 ],
1662 )
1663 }
1664
1665 pub(crate) fn index_unsupported() -> Self {
1667 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1668 }
1669
1670 pub(crate) fn index_key_exceeds_max_size_at(
1672 entity_tag: u64,
1673 physical_generation: u64,
1674 actual_length: usize,
1675 limit: usize,
1676 ) -> Self {
1677 Self::with_diagnostic_facts(
1678 ErrorClass::Unsupported,
1679 ErrorOrigin::Index,
1680 None,
1681 vec![
1682 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1683 (
1684 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1685 physical_generation,
1686 ),
1687 (
1688 diagnostic_code::DiagnosticFactTag::ComponentKind,
1689 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
1690 ),
1691 (
1692 diagnostic_code::DiagnosticFactTag::ActualLength,
1693 actual_length as u64,
1694 ),
1695 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1696 ],
1697 )
1698 }
1699
1700 pub(crate) fn index_component_exceeds_max_size_at(
1702 entity_tag: u64,
1703 physical_generation: u64,
1704 component_index: usize,
1705 actual_length: usize,
1706 limit: usize,
1707 ) -> Self {
1708 Self::with_diagnostic_facts(
1709 ErrorClass::Unsupported,
1710 ErrorOrigin::Index,
1711 None,
1712 vec![
1713 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1714 (
1715 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1716 physical_generation,
1717 ),
1718 (
1719 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1720 component_index as u64,
1721 ),
1722 (
1723 diagnostic_code::DiagnosticFactTag::ComponentKind,
1724 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1725 ),
1726 (
1727 diagnostic_code::DiagnosticFactTag::ActualLength,
1728 actual_length as u64,
1729 ),
1730 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1731 ],
1732 )
1733 }
1734
1735 pub(crate) fn index_component_exceeds_max_size() -> Self {
1738 Self::index_unsupported()
1739 }
1740
1741 pub(crate) fn serialize_unsupported() -> Self {
1743 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1744 }
1745
1746 pub(crate) fn cursor_invalid_continuation() -> Self {
1748 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1749 }
1750
1751 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1753 Self::new(
1754 ErrorClass::IncompatiblePersistedFormat,
1755 ErrorOrigin::Serialize,
1756 )
1757 }
1758
1759 #[cfg(feature = "sql")]
1762 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1763 Self {
1764 class: ErrorClass::Unsupported,
1765 origin: ErrorOrigin::Query,
1766 detail: Some(ErrorDetail::Query(
1767 QueryErrorDetail::UnsupportedSqlFeature { feature },
1768 )),
1769 }
1770 }
1771
1772 #[cfg(feature = "sql")]
1775 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1776 Self {
1777 class: ErrorClass::Unsupported,
1778 origin: ErrorOrigin::Query,
1779 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1780 }
1781 }
1782
1783 #[cfg(feature = "sql")]
1785 pub(crate) fn query_sql_lowering_with_facts(
1786 reason: diagnostic_code::SqlLoweringCode,
1787 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1788 ) -> Self {
1789 Self::with_diagnostic_facts(
1790 ErrorClass::Unsupported,
1791 ErrorOrigin::Query,
1792 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1793 facts,
1794 )
1795 }
1796
1797 pub(crate) fn query_unsupported_projection(
1800 reason: diagnostic_code::QueryProjectionCode,
1801 ) -> Self {
1802 Self {
1803 class: ErrorClass::Unsupported,
1804 origin: ErrorOrigin::Query,
1805 detail: Some(ErrorDetail::Query(
1806 QueryErrorDetail::UnsupportedProjection { reason },
1807 )),
1808 }
1809 }
1810
1811 #[cfg(feature = "sql")]
1814 pub(crate) fn query_sql_surface_mismatch(
1815 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1816 ) -> Self {
1817 Self {
1818 class: ErrorClass::Unsupported,
1819 origin: ErrorOrigin::Query,
1820 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1821 mismatch,
1822 })),
1823 }
1824 }
1825
1826 pub(crate) fn query_sql_write_boundary(
1828 boundary: diagnostic_code::SqlWriteBoundaryCode,
1829 ) -> Self {
1830 Self {
1831 class: ErrorClass::Unsupported,
1832 origin: ErrorOrigin::Query,
1833 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1834 boundary,
1835 })),
1836 }
1837 }
1838
1839 pub(crate) fn query_sql_write_boundary_with_facts(
1841 boundary: diagnostic_code::SqlWriteBoundaryCode,
1842 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1843 ) -> Self {
1844 Self::with_diagnostic_facts(
1845 ErrorClass::Unsupported,
1846 ErrorOrigin::Query,
1847 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1848 facts,
1849 )
1850 }
1851
1852 pub fn store_not_found(_key: impl Sized) -> Self {
1853 Self {
1854 class: ErrorClass::NotFound,
1855 origin: ErrorOrigin::Store,
1856 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1857 }
1858 }
1859
1860 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1862 Self::store_unsupported()
1863 }
1864
1865 #[cold]
1867 #[inline(never)]
1868 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1869 Self::new(ErrorClass::Corruption, origin)
1870 }
1871
1872 #[cold]
1874 #[inline(never)]
1875 pub(crate) fn index_plan_index_corruption() -> Self {
1876 Self::index_plan_corruption(ErrorOrigin::Index)
1877 }
1878
1879 #[cold]
1881 #[inline(never)]
1882 pub(crate) fn index_plan_store_corruption() -> Self {
1883 Self::index_plan_corruption(ErrorOrigin::Store)
1884 }
1885
1886 #[cold]
1888 #[inline(never)]
1889 pub(crate) fn index_plan_serialize_corruption() -> Self {
1890 Self::index_plan_corruption(ErrorOrigin::Serialize)
1891 }
1892
1893 #[cfg(test)]
1895 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1896 Self::new(ErrorClass::InvariantViolation, origin)
1897 }
1898
1899 #[cfg(test)]
1901 pub(crate) fn index_plan_store_invariant() -> Self {
1902 Self::index_plan_invariant(ErrorOrigin::Store)
1903 }
1904
1905 pub(crate) fn index_conflict() -> Self {
1911 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
1912 }
1913}
1914
1915impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
1916 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
1917 Self {
1918 class: ErrorClass::Unsupported,
1919 origin: ErrorOrigin::Query,
1920 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
1921 reason,
1922 })),
1923 }
1924 }
1925}
1926
1927impl fmt::Debug for InternalError {
1928 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1929 fmt_compact_diagnostic(
1930 f,
1931 self.diagnostic_code(),
1932 self.detail
1933 .as_ref()
1934 .and_then(ErrorDetail::diagnostic_detail),
1935 )
1936 }
1937}
1938
1939impl fmt::Display for InternalError {
1940 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1941 f.write_str(self.message())
1942 }
1943}
1944
1945impl std::error::Error for InternalError {}
1946
1947#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, serde::Serialize)]
1956#[cfg_attr(not(target_family = "wasm"), derive(ic_wire::Wire))]
1957pub enum ConstraintValuePathComponent {
1958 RootField { field_id: u32 },
1960
1961 RecordMember {
1963 composite_type_id: u32,
1964 member_id: u32,
1965 },
1966
1967 TupleElement {
1969 composite_type_id: u32,
1970 ordinal: u32,
1971 },
1972
1973 Newtype { composite_type_id: u32 },
1975
1976 EnumVariant { enum_type_id: u32, variant_id: u32 },
1978
1979 ListElement { index: u32 },
1981
1982 SetElement { index: u32 },
1984
1985 MapEntryKey { index: u32 },
1987
1988 MapEntryValue { index: u32 },
1990}
1991
1992impl fmt::Display for ConstraintValuePathComponent {
1993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1994 match self {
1995 Self::RootField { field_id } => write!(f, "field#{field_id}"),
1996 Self::RecordMember {
1997 composite_type_id,
1998 member_id,
1999 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2000 Self::TupleElement {
2001 composite_type_id,
2002 ordinal,
2003 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2004 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2005 Self::EnumVariant {
2006 enum_type_id,
2007 variant_id,
2008 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2009 Self::ListElement { index } => write!(f, "list[{index}]"),
2010 Self::SetElement { index } => write!(f, "set[{index}]"),
2011 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2012 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2013 }
2014 }
2015}
2016
2017#[derive(Clone, Debug, Deserialize, Eq, PartialEq, serde::Serialize)]
2024#[cfg_attr(not(target_family = "wasm"), derive(ic_wire::Wire))]
2025pub struct ConstraintValuePath {
2026 components: Vec<ConstraintValuePathComponent>,
2027}
2028
2029impl ConstraintValuePath {
2030 #[must_use]
2032 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2033 Self { components }
2034 }
2035
2036 #[must_use]
2038 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2039 self.components.as_slice()
2040 }
2041}
2042
2043impl fmt::Display for ConstraintValuePath {
2044 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2045 for (ordinal, component) in self.components.iter().enumerate() {
2046 if ordinal != 0 {
2047 f.write_str("/")?;
2048 }
2049 component.fmt(f)?;
2050 }
2051 Ok(())
2052 }
2053}
2054
2055#[derive(Clone, Debug, Deserialize, Eq, PartialEq, serde::Serialize)]
2064#[cfg_attr(not(target_family = "wasm"), derive(ic_wire::Wire))]
2065pub struct ConstraintValidationFindingOutput {
2066 accepted_schema_fingerprint: [u8; 16],
2067 entity_tag: u64,
2068 constraint_id: u32,
2069 #[serde(with = "serde_bytes")]
2070 primary_key: Vec<u8>,
2071 field_ids: Vec<u32>,
2072 value_path: Option<ConstraintValuePath>,
2073 error_code: u16,
2074}
2075
2076impl ConstraintValidationFindingOutput {
2077 #[must_use]
2079 pub(crate) const fn new(
2080 accepted_schema_fingerprint: [u8; 16],
2081 entity_tag: u64,
2082 constraint_id: u32,
2083 primary_key: Vec<u8>,
2084 field_ids: Vec<u32>,
2085 value_path: Option<ConstraintValuePath>,
2086 error_code: u16,
2087 ) -> Self {
2088 Self {
2089 accepted_schema_fingerprint,
2090 entity_tag,
2091 constraint_id,
2092 primary_key,
2093 field_ids,
2094 value_path,
2095 error_code,
2096 }
2097 }
2098
2099 #[must_use]
2101 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2102 self.accepted_schema_fingerprint
2103 }
2104
2105 #[must_use]
2107 pub const fn entity_tag(&self) -> u64 {
2108 self.entity_tag
2109 }
2110
2111 #[must_use]
2113 pub const fn constraint_id(&self) -> u32 {
2114 self.constraint_id
2115 }
2116
2117 #[must_use]
2119 pub const fn primary_key(&self) -> &[u8] {
2120 self.primary_key.as_slice()
2121 }
2122
2123 #[must_use]
2127 pub const fn field_ids(&self) -> &[u32] {
2128 self.field_ids.as_slice()
2129 }
2130
2131 #[must_use]
2133 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2134 self.value_path.as_ref()
2135 }
2136
2137 #[must_use]
2139 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2140 diagnostic_code::ErrorCode::from_raw(self.error_code)
2141 }
2142
2143 #[must_use]
2145 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2146 self.error_code().class()
2147 }
2148}
2149
2150#[derive(Clone)]
2152pub(crate) struct AcceptedConstraintFactContext {
2153 fingerprint_method: u8,
2154 accepted_schema_fingerprint: [u8; 16],
2155 entity_tag: u64,
2156 constraint_id: u32,
2157 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2158 mutation: Option<MutationDiagnosticContext>,
2159 value_path: Option<ConstraintValuePath>,
2160}
2161
2162impl AcceptedConstraintFactContext {
2163 #[must_use]
2164 pub(crate) fn write_admission(
2165 fingerprint_method: u8,
2166 accepted_schema_fingerprint: [u8; 16],
2167 entity_tag: u64,
2168 constraint_id: u32,
2169 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2170 mutation: Option<MutationDiagnosticContext>,
2171 value_path: Option<ConstraintValuePath>,
2172 ) -> Self {
2173 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2174 Self {
2175 fingerprint_method,
2176 accepted_schema_fingerprint,
2177 entity_tag,
2178 constraint_id,
2179 constraint_kind,
2180 mutation,
2181 value_path,
2182 }
2183 }
2184
2185 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2186 let path_len = self
2187 .value_path
2188 .as_ref()
2189 .map_or(0, |path| path.components().len());
2190 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2191 1 + usize::from(mutation.batch_position.is_some())
2192 });
2193 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2194 append_accepted_schema_facts(
2195 &mut facts,
2196 self.fingerprint_method,
2197 self.accepted_schema_fingerprint,
2198 );
2199 facts.push((
2200 diagnostic_code::DiagnosticFactTag::EntityTag,
2201 self.entity_tag,
2202 ));
2203 facts.push((
2204 diagnostic_code::DiagnosticFactTag::ConstraintId,
2205 u64::from(self.constraint_id),
2206 ));
2207 facts.push((
2208 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2209 self.constraint_kind.raw(),
2210 ));
2211 facts.push((
2212 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2213 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2214 ));
2215 if let Some(mutation) = self.mutation {
2216 mutation.append_operation_facts(&mut facts);
2217 }
2218 if let Some(path) = self.value_path {
2219 for component in path.components {
2220 facts.push(constraint_value_path_fact(component));
2221 }
2222 }
2223 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2224 facts
2225 }
2226}
2227
2228fn append_accepted_schema_facts(
2230 facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2231 method: u8,
2232 fingerprint: [u8; 16],
2233) {
2234 facts.extend([
2235 (
2236 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2237 u64::from(method),
2238 ),
2239 (
2240 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2241 u64::from_be_bytes([
2242 fingerprint[0],
2243 fingerprint[1],
2244 fingerprint[2],
2245 fingerprint[3],
2246 fingerprint[4],
2247 fingerprint[5],
2248 fingerprint[6],
2249 fingerprint[7],
2250 ]),
2251 ),
2252 (
2253 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2254 u64::from_be_bytes([
2255 fingerprint[8],
2256 fingerprint[9],
2257 fingerprint[10],
2258 fingerprint[11],
2259 fingerprint[12],
2260 fingerprint[13],
2261 fingerprint[14],
2262 fingerprint[15],
2263 ]),
2264 ),
2265 ]);
2266}
2267
2268fn constraint_value_path_fact(
2269 component: ConstraintValuePathComponent,
2270) -> (diagnostic_code::DiagnosticFactTag, u64) {
2271 use diagnostic_code::DiagnosticFactTag;
2272 match component {
2273 ConstraintValuePathComponent::RootField { field_id } => {
2274 (DiagnosticFactTag::RootField, u64::from(field_id))
2275 }
2276 ConstraintValuePathComponent::RecordMember {
2277 composite_type_id,
2278 member_id,
2279 } => (
2280 DiagnosticFactTag::RecordMember,
2281 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2282 ),
2283 ConstraintValuePathComponent::TupleElement {
2284 composite_type_id,
2285 ordinal,
2286 } => (
2287 DiagnosticFactTag::TupleElement,
2288 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2289 ),
2290 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2291 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2292 }
2293 ConstraintValuePathComponent::EnumVariant {
2294 enum_type_id,
2295 variant_id,
2296 } => (
2297 DiagnosticFactTag::EnumVariant,
2298 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2299 ),
2300 ConstraintValuePathComponent::ListElement { index } => {
2301 (DiagnosticFactTag::ListElement, u64::from(index))
2302 }
2303 ConstraintValuePathComponent::SetElement { index } => {
2304 (DiagnosticFactTag::SetElement, u64::from(index))
2305 }
2306 ConstraintValuePathComponent::MapEntryKey { index } => {
2307 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2308 }
2309 ConstraintValuePathComponent::MapEntryValue { index } => {
2310 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2311 }
2312 }
2313}
2314
2315pub enum ErrorDetail {
2323 DiagnosticFacts(Box<DiagnosticFactDetail>),
2325 Executor(ExecutorErrorDetail),
2327 Store(StoreError),
2328 Query(QueryErrorDetail),
2329 Recovery(RecoveryErrorDetail),
2330 }
2333
2334pub enum ExecutorErrorDetail {
2336 MutationRequiredFieldMissing,
2338 MutationManagedTimestampRegression,
2340 MutationDatabaseOwnedFieldExplicit,
2342 MutationBatchEmpty,
2344 MutationBatchTooManyItems,
2346 MutationBatchStagedBytesExceeded,
2348 MutationBatchResultBytesExceeded,
2350 MutationBatchStoreMismatch,
2352 MutationBatchTooManyEntities,
2354 MutationBatchDuplicateKey,
2356 AcceptedRowConstraintProgramCorrupt,
2358}
2359
2360pub enum RecoveryErrorDetail {
2367 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2368
2369 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2370}
2371
2372#[derive(Clone, Copy, Eq, PartialEq)]
2374pub enum RecoveryFormatMarkerError {
2375 Magic,
2376 Checksum,
2377 State,
2378}
2379
2380impl RecoveryFormatMarkerError {
2381 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2382 match self {
2383 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2384 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2385 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2386 }
2387 }
2388}
2389
2390pub enum StoreError {
2398 NotFound,
2399
2400 Corrupt,
2401
2402 InvariantViolation,
2403
2404 SchemaDdlPublicationRaceLost,
2405
2406 SchemaDdlRewriteRequiresMigration,
2407
2408 SchemaMigration {
2409 reason: diagnostic_code::SchemaMigrationCode,
2410 },
2411
2412 SchemaRowLayoutVersionExhausted,
2413
2414 JournalMutationRevisionExhausted,
2415
2416 SchemaTransitionBudgetExceeded {
2417 resource: SchemaTransitionBudgetResource,
2418 },
2419
2420 SchemaGeneratedFieldAfterDdlField,
2422
2423 SchemaGeneratedConstraintActivationStale,
2425}
2426
2427pub enum QueryErrorDetail {
2434 ExactCountMetadataUnavailable,
2436
2437 NumericOverflow,
2438
2439 NumericNotRepresentable,
2440
2441 UnsupportedSqlFeature {
2442 feature: diagnostic_code::SqlFeatureCode,
2443 },
2444
2445 SqlLowering {
2446 reason: diagnostic_code::SqlLoweringCode,
2447 },
2448
2449 UnsupportedProjection {
2450 reason: diagnostic_code::QueryProjectionCode,
2451 },
2452
2453 UnknownAggregateTargetField,
2454
2455 QueryReadAdmission {
2456 reason: diagnostic_code::QueryReadAdmissionCode,
2457 },
2458
2459 SqlSurfaceMismatch {
2460 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2461 },
2462
2463 SqlWriteBoundary {
2464 boundary: diagnostic_code::SqlWriteBoundaryCode,
2465 },
2466
2467 SchemaDdlAdmission {
2468 error: SchemaDdlAdmissionError,
2469 },
2470
2471 StaleSchemaRevision,
2472}
2473
2474impl fmt::Display for QueryErrorDetail {
2475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2476 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2477 }
2478}
2479
2480impl std::error::Error for QueryErrorDetail {}
2481
2482#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2490pub enum SchemaTransitionBudgetResource {
2491 DeletionKeys,
2493 ProjectionEntries,
2495 ProjectionWorkUnits,
2497 SourceRows,
2499 SourceRowBytes,
2501 StagedRawBytes,
2503}
2504
2505#[derive(Clone, Copy, Eq, PartialEq)]
2514pub enum SchemaDdlAdmissionError {
2515 MissingExpectedSchemaVersion,
2516
2517 MissingNextSchemaVersion,
2518
2519 StaleExpectedSchemaVersion,
2520
2521 InvalidExpectedSchemaVersion,
2522
2523 InvalidNextSchemaVersion,
2524
2525 AcceptedSchemaChangeWithoutVersionBump,
2526
2527 EmptyVersionBump,
2528
2529 VersionGap,
2530
2531 VersionRollback,
2532
2533 FingerprintMethodMismatch,
2534
2535 UnsupportedTransitionClass,
2536
2537 PhysicalRunnerMissing,
2538
2539 ValidationFailed,
2540
2541 PublicationRaceLost,
2542
2543 InvalidAddColumnDefault,
2544
2545 InvalidAlterColumnDefault,
2546
2547 RowLayoutVersionExhausted,
2548
2549 GeneratedIndexDropRejected,
2550
2551 SchemaRewriteRequiresMigration,
2552
2553 SchemaTransitionBudgetExceeded {
2554 resource: SchemaTransitionBudgetResource,
2555 },
2556
2557 GeneratedFieldDefaultChangeRejected,
2558
2559 GeneratedFieldNullabilityChangeRejected,
2560}
2561
2562impl fmt::Display for SchemaDdlAdmissionError {
2563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2564 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2565 }
2566}
2567
2568impl std::error::Error for SchemaDdlAdmissionError {}
2569
2570impl fmt::Debug for ErrorDetail {
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 ExecutorErrorDetail {
2577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2578 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2579 }
2580}
2581
2582impl fmt::Debug for StoreError {
2583 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2584 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2585 }
2586}
2587
2588impl fmt::Debug for QueryErrorDetail {
2589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2590 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2591 }
2592}
2593
2594impl fmt::Debug for RecoveryErrorDetail {
2595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2596 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2597 }
2598}
2599
2600impl fmt::Debug for RecoveryFormatMarkerError {
2601 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2602 fmt_compact_diagnostic(
2603 f,
2604 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2605 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2606 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2607 }),
2608 )
2609 }
2610}
2611
2612impl fmt::Debug for SchemaDdlAdmissionError {
2613 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2614 fmt_compact_diagnostic(
2615 f,
2616 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2617 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2618 reason: self.diagnostic_code(),
2619 }),
2620 )
2621 }
2622}
2623
2624fn fmt_compact_diagnostic(
2625 f: &mut fmt::Formatter<'_>,
2626 code: diagnostic_code::DiagnosticCode,
2627 detail: Option<diagnostic_code::DiagnosticDetail>,
2628) -> fmt::Result {
2629 write!(
2630 f,
2631 "{}",
2632 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2633 )
2634}
2635
2636impl ErrorDetail {
2637 #[must_use]
2639 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2640 match self {
2641 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2642 Self::Executor(error) => error.diagnostic_code(),
2643 Self::Store(error) => error.diagnostic_code(),
2644 Self::Query(error) => error.diagnostic_code(),
2645 Self::Recovery(error) => error.diagnostic_code(),
2646 }
2647 }
2648
2649 #[must_use]
2651 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2652 match self {
2653 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2654 Self::Executor(error) => error.diagnostic_detail(),
2655 Self::Store(error) => error.diagnostic_detail(),
2656 Self::Query(error) => error.diagnostic_detail(),
2657 Self::Recovery(error) => error.diagnostic_detail(),
2658 }
2659 }
2660
2661 #[must_use]
2663 #[cold]
2664 #[inline(never)]
2665 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2666 match self {
2667 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2668 Self::Executor(error) => error.diagnostic_facts(),
2669 Self::Query(error) => error.diagnostic_facts(),
2670 Self::Recovery(error) => error.diagnostic_facts(),
2671 Self::Store(_) => Vec::new(),
2672 }
2673 }
2674}
2675
2676impl ExecutorErrorDetail {
2677 #[must_use]
2679 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2680 match self {
2681 Self::MutationRequiredFieldMissing
2682 | Self::MutationDatabaseOwnedFieldExplicit
2683 | Self::MutationBatchEmpty
2684 | Self::MutationBatchTooManyItems
2685 | Self::MutationBatchTooManyEntities
2686 | Self::MutationBatchStagedBytesExceeded
2687 | Self::MutationBatchResultBytesExceeded => {
2688 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2689 }
2690 Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2691 diagnostic_code::DiagnosticCode::RuntimeConflict
2692 }
2693 Self::MutationManagedTimestampRegression => {
2694 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2695 }
2696 Self::AcceptedRowConstraintProgramCorrupt => {
2697 diagnostic_code::DiagnosticCode::RuntimeCorruption
2698 }
2699 }
2700 }
2701
2702 #[must_use]
2704 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2705 match self {
2706 Self::MutationRequiredFieldMissing => {
2707 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2708 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2709 })
2710 }
2711 Self::MutationDatabaseOwnedFieldExplicit => {
2712 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2713 boundary:
2714 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2715 })
2716 }
2717 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2718 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2719 }),
2720 Self::MutationBatchTooManyItems => {
2721 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2722 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2723 })
2724 }
2725 Self::MutationBatchStagedBytesExceeded => {
2726 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2727 boundary:
2728 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2729 })
2730 }
2731 Self::MutationBatchResultBytesExceeded => {
2732 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2733 boundary:
2734 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2735 })
2736 }
2737 Self::MutationBatchStoreMismatch => {
2738 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2739 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2740 })
2741 }
2742 Self::MutationBatchTooManyEntities => {
2743 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2744 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2745 })
2746 }
2747 Self::MutationBatchDuplicateKey => {
2748 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2749 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2750 })
2751 }
2752 Self::MutationManagedTimestampRegression => {
2753 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2754 boundary:
2755 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2756 })
2757 }
2758 Self::AcceptedRowConstraintProgramCorrupt => {
2759 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2760 boundary:
2761 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2762 })
2763 }
2764 }
2765 }
2766
2767 #[must_use]
2769 #[cold]
2770 #[inline(never)]
2771 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2772 Vec::new()
2773 }
2774}
2775
2776impl RecoveryErrorDetail {
2777 #[must_use]
2779 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2780 match self {
2781 Self::UnsupportedFormatVersion { .. } => {
2782 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2783 }
2784 Self::MalformedFormatMarker { .. } => {
2785 diagnostic_code::DiagnosticCode::RuntimeCorruption
2786 }
2787 }
2788 }
2789
2790 #[must_use]
2792 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2793 let kind = match self {
2794 Self::UnsupportedFormatVersion { .. } => {
2795 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2796 }
2797 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2798 };
2799
2800 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2801 }
2802
2803 #[must_use]
2805 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2806 match self {
2807 Self::UnsupportedFormatVersion { found, required } => {
2808 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2809 facts.push((
2810 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2811 u64::from(*required),
2812 ));
2813 if let Some(found) = found {
2814 facts.push((
2815 diagnostic_code::DiagnosticFactTag::ActualVersion,
2816 u64::from(*found),
2817 ));
2818 }
2819 facts
2820 }
2821 Self::MalformedFormatMarker { reason } => vec![(
2822 diagnostic_code::DiagnosticFactTag::DecodeReason,
2823 reason.diagnostic_decode_reason().raw(),
2824 )],
2825 }
2826 }
2827}
2828
2829impl StoreError {
2830 #[must_use]
2832 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2833 match self {
2834 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2835 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2836 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2837 Self::SchemaDdlPublicationRaceLost
2838 | Self::SchemaDdlRewriteRequiresMigration
2839 | Self::SchemaRowLayoutVersionExhausted
2840 | Self::SchemaTransitionBudgetExceeded { .. } => {
2841 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2842 }
2843 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2844 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2845 }
2846 Self::SchemaGeneratedConstraintActivationStale => {
2847 diagnostic_code::DiagnosticCode::RuntimeConflict
2848 }
2849 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2850 }
2851 }
2852
2853 #[must_use]
2855 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2856 match self {
2857 Self::SchemaDdlPublicationRaceLost => {
2858 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2859 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2860 })
2861 }
2862 Self::SchemaDdlRewriteRequiresMigration => {
2863 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2864 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2865 })
2866 }
2867 Self::SchemaMigration { reason } => {
2868 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2869 }
2870 Self::SchemaRowLayoutVersionExhausted => {
2871 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2872 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2873 })
2874 }
2875 Self::JournalMutationRevisionExhausted => {
2876 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2877 boundary:
2878 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2879 })
2880 }
2881 Self::SchemaTransitionBudgetExceeded { .. } => {
2882 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2883 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2884 })
2885 }
2886 Self::SchemaGeneratedFieldAfterDdlField => {
2887 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2888 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2889 })
2890 }
2891 Self::SchemaGeneratedConstraintActivationStale => {
2892 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2893 boundary:
2894 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2895 })
2896 }
2897 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2898 }
2899 }
2900}
2901
2902impl QueryErrorDetail {
2903 #[must_use]
2905 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2906 match self {
2907 Self::ExactCountMetadataUnavailable => {
2908 diagnostic_code::DiagnosticCode::QueryExactCountMetadataUnavailable
2909 }
2910 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
2911 Self::NumericNotRepresentable => {
2912 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
2913 }
2914 Self::UnsupportedSqlFeature { .. } => {
2915 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
2916 }
2917 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
2918 Self::UnsupportedProjection { .. } => {
2919 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
2920 }
2921 Self::UnknownAggregateTargetField => {
2922 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
2923 }
2924 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
2925 Self::SqlSurfaceMismatch { .. } => {
2926 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
2927 }
2928 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
2929 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2930 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
2931 }
2932 }
2933
2934 #[must_use]
2936 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2937 match self {
2938 Self::UnsupportedSqlFeature { feature } => {
2939 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
2940 }
2941 Self::SqlLowering { reason } => {
2942 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
2943 }
2944 Self::UnsupportedProjection { reason } => {
2945 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
2946 }
2947 Self::QueryReadAdmission { reason } => {
2948 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
2949 }
2950 Self::SqlSurfaceMismatch { mismatch } => {
2951 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
2952 mismatch: *mismatch,
2953 })
2954 }
2955 Self::SqlWriteBoundary { boundary } => {
2956 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
2957 boundary: *boundary,
2958 })
2959 }
2960 Self::SchemaDdlAdmission { error } => {
2961 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2962 reason: error.diagnostic_code(),
2963 })
2964 }
2965 Self::ExactCountMetadataUnavailable
2966 | Self::NumericOverflow
2967 | Self::NumericNotRepresentable
2968 | Self::UnknownAggregateTargetField
2969 | Self::StaleSchemaRevision => None,
2970 }
2971 }
2972
2973 #[must_use]
2975 #[cold]
2976 #[inline(never)]
2977 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2978 Vec::new()
2979 }
2980}
2981
2982impl SchemaDdlAdmissionError {
2983 #[must_use]
2985 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
2986 match self {
2987 Self::MissingExpectedSchemaVersion => {
2988 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
2989 }
2990 Self::MissingNextSchemaVersion => {
2991 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
2992 }
2993 Self::StaleExpectedSchemaVersion => {
2994 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
2995 }
2996 Self::InvalidExpectedSchemaVersion => {
2997 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
2998 }
2999 Self::InvalidNextSchemaVersion => {
3000 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3001 }
3002 Self::AcceptedSchemaChangeWithoutVersionBump => {
3003 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3004 }
3005 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3006 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3007 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3008 Self::FingerprintMethodMismatch => {
3009 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3010 }
3011 Self::UnsupportedTransitionClass => {
3012 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3013 }
3014 Self::PhysicalRunnerMissing => {
3015 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3016 }
3017 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3018 Self::PublicationRaceLost => {
3019 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3020 }
3021 Self::InvalidAddColumnDefault => {
3022 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3023 }
3024 Self::InvalidAlterColumnDefault => {
3025 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3026 }
3027 Self::GeneratedIndexDropRejected => {
3028 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3029 }
3030 Self::SchemaRewriteRequiresMigration => {
3031 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3032 }
3033 Self::SchemaTransitionBudgetExceeded { .. } => {
3034 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3035 }
3036 Self::GeneratedFieldDefaultChangeRejected => {
3037 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3038 }
3039 Self::GeneratedFieldNullabilityChangeRejected => {
3040 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3041 }
3042 Self::RowLayoutVersionExhausted => {
3043 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3044 }
3045 }
3046 }
3047}
3048
3049#[repr(u8)]
3056#[derive(Clone, Copy, Eq, PartialEq)]
3057pub enum ErrorClass {
3058 Corruption,
3059 IncompatiblePersistedFormat,
3060 NotFound,
3061 Internal,
3062 Conflict,
3063 Unsupported,
3064 InvariantViolation,
3065}
3066
3067impl ErrorClass {
3068 #[must_use]
3070 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3071 match self {
3072 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3073 diagnostic_code::DiagnosticCode::StoreCorruption
3074 }
3075 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3076 Self::IncompatiblePersistedFormat => {
3077 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3078 }
3079 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3080 diagnostic_code::DiagnosticCode::StoreNotFound
3081 }
3082 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3083 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3084 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3085 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3086 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3087 }
3088 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3089 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3090 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3091 }
3092 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3093 }
3094 }
3095}
3096
3097impl fmt::Debug for ErrorClass {
3098 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3099 write!(f, "{}", *self as u8)
3100 }
3101}
3102
3103#[repr(u8)]
3110#[derive(Clone, Copy, Eq, PartialEq)]
3111pub enum ErrorOrigin {
3112 Serialize,
3113 Store,
3114 Index,
3115 Identity,
3116 Query,
3117 Planner,
3118 Cursor,
3119 Recovery,
3120 Response,
3121 Executor,
3122 Interface,
3123}
3124
3125impl ErrorOrigin {
3126 #[must_use]
3128 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3129 match self {
3130 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3131 Self::Store => diagnostic_code::ErrorOrigin::Store,
3132 Self::Index => diagnostic_code::ErrorOrigin::Index,
3133 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3134 Self::Query => diagnostic_code::ErrorOrigin::Query,
3135 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3136 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3137 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3138 Self::Response => diagnostic_code::ErrorOrigin::Response,
3139 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3140 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3141 }
3142 }
3143}
3144
3145impl fmt::Debug for ErrorOrigin {
3146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3147 write!(f, "{}", *self as u8)
3148 }
3149}