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 secondary_index_prefix_spec_required() -> Self {
698 Self::query_executor_invariant()
699 }
700
701 pub(crate) fn index_range_limit_spec_required() -> Self {
703 Self::query_executor_invariant()
704 }
705
706 #[cold]
708 #[inline(never)]
709 pub(crate) fn mutation_atomic_save_duplicate_key(
710 entity_tag: u64,
711 first_position: u32,
712 duplicate_position: u32,
713 ) -> Self {
714 Self::mutation_boundary_with_facts(
715 ErrorClass::Conflict,
716 diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
717 vec![
718 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
719 (
720 diagnostic_code::DiagnosticFactTag::FirstBatchPosition,
721 u64::from(first_position),
722 ),
723 (
724 diagnostic_code::DiagnosticFactTag::DuplicateBatchPosition,
725 u64::from(duplicate_position),
726 ),
727 ],
728 )
729 }
730
731 #[cold]
733 #[inline(never)]
734 pub(crate) fn mutation_batch_empty() -> Self {
735 Self::mutation_boundary_with_facts(
736 ErrorClass::Unsupported,
737 diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
738 vec![(diagnostic_code::DiagnosticFactTag::ActualCount, 0)],
739 )
740 }
741
742 #[cold]
744 #[inline(never)]
745 pub(crate) fn mutation_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
746 Self::mutation_boundary_with_facts(
747 ErrorClass::Unsupported,
748 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
749 vec![
750 (
751 diagnostic_code::DiagnosticFactTag::ActualCount,
752 actual_count as u64,
753 ),
754 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
755 ],
756 )
757 }
758
759 #[cold]
761 #[inline(never)]
762 pub(crate) fn mutation_batch_staged_bytes_exceeded(
763 actual_bytes: Option<usize>,
764 limit: usize,
765 ) -> Self {
766 let mut facts = Vec::with_capacity(1 + usize::from(actual_bytes.is_some()));
767 if let Some(actual_bytes) = actual_bytes {
768 facts.push((
769 diagnostic_code::DiagnosticFactTag::ActualLength,
770 actual_bytes as u64,
771 ));
772 }
773 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
774 Self::mutation_boundary_with_facts(
775 ErrorClass::Unsupported,
776 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
777 facts,
778 )
779 }
780
781 #[cold]
783 #[inline(never)]
784 pub(crate) fn mutation_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
785 Self::mutation_boundary_with_facts(
786 ErrorClass::Unsupported,
787 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
788 vec![
789 (
790 diagnostic_code::DiagnosticFactTag::ActualLength,
791 actual_bytes as u64,
792 ),
793 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
794 ],
795 )
796 }
797
798 #[cold]
800 #[inline(never)]
801 pub(crate) fn mutation_batch_commit_work_exceeded(
802 actual_units: Option<usize>,
803 limit: usize,
804 ) -> Self {
805 let mut facts = Vec::with_capacity(1 + usize::from(actual_units.is_some()));
806 if let Some(actual_units) = actual_units {
807 facts.push((
808 diagnostic_code::DiagnosticFactTag::ActualCount,
809 actual_units as u64,
810 ));
811 }
812 facts.push((diagnostic_code::DiagnosticFactTag::Limit, limit as u64));
813 Self::mutation_boundary_with_facts(
814 ErrorClass::Unsupported,
815 diagnostic_code::RuntimeBoundaryCode::MutationBatchCommitWorkExceeded,
816 facts,
817 )
818 }
819
820 pub(crate) fn convergence_backlog_pressure(
822 resource: diagnostic_code::DiagnosticBacklogResource,
823 current: u64,
824 proposed: u64,
825 limit: u64,
826 ) -> Self {
827 Self::mutation_boundary_with_facts(
828 ErrorClass::Conflict,
829 diagnostic_code::RuntimeBoundaryCode::ConvergenceBacklogPressure,
830 vec![
831 (
832 diagnostic_code::DiagnosticFactTag::BacklogResource,
833 resource.raw(),
834 ),
835 (diagnostic_code::DiagnosticFactTag::CurrentCount, current),
836 (diagnostic_code::DiagnosticFactTag::ProposedCount, proposed),
837 (diagnostic_code::DiagnosticFactTag::Limit, limit),
838 ],
839 )
840 }
841
842 #[cold]
844 #[inline(never)]
845 pub(crate) fn exact_key_batch_too_many_items(actual_count: usize, limit: usize) -> Self {
846 Self::exact_key_batch_boundary_with_facts(
847 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchTooManyItems,
848 vec![
849 (
850 diagnostic_code::DiagnosticFactTag::ActualCount,
851 actual_count as u64,
852 ),
853 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
854 ],
855 )
856 }
857
858 #[cold]
860 #[inline(never)]
861 pub(crate) fn exact_key_batch_input_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
862 Self::exact_key_batch_bytes_exceeded(
863 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchInputBytesExceeded,
864 actual_bytes,
865 limit,
866 )
867 }
868
869 #[cold]
871 #[inline(never)]
872 pub(crate) fn exact_key_batch_stored_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
873 Self::exact_key_batch_bytes_exceeded(
874 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchStoredBytesExceeded,
875 actual_bytes,
876 limit,
877 )
878 }
879
880 #[cold]
882 #[inline(never)]
883 pub(crate) fn exact_key_batch_result_bytes_exceeded(actual_bytes: usize, limit: usize) -> Self {
884 Self::exact_key_batch_bytes_exceeded(
885 diagnostic_code::RuntimeBoundaryCode::ExactKeyBatchResultBytesExceeded,
886 actual_bytes,
887 limit,
888 )
889 }
890
891 #[cold]
892 #[inline(never)]
893 fn exact_key_batch_bytes_exceeded(
894 boundary: diagnostic_code::RuntimeBoundaryCode,
895 actual_bytes: usize,
896 limit: usize,
897 ) -> Self {
898 Self::exact_key_batch_boundary_with_facts(
899 boundary,
900 vec![
901 (
902 diagnostic_code::DiagnosticFactTag::ActualLength,
903 actual_bytes as u64,
904 ),
905 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
906 ],
907 )
908 }
909
910 #[cold]
912 #[inline(never)]
913 pub(crate) fn mutation_batch_store_mismatch(
914 batch_position: u32,
915 expected_entity_tag: u64,
916 actual_entity_tag: u64,
917 ) -> Self {
918 Self::mutation_boundary_with_facts(
919 ErrorClass::Conflict,
920 diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
921 vec![
922 (
923 diagnostic_code::DiagnosticFactTag::BatchPosition,
924 u64::from(batch_position),
925 ),
926 (
927 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
928 expected_entity_tag,
929 ),
930 (
931 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
932 actual_entity_tag,
933 ),
934 ],
935 )
936 }
937
938 #[cold]
940 #[inline(never)]
941 pub(crate) fn mutation_batch_too_many_entities(actual_count: usize, limit: usize) -> Self {
942 Self::mutation_boundary_with_facts(
943 ErrorClass::Unsupported,
944 diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
945 vec![
946 (
947 diagnostic_code::DiagnosticFactTag::ActualCount,
948 actual_count as u64,
949 ),
950 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
951 ],
952 )
953 }
954
955 pub(crate) fn mutation_index_store_generation_changed(
957 _expected_generation: u64,
958 _observed_generation: u64,
959 ) -> Self {
960 Self::executor_invariant()
961 }
962
963 #[cold]
965 #[inline(never)]
966 pub(crate) fn planner_invariant() -> Self {
967 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Planner)
968 }
969
970 pub(crate) fn query_invalid_logical_plan() -> Self {
972 Self::planner_invariant()
973 }
974
975 pub(crate) fn store_invariant() -> Self {
977 Self::new(ErrorClass::InvariantViolation, ErrorOrigin::Store)
978 }
979
980 #[cold]
982 #[inline(never)]
983 pub(crate) fn store_internal() -> Self {
984 Self::new(ErrorClass::Internal, ErrorOrigin::Store)
985 }
986
987 pub(crate) fn commit_memory_id_unconfigured() -> Self {
989 Self::store_internal()
990 }
991
992 pub(crate) fn commit_store_uninitialized() -> Self {
994 Self::store_invariant()
995 }
996
997 pub(crate) fn database_incarnation_generation_failed() -> Self {
999 Self::store_internal()
1000 }
1001
1002 pub(crate) fn database_incarnation_invalid() -> Self {
1004 Self::store_corruption()
1005 }
1006
1007 pub(crate) fn recovery_unsupported_database_format(found: Option<u16>, required: u16) -> Self {
1009 Self {
1010 class: ErrorClass::IncompatiblePersistedFormat,
1011 origin: ErrorOrigin::Recovery,
1012 detail: Some(ErrorDetail::Recovery(
1013 RecoveryErrorDetail::UnsupportedFormatVersion { found, required },
1014 )),
1015 }
1016 }
1017
1018 pub(crate) fn recovery_malformed_database_format_marker(
1020 reason: RecoveryFormatMarkerError,
1021 ) -> Self {
1022 Self {
1023 class: ErrorClass::Corruption,
1024 origin: ErrorOrigin::Recovery,
1025 detail: Some(ErrorDetail::Recovery(
1026 RecoveryErrorDetail::MalformedFormatMarker { reason },
1027 )),
1028 }
1029 }
1030
1031 pub(crate) fn recovery_database_format_control_unavailable() -> Self {
1033 Self::new(ErrorClass::Internal, ErrorOrigin::Recovery)
1034 }
1035
1036 pub(crate) fn recovery_pending() -> Self {
1038 Self::with_diagnostic_facts(
1039 ErrorClass::Conflict,
1040 ErrorOrigin::Recovery,
1041 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1042 boundary: diagnostic_code::RuntimeBoundaryCode::DatabaseStartupRecoveryPending,
1043 }),
1044 Vec::new(),
1045 )
1046 }
1047
1048 pub(crate) fn startup_control_corruption() -> Self {
1050 Self::new(ErrorClass::Corruption, ErrorOrigin::Recovery)
1051 }
1052
1053 pub(crate) fn commit_control_memory_growth_failed() -> Self {
1055 Self::store_internal()
1056 }
1057
1058 #[cfg(not(test))]
1060 pub(crate) fn database_format_memory_registration_failed(_err: impl Sized) -> Self {
1061 Self::store_internal()
1062 }
1063
1064 pub(crate) fn recovery_effect_verification_failed() -> Self {
1066 Self::store_corruption()
1067 }
1068
1069 #[cold]
1071 #[inline(never)]
1072 pub(crate) fn index_internal() -> Self {
1073 Self::new(ErrorClass::Internal, ErrorOrigin::Index)
1074 }
1075
1076 pub(crate) fn structural_index_removal_entity_key_required() -> Self {
1078 Self::index_internal()
1079 }
1080
1081 pub(crate) fn structural_index_insertion_entity_key_required() -> Self {
1083 Self::index_internal()
1084 }
1085
1086 pub(crate) fn index_commit_op_old_entity_key_required() -> Self {
1088 Self::index_internal()
1089 }
1090
1091 pub(crate) fn index_commit_op_new_entity_key_required() -> Self {
1093 Self::index_internal()
1094 }
1095
1096 #[cfg(test)]
1098 pub(crate) fn query_internal() -> Self {
1099 Self::new(ErrorClass::Internal, ErrorOrigin::Query)
1100 }
1101
1102 #[cold]
1104 #[inline(never)]
1105 pub(crate) fn query_unsupported() -> Self {
1106 Self::new(ErrorClass::Unsupported, ErrorOrigin::Query)
1107 }
1108
1109 pub(crate) fn query_explain_output_exceeded(limit: u64, observed: u64) -> Self {
1112 Self::with_diagnostic_facts(
1113 ErrorClass::Unsupported,
1114 ErrorOrigin::Query,
1115 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1116 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainOutputExceeded,
1117 }),
1118 vec![
1119 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1120 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1121 ],
1122 )
1123 }
1124
1125 pub(crate) fn query_explain_depth_exceeded(limit: u64, observed: u64) -> Self {
1128 Self::with_diagnostic_facts(
1129 ErrorClass::Unsupported,
1130 ErrorOrigin::Query,
1131 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1132 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainDepthExceeded,
1133 }),
1134 vec![
1135 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1136 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1137 ],
1138 )
1139 }
1140
1141 #[cold]
1144 #[inline(never)]
1145 pub(crate) fn query_stale_accepted_schema_revision(
1146 expected_revision: u64,
1147 current_revision: Option<u64>,
1148 ) -> Self {
1149 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1150 facts.push((
1151 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1152 expected_revision,
1153 ));
1154 if let Some(current_revision) = current_revision {
1155 facts.push((
1156 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1157 current_revision,
1158 ));
1159 }
1160 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1161 }
1162
1163 #[cold]
1165 #[inline(never)]
1166 #[cfg(feature = "sql")]
1167 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1168 Self {
1169 class: ErrorClass::Unsupported,
1170 origin: ErrorOrigin::Query,
1171 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1172 error,
1173 })),
1174 }
1175 }
1176
1177 #[cold]
1179 #[inline(never)]
1180 pub(crate) fn query_numeric_overflow() -> Self {
1181 Self {
1182 class: ErrorClass::Unsupported,
1183 origin: ErrorOrigin::Query,
1184 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1185 }
1186 }
1187
1188 #[cold]
1191 #[inline(never)]
1192 pub(crate) fn query_numeric_not_representable() -> Self {
1193 Self {
1194 class: ErrorClass::Unsupported,
1195 origin: ErrorOrigin::Query,
1196 detail: Some(ErrorDetail::Query(
1197 QueryErrorDetail::NumericNotRepresentable,
1198 )),
1199 }
1200 }
1201
1202 #[cold]
1204 #[inline(never)]
1205 pub(crate) fn serialize_internal() -> Self {
1206 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1207 }
1208
1209 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1211 Self::persisted_row_encode_internal()
1212 }
1213
1214 pub(crate) fn persisted_row_encode_internal() -> Self {
1216 Self::serialize_internal()
1217 }
1218
1219 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1221 Self::persisted_row_encode_internal()
1222 }
1223
1224 #[cold]
1226 #[inline(never)]
1227 pub(crate) fn store_corruption() -> Self {
1228 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1229 }
1230
1231 pub(crate) fn commit_corruption() -> Self {
1233 Self::store_corruption()
1234 }
1235
1236 pub(crate) fn commit_component_corruption() -> Self {
1238 Self::commit_corruption()
1239 }
1240
1241 pub(crate) fn commit_id_generation_failed() -> Self {
1243 Self::store_internal()
1244 }
1245
1246 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1248 Self::store_unsupported()
1249 }
1250
1251 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1253 Self::with_diagnostic_facts(
1254 ErrorClass::Corruption,
1255 ErrorOrigin::Store,
1256 None,
1257 vec![
1258 (
1259 diagnostic_code::DiagnosticFactTag::ComponentKind,
1260 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1261 ),
1262 (
1263 diagnostic_code::DiagnosticFactTag::ActualLength,
1264 actual_length as u64,
1265 ),
1266 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1267 ],
1268 )
1269 }
1270
1271 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1273 Self::commit_corruption()
1274 }
1275
1276 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1278 Self::store_unsupported()
1279 }
1280
1281 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1283 Self::store_unsupported()
1284 }
1285
1286 #[cold]
1288 #[inline(never)]
1289 pub(crate) fn index_corruption() -> Self {
1290 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1291 }
1292
1293 pub(crate) fn index_unique_validation_corruption() -> Self {
1295 Self::index_plan_index_corruption()
1296 }
1297
1298 pub(crate) fn structural_index_entry_corruption() -> Self {
1300 Self::index_plan_index_corruption()
1301 }
1302
1303 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1305 Self::index_invariant()
1306 }
1307
1308 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1310 Self::index_plan_serialize_corruption()
1311 }
1312
1313 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1315 Self::index_plan_serialize_corruption()
1316 }
1317
1318 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1320 Self::index_plan_serialize_corruption()
1321 }
1322
1323 pub(crate) fn index_unique_validation_row_required() -> Self {
1325 Self::index_plan_store_corruption()
1326 }
1327
1328 pub(crate) fn index_only_predicate_component_required() -> Self {
1330 Self::index_invariant()
1331 }
1332
1333 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1335 Self::index_invariant()
1336 }
1337
1338 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1340 Self::index_invariant()
1341 }
1342
1343 pub(crate) fn index_scan_key_corrupted_during(
1345 _context: &'static str,
1346 _err: impl Sized,
1347 ) -> Self {
1348 Self::index_corruption()
1349 }
1350
1351 pub(crate) fn index_projection_component_required(
1353 _index_name: &str,
1354 _component_index: usize,
1355 ) -> Self {
1356 Self::index_invariant()
1357 }
1358
1359 pub(crate) fn index_entry_decode_failed() -> Self {
1361 Self::index_corruption()
1362 }
1363
1364 pub(crate) fn serialize_corruption() -> Self {
1366 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1367 }
1368
1369 pub(crate) fn persisted_row_decode_corruption() -> Self {
1371 Self::serialize_corruption()
1372 }
1373
1374 pub(crate) fn persisted_row_layout_outside_accepted_window(
1376 row_layout: u32,
1377 history_floor: u32,
1378 current_layout: u32,
1379 ) -> Self {
1380 Self::with_diagnostic_facts(
1381 ErrorClass::Corruption,
1382 ErrorOrigin::Serialize,
1383 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1384 boundary:
1385 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1386 }),
1387 vec![
1388 (
1389 diagnostic_code::DiagnosticFactTag::RowLayout,
1390 u64::from(row_layout),
1391 ),
1392 (
1393 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1394 u64::from(history_floor),
1395 ),
1396 (
1397 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1398 u64::from(current_layout),
1399 ),
1400 ],
1401 )
1402 }
1403
1404 pub(crate) fn persisted_row_slot_count_mismatch(
1406 row_layout: u32,
1407 expected_slot_count: usize,
1408 actual_slot_count: usize,
1409 ) -> Self {
1410 Self::with_diagnostic_facts(
1411 ErrorClass::Corruption,
1412 ErrorOrigin::Serialize,
1413 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1414 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1415 }),
1416 vec![
1417 (
1418 diagnostic_code::DiagnosticFactTag::RowLayout,
1419 u64::from(row_layout),
1420 ),
1421 (
1422 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1423 expected_slot_count as u64,
1424 ),
1425 (
1426 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1427 actual_slot_count as u64,
1428 ),
1429 ],
1430 )
1431 }
1432
1433 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1435 Self::persisted_row_field_decode_corruption(field_name)
1436 }
1437
1438 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1440 Self::persisted_row_decode_corruption()
1441 }
1442
1443 pub(crate) fn persisted_row_field_kind_decode_failed(
1445 field_name: &str,
1446 _field_kind: impl fmt::Debug,
1447 _detail: impl Sized,
1448 ) -> Self {
1449 Self::persisted_row_field_decode_corruption(field_name)
1450 }
1451
1452 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1454 Self::persisted_row_field_decode_corruption(field_name)
1455 }
1456
1457 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1459 Self::persisted_row_field_decode_corruption(field_name)
1460 }
1461
1462 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1464 Self::persisted_row_field_decode_corruption(field_name)
1465 }
1466
1467 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1469 Self::persisted_row_field_decode_corruption(field_name)
1470 }
1471
1472 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1474 Self::persisted_row_field_decode_corruption(field_name)
1475 }
1476
1477 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1479 Self::index_invariant()
1480 }
1481
1482 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1484 _model_path: &str,
1485 _slot: usize,
1486 ) -> Self {
1487 Self::index_invariant()
1488 }
1489
1490 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1492 _data_key: impl fmt::Debug,
1493 _detail: impl Sized,
1494 ) -> Self {
1495 Self::persisted_row_decode_corruption()
1496 }
1497
1498 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1500 Self::persisted_row_decode_corruption()
1501 }
1502
1503 pub(crate) fn persisted_row_key_mismatch() -> Self {
1505 Self::store_corruption()
1506 }
1507
1508 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1510 Self::persisted_row_field_decode_corruption(field_name)
1511 }
1512
1513 pub(crate) fn reverse_index_entry_corrupted(
1515 _source_path: &str,
1516 _field_name: &str,
1517 _target_path: &str,
1518 _index_key: impl fmt::Debug,
1519 _detail: impl Sized,
1520 ) -> Self {
1521 Self::index_corruption()
1522 }
1523
1524 pub(crate) fn relation_target_store_missing(
1526 _source_path: &str,
1527 _field_name: &str,
1528 _target_path: &str,
1529 _store_path: &str,
1530 _detail: impl Sized,
1531 ) -> Self {
1532 Self::executor_internal()
1533 }
1534
1535 pub(crate) fn with_relation_identity(self, entity_tag: u64, relation_id: u32) -> Self {
1537 if self.diagnostic().error_code() != diagnostic_code::ErrorCode::RUNTIME_INTERNAL {
1538 return self;
1539 }
1540 let mut facts = vec![
1541 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1542 (
1543 diagnostic_code::DiagnosticFactTag::RelationId,
1544 u64::from(relation_id),
1545 ),
1546 ];
1547 facts.extend(self.diagnostic_facts());
1548 Self::with_diagnostic_facts(self.class, self.origin, None, facts)
1549 }
1550
1551 pub(crate) fn relation_target_primary_key_arity_mismatch(
1553 expected_arity: usize,
1554 actual_arity: usize,
1555 ) -> Self {
1556 Self::with_diagnostic_facts(
1557 ErrorClass::Internal,
1558 ErrorOrigin::Executor,
1559 None,
1560 vec![
1561 (
1562 diagnostic_code::DiagnosticFactTag::ComponentKind,
1563 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1564 ),
1565 (
1566 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1567 expected_arity as u64,
1568 ),
1569 (
1570 diagnostic_code::DiagnosticFactTag::ActualArity,
1571 actual_arity as u64,
1572 ),
1573 ],
1574 )
1575 }
1576
1577 pub(crate) fn relation_target_key_decode_failed(
1579 _context_label: &str,
1580 _source_path: &str,
1581 _field_name: &str,
1582 _target_path: &str,
1583 _detail: impl Sized,
1584 ) -> Self {
1585 Self::identity_corruption()
1586 }
1587
1588 pub(crate) fn relation_target_entity_mismatch(
1590 _context_label: &str,
1591 _source_path: &str,
1592 _field_name: &str,
1593 _target_path: &str,
1594 _target_entity_name: &str,
1595 expected_tag: u64,
1596 actual_tag: u64,
1597 ) -> Self {
1598 Self::with_diagnostic_facts(
1599 ErrorClass::Corruption,
1600 ErrorOrigin::Store,
1601 None,
1602 vec![
1603 (
1604 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1605 expected_tag,
1606 ),
1607 (
1608 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1609 actual_tag,
1610 ),
1611 ],
1612 )
1613 }
1614
1615 pub(crate) fn relation_source_row_decode_failed(
1617 _source_path: &str,
1618 _field_name: &str,
1619 _target_path: &str,
1620 _detail: impl Sized,
1621 ) -> Self {
1622 Self::persisted_row_decode_corruption()
1623 }
1624
1625 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1627 _source_path: &str,
1628 _field_name: &str,
1629 _target_path: &str,
1630 ) -> Self {
1631 Self::persisted_row_decode_corruption()
1632 }
1633
1634 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1636 Self::persisted_row_decode_corruption()
1637 }
1638
1639 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1641 Self::index_corruption()
1642 }
1643
1644 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1646 Self::index_corruption()
1647 }
1648
1649 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1651 Self::index_corruption()
1652 }
1653
1654 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1656 Self::index_corruption()
1657 }
1658
1659 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1661 Self::index_corruption()
1662 }
1663
1664 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1666 Self::index_corruption()
1667 }
1668
1669 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1671 Self::index_corruption()
1672 }
1673
1674 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1676 Self::index_corruption()
1677 }
1678
1679 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1681 Self::index_corruption()
1682 }
1683
1684 pub(crate) fn identity_corruption() -> Self {
1686 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1687 }
1688
1689 pub(crate) fn identity_state_corruption() -> Self {
1691 Self::identity_corruption()
1692 }
1693
1694 pub(crate) fn identity_state_conflict() -> Self {
1696 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1697 }
1698
1699 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1701 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1702 }
1703
1704 pub(crate) fn identity_exhausted() -> Self {
1706 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1707 }
1708
1709 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1711 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1712 }
1713
1714 #[cold]
1716 #[inline(never)]
1717 pub(crate) fn store_unsupported() -> Self {
1718 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1719 }
1720
1721 pub(crate) fn schema_application_conflict() -> Self {
1723 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1724 }
1725
1726 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1728 let class = match reason.diagnostic_code() {
1729 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1730 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1731 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1732 _ => ErrorClass::Internal,
1733 };
1734 Self {
1735 class,
1736 origin: ErrorOrigin::Store,
1737 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1738 }
1739 }
1740
1741 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1743 Self {
1744 class: ErrorClass::Unsupported,
1745 origin: ErrorOrigin::Store,
1746 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1747 }
1748 }
1749
1750 #[cfg(feature = "sql")]
1752 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1753 Self {
1754 class: ErrorClass::Unsupported,
1755 origin: ErrorOrigin::Store,
1756 detail: Some(ErrorDetail::Store(
1757 StoreError::SchemaDdlRewriteRequiresMigration,
1758 )),
1759 }
1760 }
1761
1762 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1764 Self {
1765 class: ErrorClass::Unsupported,
1766 origin: ErrorOrigin::Store,
1767 detail: Some(ErrorDetail::Store(
1768 StoreError::JournalMutationRevisionExhausted,
1769 )),
1770 }
1771 }
1772
1773 pub(crate) fn schema_transition_budget_exceeded(
1775 resource: SchemaTransitionBudgetResource,
1776 ) -> Self {
1777 Self {
1778 class: ErrorClass::Unsupported,
1779 origin: ErrorOrigin::Store,
1780 detail: Some(ErrorDetail::Store(
1781 StoreError::SchemaTransitionBudgetExceeded { resource },
1782 )),
1783 }
1784 }
1785
1786 pub(crate) fn unsupported_entity_tag_in_data_store(
1788 _entity_tag: crate::types::EntityTag,
1789 ) -> Self {
1790 Self::store_unsupported()
1791 }
1792
1793 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1795 Self::store_internal()
1796 }
1797
1798 pub(crate) fn index_unsupported() -> Self {
1800 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1801 }
1802
1803 pub(crate) fn index_component_exceeds_max_size_at(
1805 entity_tag: u64,
1806 physical_generation: u64,
1807 component_index: usize,
1808 actual_length: usize,
1809 limit: usize,
1810 ) -> Self {
1811 Self::with_diagnostic_facts(
1812 ErrorClass::Unsupported,
1813 ErrorOrigin::Index,
1814 None,
1815 vec![
1816 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1817 (
1818 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1819 physical_generation,
1820 ),
1821 (
1822 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1823 component_index as u64,
1824 ),
1825 (
1826 diagnostic_code::DiagnosticFactTag::ComponentKind,
1827 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1828 ),
1829 (
1830 diagnostic_code::DiagnosticFactTag::ActualLength,
1831 actual_length as u64,
1832 ),
1833 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1834 ],
1835 )
1836 }
1837
1838 pub(crate) fn index_component_exceeds_max_size() -> Self {
1841 Self::index_unsupported()
1842 }
1843
1844 pub(crate) fn serialize_unsupported() -> Self {
1846 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1847 }
1848
1849 pub(crate) fn cursor_invalid_continuation() -> Self {
1851 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1852 }
1853
1854 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1856 Self::new(
1857 ErrorClass::IncompatiblePersistedFormat,
1858 ErrorOrigin::Serialize,
1859 )
1860 }
1861
1862 #[cfg(feature = "sql")]
1865 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1866 Self {
1867 class: ErrorClass::Unsupported,
1868 origin: ErrorOrigin::Query,
1869 detail: Some(ErrorDetail::Query(
1870 QueryErrorDetail::UnsupportedSqlFeature { feature },
1871 )),
1872 }
1873 }
1874
1875 #[cfg(feature = "sql")]
1878 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1879 Self {
1880 class: ErrorClass::Unsupported,
1881 origin: ErrorOrigin::Query,
1882 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1883 }
1884 }
1885
1886 #[cfg(feature = "sql")]
1888 pub(crate) fn query_sql_lowering_with_facts(
1889 reason: diagnostic_code::SqlLoweringCode,
1890 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1891 ) -> Self {
1892 Self::with_diagnostic_facts(
1893 ErrorClass::Unsupported,
1894 ErrorOrigin::Query,
1895 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1896 facts,
1897 )
1898 }
1899
1900 pub(crate) fn query_unsupported_projection(
1903 reason: diagnostic_code::QueryProjectionCode,
1904 ) -> Self {
1905 Self {
1906 class: ErrorClass::Unsupported,
1907 origin: ErrorOrigin::Query,
1908 detail: Some(ErrorDetail::Query(
1909 QueryErrorDetail::UnsupportedProjection { reason },
1910 )),
1911 }
1912 }
1913
1914 #[cfg(feature = "sql")]
1917 pub(crate) fn query_sql_surface_mismatch(
1918 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1919 ) -> Self {
1920 Self {
1921 class: ErrorClass::Unsupported,
1922 origin: ErrorOrigin::Query,
1923 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1924 mismatch,
1925 })),
1926 }
1927 }
1928
1929 pub(crate) fn query_sql_write_boundary(
1931 boundary: diagnostic_code::SqlWriteBoundaryCode,
1932 ) -> Self {
1933 Self {
1934 class: ErrorClass::Unsupported,
1935 origin: ErrorOrigin::Query,
1936 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1937 boundary,
1938 })),
1939 }
1940 }
1941
1942 pub(crate) fn query_sql_write_boundary_with_facts(
1944 boundary: diagnostic_code::SqlWriteBoundaryCode,
1945 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1946 ) -> Self {
1947 Self::with_diagnostic_facts(
1948 ErrorClass::Unsupported,
1949 ErrorOrigin::Query,
1950 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1951 facts,
1952 )
1953 }
1954
1955 pub fn store_not_found(_key: impl Sized) -> Self {
1956 Self {
1957 class: ErrorClass::NotFound,
1958 origin: ErrorOrigin::Store,
1959 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1960 }
1961 }
1962
1963 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1965 Self::store_unsupported()
1966 }
1967
1968 #[cold]
1970 #[inline(never)]
1971 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1972 Self::new(ErrorClass::Corruption, origin)
1973 }
1974
1975 #[cold]
1977 #[inline(never)]
1978 pub(crate) fn index_plan_index_corruption() -> Self {
1979 Self::index_plan_corruption(ErrorOrigin::Index)
1980 }
1981
1982 #[cold]
1984 #[inline(never)]
1985 pub(crate) fn index_plan_store_corruption() -> Self {
1986 Self::index_plan_corruption(ErrorOrigin::Store)
1987 }
1988
1989 #[cold]
1991 #[inline(never)]
1992 pub(crate) fn index_plan_serialize_corruption() -> Self {
1993 Self::index_plan_corruption(ErrorOrigin::Serialize)
1994 }
1995
1996 #[cfg(test)]
1998 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
1999 Self::new(ErrorClass::InvariantViolation, origin)
2000 }
2001
2002 #[cfg(test)]
2004 pub(crate) fn index_plan_store_invariant() -> Self {
2005 Self::index_plan_invariant(ErrorOrigin::Store)
2006 }
2007
2008 pub(crate) fn index_conflict() -> Self {
2014 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
2015 }
2016}
2017
2018impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
2019 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
2020 Self {
2021 class: ErrorClass::Unsupported,
2022 origin: ErrorOrigin::Query,
2023 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
2024 reason,
2025 })),
2026 }
2027 }
2028}
2029
2030impl fmt::Debug for InternalError {
2031 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2032 fmt_compact_diagnostic(
2033 f,
2034 self.diagnostic_code(),
2035 self.detail
2036 .as_ref()
2037 .and_then(ErrorDetail::diagnostic_detail),
2038 )
2039 }
2040}
2041
2042impl fmt::Display for InternalError {
2043 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2044 f.write_str(self.message())
2045 }
2046}
2047
2048impl std::error::Error for InternalError {}
2049
2050#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2059pub enum ConstraintValuePathComponent {
2060 RootField { field_id: u32 },
2062
2063 RecordMember {
2065 composite_type_id: u32,
2066 member_id: u32,
2067 },
2068
2069 TupleElement {
2071 composite_type_id: u32,
2072 ordinal: u32,
2073 },
2074
2075 Newtype { composite_type_id: u32 },
2077
2078 EnumVariant { enum_type_id: u32, variant_id: u32 },
2080
2081 ListElement { index: u32 },
2083
2084 SetElement { index: u32 },
2086
2087 MapEntryKey { index: u32 },
2089
2090 MapEntryValue { index: u32 },
2092}
2093
2094impl fmt::Display for ConstraintValuePathComponent {
2095 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2096 match self {
2097 Self::RootField { field_id } => write!(f, "field#{field_id}"),
2098 Self::RecordMember {
2099 composite_type_id,
2100 member_id,
2101 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2102 Self::TupleElement {
2103 composite_type_id,
2104 ordinal,
2105 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2106 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2107 Self::EnumVariant {
2108 enum_type_id,
2109 variant_id,
2110 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2111 Self::ListElement { index } => write!(f, "list[{index}]"),
2112 Self::SetElement { index } => write!(f, "set[{index}]"),
2113 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2114 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2115 }
2116 }
2117}
2118
2119#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2126pub struct ConstraintValuePath {
2127 components: Vec<ConstraintValuePathComponent>,
2128}
2129
2130impl ConstraintValuePath {
2131 #[must_use]
2133 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2134 Self { components }
2135 }
2136
2137 #[must_use]
2139 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2140 self.components.as_slice()
2141 }
2142}
2143
2144impl fmt::Display for ConstraintValuePath {
2145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2146 for (ordinal, component) in self.components.iter().enumerate() {
2147 if ordinal != 0 {
2148 f.write_str("/")?;
2149 }
2150 component.fmt(f)?;
2151 }
2152 Ok(())
2153 }
2154}
2155
2156#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2165pub struct ConstraintValidationFindingOutput {
2166 accepted_schema_fingerprint: [u8; 16],
2167 entity_tag: u64,
2168 constraint_id: u32,
2169 primary_key: Vec<u8>,
2170 field_ids: Vec<u32>,
2171 value_path: Option<ConstraintValuePath>,
2172 error_code: u16,
2173}
2174
2175impl ConstraintValidationFindingOutput {
2176 #[must_use]
2178 pub(crate) const fn new(
2179 accepted_schema_fingerprint: [u8; 16],
2180 entity_tag: u64,
2181 constraint_id: u32,
2182 primary_key: Vec<u8>,
2183 field_ids: Vec<u32>,
2184 value_path: Option<ConstraintValuePath>,
2185 error_code: u16,
2186 ) -> Self {
2187 Self {
2188 accepted_schema_fingerprint,
2189 entity_tag,
2190 constraint_id,
2191 primary_key,
2192 field_ids,
2193 value_path,
2194 error_code,
2195 }
2196 }
2197
2198 #[must_use]
2200 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2201 self.accepted_schema_fingerprint
2202 }
2203
2204 #[must_use]
2206 pub const fn entity_tag(&self) -> u64 {
2207 self.entity_tag
2208 }
2209
2210 #[must_use]
2212 pub const fn constraint_id(&self) -> u32 {
2213 self.constraint_id
2214 }
2215
2216 #[must_use]
2218 pub const fn primary_key(&self) -> &[u8] {
2219 self.primary_key.as_slice()
2220 }
2221
2222 #[must_use]
2224 pub const fn field_ids(&self) -> &[u32] {
2225 self.field_ids.as_slice()
2226 }
2227
2228 #[must_use]
2230 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2231 self.value_path.as_ref()
2232 }
2233
2234 #[must_use]
2236 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2237 diagnostic_code::ErrorCode::from_raw(self.error_code)
2238 }
2239
2240 #[must_use]
2242 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2243 self.error_code().class()
2244 }
2245}
2246
2247#[derive(Clone)]
2249pub(crate) struct AcceptedConstraintFactContext {
2250 fingerprint_method: u8,
2251 accepted_schema_fingerprint: [u8; 16],
2252 entity_tag: u64,
2253 constraint_id: u32,
2254 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2255 mutation: Option<MutationDiagnosticContext>,
2256 value_path: Option<ConstraintValuePath>,
2257}
2258
2259impl AcceptedConstraintFactContext {
2260 #[must_use]
2261 pub(crate) fn write_admission(
2262 fingerprint_method: u8,
2263 accepted_schema_fingerprint: [u8; 16],
2264 entity_tag: u64,
2265 constraint_id: u32,
2266 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2267 mutation: Option<MutationDiagnosticContext>,
2268 value_path: Option<ConstraintValuePath>,
2269 ) -> Self {
2270 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2271 Self {
2272 fingerprint_method,
2273 accepted_schema_fingerprint,
2274 entity_tag,
2275 constraint_id,
2276 constraint_kind,
2277 mutation,
2278 value_path,
2279 }
2280 }
2281
2282 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2283 let path_len = self
2284 .value_path
2285 .as_ref()
2286 .map_or(0, |path| path.components().len());
2287 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2288 1 + usize::from(mutation.batch_position.is_some())
2289 });
2290 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2291 append_accepted_schema_facts(
2292 &mut facts,
2293 self.fingerprint_method,
2294 self.accepted_schema_fingerprint,
2295 );
2296 facts.push((
2297 diagnostic_code::DiagnosticFactTag::EntityTag,
2298 self.entity_tag,
2299 ));
2300 facts.push((
2301 diagnostic_code::DiagnosticFactTag::ConstraintId,
2302 u64::from(self.constraint_id),
2303 ));
2304 facts.push((
2305 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2306 self.constraint_kind.raw(),
2307 ));
2308 facts.push((
2309 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2310 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2311 ));
2312 if let Some(mutation) = self.mutation {
2313 mutation.append_operation_facts(&mut facts);
2314 }
2315 if let Some(path) = self.value_path {
2316 for component in path.components {
2317 facts.push(constraint_value_path_fact(component));
2318 }
2319 }
2320 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2321 facts
2322 }
2323}
2324
2325fn append_accepted_schema_facts(
2327 facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2328 method: u8,
2329 fingerprint: [u8; 16],
2330) {
2331 facts.extend([
2332 (
2333 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2334 u64::from(method),
2335 ),
2336 (
2337 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2338 u64::from_be_bytes([
2339 fingerprint[0],
2340 fingerprint[1],
2341 fingerprint[2],
2342 fingerprint[3],
2343 fingerprint[4],
2344 fingerprint[5],
2345 fingerprint[6],
2346 fingerprint[7],
2347 ]),
2348 ),
2349 (
2350 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2351 u64::from_be_bytes([
2352 fingerprint[8],
2353 fingerprint[9],
2354 fingerprint[10],
2355 fingerprint[11],
2356 fingerprint[12],
2357 fingerprint[13],
2358 fingerprint[14],
2359 fingerprint[15],
2360 ]),
2361 ),
2362 ]);
2363}
2364
2365fn constraint_value_path_fact(
2366 component: ConstraintValuePathComponent,
2367) -> (diagnostic_code::DiagnosticFactTag, u64) {
2368 use diagnostic_code::DiagnosticFactTag;
2369 match component {
2370 ConstraintValuePathComponent::RootField { field_id } => {
2371 (DiagnosticFactTag::RootField, u64::from(field_id))
2372 }
2373 ConstraintValuePathComponent::RecordMember {
2374 composite_type_id,
2375 member_id,
2376 } => (
2377 DiagnosticFactTag::RecordMember,
2378 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2379 ),
2380 ConstraintValuePathComponent::TupleElement {
2381 composite_type_id,
2382 ordinal,
2383 } => (
2384 DiagnosticFactTag::TupleElement,
2385 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2386 ),
2387 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2388 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2389 }
2390 ConstraintValuePathComponent::EnumVariant {
2391 enum_type_id,
2392 variant_id,
2393 } => (
2394 DiagnosticFactTag::EnumVariant,
2395 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2396 ),
2397 ConstraintValuePathComponent::ListElement { index } => {
2398 (DiagnosticFactTag::ListElement, u64::from(index))
2399 }
2400 ConstraintValuePathComponent::SetElement { index } => {
2401 (DiagnosticFactTag::SetElement, u64::from(index))
2402 }
2403 ConstraintValuePathComponent::MapEntryKey { index } => {
2404 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2405 }
2406 ConstraintValuePathComponent::MapEntryValue { index } => {
2407 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2408 }
2409 }
2410}
2411
2412pub enum ErrorDetail {
2420 DiagnosticFacts(Box<DiagnosticFactDetail>),
2422 Executor(ExecutorErrorDetail),
2424 Store(StoreError),
2425 Query(QueryErrorDetail),
2426 Recovery(RecoveryErrorDetail),
2427 }
2430
2431pub enum ExecutorErrorDetail {
2433 MutationRequiredFieldMissing,
2435 MutationManagedTimestampRegression,
2437 MutationDatabaseOwnedFieldExplicit,
2439 MutationBatchEmpty,
2441 MutationBatchTooManyItems,
2443 MutationBatchStagedBytesExceeded,
2445 MutationBatchResultBytesExceeded,
2447 MutationBatchStoreMismatch,
2449 MutationBatchTooManyEntities,
2451 MutationBatchDuplicateKey,
2453 AcceptedRowConstraintProgramCorrupt,
2455}
2456
2457pub enum RecoveryErrorDetail {
2464 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2465
2466 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2467}
2468
2469#[derive(Clone, Copy, Eq, PartialEq)]
2471pub enum RecoveryFormatMarkerError {
2472 Magic,
2473 Checksum,
2474 State,
2475}
2476
2477impl RecoveryFormatMarkerError {
2478 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2479 match self {
2480 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2481 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2482 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2483 }
2484 }
2485}
2486
2487pub enum StoreError {
2495 NotFound,
2496
2497 Corrupt,
2498
2499 InvariantViolation,
2500
2501 SchemaDdlPublicationRaceLost,
2502
2503 SchemaDdlRewriteRequiresMigration,
2504
2505 SchemaMigration {
2506 reason: diagnostic_code::SchemaMigrationCode,
2507 },
2508
2509 SchemaRowLayoutVersionExhausted,
2510
2511 JournalMutationRevisionExhausted,
2512
2513 SchemaTransitionBudgetExceeded {
2514 resource: SchemaTransitionBudgetResource,
2515 },
2516
2517 SchemaGeneratedFieldAfterDdlField,
2519
2520 SchemaGeneratedConstraintActivationStale,
2522}
2523
2524pub enum QueryErrorDetail {
2531 NumericOverflow,
2532
2533 NumericNotRepresentable,
2534
2535 UnsupportedSqlFeature {
2536 feature: diagnostic_code::SqlFeatureCode,
2537 },
2538
2539 SqlLowering {
2540 reason: diagnostic_code::SqlLoweringCode,
2541 },
2542
2543 UnsupportedProjection {
2544 reason: diagnostic_code::QueryProjectionCode,
2545 },
2546
2547 UnknownAggregateTargetField,
2548
2549 QueryReadAdmission {
2550 reason: diagnostic_code::QueryReadAdmissionCode,
2551 },
2552
2553 SqlSurfaceMismatch {
2554 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2555 },
2556
2557 SqlWriteBoundary {
2558 boundary: diagnostic_code::SqlWriteBoundaryCode,
2559 },
2560
2561 SchemaDdlAdmission {
2562 error: SchemaDdlAdmissionError,
2563 },
2564
2565 StaleSchemaRevision,
2566}
2567
2568impl fmt::Display for QueryErrorDetail {
2569 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2570 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2571 }
2572}
2573
2574impl std::error::Error for QueryErrorDetail {}
2575
2576#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2584pub enum SchemaTransitionBudgetResource {
2585 DeletionKeys,
2587 ProjectionEntries,
2589 ProjectionWorkUnits,
2591 SourceRows,
2593 SourceRowBytes,
2595 StagedRawBytes,
2597}
2598
2599#[derive(Clone, Copy, Eq, PartialEq)]
2608pub enum SchemaDdlAdmissionError {
2609 MissingExpectedSchemaVersion,
2610
2611 MissingNextSchemaVersion,
2612
2613 StaleExpectedSchemaVersion,
2614
2615 InvalidExpectedSchemaVersion,
2616
2617 InvalidNextSchemaVersion,
2618
2619 AcceptedSchemaChangeWithoutVersionBump,
2620
2621 EmptyVersionBump,
2622
2623 VersionGap,
2624
2625 VersionRollback,
2626
2627 FingerprintMethodMismatch,
2628
2629 UnsupportedTransitionClass,
2630
2631 PhysicalRunnerMissing,
2632
2633 ValidationFailed,
2634
2635 PublicationRaceLost,
2636
2637 InvalidAddColumnDefault,
2638
2639 InvalidAlterColumnDefault,
2640
2641 RowLayoutVersionExhausted,
2642
2643 GeneratedIndexDropRejected,
2644
2645 SchemaRewriteRequiresMigration,
2646
2647 SchemaTransitionBudgetExceeded {
2648 resource: SchemaTransitionBudgetResource,
2649 },
2650
2651 GeneratedFieldDefaultChangeRejected,
2652
2653 GeneratedFieldNullabilityChangeRejected,
2654}
2655
2656impl fmt::Display for SchemaDdlAdmissionError {
2657 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2658 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2659 }
2660}
2661
2662impl std::error::Error for SchemaDdlAdmissionError {}
2663
2664impl fmt::Debug for ErrorDetail {
2665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2666 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2667 }
2668}
2669
2670impl fmt::Debug for ExecutorErrorDetail {
2671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2672 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2673 }
2674}
2675
2676impl fmt::Debug for StoreError {
2677 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2678 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2679 }
2680}
2681
2682impl fmt::Debug for QueryErrorDetail {
2683 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2684 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2685 }
2686}
2687
2688impl fmt::Debug for RecoveryErrorDetail {
2689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2690 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2691 }
2692}
2693
2694impl fmt::Debug for RecoveryFormatMarkerError {
2695 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2696 fmt_compact_diagnostic(
2697 f,
2698 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2699 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2700 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2701 }),
2702 )
2703 }
2704}
2705
2706impl fmt::Debug for SchemaDdlAdmissionError {
2707 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2708 fmt_compact_diagnostic(
2709 f,
2710 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2711 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2712 reason: self.diagnostic_code(),
2713 }),
2714 )
2715 }
2716}
2717
2718fn fmt_compact_diagnostic(
2719 f: &mut fmt::Formatter<'_>,
2720 code: diagnostic_code::DiagnosticCode,
2721 detail: Option<diagnostic_code::DiagnosticDetail>,
2722) -> fmt::Result {
2723 write!(
2724 f,
2725 "{}",
2726 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2727 )
2728}
2729
2730impl ErrorDetail {
2731 #[must_use]
2733 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2734 match self {
2735 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2736 Self::Executor(error) => error.diagnostic_code(),
2737 Self::Store(error) => error.diagnostic_code(),
2738 Self::Query(error) => error.diagnostic_code(),
2739 Self::Recovery(error) => error.diagnostic_code(),
2740 }
2741 }
2742
2743 #[must_use]
2745 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2746 match self {
2747 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2748 Self::Executor(error) => error.diagnostic_detail(),
2749 Self::Store(error) => error.diagnostic_detail(),
2750 Self::Query(error) => error.diagnostic_detail(),
2751 Self::Recovery(error) => error.diagnostic_detail(),
2752 }
2753 }
2754
2755 #[must_use]
2757 #[cold]
2758 #[inline(never)]
2759 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2760 match self {
2761 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2762 Self::Executor(error) => error.diagnostic_facts(),
2763 Self::Query(error) => error.diagnostic_facts(),
2764 Self::Recovery(error) => error.diagnostic_facts(),
2765 Self::Store(_) => Vec::new(),
2766 }
2767 }
2768}
2769
2770impl ExecutorErrorDetail {
2771 #[must_use]
2773 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2774 match self {
2775 Self::MutationRequiredFieldMissing
2776 | Self::MutationDatabaseOwnedFieldExplicit
2777 | Self::MutationBatchEmpty
2778 | Self::MutationBatchTooManyItems
2779 | Self::MutationBatchTooManyEntities
2780 | Self::MutationBatchStagedBytesExceeded
2781 | Self::MutationBatchResultBytesExceeded => {
2782 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2783 }
2784 Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2785 diagnostic_code::DiagnosticCode::RuntimeConflict
2786 }
2787 Self::MutationManagedTimestampRegression => {
2788 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2789 }
2790 Self::AcceptedRowConstraintProgramCorrupt => {
2791 diagnostic_code::DiagnosticCode::RuntimeCorruption
2792 }
2793 }
2794 }
2795
2796 #[must_use]
2798 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2799 match self {
2800 Self::MutationRequiredFieldMissing => {
2801 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2802 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2803 })
2804 }
2805 Self::MutationDatabaseOwnedFieldExplicit => {
2806 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2807 boundary:
2808 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2809 })
2810 }
2811 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2812 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2813 }),
2814 Self::MutationBatchTooManyItems => {
2815 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2816 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2817 })
2818 }
2819 Self::MutationBatchStagedBytesExceeded => {
2820 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2821 boundary:
2822 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2823 })
2824 }
2825 Self::MutationBatchResultBytesExceeded => {
2826 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2827 boundary:
2828 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2829 })
2830 }
2831 Self::MutationBatchStoreMismatch => {
2832 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2833 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2834 })
2835 }
2836 Self::MutationBatchTooManyEntities => {
2837 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2838 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2839 })
2840 }
2841 Self::MutationBatchDuplicateKey => {
2842 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2843 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2844 })
2845 }
2846 Self::MutationManagedTimestampRegression => {
2847 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2848 boundary:
2849 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2850 })
2851 }
2852 Self::AcceptedRowConstraintProgramCorrupt => {
2853 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2854 boundary:
2855 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2856 })
2857 }
2858 }
2859 }
2860
2861 #[must_use]
2863 #[cold]
2864 #[inline(never)]
2865 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2866 Vec::new()
2867 }
2868}
2869
2870impl RecoveryErrorDetail {
2871 #[must_use]
2873 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2874 match self {
2875 Self::UnsupportedFormatVersion { .. } => {
2876 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2877 }
2878 Self::MalformedFormatMarker { .. } => {
2879 diagnostic_code::DiagnosticCode::RuntimeCorruption
2880 }
2881 }
2882 }
2883
2884 #[must_use]
2886 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2887 let kind = match self {
2888 Self::UnsupportedFormatVersion { .. } => {
2889 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2890 }
2891 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2892 };
2893
2894 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2895 }
2896
2897 #[must_use]
2899 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2900 match self {
2901 Self::UnsupportedFormatVersion { found, required } => {
2902 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2903 facts.push((
2904 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2905 u64::from(*required),
2906 ));
2907 if let Some(found) = found {
2908 facts.push((
2909 diagnostic_code::DiagnosticFactTag::ActualVersion,
2910 u64::from(*found),
2911 ));
2912 }
2913 facts
2914 }
2915 Self::MalformedFormatMarker { reason } => vec![(
2916 diagnostic_code::DiagnosticFactTag::DecodeReason,
2917 reason.diagnostic_decode_reason().raw(),
2918 )],
2919 }
2920 }
2921}
2922
2923impl StoreError {
2924 #[must_use]
2926 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2927 match self {
2928 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2929 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2930 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2931 Self::SchemaDdlPublicationRaceLost
2932 | Self::SchemaDdlRewriteRequiresMigration
2933 | Self::SchemaRowLayoutVersionExhausted
2934 | Self::SchemaTransitionBudgetExceeded { .. } => {
2935 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2936 }
2937 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2938 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2939 }
2940 Self::SchemaGeneratedConstraintActivationStale => {
2941 diagnostic_code::DiagnosticCode::RuntimeConflict
2942 }
2943 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2944 }
2945 }
2946
2947 #[must_use]
2949 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2950 match self {
2951 Self::SchemaDdlPublicationRaceLost => {
2952 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2953 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2954 })
2955 }
2956 Self::SchemaDdlRewriteRequiresMigration => {
2957 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2958 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2959 })
2960 }
2961 Self::SchemaMigration { reason } => {
2962 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2963 }
2964 Self::SchemaRowLayoutVersionExhausted => {
2965 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2966 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2967 })
2968 }
2969 Self::JournalMutationRevisionExhausted => {
2970 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2971 boundary:
2972 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2973 })
2974 }
2975 Self::SchemaTransitionBudgetExceeded { .. } => {
2976 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2977 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2978 })
2979 }
2980 Self::SchemaGeneratedFieldAfterDdlField => {
2981 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2982 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2983 })
2984 }
2985 Self::SchemaGeneratedConstraintActivationStale => {
2986 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2987 boundary:
2988 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
2989 })
2990 }
2991 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
2992 }
2993 }
2994}
2995
2996impl QueryErrorDetail {
2997 #[must_use]
2999 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
3000 match self {
3001 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
3002 Self::NumericNotRepresentable => {
3003 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
3004 }
3005 Self::UnsupportedSqlFeature { .. } => {
3006 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
3007 }
3008 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
3009 Self::UnsupportedProjection { .. } => {
3010 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
3011 }
3012 Self::UnknownAggregateTargetField => {
3013 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
3014 }
3015 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
3016 Self::SqlSurfaceMismatch { .. } => {
3017 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
3018 }
3019 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
3020 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
3021 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
3022 }
3023 }
3024
3025 #[must_use]
3027 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
3028 match self {
3029 Self::UnsupportedSqlFeature { feature } => {
3030 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
3031 }
3032 Self::SqlLowering { reason } => {
3033 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
3034 }
3035 Self::UnsupportedProjection { reason } => {
3036 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
3037 }
3038 Self::QueryReadAdmission { reason } => {
3039 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
3040 }
3041 Self::SqlSurfaceMismatch { mismatch } => {
3042 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
3043 mismatch: *mismatch,
3044 })
3045 }
3046 Self::SqlWriteBoundary { boundary } => {
3047 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
3048 boundary: *boundary,
3049 })
3050 }
3051 Self::SchemaDdlAdmission { error } => {
3052 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3053 reason: error.diagnostic_code(),
3054 })
3055 }
3056 Self::NumericOverflow
3057 | Self::NumericNotRepresentable
3058 | Self::UnknownAggregateTargetField
3059 | Self::StaleSchemaRevision => None,
3060 }
3061 }
3062
3063 #[must_use]
3065 #[cold]
3066 #[inline(never)]
3067 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3068 Vec::new()
3069 }
3070}
3071
3072impl SchemaDdlAdmissionError {
3073 #[must_use]
3075 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3076 match self {
3077 Self::MissingExpectedSchemaVersion => {
3078 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3079 }
3080 Self::MissingNextSchemaVersion => {
3081 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3082 }
3083 Self::StaleExpectedSchemaVersion => {
3084 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3085 }
3086 Self::InvalidExpectedSchemaVersion => {
3087 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3088 }
3089 Self::InvalidNextSchemaVersion => {
3090 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3091 }
3092 Self::AcceptedSchemaChangeWithoutVersionBump => {
3093 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3094 }
3095 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3096 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3097 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3098 Self::FingerprintMethodMismatch => {
3099 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3100 }
3101 Self::UnsupportedTransitionClass => {
3102 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3103 }
3104 Self::PhysicalRunnerMissing => {
3105 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3106 }
3107 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3108 Self::PublicationRaceLost => {
3109 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3110 }
3111 Self::InvalidAddColumnDefault => {
3112 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3113 }
3114 Self::InvalidAlterColumnDefault => {
3115 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3116 }
3117 Self::GeneratedIndexDropRejected => {
3118 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3119 }
3120 Self::SchemaRewriteRequiresMigration => {
3121 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3122 }
3123 Self::SchemaTransitionBudgetExceeded { .. } => {
3124 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3125 }
3126 Self::GeneratedFieldDefaultChangeRejected => {
3127 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3128 }
3129 Self::GeneratedFieldNullabilityChangeRejected => {
3130 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3131 }
3132 Self::RowLayoutVersionExhausted => {
3133 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3134 }
3135 }
3136 }
3137}
3138
3139#[repr(u8)]
3146#[derive(Clone, Copy, Eq, PartialEq)]
3147pub enum ErrorClass {
3148 Corruption,
3149 IncompatiblePersistedFormat,
3150 NotFound,
3151 Internal,
3152 Conflict,
3153 Unsupported,
3154 InvariantViolation,
3155}
3156
3157impl ErrorClass {
3158 #[must_use]
3160 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3161 match self {
3162 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3163 diagnostic_code::DiagnosticCode::StoreCorruption
3164 }
3165 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3166 Self::IncompatiblePersistedFormat => {
3167 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3168 }
3169 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3170 diagnostic_code::DiagnosticCode::StoreNotFound
3171 }
3172 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3173 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3174 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3175 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3176 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3177 }
3178 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3179 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3180 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3181 }
3182 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3183 }
3184 }
3185}
3186
3187impl fmt::Debug for ErrorClass {
3188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3189 write!(f, "{}", *self as u8)
3190 }
3191}
3192
3193#[repr(u8)]
3200#[derive(Clone, Copy, Eq, PartialEq)]
3201pub enum ErrorOrigin {
3202 Serialize,
3203 Store,
3204 Index,
3205 Identity,
3206 Query,
3207 Planner,
3208 Cursor,
3209 Recovery,
3210 Response,
3211 Executor,
3212 Interface,
3213}
3214
3215impl ErrorOrigin {
3216 #[must_use]
3218 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3219 match self {
3220 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3221 Self::Store => diagnostic_code::ErrorOrigin::Store,
3222 Self::Index => diagnostic_code::ErrorOrigin::Index,
3223 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3224 Self::Query => diagnostic_code::ErrorOrigin::Query,
3225 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3226 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3227 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3228 Self::Response => diagnostic_code::ErrorOrigin::Response,
3229 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3230 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3231 }
3232 }
3233}
3234
3235impl fmt::Debug for ErrorOrigin {
3236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3237 write!(f, "{}", *self as u8)
3238 }
3239}