1#[cfg(test)]
9mod tests;
10
11use candid::CandidType;
12use icydb_diagnostic_code as diagnostic_code;
13use serde::Deserialize;
14use std::fmt;
15
16pub(crate) const COMPACT_QUERY_DIAGNOSTIC_MESSAGE: &str = "query diagnostic";
17const COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE: &str = "runtime diagnostic";
18const COMPACT_STORE_DIAGNOSTIC_MESSAGE: &str = "store diagnostic";
19const COMPACT_INDEX_DIAGNOSTIC_MESSAGE: &str = "index diagnostic";
20const COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE: &str = "serialize diagnostic";
21const COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE: &str = "identity diagnostic";
22
23const fn compact_message_for(_class: ErrorClass, origin: ErrorOrigin) -> &'static str {
24 match origin {
25 ErrorOrigin::Serialize => COMPACT_SERIALIZE_DIAGNOSTIC_MESSAGE,
26 ErrorOrigin::Store => COMPACT_STORE_DIAGNOSTIC_MESSAGE,
27 ErrorOrigin::Index => COMPACT_INDEX_DIAGNOSTIC_MESSAGE,
28 ErrorOrigin::Identity => COMPACT_IDENTITY_DIAGNOSTIC_MESSAGE,
29 ErrorOrigin::Query | ErrorOrigin::Planner | ErrorOrigin::Response => {
30 COMPACT_QUERY_DIAGNOSTIC_MESSAGE
31 }
32 ErrorOrigin::Cursor
33 | ErrorOrigin::Recovery
34 | ErrorOrigin::Executor
35 | ErrorOrigin::Interface => COMPACT_RUNTIME_DIAGNOSTIC_MESSAGE,
36 }
37}
38
39#[derive(Clone, Copy, Debug)]
135pub(crate) struct MutationDiagnosticContext {
136 fingerprint_method: u8,
137 accepted_schema_fingerprint: [u8; 16],
138 entity_tag: u64,
139 operation: diagnostic_code::DiagnosticMutationOperation,
140 batch_position: Option<u32>,
141}
142
143impl MutationDiagnosticContext {
144 #[must_use]
146 pub(crate) const fn new(
147 fingerprint_method: u8,
148 accepted_schema_fingerprint: [u8; 16],
149 entity_tag: u64,
150 operation: diagnostic_code::DiagnosticMutationOperation,
151 batch_position: u32,
152 ) -> Self {
153 Self {
154 fingerprint_method,
155 accepted_schema_fingerprint,
156 entity_tag,
157 operation,
158 batch_position: Some(batch_position),
159 }
160 }
161
162 #[must_use]
164 pub(crate) const fn operation_only(
165 fingerprint_method: u8,
166 accepted_schema_fingerprint: [u8; 16],
167 entity_tag: u64,
168 operation: diagnostic_code::DiagnosticMutationOperation,
169 ) -> Self {
170 Self {
171 fingerprint_method,
172 accepted_schema_fingerprint,
173 entity_tag,
174 operation,
175 batch_position: None,
176 }
177 }
178
179 fn facts(self, field_id: Option<u32>) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
180 let mut facts = Vec::with_capacity(
181 5 + usize::from(field_id.is_some()) + usize::from(self.batch_position.is_some()),
182 );
183 append_accepted_schema_facts(
184 &mut facts,
185 self.fingerprint_method,
186 self.accepted_schema_fingerprint,
187 );
188 facts.push((
189 diagnostic_code::DiagnosticFactTag::EntityTag,
190 self.entity_tag,
191 ));
192 if let Some(field_id) = field_id {
193 facts.push((
194 diagnostic_code::DiagnosticFactTag::FieldId,
195 u64::from(field_id),
196 ));
197 }
198 self.append_operation_facts(&mut facts);
199 facts
200 }
201
202 #[must_use]
203 pub(crate) const fn entity_tag(self) -> u64 {
204 self.entity_tag
205 }
206
207 fn append_operation_facts(self, facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>) {
208 facts.push((
209 diagnostic_code::DiagnosticFactTag::MutationOperation,
210 self.operation.raw(),
211 ));
212 if let Some(batch_position) = self.batch_position {
213 facts.push((
214 diagnostic_code::DiagnosticFactTag::BatchPosition,
215 u64::from(batch_position),
216 ));
217 }
218 }
219}
220
221pub struct DiagnosticFactDetail {
223 diagnostic: diagnostic_code::Diagnostic,
224 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
225}
226
227pub struct InternalError {
235 pub(crate) class: ErrorClass,
236 pub(crate) origin: ErrorOrigin,
237
238 pub(crate) detail: Option<ErrorDetail>,
241}
242
243#[expect(
244 clippy::missing_const_for_fn,
245 reason = "internal error constructors stay non-const so compact diagnostic construction does not force const churn across subsystem helper seams"
246)]
247impl InternalError {
248 #[must_use]
252 #[cold]
253 #[inline(never)]
254 pub fn new(class: ErrorClass, origin: ErrorOrigin) -> Self {
255 let detail = match (class, origin) {
256 (ErrorClass::Corruption, ErrorOrigin::Store) => {
257 Some(ErrorDetail::Store(StoreError::Corrupt))
258 }
259 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
260 Some(ErrorDetail::Store(StoreError::InvariantViolation))
261 }
262 _ => None,
263 };
264
265 Self {
266 class,
267 origin,
268 detail,
269 }
270 }
271
272 #[must_use]
274 pub const fn class(&self) -> ErrorClass {
275 self.class
276 }
277
278 #[must_use]
280 pub const fn origin(&self) -> ErrorOrigin {
281 self.origin
282 }
283
284 #[must_use]
286 pub const fn message(&self) -> &'static str {
287 compact_message_for(self.class, self.origin)
288 }
289
290 #[must_use]
292 pub const fn detail(&self) -> Option<&ErrorDetail> {
293 self.detail.as_ref()
294 }
295
296 #[must_use]
298 pub fn diagnostic(&self) -> diagnostic_code::Diagnostic {
299 diagnostic_code::Diagnostic::new(
300 self.diagnostic_code(),
301 self.origin.diagnostic_origin(),
302 self.detail
303 .as_ref()
304 .and_then(ErrorDetail::diagnostic_detail),
305 )
306 }
307
308 #[must_use]
310 #[cold]
311 #[inline(never)]
312 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
313 self.detail
314 .as_ref()
315 .map_or_else(Vec::new, ErrorDetail::diagnostic_facts)
316 }
317
318 #[must_use]
320 pub fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
321 self.detail.as_ref().map_or_else(
322 || self.class.diagnostic_code(self.origin),
323 ErrorDetail::diagnostic_code,
324 )
325 }
326
327 #[must_use]
329 pub fn into_message(self) -> String {
330 self.message().to_string()
331 }
332
333 #[cold]
335 #[inline(never)]
336 pub(crate) fn classified(class: ErrorClass, origin: ErrorOrigin) -> Self {
337 Self::new(class, origin)
338 }
339
340 #[cold]
341 #[inline(never)]
342 fn with_diagnostic_facts(
343 class: ErrorClass,
344 origin: ErrorOrigin,
345 detail: Option<diagnostic_code::DiagnosticDetail>,
346 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
347 ) -> Self {
348 let code = match detail {
349 Some(detail) => detail.diagnostic_code(),
350 None => class.diagnostic_code(origin),
351 };
352 let diagnostic = diagnostic_code::Diagnostic::new(code, origin.diagnostic_origin(), detail);
353 if diagnostic_code::validate_known_diagnostic_fact_schema(
354 diagnostic.error_code(),
355 facts.as_slice(),
356 )
357 .is_err()
358 {
359 return Self::new(ErrorClass::InvariantViolation, origin);
360 }
361 Self {
362 class,
363 origin,
364 detail: Some(ErrorDetail::DiagnosticFacts(Box::new(
365 DiagnosticFactDetail { diagnostic, facts },
366 ))),
367 }
368 }
369
370 #[cold]
371 #[inline(never)]
372 fn mutation_boundary_with_facts(
373 class: ErrorClass,
374 boundary: diagnostic_code::RuntimeBoundaryCode,
375 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
376 ) -> Self {
377 Self::with_diagnostic_facts(
378 class,
379 ErrorOrigin::Executor,
380 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
381 facts,
382 )
383 }
384
385 #[cold]
386 #[inline(never)]
387 fn exact_key_batch_boundary_with_facts(
388 boundary: diagnostic_code::RuntimeBoundaryCode,
389 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
390 ) -> Self {
391 Self::with_diagnostic_facts(
392 ErrorClass::Unsupported,
393 ErrorOrigin::Query,
394 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary { boundary }),
395 facts,
396 )
397 }
398
399 pub(crate) fn sql_query_entity_not_found() -> Self {
401 Self::with_diagnostic_facts(
402 ErrorClass::NotFound,
403 ErrorOrigin::Interface,
404 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
405 boundary: diagnostic_code::RuntimeBoundaryCode::SqlQueryEntityNotFound,
406 }),
407 Vec::new(),
408 )
409 }
410
411 #[cold]
413 #[inline(never)]
414 pub(crate) fn execution_budget_exceeded(
415 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
416 limit: u64,
417 observed: u64,
418 scope: diagnostic_code::DiagnosticExecutionBudgetScope,
419 lane: diagnostic_code::DiagnosticExecutionLane,
420 normalized_shape_fingerprint_prefix: u64,
421 ) -> Self {
422 Self::with_diagnostic_facts(
423 ErrorClass::Unsupported,
424 ErrorOrigin::Executor,
425 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
426 boundary: diagnostic_code::RuntimeBoundaryCode::ExecutionBudgetExceeded,
427 }),
428 vec![
429 (
430 diagnostic_code::DiagnosticFactTag::BudgetResource,
431 resource.raw(),
432 ),
433 (diagnostic_code::DiagnosticFactTag::Limit, limit),
434 (diagnostic_code::DiagnosticFactTag::Actual, observed),
435 (
436 diagnostic_code::DiagnosticFactTag::ExecutionBudgetScope,
437 scope.raw(),
438 ),
439 (
440 diagnostic_code::DiagnosticFactTag::ExecutionLane,
441 lane.raw(),
442 ),
443 (
444 diagnostic_code::DiagnosticFactTag::QueryShapeFingerprintPrefix,
445 normalized_shape_fingerprint_prefix,
446 ),
447 ],
448 )
449 }
450
451 #[cold]
453 #[inline(never)]
454 pub(crate) fn relation_budget_exceeded(
455 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
456 limit: u64,
457 observed: u64,
458 ) -> Self {
459 Self::execution_budget_exceeded(
460 resource,
461 limit,
462 observed,
463 diagnostic_code::DiagnosticExecutionBudgetScope::Execution,
464 diagnostic_code::DiagnosticExecutionLane::Mutation,
465 0,
466 )
467 }
468
469 #[cold]
471 #[inline(never)]
472 pub(crate) fn page_unit_too_large(
473 resource: diagnostic_code::DiagnosticExecutionBudgetResource,
474 limit: u64,
475 attempted: u64,
476 ) -> Self {
477 Self::with_diagnostic_facts(
478 ErrorClass::Unsupported,
479 ErrorOrigin::Executor,
480 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
481 boundary: diagnostic_code::RuntimeBoundaryCode::PageUnitTooLarge,
482 }),
483 vec![
484 (
485 diagnostic_code::DiagnosticFactTag::BudgetResource,
486 resource.raw(),
487 ),
488 (diagnostic_code::DiagnosticFactTag::Limit, limit),
489 (diagnostic_code::DiagnosticFactTag::Actual, attempted),
490 ],
491 )
492 }
493
494 #[cold]
499 #[inline(never)]
500 pub(crate) fn with_origin(self, origin: ErrorOrigin) -> Self {
501 match self.detail {
502 Some(ErrorDetail::DiagnosticFacts(detail)) => Self::with_diagnostic_facts(
503 self.class,
504 origin,
505 detail.diagnostic.detail().copied(),
506 detail.facts,
507 ),
508 _ => Self::classified(self.class, origin),
509 }
510 }
511
512 #[cold]
514 #[inline(never)]
515 pub(crate) fn index_invariant() -> Self {
516 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Index)
517 }
518
519 pub(crate) fn index_key_field_count_exceeds_max(
521 entity_tag: u64,
522 physical_generation: u64,
523 field_count: usize,
524 max_fields: usize,
525 ) -> Self {
526 Self::with_diagnostic_facts(
527 ErrorClass::InvariantViolation,
528 ErrorOrigin::Index,
529 None,
530 vec![
531 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
532 (
533 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
534 physical_generation,
535 ),
536 (
537 diagnostic_code::DiagnosticFactTag::ComponentKind,
538 diagnostic_code::DiagnosticComponentKind::IndexKey.raw(),
539 ),
540 (
541 diagnostic_code::DiagnosticFactTag::ActualArity,
542 field_count as u64,
543 ),
544 (
545 diagnostic_code::DiagnosticFactTag::Maximum,
546 max_fields as u64,
547 ),
548 ],
549 )
550 }
551
552 pub(crate) fn index_expression_source_type_mismatch(
554 _index_name: &str,
555 _expression: impl Sized,
556 _expected: impl Sized,
557 _source_label: &str,
558 ) -> Self {
559 Self::index_invariant()
560 }
561
562 #[cold]
565 #[inline(never)]
566 pub(crate) fn planner_executor_invariant() -> Self {
567 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
568 }
569
570 #[cold]
573 #[inline(never)]
574 pub(crate) fn query_executor_invariant() -> Self {
575 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Query)
576 }
577
578 #[cold]
581 #[inline(never)]
582 pub(crate) fn cursor_executor_invariant() -> Self {
583 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Cursor)
584 }
585
586 #[cold]
588 #[inline(never)]
589 pub(crate) fn executor_invariant() -> Self {
590 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Executor)
591 }
592
593 #[cold]
595 #[inline(never)]
596 pub(crate) fn executor_internal() -> Self {
597 Self::new(ErrorClass::Internal, ErrorOrigin::Executor)
598 }
599
600 #[cold]
602 #[inline(never)]
603 pub(crate) fn executor_unsupported() -> Self {
604 Self::new(ErrorClass::Unsupported, ErrorOrigin::Executor)
605 }
606
607 #[cold]
609 #[inline(never)]
610 pub(crate) fn mutation_database_owned_field_explicit(
611 context: MutationDiagnosticContext,
612 field_id: u32,
613 ) -> Self {
614 Self::mutation_boundary_with_facts(
615 ErrorClass::Unsupported,
616 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
617 context.facts(Some(field_id)),
618 )
619 }
620
621 #[must_use]
623 #[cold]
624 #[inline(never)]
625 pub(crate) fn mutation_required_field_missing(
626 context: MutationDiagnosticContext,
627 field_id: u32,
628 ) -> Self {
629 Self::mutation_boundary_with_facts(
630 ErrorClass::Unsupported,
631 diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
632 context.facts(Some(field_id)),
633 )
634 }
635
636 #[must_use]
638 #[cold]
639 #[inline(never)]
640 pub(crate) fn mutation_managed_timestamp_regression(
641 context: MutationDiagnosticContext,
642 ) -> Self {
643 Self::mutation_boundary_with_facts(
644 ErrorClass::InvariantViolation,
645 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
646 context.facts(None),
647 )
648 }
649
650 pub(crate) fn mutation_constraint_violation(context: AcceptedConstraintFactContext) -> Self {
652 Self::mutation_boundary_with_facts(
653 ErrorClass::InvariantViolation,
654 diagnostic_code::RuntimeBoundaryCode::ConstraintViolation,
655 context.facts(),
656 )
657 }
658
659 pub(crate) fn accepted_row_constraint_program_corrupt() -> Self {
661 Self {
662 class: ErrorClass::Corruption,
663 origin: ErrorOrigin::Executor,
664 detail: Some(ErrorDetail::Executor(
665 ExecutorErrorDetail::AcceptedRowConstraintProgramCorrupt,
666 )),
667 }
668 }
669
670 pub(crate) fn mutation_constraint_activation_write_blocked(
672 context: AcceptedConstraintFactContext,
673 ) -> Self {
674 Self::mutation_boundary_with_facts(
675 ErrorClass::Conflict,
676 diagnostic_code::RuntimeBoundaryCode::ConstraintActivationWriteBlocked,
677 context.facts(),
678 )
679 }
680
681 pub(crate) fn scalar_page_cursor_boundary_order_required() -> Self {
683 Self::query_executor_invariant()
684 }
685
686 pub(crate) fn scalar_page_cursor_boundary_after_ordering_required() -> Self {
688 Self::query_executor_invariant()
689 }
690
691 pub(crate) fn scalar_page_pagination_after_ordering_required() -> Self {
693 Self::query_executor_invariant()
694 }
695
696 pub(crate) fn fast_stream_route_kind_request_match_required() -> Self {
698 Self::query_executor_invariant()
699 }
700
701 pub(crate) fn secondary_index_prefix_spec_required() -> Self {
703 Self::query_executor_invariant()
704 }
705
706 pub(crate) fn index_range_limit_spec_required() -> Self {
708 Self::query_executor_invariant()
709 }
710
711 #[cold]
713 #[inline(never)]
714 pub(crate) fn mutation_atomic_save_duplicate_key(
715 entity_tag: u64,
716 first_position: u32,
717 duplicate_position: u32,
718 ) -> Self {
719 Self::mutation_boundary_with_facts(
720 ErrorClass::Conflict,
721 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
722 vec![
723 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
724 (
725 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
726 u64::from(first_position),
727 ),
728 (
729 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
730 u64::from(duplicate_position),
731 ),
732 ],
733 )
734 }
735
736 #[cold]
738 #[inline(never)]
739 pub(crate) fn mutation_batch_empty() -> Self {
740 Self::mutation_boundary_with_facts(
741 ErrorClass::Unsupported,
742 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
743 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
744 )
745 }
746
747 #[cold]
749 #[inline(never)]
750 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
751 Self::mutation_boundary_with_facts(
752 ErrorClass::Unsupported,
753 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
754 vec![
755 (
756 diagnostic_code::DiagnosticFactTag::ActualCount,
757 actual_count as u64,
758 ),
759 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
760 ],
761 )
762 }
763
764 #[cold]
766 #[inline(never)]
767 pub(crate) fn mutation_batch_staged_bytes_exceeded(
768 actual_bytes: Option<usize>,
769 limit: usize,
770 ) -> Self {
771 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
772 if let Some(actual_bytes) = actual_bytes {
773 facts.push((
774 diagnostic_code::DiagnosticFactTag::ActualLength,
775 actual_bytes as u64,
776 ));
777 }
778 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
779 Self::mutation_boundary_with_facts(
780 ErrorClass::Unsupported,
781 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
782 facts,
783 )
784 }
785
786 #[cold]
788 #[inline(never)]
789 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
790 Self::mutation_boundary_with_facts(
791 ErrorClass::Unsupported,
792 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
793 vec![
794 (
795 diagnostic_code::DiagnosticFactTag::ActualLength,
796 actual_bytes as u64,
797 ),
798 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
799 ],
800 )
801 }
802
803 #[cold]
805 #[inline(never)]
806 pub(crate) fn mutation_batch_commit_work_exceeded(
807 actual_units: Option<usize>,
808 limit: usize,
809 ) -> Self {
810 let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
811 if let Some(actual_units) = actual_units {
812 facts.push((
813 diagnostic_code::DiagnosticFactTag::ActualCount,
814 actual_units as u64,
815 ));
816 }
817 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
818 Self::mutation_boundary_with_facts(
819 ErrorClass::Unsupported,
820 diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
821 facts,
822 )
823 }
824
825 pub(crate) fn convergence_backlog_pressure(
827 resource: diagnostic_code::DiagnosticBacklogResource,
828 current: u64,
829 proposed: u64,
830 limit: u64,
831 ) -> Self {
832 Self::mutation_boundary_with_facts(
833 ErrorClass::Conflict,
834 diagnostic_code::RuntimeBoundaryCode::ConvergenceBacklogPressure,
835 vec![
836 (
837 diagnostic_code::DiagnosticFactTag::BacklogResource,
838 resource.raw(),
839 ),
840 (diagnostic_code::DiagnosticFactTag::CurrentCount, current),
841 (diagnostic_code::DiagnosticFactTag::ProposedCount, proposed),
842 (diagnostic_code::DiagnosticFactTag::Limit, limit),
843 ],
844 )
845 }
846
847 #[cold]
849 #[inline(never)]
850 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
851 Self::exact_key_batch_boundary_with_facts(
852 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
853 vec![
854 (
855 diagnostic_code::DiagnosticFactTag::ActualCount,
856 actual_count as u64,
857 ),
858 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
859 ],
860 )
861 }
862
863 #[cold]
865 #[inline(never)]
866 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
867 Self::exact_key_batch_bytes_exceeded(
868 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
869 actual_bytes,
870 limit,
871 )
872 }
873
874 #[cold]
876 #[inline(never)]
877 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
878 Self::exact_key_batch_bytes_exceeded(
879 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
880 actual_bytes,
881 limit,
882 )
883 }
884
885 #[cold]
887 #[inline(never)]
888 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
889 Self::exact_key_batch_bytes_exceeded(
890 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
891 actual_bytes,
892 limit,
893 )
894 }
895
896 #[cold]
897 #[inline(never)]
898 fn exact_key_batch_bytes_exceeded(
899 boundary: diagnostic_code::RuntimeBoundaryCode,
900 actual_bytes: usize,
901 limit: usize,
902 ) -> Self {
903 Self::exact_key_batch_boundary_with_facts(
904 boundary,
905 vec![
906 (
907 diagnostic_code::DiagnosticFactTag::ActualLength,
908 actual_bytes as u64,
909 ),
910 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
911 ],
912 )
913 }
914
915 #[cold]
917 #[inline(never)]
918 pub(crate) fn mutation_batch_store_mismatch(
919 batch_position: u32,
920 expected_entity_tag: u64,
921 actual_entity_tag: u64,
922 ) -> Self {
923 Self::mutation_boundary_with_facts(
924 ErrorClass::Conflict,
925 diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
926 vec![
927 (
928 diagnostic_code::DiagnosticFactTag::BatchPosition,
929 u64::from(batch_position),
930 ),
931 (
932 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
933 expected_entity_tag,
934 ),
935 (
936 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
937 actual_entity_tag,
938 ),
939 ],
940 )
941 }
942
943 #[cold]
945 #[inline(never)]
946 pub(crate) fn mutation_batch_too_many_entities(actual_count: usize, limit: usize) -> Self {
947 Self::mutation_boundary_with_facts(
948 ErrorClass::Unsupported,
949 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
950 vec![
951 (
952 diagnostic_code::DiagnosticFactTag::ActualCount,
953 actual_count as u64,
954 ),
955 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
956 ],
957 )
958 }
959
960 pub(crate) fn mutation_index_store_generation_changed(
962 _expected_generation: u64,
963 _observed_generation: u64,
964 ) -> Self {
965 Self::executor_invariant()
966 }
967
968 #[cold]
970 #[inline(never)]
971 pub(crate) fn planner_invariant() -> Self {
972 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
973 }
974
975 pub(crate) fn query_invalid_logical_plan() -> Self {
977 Self::planner_invariant()
978 }
979
980 pub(crate) fn store_invariant() -> Self {
982 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
983 }
984
985 #[cold]
987 #[inline(never)]
988 pub(crate) fn store_internal() -> Self {
989 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
990 }
991
992 pub(crate) fn commit_memory_id_unconfigured() -> Self {
994 Self::store_internal()
995 }
996
997 pub(crate) fn commit_store_uninitialized() -> Self {
999 Self::store_invariant()
1000 }
1001
1002 pub(crate) fn commit_memory_id_mismatch(cached_id: u8, configured_id: u8) -> Self {
1004 Self::with_diagnostic_facts(
1005 ErrorClass::Internal,
1006 ErrorOrigin::Store,
1007 None,
1008 vec![
1009 (
1010 diagnostic_code::DiagnosticFactTag::ExpectedMemoryId,
1011 u64::from(cached_id),
1012 ),
1013 (
1014 diagnostic_code::DiagnosticFactTag::ActualMemoryId,
1015 u64::from(configured_id),
1016 ),
1017 ],
1018 )
1019 }
1020
1021 pub(crate) fn commit_memory_stable_key_mismatch(
1023 _cached_key: &str,
1024 _configured_key: &str,
1025 ) -> Self {
1026 Self::store_internal()
1027 }
1028
1029 pub(crate) fn database_incarnation_generation_failed() -> Self {
1031 Self::store_internal()
1032 }
1033
1034 pub(crate) fn database_incarnation_invalid() -> Self {
1036 Self::store_corruption()
1037 }
1038
1039 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
1041 Self {
1042 class: ErrorClass::IncompatiblePersistedFormat,
1043 origin: ErrorOrigin::Recovery,
1044 detail: Some(ErrorDetail::Recovery(
1045 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
1046 )),
1047 }
1048 }
1049
1050 pub(crate) fn recovery_malformed_database_format_marker(
1052 reason: RecoveryFormatMarkerError,
1053 ) -> Self {
1054 Self {
1055 class: ErrorClass::Corruption,
1056 origin: ErrorOrigin::Recovery,
1057 detail: Some(ErrorDetail::Recovery(
1058 RecoveryErrorDetail::MalformedFormatMarker { reason },
1059 )),
1060 }
1061 }
1062
1063 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1065 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1066 }
1067
1068 pub(crate) fn recovery_pending() -> Self {
1070 Self::with_diagnostic_facts(
1071 ErrorClass::Conflict,
1072 ErrorOrigin::Recovery,
1073 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1074 boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1075 }),
1076 Vec::new(),
1077 )
1078 }
1079
1080 pub(crate) fn startup_control_corruption() -> Self {
1082 Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1083 }
1084
1085 pub(crate) fn commit_control_memory_growth_failed() -> Self {
1087 Self::store_internal()
1088 }
1089
1090 #[cfg(not(test))]
1092 pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1093 Self::store_internal()
1094 }
1095
1096 pub(crate) fn recovery_effect_verification_failed() -> Self {
1098 Self::store_corruption()
1099 }
1100
1101 #[cold]
1103 #[inline(never)]
1104 pub(crate) fn index_internal() -> Self {
1105 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1106 }
1107
1108 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1110 Self::index_internal()
1111 }
1112
1113 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1115 Self::index_internal()
1116 }
1117
1118 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1120 Self::index_internal()
1121 }
1122
1123 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1125 Self::index_internal()
1126 }
1127
1128 #[cfg(test)]
1130 pub(crate) fn query_internal() -> Self {
1131 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1132 }
1133
1134 #[cold]
1136 #[inline(never)]
1137 pub(crate) fn query_unsupported() -> Self {
1138 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1139 }
1140
1141 pub(crate) fn query_explain_output_exceeded(limit: u64, observed: u64) -> Self {
1144 Self::with_diagnostic_facts(
1145 ErrorClass::Unsupported,
1146 ErrorOrigin::Query,
1147 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1148 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainOutputExceeded,
1149 }),
1150 vec![
1151 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1152 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1153 ],
1154 )
1155 }
1156
1157 pub(crate) fn query_explain_depth_exceeded(limit: u64, observed: u64) -> Self {
1160 Self::with_diagnostic_facts(
1161 ErrorClass::Unsupported,
1162 ErrorOrigin::Query,
1163 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1164 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainDepthExceeded,
1165 }),
1166 vec![
1167 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1168 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1169 ],
1170 )
1171 }
1172
1173 #[cold]
1176 #[inline(never)]
1177 pub(crate) fn query_stale_accepted_schema_revision(
1178 expected_revision: u64,
1179 current_revision: Option<u64>,
1180 ) -> Self {
1181 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1182 facts.push((
1183 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1184 expected_revision,
1185 ));
1186 if let Some(current_revision) = current_revision {
1187 facts.push((
1188 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1189 current_revision,
1190 ));
1191 }
1192 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1193 }
1194
1195 #[cold]
1197 #[inline(never)]
1198 #[cfg(feature = "sql")]
1199 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1200 Self {
1201 class: ErrorClass::Unsupported,
1202 origin: ErrorOrigin::Query,
1203 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1204 error,
1205 })),
1206 }
1207 }
1208
1209 #[cold]
1211 #[inline(never)]
1212 pub(crate) fn query_numeric_overflow() -> Self {
1213 Self {
1214 class: ErrorClass::Unsupported,
1215 origin: ErrorOrigin::Query,
1216 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1217 }
1218 }
1219
1220 #[cold]
1223 #[inline(never)]
1224 pub(crate) fn query_numeric_not_representable() -> Self {
1225 Self {
1226 class: ErrorClass::Unsupported,
1227 origin: ErrorOrigin::Query,
1228 detail: Some(ErrorDetail::Query(
1229 QueryErrorDetail::NumericNotRepresentable,
1230 )),
1231 }
1232 }
1233
1234 #[cold]
1236 #[inline(never)]
1237 pub(crate) fn serialize_internal() -> Self {
1238 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1239 }
1240
1241 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1243 Self::persisted_row_encode_internal()
1244 }
1245
1246 pub(crate) fn persisted_row_encode_internal() -> Self {
1248 Self::serialize_internal()
1249 }
1250
1251 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1253 Self::persisted_row_encode_internal()
1254 }
1255
1256 #[cold]
1258 #[inline(never)]
1259 pub(crate) fn store_corruption() -> Self {
1260 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1261 }
1262
1263 pub(crate) fn commit_corruption() -> Self {
1265 Self::store_corruption()
1266 }
1267
1268 pub(crate) fn commit_component_corruption() -> Self {
1270 Self::commit_corruption()
1271 }
1272
1273 pub(crate) fn commit_id_generation_failed() -> Self {
1275 Self::store_internal()
1276 }
1277
1278 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1280 Self::store_unsupported()
1281 }
1282
1283 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1285 Self::with_diagnostic_facts(
1286 ErrorClass::Corruption,
1287 ErrorOrigin::Store,
1288 None,
1289 vec![
1290 (
1291 diagnostic_code::DiagnosticFactTag::ComponentKind,
1292 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1293 ),
1294 (
1295 diagnostic_code::DiagnosticFactTag::ActualLength,
1296 actual_length as u64,
1297 ),
1298 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1299 ],
1300 )
1301 }
1302
1303 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1305 Self::commit_corruption()
1306 }
1307
1308 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1310 Self::store_unsupported()
1311 }
1312
1313 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1315 Self::store_unsupported()
1316 }
1317
1318 #[cold]
1320 #[inline(never)]
1321 pub(crate) fn index_corruption() -> Self {
1322 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1323 }
1324
1325 pub(crate) fn index_unique_validation_corruption() -> Self {
1327 Self::index_plan_index_corruption()
1328 }
1329
1330 pub(crate) fn structural_index_entry_corruption() -> Self {
1332 Self::index_plan_index_corruption()
1333 }
1334
1335 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1337 Self::index_invariant()
1338 }
1339
1340 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1342 Self::index_plan_serialize_corruption()
1343 }
1344
1345 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1347 Self::index_plan_serialize_corruption()
1348 }
1349
1350 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1352 Self::index_plan_serialize_corruption()
1353 }
1354
1355 pub(crate) fn index_unique_validation_row_required() -> Self {
1357 Self::index_plan_store_corruption()
1358 }
1359
1360 pub(crate) fn index_only_predicate_component_required() -> Self {
1362 Self::index_invariant()
1363 }
1364
1365 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1367 Self::index_invariant()
1368 }
1369
1370 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1372 Self::index_invariant()
1373 }
1374
1375 pub(crate) fn index_scan_key_corrupted_during(
1377 _context: &'static str,
1378 _err: impl Sized,
1379 ) -> Self {
1380 Self::index_corruption()
1381 }
1382
1383 pub(crate) fn index_projection_component_required(
1385 _index_name: &str,
1386 _component_index: usize,
1387 ) -> Self {
1388 Self::index_invariant()
1389 }
1390
1391 pub(crate) fn index_entry_decode_failed() -> Self {
1393 Self::index_corruption()
1394 }
1395
1396 pub(crate) fn serialize_corruption() -> Self {
1398 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1399 }
1400
1401 pub(crate) fn persisted_row_decode_corruption() -> Self {
1403 Self::serialize_corruption()
1404 }
1405
1406 pub(crate) fn persisted_row_layout_outside_accepted_window(
1408 row_layout: u32,
1409 history_floor: u32,
1410 current_layout: u32,
1411 ) -> Self {
1412 Self::with_diagnostic_facts(
1413 ErrorClass::Corruption,
1414 ErrorOrigin::Serialize,
1415 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1416 boundary:
1417 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1418 }),
1419 vec![
1420 (
1421 diagnostic_code::DiagnosticFactTag::RowLayout,
1422 u64::from(row_layout),
1423 ),
1424 (
1425 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1426 u64::from(history_floor),
1427 ),
1428 (
1429 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1430 u64::from(current_layout),
1431 ),
1432 ],
1433 )
1434 }
1435
1436 pub(crate) fn persisted_row_slot_count_mismatch(
1438 row_layout: u32,
1439 expected_slot_count: usize,
1440 actual_slot_count: usize,
1441 ) -> Self {
1442 Self::with_diagnostic_facts(
1443 ErrorClass::Corruption,
1444 ErrorOrigin::Serialize,
1445 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1446 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1447 }),
1448 vec![
1449 (
1450 diagnostic_code::DiagnosticFactTag::RowLayout,
1451 u64::from(row_layout),
1452 ),
1453 (
1454 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1455 expected_slot_count as u64,
1456 ),
1457 (
1458 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1459 actual_slot_count as u64,
1460 ),
1461 ],
1462 )
1463 }
1464
1465 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1467 Self::persisted_row_field_decode_corruption(field_name)
1468 }
1469
1470 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1472 Self::persisted_row_decode_corruption()
1473 }
1474
1475 pub(crate) fn persisted_row_field_kind_decode_failed(
1477 field_name: &str,
1478 _field_kind: impl fmt::Debug,
1479 _detail: impl Sized,
1480 ) -> Self {
1481 Self::persisted_row_field_decode_corruption(field_name)
1482 }
1483
1484 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1486 Self::persisted_row_field_decode_corruption(field_name)
1487 }
1488
1489 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1491 Self::persisted_row_field_decode_corruption(field_name)
1492 }
1493
1494 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1496 Self::persisted_row_field_decode_corruption(field_name)
1497 }
1498
1499 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1501 Self::persisted_row_field_decode_corruption(field_name)
1502 }
1503
1504 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1506 Self::persisted_row_field_decode_corruption(field_name)
1507 }
1508
1509 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1511 Self::index_invariant()
1512 }
1513
1514 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1516 _model_path: &str,
1517 _slot: usize,
1518 ) -> Self {
1519 Self::index_invariant()
1520 }
1521
1522 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1524 _data_key: impl fmt::Debug,
1525 _detail: impl Sized,
1526 ) -> Self {
1527 Self::persisted_row_decode_corruption()
1528 }
1529
1530 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1532 Self::persisted_row_decode_corruption()
1533 }
1534
1535 pub(crate) fn persisted_row_key_mismatch() -> Self {
1537 Self::store_corruption()
1538 }
1539
1540 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1542 Self::persisted_row_field_decode_corruption(field_name)
1543 }
1544
1545 pub(crate) fn reverse_index_entry_corrupted(
1547 _source_path: &str,
1548 _field_name: &str,
1549 _target_path: &str,
1550 _index_key: impl fmt::Debug,
1551 _detail: impl Sized,
1552 ) -> Self {
1553 Self::index_corruption()
1554 }
1555
1556 pub(crate) fn relation_target_store_missing(
1558 _source_path: &str,
1559 _field_name: &str,
1560 _target_path: &str,
1561 _store_path: &str,
1562 _detail: impl Sized,
1563 ) -> Self {
1564 Self::executor_internal()
1565 }
1566
1567 pub(crate) fn with_relation_identity(self, entity_tag: u64, relation_id: u32) -> Self {
1569 if self.diagnostic().error_code() != diagnostic_code::ErrorCode::RUNTIME_INTERNAL {
1570 return self;
1571 }
1572 let mut facts = vec![
1573 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1574 (
1575 diagnostic_code::DiagnosticFactTag::RelationId,
1576 u64::from(relation_id),
1577 ),
1578 ];
1579 facts.extend(self.diagnostic_facts());
1580 Self::with_diagnostic_facts(self.class, self.origin, None, facts)
1581 }
1582
1583 pub(crate) fn relation_target_primary_key_arity_mismatch(
1585 expected_arity: usize,
1586 actual_arity: usize,
1587 ) -> Self {
1588 Self::with_diagnostic_facts(
1589 ErrorClass::Internal,
1590 ErrorOrigin::Executor,
1591 None,
1592 vec![
1593 (
1594 diagnostic_code::DiagnosticFactTag::ComponentKind,
1595 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1596 ),
1597 (
1598 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1599 expected_arity as u64,
1600 ),
1601 (
1602 diagnostic_code::DiagnosticFactTag::ActualArity,
1603 actual_arity as u64,
1604 ),
1605 ],
1606 )
1607 }
1608
1609 pub(crate) fn relation_target_key_decode_failed(
1611 _context_label: &str,
1612 _source_path: &str,
1613 _field_name: &str,
1614 _target_path: &str,
1615 _detail: impl Sized,
1616 ) -> Self {
1617 Self::identity_corruption()
1618 }
1619
1620 pub(crate) fn relation_target_entity_mismatch(
1622 _context_label: &str,
1623 _source_path: &str,
1624 _field_name: &str,
1625 _target_path: &str,
1626 _target_entity_name: &str,
1627 expected_tag: u64,
1628 actual_tag: u64,
1629 ) -> Self {
1630 Self::with_diagnostic_facts(
1631 ErrorClass::Corruption,
1632 ErrorOrigin::Store,
1633 None,
1634 vec![
1635 (
1636 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1637 expected_tag,
1638 ),
1639 (
1640 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1641 actual_tag,
1642 ),
1643 ],
1644 )
1645 }
1646
1647 pub(crate) fn relation_source_row_decode_failed(
1649 _source_path: &str,
1650 _field_name: &str,
1651 _target_path: &str,
1652 _detail: impl Sized,
1653 ) -> Self {
1654 Self::persisted_row_decode_corruption()
1655 }
1656
1657 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1659 _source_path: &str,
1660 _field_name: &str,
1661 _target_path: &str,
1662 ) -> Self {
1663 Self::persisted_row_decode_corruption()
1664 }
1665
1666 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1668 Self::persisted_row_decode_corruption()
1669 }
1670
1671 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1673 Self::index_corruption()
1674 }
1675
1676 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1678 Self::index_corruption()
1679 }
1680
1681 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1683 Self::index_corruption()
1684 }
1685
1686 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1688 Self::index_corruption()
1689 }
1690
1691 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1693 Self::index_corruption()
1694 }
1695
1696 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1698 Self::index_corruption()
1699 }
1700
1701 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1703 Self::index_corruption()
1704 }
1705
1706 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1708 Self::index_corruption()
1709 }
1710
1711 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1713 Self::index_corruption()
1714 }
1715
1716 pub(crate) fn identity_corruption() -> Self {
1718 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1719 }
1720
1721 pub(crate) fn identity_state_corruption() -> Self {
1723 Self::identity_corruption()
1724 }
1725
1726 pub(crate) fn identity_state_conflict() -> Self {
1728 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1729 }
1730
1731 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1733 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1734 }
1735
1736 pub(crate) fn identity_exhausted() -> Self {
1738 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1739 }
1740
1741 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1743 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1744 }
1745
1746 #[cold]
1748 #[inline(never)]
1749 pub(crate) fn store_unsupported() -> Self {
1750 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1751 }
1752
1753 pub(crate) fn schema_application_conflict() -> Self {
1755 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1756 }
1757
1758 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1760 let class = match reason.diagnostic_code() {
1761 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1762 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1763 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1764 _ => ErrorClass::Internal,
1765 };
1766 Self {
1767 class,
1768 origin: ErrorOrigin::Store,
1769 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1770 }
1771 }
1772
1773 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1775 Self {
1776 class: ErrorClass::Unsupported,
1777 origin: ErrorOrigin::Store,
1778 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1779 }
1780 }
1781
1782 #[cfg(feature = "sql")]
1784 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1785 Self {
1786 class: ErrorClass::Unsupported,
1787 origin: ErrorOrigin::Store,
1788 detail: Some(ErrorDetail::Store(
1789 StoreError::SchemaDdlRewriteRequiresMigration,
1790 )),
1791 }
1792 }
1793
1794 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1796 Self {
1797 class: ErrorClass::Unsupported,
1798 origin: ErrorOrigin::Store,
1799 detail: Some(ErrorDetail::Store(
1800 StoreError::JournalMutationRevisionExhausted,
1801 )),
1802 }
1803 }
1804
1805 pub(crate) fn schema_transition_budget_exceeded(
1807 resource: SchemaTransitionBudgetResource,
1808 ) -> Self {
1809 Self {
1810 class: ErrorClass::Unsupported,
1811 origin: ErrorOrigin::Store,
1812 detail: Some(ErrorDetail::Store(
1813 StoreError::SchemaTransitionBudgetExceeded { resource },
1814 )),
1815 }
1816 }
1817
1818 pub(crate) fn unsupported_entity_tag_in_data_store(
1820 _entity_tag: crate::types::EntityTag,
1821 ) -> Self {
1822 Self::store_unsupported()
1823 }
1824
1825 #[cfg(not(test))]
1827 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1828 Self::store_internal()
1829 }
1830
1831 pub(crate) fn index_unsupported() -> Self {
1833 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1834 }
1835
1836 pub(crate) fn index_component_exceeds_max_size_at(
1838 entity_tag: u64,
1839 physical_generation: u64,
1840 component_index: usize,
1841 actual_length: usize,
1842 limit: usize,
1843 ) -> Self {
1844 Self::with_diagnostic_facts(
1845 ErrorClass::Unsupported,
1846 ErrorOrigin::Index,
1847 None,
1848 vec![
1849 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1850 (
1851 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1852 physical_generation,
1853 ),
1854 (
1855 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1856 component_index as u64,
1857 ),
1858 (
1859 diagnostic_code::DiagnosticFactTag::ComponentKind,
1860 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1861 ),
1862 (
1863 diagnostic_code::DiagnosticFactTag::ActualLength,
1864 actual_length as u64,
1865 ),
1866 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1867 ],
1868 )
1869 }
1870
1871 pub(crate) fn index_component_exceeds_max_size() -> Self {
1874 Self::index_unsupported()
1875 }
1876
1877 pub(crate) fn serialize_unsupported() -> Self {
1879 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1880 }
1881
1882 pub(crate) fn cursor_invalid_continuation() -> Self {
1884 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1885 }
1886
1887 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1889 Self::new(
1890 ErrorClass::IncompatiblePersistedFormat,
1891 ErrorOrigin::Serialize,
1892 )
1893 }
1894
1895 #[cfg(feature = "sql")]
1898 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1899 Self {
1900 class: ErrorClass::Unsupported,
1901 origin: ErrorOrigin::Query,
1902 detail: Some(ErrorDetail::Query(
1903 QueryErrorDetail::UnsupportedSqlFeature { feature },
1904 )),
1905 }
1906 }
1907
1908 #[cfg(feature = "sql")]
1911 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1912 Self {
1913 class: ErrorClass::Unsupported,
1914 origin: ErrorOrigin::Query,
1915 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1916 }
1917 }
1918
1919 #[cfg(feature = "sql")]
1921 pub(crate) fn query_sql_lowering_with_facts(
1922 reason: diagnostic_code::SqlLoweringCode,
1923 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1924 ) -> Self {
1925 Self::with_diagnostic_facts(
1926 ErrorClass::Unsupported,
1927 ErrorOrigin::Query,
1928 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1929 facts,
1930 )
1931 }
1932
1933 pub(crate) fn query_unsupported_projection(
1936 reason: diagnostic_code::QueryProjectionCode,
1937 ) -> Self {
1938 Self {
1939 class: ErrorClass::Unsupported,
1940 origin: ErrorOrigin::Query,
1941 detail: Some(ErrorDetail::Query(
1942 QueryErrorDetail::UnsupportedProjection { reason },
1943 )),
1944 }
1945 }
1946
1947 #[cfg(feature = "sql")]
1950 pub(crate) fn query_sql_surface_mismatch(
1951 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1952 ) -> Self {
1953 Self {
1954 class: ErrorClass::Unsupported,
1955 origin: ErrorOrigin::Query,
1956 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1957 mismatch,
1958 })),
1959 }
1960 }
1961
1962 pub(crate) fn query_sql_write_boundary(
1964 boundary: diagnostic_code::SqlWriteBoundaryCode,
1965 ) -> Self {
1966 Self {
1967 class: ErrorClass::Unsupported,
1968 origin: ErrorOrigin::Query,
1969 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1970 boundary,
1971 })),
1972 }
1973 }
1974
1975 pub(crate) fn query_sql_write_boundary_with_facts(
1977 boundary: diagnostic_code::SqlWriteBoundaryCode,
1978 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1979 ) -> Self {
1980 Self::with_diagnostic_facts(
1981 ErrorClass::Unsupported,
1982 ErrorOrigin::Query,
1983 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1984 facts,
1985 )
1986 }
1987
1988 pub fn store_not_found(_key: impl Sized) -> Self {
1989 Self {
1990 class: ErrorClass::NotFound,
1991 origin: ErrorOrigin::Store,
1992 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1993 }
1994 }
1995
1996 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1998 Self::store_unsupported()
1999 }
2000
2001 #[cold]
2003 #[inline(never)]
2004 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
2005 Self::new(ErrorClass::Corruption, origin)
2006 }
2007
2008 #[cold]
2010 #[inline(never)]
2011 pub(crate) fn index_plan_index_corruption() -> Self {
2012 Self::index_plan_corruption(ErrorOrigin::Index)
2013 }
2014
2015 #[cold]
2017 #[inline(never)]
2018 pub(crate) fn index_plan_store_corruption() -> Self {
2019 Self::index_plan_corruption(ErrorOrigin::Store)
2020 }
2021
2022 #[cold]
2024 #[inline(never)]
2025 pub(crate) fn index_plan_serialize_corruption() -> Self {
2026 Self::index_plan_corruption(ErrorOrigin::Serialize)
2027 }
2028
2029 #[cfg(test)]
2031 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
2032 Self::new(ErrorClass::InvariantViolation, origin)
2033 }
2034
2035 #[cfg(test)]
2037 pub(crate) fn index_plan_store_invariant() -> Self {
2038 Self::index_plan_invariant(ErrorOrigin::Store)
2039 }
2040
2041 pub(crate) fn index_conflict() -> Self {
2047 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
2048 }
2049}
2050
2051impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
2052 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
2053 Self {
2054 class: ErrorClass::Unsupported,
2055 origin: ErrorOrigin::Query,
2056 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
2057 reason,
2058 })),
2059 }
2060 }
2061}
2062
2063impl fmt::Debug for InternalError {
2064 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2065 fmt_compact_diagnostic(
2066 f,
2067 self.diagnostic_code(),
2068 self.detail
2069 .as_ref()
2070 .and_then(ErrorDetail::diagnostic_detail),
2071 )
2072 }
2073}
2074
2075impl fmt::Display for InternalError {
2076 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2077 f.write_str(self.message())
2078 }
2079}
2080
2081impl std::error::Error for InternalError {}
2082
2083#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2092pub enum ConstraintValuePathComponent {
2093 RootField { field_id: u32 },
2095
2096 RecordMember {
2098 composite_type_id: u32,
2099 member_id: u32,
2100 },
2101
2102 TupleElement {
2104 composite_type_id: u32,
2105 ordinal: u32,
2106 },
2107
2108 Newtype { composite_type_id: u32 },
2110
2111 EnumVariant { enum_type_id: u32, variant_id: u32 },
2113
2114 ListElement { index: u32 },
2116
2117 SetElement { index: u32 },
2119
2120 MapEntryKey { index: u32 },
2122
2123 MapEntryValue { index: u32 },
2125}
2126
2127impl fmt::Display for ConstraintValuePathComponent {
2128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2129 match self {
2130 Self::RootField { field_id } => write!(f, "field#{field_id}"),
2131 Self::RecordMember {
2132 composite_type_id,
2133 member_id,
2134 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2135 Self::TupleElement {
2136 composite_type_id,
2137 ordinal,
2138 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2139 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2140 Self::EnumVariant {
2141 enum_type_id,
2142 variant_id,
2143 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2144 Self::ListElement { index } => write!(f, "list[{index}]"),
2145 Self::SetElement { index } => write!(f, "set[{index}]"),
2146 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2147 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2148 }
2149 }
2150}
2151
2152#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2159pub struct ConstraintValuePath {
2160 components: Vec<ConstraintValuePathComponent>,
2161}
2162
2163impl ConstraintValuePath {
2164 #[must_use]
2166 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2167 Self { components }
2168 }
2169
2170 #[must_use]
2172 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2173 self.components.as_slice()
2174 }
2175}
2176
2177impl fmt::Display for ConstraintValuePath {
2178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2179 for (ordinal, component) in self.components.iter().enumerate() {
2180 if ordinal != 0 {
2181 f.write_str("/")?;
2182 }
2183 component.fmt(f)?;
2184 }
2185 Ok(())
2186 }
2187}
2188
2189#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2198pub struct ConstraintValidationFindingOutput {
2199 accepted_schema_fingerprint: [u8; 16],
2200 entity_tag: u64,
2201 constraint_id: u32,
2202 primary_key: Vec<u8>,
2203 field_ids: Vec<u32>,
2204 value_path: Option<ConstraintValuePath>,
2205 error_code: u16,
2206}
2207
2208impl ConstraintValidationFindingOutput {
2209 #[must_use]
2211 pub(crate) const fn new(
2212 accepted_schema_fingerprint: [u8; 16],
2213 entity_tag: u64,
2214 constraint_id: u32,
2215 primary_key: Vec<u8>,
2216 field_ids: Vec<u32>,
2217 value_path: Option<ConstraintValuePath>,
2218 error_code: u16,
2219 ) -> Self {
2220 Self {
2221 accepted_schema_fingerprint,
2222 entity_tag,
2223 constraint_id,
2224 primary_key,
2225 field_ids,
2226 value_path,
2227 error_code,
2228 }
2229 }
2230
2231 #[must_use]
2233 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2234 self.accepted_schema_fingerprint
2235 }
2236
2237 #[must_use]
2239 pub const fn entity_tag(&self) -> u64 {
2240 self.entity_tag
2241 }
2242
2243 #[must_use]
2245 pub const fn constraint_id(&self) -> u32 {
2246 self.constraint_id
2247 }
2248
2249 #[must_use]
2251 pub const fn primary_key(&self) -> &[u8] {
2252 self.primary_key.as_slice()
2253 }
2254
2255 #[must_use]
2257 pub const fn field_ids(&self) -> &[u32] {
2258 self.field_ids.as_slice()
2259 }
2260
2261 #[must_use]
2263 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2264 self.value_path.as_ref()
2265 }
2266
2267 #[must_use]
2269 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2270 diagnostic_code::ErrorCode::from_raw(self.error_code)
2271 }
2272
2273 #[must_use]
2275 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2276 self.error_code().class()
2277 }
2278}
2279
2280#[derive(Clone)]
2282pub(crate) struct AcceptedConstraintFactContext {
2283 fingerprint_method: u8,
2284 accepted_schema_fingerprint: [u8; 16],
2285 entity_tag: u64,
2286 constraint_id: u32,
2287 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2288 mutation: Option<MutationDiagnosticContext>,
2289 value_path: Option<ConstraintValuePath>,
2290}
2291
2292impl AcceptedConstraintFactContext {
2293 #[must_use]
2294 pub(crate) fn write_admission(
2295 fingerprint_method: u8,
2296 accepted_schema_fingerprint: [u8; 16],
2297 entity_tag: u64,
2298 constraint_id: u32,
2299 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2300 mutation: Option<MutationDiagnosticContext>,
2301 value_path: Option<ConstraintValuePath>,
2302 ) -> Self {
2303 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2304 Self {
2305 fingerprint_method,
2306 accepted_schema_fingerprint,
2307 entity_tag,
2308 constraint_id,
2309 constraint_kind,
2310 mutation,
2311 value_path,
2312 }
2313 }
2314
2315 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2316 let path_len = self
2317 .value_path
2318 .as_ref()
2319 .map_or(0, |path| path.components().len());
2320 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2321 1 + usize::from(mutation.batch_position.is_some())
2322 });
2323 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2324 append_accepted_schema_facts(
2325 &mut facts,
2326 self.fingerprint_method,
2327 self.accepted_schema_fingerprint,
2328 );
2329 facts.push((
2330 diagnostic_code::DiagnosticFactTag::EntityTag,
2331 self.entity_tag,
2332 ));
2333 facts.push((
2334 diagnostic_code::DiagnosticFactTag::ConstraintId,
2335 u64::from(self.constraint_id),
2336 ));
2337 facts.push((
2338 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2339 self.constraint_kind.raw(),
2340 ));
2341 facts.push((
2342 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2343 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2344 ));
2345 if let Some(mutation) = self.mutation {
2346 mutation.append_operation_facts(&mut facts);
2347 }
2348 if let Some(path) = self.value_path {
2349 for component in path.components {
2350 facts.push(constraint_value_path_fact(component));
2351 }
2352 }
2353 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2354 facts
2355 }
2356}
2357
2358fn append_accepted_schema_facts(
2360 facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2361 method: u8,
2362 fingerprint: [u8; 16],
2363) {
2364 facts.extend([
2365 (
2366 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2367 u64::from(method),
2368 ),
2369 (
2370 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2371 u64::from_be_bytes([
2372 fingerprint[0],
2373 fingerprint[1],
2374 fingerprint[2],
2375 fingerprint[3],
2376 fingerprint[4],
2377 fingerprint[5],
2378 fingerprint[6],
2379 fingerprint[7],
2380 ]),
2381 ),
2382 (
2383 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2384 u64::from_be_bytes([
2385 fingerprint[8],
2386 fingerprint[9],
2387 fingerprint[10],
2388 fingerprint[11],
2389 fingerprint[12],
2390 fingerprint[13],
2391 fingerprint[14],
2392 fingerprint[15],
2393 ]),
2394 ),
2395 ]);
2396}
2397
2398fn constraint_value_path_fact(
2399 component: ConstraintValuePathComponent,
2400) -> (diagnostic_code::DiagnosticFactTag, u64) {
2401 use diagnostic_code::DiagnosticFactTag;
2402 match component {
2403 ConstraintValuePathComponent::RootField { field_id } => {
2404 (DiagnosticFactTag::RootField, u64::from(field_id))
2405 }
2406 ConstraintValuePathComponent::RecordMember {
2407 composite_type_id,
2408 member_id,
2409 } => (
2410 DiagnosticFactTag::RecordMember,
2411 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2412 ),
2413 ConstraintValuePathComponent::TupleElement {
2414 composite_type_id,
2415 ordinal,
2416 } => (
2417 DiagnosticFactTag::TupleElement,
2418 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2419 ),
2420 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2421 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2422 }
2423 ConstraintValuePathComponent::EnumVariant {
2424 enum_type_id,
2425 variant_id,
2426 } => (
2427 DiagnosticFactTag::EnumVariant,
2428 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2429 ),
2430 ConstraintValuePathComponent::ListElement { index } => {
2431 (DiagnosticFactTag::ListElement, u64::from(index))
2432 }
2433 ConstraintValuePathComponent::SetElement { index } => {
2434 (DiagnosticFactTag::SetElement, u64::from(index))
2435 }
2436 ConstraintValuePathComponent::MapEntryKey { index } => {
2437 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2438 }
2439 ConstraintValuePathComponent::MapEntryValue { index } => {
2440 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2441 }
2442 }
2443}
2444
2445pub enum ErrorDetail {
2453 DiagnosticFacts(Box<DiagnosticFactDetail>),
2455 Executor(ExecutorErrorDetail),
2457 Store(StoreError),
2458 Query(QueryErrorDetail),
2459 Recovery(RecoveryErrorDetail),
2460 }
2463
2464pub enum ExecutorErrorDetail {
2466 MutationRequiredFieldMissing,
2468 MutationManagedTimestampRegression,
2470 MutationDatabaseOwnedFieldExplicit,
2472 MutationBatchEmpty,
2474 MutationBatchTooManyItems,
2476 MutationBatchStagedBytesExceeded,
2478 MutationBatchResultBytesExceeded,
2480 MutationBatchStoreMismatch,
2482 MutationBatchTooManyEntities,
2484 MutationBatchDuplicateKey,
2486 AcceptedRowConstraintProgramCorrupt,
2488}
2489
2490pub enum RecoveryErrorDetail {
2497 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2498
2499 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2500}
2501
2502#[derive(Clone, Copy, Eq, PartialEq)]
2504pub enum RecoveryFormatMarkerError {
2505 Magic,
2506 Checksum,
2507 State,
2508}
2509
2510impl RecoveryFormatMarkerError {
2511 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2512 match self {
2513 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2514 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2515 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2516 }
2517 }
2518}
2519
2520pub enum StoreError {
2528 NotFound,
2529
2530 Corrupt,
2531
2532 InvariantViolation,
2533
2534 SchemaDdlPublicationRaceLost,
2535
2536 SchemaDdlRewriteRequiresMigration,
2537
2538 SchemaMigration {
2539 reason: diagnostic_code::SchemaMigrationCode,
2540 },
2541
2542 SchemaRowLayoutVersionExhausted,
2543
2544 JournalMutationRevisionExhausted,
2545
2546 SchemaTransitionBudgetExceeded {
2547 resource: SchemaTransitionBudgetResource,
2548 },
2549
2550 SchemaGeneratedFieldAfterDdlField,
2552
2553 SchemaGeneratedConstraintActivationStale,
2555}
2556
2557pub enum QueryErrorDetail {
2564 NumericOverflow,
2565
2566 NumericNotRepresentable,
2567
2568 UnsupportedSqlFeature {
2569 feature: diagnostic_code::SqlFeatureCode,
2570 },
2571
2572 SqlLowering {
2573 reason: diagnostic_code::SqlLoweringCode,
2574 },
2575
2576 UnsupportedProjection {
2577 reason: diagnostic_code::QueryProjectionCode,
2578 },
2579
2580 UnknownAggregateTargetField,
2581
2582 QueryReadAdmission {
2583 reason: diagnostic_code::QueryReadAdmissionCode,
2584 },
2585
2586 SqlSurfaceMismatch {
2587 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2588 },
2589
2590 SqlWriteBoundary {
2591 boundary: diagnostic_code::SqlWriteBoundaryCode,
2592 },
2593
2594 SchemaDdlAdmission {
2595 error: SchemaDdlAdmissionError,
2596 },
2597
2598 StaleSchemaRevision,
2599}
2600
2601impl fmt::Display for QueryErrorDetail {
2602 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2603 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2604 }
2605}
2606
2607impl std::error::Error for QueryErrorDetail {}
2608
2609#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2617pub enum SchemaTransitionBudgetResource {
2618 DeletionKeys,
2620 ProjectionEntries,
2622 ProjectionWorkUnits,
2624 SourceRows,
2626 SourceRowBytes,
2628 StagedRawBytes,
2630}
2631
2632#[derive(Clone, Copy, Eq, PartialEq)]
2641pub enum SchemaDdlAdmissionError {
2642 MissingExpectedSchemaVersion,
2643
2644 MissingNextSchemaVersion,
2645
2646 StaleExpectedSchemaVersion,
2647
2648 InvalidExpectedSchemaVersion,
2649
2650 InvalidNextSchemaVersion,
2651
2652 AcceptedSchemaChangeWithoutVersionBump,
2653
2654 EmptyVersionBump,
2655
2656 VersionGap,
2657
2658 VersionRollback,
2659
2660 FingerprintMethodMismatch,
2661
2662 UnsupportedTransitionClass,
2663
2664 PhysicalRunnerMissing,
2665
2666 ValidationFailed,
2667
2668 PublicationRaceLost,
2669
2670 InvalidAddColumnDefault,
2671
2672 InvalidAlterColumnDefault,
2673
2674 RowLayoutVersionExhausted,
2675
2676 GeneratedIndexDropRejected,
2677
2678 SchemaRewriteRequiresMigration,
2679
2680 SchemaTransitionBudgetExceeded {
2681 resource: SchemaTransitionBudgetResource,
2682 },
2683
2684 GeneratedFieldDefaultChangeRejected,
2685
2686 GeneratedFieldNullabilityChangeRejected,
2687}
2688
2689impl fmt::Display for SchemaDdlAdmissionError {
2690 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2691 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2692 }
2693}
2694
2695impl std::error::Error for SchemaDdlAdmissionError {}
2696
2697impl fmt::Debug for ErrorDetail {
2698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2699 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2700 }
2701}
2702
2703impl fmt::Debug for ExecutorErrorDetail {
2704 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2705 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2706 }
2707}
2708
2709impl fmt::Debug for StoreError {
2710 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2711 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2712 }
2713}
2714
2715impl fmt::Debug for QueryErrorDetail {
2716 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2717 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2718 }
2719}
2720
2721impl fmt::Debug for RecoveryErrorDetail {
2722 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2723 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2724 }
2725}
2726
2727impl fmt::Debug for RecoveryFormatMarkerError {
2728 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2729 fmt_compact_diagnostic(
2730 f,
2731 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2732 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2733 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2734 }),
2735 )
2736 }
2737}
2738
2739impl fmt::Debug for SchemaDdlAdmissionError {
2740 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2741 fmt_compact_diagnostic(
2742 f,
2743 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2744 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2745 reason: self.diagnostic_code(),
2746 }),
2747 )
2748 }
2749}
2750
2751fn fmt_compact_diagnostic(
2752 f: &mut fmt::Formatter<'_>,
2753 code: diagnostic_code::DiagnosticCode,
2754 detail: Option<diagnostic_code::DiagnosticDetail>,
2755) -> fmt::Result {
2756 write!(
2757 f,
2758 "{}",
2759 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2760 )
2761}
2762
2763impl ErrorDetail {
2764 #[must_use]
2766 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2767 match self {
2768 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2769 Self::Executor(error) => error.diagnostic_code(),
2770 Self::Store(error) => error.diagnostic_code(),
2771 Self::Query(error) => error.diagnostic_code(),
2772 Self::Recovery(error) => error.diagnostic_code(),
2773 }
2774 }
2775
2776 #[must_use]
2778 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2779 match self {
2780 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2781 Self::Executor(error) => error.diagnostic_detail(),
2782 Self::Store(error) => error.diagnostic_detail(),
2783 Self::Query(error) => error.diagnostic_detail(),
2784 Self::Recovery(error) => error.diagnostic_detail(),
2785 }
2786 }
2787
2788 #[must_use]
2790 #[cold]
2791 #[inline(never)]
2792 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2793 match self {
2794 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2795 Self::Executor(error) => error.diagnostic_facts(),
2796 Self::Query(error) => error.diagnostic_facts(),
2797 Self::Recovery(error) => error.diagnostic_facts(),
2798 Self::Store(_) => Vec::new(),
2799 }
2800 }
2801}
2802
2803impl ExecutorErrorDetail {
2804 #[must_use]
2806 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2807 match self {
2808 Self::MutationRequiredFieldMissing
2809 | Self::MutationDatabaseOwnedFieldExplicit
2810 | Self::MutationBatchEmpty
2811 | Self::MutationBatchTooManyItems
2812 | Self::MutationBatchTooManyEntities
2813 | Self::MutationBatchStagedBytesExceeded
2814 | Self::MutationBatchResultBytesExceeded => {
2815 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2816 }
2817 Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2818 diagnostic_code::DiagnosticCode::RuntimeConflict
2819 }
2820 Self::MutationManagedTimestampRegression => {
2821 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2822 }
2823 Self::AcceptedRowConstraintProgramCorrupt => {
2824 diagnostic_code::DiagnosticCode::RuntimeCorruption
2825 }
2826 }
2827 }
2828
2829 #[must_use]
2831 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2832 match self {
2833 Self::MutationRequiredFieldMissing => {
2834 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2835 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2836 })
2837 }
2838 Self::MutationDatabaseOwnedFieldExplicit => {
2839 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2840 boundary:
2841 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2842 })
2843 }
2844 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2845 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2846 }),
2847 Self::MutationBatchTooManyItems => {
2848 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2849 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2850 })
2851 }
2852 Self::MutationBatchStagedBytesExceeded => {
2853 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2854 boundary:
2855 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2856 })
2857 }
2858 Self::MutationBatchResultBytesExceeded => {
2859 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2860 boundary:
2861 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2862 })
2863 }
2864 Self::MutationBatchStoreMismatch => {
2865 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2866 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2867 })
2868 }
2869 Self::MutationBatchTooManyEntities => {
2870 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2871 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2872 })
2873 }
2874 Self::MutationBatchDuplicateKey => {
2875 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2876 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2877 })
2878 }
2879 Self::MutationManagedTimestampRegression => {
2880 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2881 boundary:
2882 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2883 })
2884 }
2885 Self::AcceptedRowConstraintProgramCorrupt => {
2886 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2887 boundary:
2888 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2889 })
2890 }
2891 }
2892 }
2893
2894 #[must_use]
2896 #[cold]
2897 #[inline(never)]
2898 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2899 Vec::new()
2900 }
2901}
2902
2903impl RecoveryErrorDetail {
2904 #[must_use]
2906 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2907 match self {
2908 Self::UnsupportedFormatVersion { .. } => {
2909 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2910 }
2911 Self::MalformedFormatMarker { .. } => {
2912 diagnostic_code::DiagnosticCode::RuntimeCorruption
2913 }
2914 }
2915 }
2916
2917 #[must_use]
2919 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2920 let kind = match self {
2921 Self::UnsupportedFormatVersion { .. } => {
2922 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2923 }
2924 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2925 };
2926
2927 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2928 }
2929
2930 #[must_use]
2932 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2933 match self {
2934 Self::UnsupportedFormatVersion { found, required } => {
2935 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2936 facts.push((
2937 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2938 u64::from(*required),
2939 ));
2940 if let Some(found) = found {
2941 facts.push((
2942 diagnostic_code::DiagnosticFactTag::ActualVersion,
2943 u64::from(*found),
2944 ));
2945 }
2946 facts
2947 }
2948 Self::MalformedFormatMarker { reason } => vec![(
2949 diagnostic_code::DiagnosticFactTag::DecodeReason,
2950 reason.diagnostic_decode_reason().raw(),
2951 )],
2952 }
2953 }
2954}
2955
2956impl StoreError {
2957 #[must_use]
2959 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2960 match self {
2961 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2962 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2963 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2964 Self::SchemaDdlPublicationRaceLost
2965 | Self::SchemaDdlRewriteRequiresMigration
2966 | Self::SchemaRowLayoutVersionExhausted
2967 | Self::SchemaTransitionBudgetExceeded { .. } => {
2968 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2969 }
2970 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2971 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2972 }
2973 Self::SchemaGeneratedConstraintActivationStale => {
2974 diagnostic_code::DiagnosticCode::RuntimeConflict
2975 }
2976 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2977 }
2978 }
2979
2980 #[must_use]
2982 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2983 match self {
2984 Self::SchemaDdlPublicationRaceLost => {
2985 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2986 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2987 })
2988 }
2989 Self::SchemaDdlRewriteRequiresMigration => {
2990 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2991 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2992 })
2993 }
2994 Self::SchemaMigration { reason } => {
2995 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2996 }
2997 Self::SchemaRowLayoutVersionExhausted => {
2998 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2999 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
3000 })
3001 }
3002 Self::JournalMutationRevisionExhausted => {
3003 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3004 boundary:
3005 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
3006 })
3007 }
3008 Self::SchemaTransitionBudgetExceeded { .. } => {
3009 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3010 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
3011 })
3012 }
3013 Self::SchemaGeneratedFieldAfterDdlField => {
3014 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3015 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
3016 })
3017 }
3018 Self::SchemaGeneratedConstraintActivationStale => {
3019 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3020 boundary:
3021 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
3022 })
3023 }
3024 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
3025 }
3026 }
3027}
3028
3029impl QueryErrorDetail {
3030 #[must_use]
3032 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
3033 match self {
3034 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
3035 Self::NumericNotRepresentable => {
3036 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
3037 }
3038 Self::UnsupportedSqlFeature { .. } => {
3039 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
3040 }
3041 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
3042 Self::UnsupportedProjection { .. } => {
3043 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
3044 }
3045 Self::UnknownAggregateTargetField => {
3046 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
3047 }
3048 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
3049 Self::SqlSurfaceMismatch { .. } => {
3050 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
3051 }
3052 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
3053 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
3054 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
3055 }
3056 }
3057
3058 #[must_use]
3060 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
3061 match self {
3062 Self::UnsupportedSqlFeature { feature } => {
3063 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
3064 }
3065 Self::SqlLowering { reason } => {
3066 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
3067 }
3068 Self::UnsupportedProjection { reason } => {
3069 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
3070 }
3071 Self::QueryReadAdmission { reason } => {
3072 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
3073 }
3074 Self::SqlSurfaceMismatch { mismatch } => {
3075 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
3076 mismatch: *mismatch,
3077 })
3078 }
3079 Self::SqlWriteBoundary { boundary } => {
3080 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
3081 boundary: *boundary,
3082 })
3083 }
3084 Self::SchemaDdlAdmission { error } => {
3085 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3086 reason: error.diagnostic_code(),
3087 })
3088 }
3089 Self::NumericOverflow
3090 | Self::NumericNotRepresentable
3091 | Self::UnknownAggregateTargetField
3092 | Self::StaleSchemaRevision => None,
3093 }
3094 }
3095
3096 #[must_use]
3098 #[cold]
3099 #[inline(never)]
3100 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3101 Vec::new()
3102 }
3103}
3104
3105impl SchemaDdlAdmissionError {
3106 #[must_use]
3108 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3109 match self {
3110 Self::MissingExpectedSchemaVersion => {
3111 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3112 }
3113 Self::MissingNextSchemaVersion => {
3114 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3115 }
3116 Self::StaleExpectedSchemaVersion => {
3117 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3118 }
3119 Self::InvalidExpectedSchemaVersion => {
3120 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3121 }
3122 Self::InvalidNextSchemaVersion => {
3123 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3124 }
3125 Self::AcceptedSchemaChangeWithoutVersionBump => {
3126 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3127 }
3128 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3129 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3130 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3131 Self::FingerprintMethodMismatch => {
3132 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3133 }
3134 Self::UnsupportedTransitionClass => {
3135 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3136 }
3137 Self::PhysicalRunnerMissing => {
3138 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3139 }
3140 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3141 Self::PublicationRaceLost => {
3142 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3143 }
3144 Self::InvalidAddColumnDefault => {
3145 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3146 }
3147 Self::InvalidAlterColumnDefault => {
3148 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3149 }
3150 Self::GeneratedIndexDropRejected => {
3151 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3152 }
3153 Self::SchemaRewriteRequiresMigration => {
3154 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3155 }
3156 Self::SchemaTransitionBudgetExceeded { .. } => {
3157 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3158 }
3159 Self::GeneratedFieldDefaultChangeRejected => {
3160 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3161 }
3162 Self::GeneratedFieldNullabilityChangeRejected => {
3163 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3164 }
3165 Self::RowLayoutVersionExhausted => {
3166 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3167 }
3168 }
3169 }
3170}
3171
3172#[repr(u8)]
3179#[derive(Clone, Copy, Eq, PartialEq)]
3180pub enum ErrorClass {
3181 Corruption,
3182 IncompatiblePersistedFormat,
3183 NotFound,
3184 Internal,
3185 Conflict,
3186 Unsupported,
3187 InvariantViolation,
3188}
3189
3190impl ErrorClass {
3191 #[must_use]
3193 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3194 match self {
3195 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3196 diagnostic_code::DiagnosticCode::StoreCorruption
3197 }
3198 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3199 Self::IncompatiblePersistedFormat => {
3200 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3201 }
3202 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3203 diagnostic_code::DiagnosticCode::StoreNotFound
3204 }
3205 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3206 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3207 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3208 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3209 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3210 }
3211 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3212 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3213 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3214 }
3215 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3216 }
3217 }
3218}
3219
3220impl fmt::Debug for ErrorClass {
3221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3222 write!(f, "{}", *self as u8)
3223 }
3224}
3225
3226#[repr(u8)]
3233#[derive(Clone, Copy, Eq, PartialEq)]
3234pub enum ErrorOrigin {
3235 Serialize,
3236 Store,
3237 Index,
3238 Identity,
3239 Query,
3240 Planner,
3241 Cursor,
3242 Recovery,
3243 Response,
3244 Executor,
3245 Interface,
3246}
3247
3248impl ErrorOrigin {
3249 #[must_use]
3251 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3252 match self {
3253 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3254 Self::Store => diagnostic_code::ErrorOrigin::Store,
3255 Self::Index => diagnostic_code::ErrorOrigin::Index,
3256 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3257 Self::Query => diagnostic_code::ErrorOrigin::Query,
3258 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3259 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3260 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3261 Self::Response => diagnostic_code::ErrorOrigin::Response,
3262 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3263 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3264 }
3265 }
3266}
3267
3268impl fmt::Debug for ErrorOrigin {
3269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3270 write!(f, "{}", *self as u8)
3271 }
3272}