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 #[cold]
1111 #[inline(never)]
1112 pub(crate) fn query_exact_count_metadata_unavailable() -> Self {
1113 Self {
1114 class: ErrorClass::Unsupported,
1115 origin: ErrorOrigin::Query,
1116 detail: Some(ErrorDetail::Query(
1117 QueryErrorDetail::ExactCountMetadataUnavailable,
1118 )),
1119 }
1120 }
1121
1122 pub(crate) fn query_explain_output_exceeded(limit: u64, observed: u64) -> Self {
1125 Self::with_diagnostic_facts(
1126 ErrorClass::Unsupported,
1127 ErrorOrigin::Query,
1128 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1129 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainOutputExceeded,
1130 }),
1131 vec![
1132 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1133 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1134 ],
1135 )
1136 }
1137
1138 pub(crate) fn query_explain_depth_exceeded(limit: u64, observed: u64) -> Self {
1141 Self::with_diagnostic_facts(
1142 ErrorClass::Unsupported,
1143 ErrorOrigin::Query,
1144 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1145 boundary: diagnostic_code::RuntimeBoundaryCode::QueryExplainDepthExceeded,
1146 }),
1147 vec![
1148 (diagnostic_code::DiagnosticFactTag::Limit, limit),
1149 (diagnostic_code::DiagnosticFactTag::Actual, observed),
1150 ],
1151 )
1152 }
1153
1154 #[cold]
1157 #[inline(never)]
1158 pub(crate) fn query_stale_accepted_schema_revision(
1159 expected_revision: u64,
1160 current_revision: Option<u64>,
1161 ) -> Self {
1162 let mut facts = Vec::with_capacity(1 + usize::from(current_revision.is_some()));
1163 facts.push((
1164 diagnostic_code::DiagnosticFactTag::ExpectedRevision,
1165 expected_revision,
1166 ));
1167 if let Some(current_revision) = current_revision {
1168 facts.push((
1169 diagnostic_code::DiagnosticFactTag::CurrentRevision,
1170 current_revision,
1171 ));
1172 }
1173 Self::with_diagnostic_facts(ErrorClass::Conflict, ErrorOrigin::Query, None, facts)
1174 }
1175
1176 #[cold]
1178 #[inline(never)]
1179 #[cfg(feature = "sql")]
1180 pub(crate) fn query_schema_ddl_admission(error: SchemaDdlAdmissionError) -> Self {
1181 Self {
1182 class: ErrorClass::Unsupported,
1183 origin: ErrorOrigin::Query,
1184 detail: Some(ErrorDetail::Query(QueryErrorDetail::SchemaDdlAdmission {
1185 error,
1186 })),
1187 }
1188 }
1189
1190 #[cold]
1192 #[inline(never)]
1193 pub(crate) fn query_numeric_overflow() -> Self {
1194 Self {
1195 class: ErrorClass::Unsupported,
1196 origin: ErrorOrigin::Query,
1197 detail: Some(ErrorDetail::Query(QueryErrorDetail::NumericOverflow)),
1198 }
1199 }
1200
1201 #[cold]
1204 #[inline(never)]
1205 pub(crate) fn query_numeric_not_representable() -> Self {
1206 Self {
1207 class: ErrorClass::Unsupported,
1208 origin: ErrorOrigin::Query,
1209 detail: Some(ErrorDetail::Query(
1210 QueryErrorDetail::NumericNotRepresentable,
1211 )),
1212 }
1213 }
1214
1215 #[cold]
1217 #[inline(never)]
1218 pub(crate) fn serialize_internal() -> Self {
1219 Self::new(ErrorClass::Internal, ErrorOrigin::Serialize)
1220 }
1221
1222 pub(crate) fn persisted_row_encode_failed(_detail: impl Sized) -> Self {
1224 Self::persisted_row_encode_internal()
1225 }
1226
1227 pub(crate) fn persisted_row_encode_internal() -> Self {
1229 Self::serialize_internal()
1230 }
1231
1232 pub(crate) fn persisted_row_field_encode_internal(_field_name: &str) -> Self {
1234 Self::persisted_row_encode_internal()
1235 }
1236
1237 #[cold]
1239 #[inline(never)]
1240 pub(crate) fn store_corruption() -> Self {
1241 Self::new(ErrorClass::Corruption, ErrorOrigin::Store)
1242 }
1243
1244 pub(crate) fn commit_corruption() -> Self {
1246 Self::store_corruption()
1247 }
1248
1249 pub(crate) fn commit_component_corruption() -> Self {
1251 Self::commit_corruption()
1252 }
1253
1254 pub(crate) fn commit_id_generation_failed() -> Self {
1256 Self::store_internal()
1257 }
1258
1259 pub(crate) fn commit_marker_payload_exceeds_u32_length_limit() -> Self {
1261 Self::store_unsupported()
1262 }
1263
1264 pub(crate) fn commit_component_length_invalid(actual_length: usize, limit: usize) -> Self {
1266 Self::with_diagnostic_facts(
1267 ErrorClass::Corruption,
1268 ErrorOrigin::Store,
1269 None,
1270 vec![
1271 (
1272 diagnostic_code::DiagnosticFactTag::ComponentKind,
1273 diagnostic_code::DiagnosticComponentKind::CommitDataKey.raw(),
1274 ),
1275 (
1276 diagnostic_code::DiagnosticFactTag::ActualLength,
1277 actual_length as u64,
1278 ),
1279 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1280 ],
1281 )
1282 }
1283
1284 pub(crate) fn commit_marker_exceeds_max_size() -> Self {
1286 Self::commit_corruption()
1287 }
1288
1289 pub(crate) fn commit_control_slot_exceeds_max_size() -> Self {
1291 Self::store_unsupported()
1292 }
1293
1294 pub(crate) fn commit_control_slot_marker_bytes_exceed_u32_length_limit() -> Self {
1296 Self::store_unsupported()
1297 }
1298
1299 #[cold]
1301 #[inline(never)]
1302 pub(crate) fn index_corruption() -> Self {
1303 Self::new(ErrorClass::Corruption, ErrorOrigin::Index)
1304 }
1305
1306 pub(crate) fn index_unique_validation_corruption() -> Self {
1308 Self::index_plan_index_corruption()
1309 }
1310
1311 pub(crate) fn structural_index_entry_corruption() -> Self {
1313 Self::index_plan_index_corruption()
1314 }
1315
1316 pub(crate) fn index_unique_validation_entity_key_required() -> Self {
1318 Self::index_invariant()
1319 }
1320
1321 pub(crate) fn index_unique_validation_row_deserialize_failed() -> Self {
1323 Self::index_plan_serialize_corruption()
1324 }
1325
1326 pub(crate) fn index_unique_validation_primary_key_decode_failed() -> Self {
1328 Self::index_plan_serialize_corruption()
1329 }
1330
1331 pub(crate) fn index_unique_validation_key_rebuild_failed() -> Self {
1333 Self::index_plan_serialize_corruption()
1334 }
1335
1336 pub(crate) fn index_unique_validation_row_required() -> Self {
1338 Self::index_plan_store_corruption()
1339 }
1340
1341 pub(crate) fn index_only_predicate_component_required() -> Self {
1343 Self::index_invariant()
1344 }
1345
1346 pub(crate) fn index_scan_continuation_anchor_within_envelope_required() -> Self {
1348 Self::index_invariant()
1349 }
1350
1351 pub(crate) fn index_scan_continuation_advancement_required() -> Self {
1353 Self::index_invariant()
1354 }
1355
1356 pub(crate) fn index_scan_key_corrupted_during(
1358 _context: &'static str,
1359 _err: impl Sized,
1360 ) -> Self {
1361 Self::index_corruption()
1362 }
1363
1364 pub(crate) fn index_projection_component_required(
1366 _index_name: &str,
1367 _component_index: usize,
1368 ) -> Self {
1369 Self::index_invariant()
1370 }
1371
1372 pub(crate) fn index_entry_decode_failed() -> Self {
1374 Self::index_corruption()
1375 }
1376
1377 pub(crate) fn serialize_corruption() -> Self {
1379 Self::new(ErrorClass::Corruption, ErrorOrigin::Serialize)
1380 }
1381
1382 pub(crate) fn persisted_row_decode_corruption() -> Self {
1384 Self::serialize_corruption()
1385 }
1386
1387 pub(crate) fn persisted_row_layout_outside_accepted_window(
1389 row_layout: u32,
1390 history_floor: u32,
1391 current_layout: u32,
1392 ) -> Self {
1393 Self::with_diagnostic_facts(
1394 ErrorClass::Corruption,
1395 ErrorOrigin::Serialize,
1396 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1397 boundary:
1398 diagnostic_code::RuntimeBoundaryCode::PersistedRowLayoutOutsideAcceptedWindow,
1399 }),
1400 vec![
1401 (
1402 diagnostic_code::DiagnosticFactTag::RowLayout,
1403 u64::from(row_layout),
1404 ),
1405 (
1406 diagnostic_code::DiagnosticFactTag::HistoryFloor,
1407 u64::from(history_floor),
1408 ),
1409 (
1410 diagnostic_code::DiagnosticFactTag::CurrentLayout,
1411 u64::from(current_layout),
1412 ),
1413 ],
1414 )
1415 }
1416
1417 pub(crate) fn persisted_row_slot_count_mismatch(
1419 row_layout: u32,
1420 expected_slot_count: usize,
1421 actual_slot_count: usize,
1422 ) -> Self {
1423 Self::with_diagnostic_facts(
1424 ErrorClass::Corruption,
1425 ErrorOrigin::Serialize,
1426 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
1427 boundary: diagnostic_code::RuntimeBoundaryCode::PersistedRowSlotCountMismatch,
1428 }),
1429 vec![
1430 (
1431 diagnostic_code::DiagnosticFactTag::RowLayout,
1432 u64::from(row_layout),
1433 ),
1434 (
1435 diagnostic_code::DiagnosticFactTag::ExpectedSlotCount,
1436 expected_slot_count as u64,
1437 ),
1438 (
1439 diagnostic_code::DiagnosticFactTag::ActualSlotCount,
1440 actual_slot_count as u64,
1441 ),
1442 ],
1443 )
1444 }
1445
1446 pub(crate) fn persisted_row_field_decode_failed(field_name: &str, _detail: impl Sized) -> Self {
1448 Self::persisted_row_field_decode_corruption(field_name)
1449 }
1450
1451 pub(crate) fn persisted_row_field_decode_corruption(_field_name: &str) -> Self {
1453 Self::persisted_row_decode_corruption()
1454 }
1455
1456 pub(crate) fn persisted_row_field_kind_decode_failed(
1458 field_name: &str,
1459 _field_kind: impl fmt::Debug,
1460 _detail: impl Sized,
1461 ) -> Self {
1462 Self::persisted_row_field_decode_corruption(field_name)
1463 }
1464
1465 pub(crate) fn persisted_row_field_payload_exact_len_required(field_name: &str) -> Self {
1467 Self::persisted_row_field_decode_corruption(field_name)
1468 }
1469
1470 pub(crate) fn persisted_row_field_payload_must_be_empty(field_name: &str) -> Self {
1472 Self::persisted_row_field_decode_corruption(field_name)
1473 }
1474
1475 pub(crate) fn persisted_row_field_payload_invalid_byte(field_name: &str) -> Self {
1477 Self::persisted_row_field_decode_corruption(field_name)
1478 }
1479
1480 pub(crate) fn persisted_row_field_payload_non_finite(field_name: &str) -> Self {
1482 Self::persisted_row_field_decode_corruption(field_name)
1483 }
1484
1485 pub(crate) fn persisted_row_field_text_payload_invalid_utf8(field_name: &str) -> Self {
1487 Self::persisted_row_field_decode_corruption(field_name)
1488 }
1489
1490 pub(crate) fn persisted_row_slot_lookup_out_of_bounds(_model_path: &str, _slot: usize) -> Self {
1492 Self::index_invariant()
1493 }
1494
1495 pub(crate) fn persisted_row_slot_cache_lookup_out_of_bounds(
1497 _model_path: &str,
1498 _slot: usize,
1499 ) -> Self {
1500 Self::index_invariant()
1501 }
1502
1503 pub(crate) fn persisted_row_primary_key_not_primary_key_encodable(
1505 _data_key: impl fmt::Debug,
1506 _detail: impl Sized,
1507 ) -> Self {
1508 Self::persisted_row_decode_corruption()
1509 }
1510
1511 pub(crate) fn persisted_row_primary_key_slot_missing(_data_key: impl fmt::Debug) -> Self {
1513 Self::persisted_row_decode_corruption()
1514 }
1515
1516 pub(crate) fn persisted_row_key_mismatch() -> Self {
1518 Self::store_corruption()
1519 }
1520
1521 pub(crate) fn persisted_row_declared_field_missing(field_name: &str) -> Self {
1523 Self::persisted_row_field_decode_corruption(field_name)
1524 }
1525
1526 pub(crate) fn reverse_index_entry_corrupted(
1528 _source_path: &str,
1529 _field_name: &str,
1530 _target_path: &str,
1531 _index_key: impl fmt::Debug,
1532 _detail: impl Sized,
1533 ) -> Self {
1534 Self::index_corruption()
1535 }
1536
1537 pub(crate) fn relation_target_store_missing(
1539 _source_path: &str,
1540 _field_name: &str,
1541 _target_path: &str,
1542 _store_path: &str,
1543 _detail: impl Sized,
1544 ) -> Self {
1545 Self::executor_internal()
1546 }
1547
1548 pub(crate) fn with_relation_identity(self, entity_tag: u64, relation_id: u32) -> Self {
1550 if self.diagnostic().error_code() != diagnostic_code::ErrorCode::RUNTIME_INTERNAL {
1551 return self;
1552 }
1553 let mut facts = vec![
1554 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1555 (
1556 diagnostic_code::DiagnosticFactTag::RelationId,
1557 u64::from(relation_id),
1558 ),
1559 ];
1560 facts.extend(self.diagnostic_facts());
1561 Self::with_diagnostic_facts(self.class, self.origin, None, facts)
1562 }
1563
1564 pub(crate) fn relation_target_primary_key_arity_mismatch(
1566 expected_arity: usize,
1567 actual_arity: usize,
1568 ) -> Self {
1569 Self::with_diagnostic_facts(
1570 ErrorClass::Internal,
1571 ErrorOrigin::Executor,
1572 None,
1573 vec![
1574 (
1575 diagnostic_code::DiagnosticFactTag::ComponentKind,
1576 diagnostic_code::DiagnosticComponentKind::RelationTargetPrimaryKey.raw(),
1577 ),
1578 (
1579 diagnostic_code::DiagnosticFactTag::ExpectedArity,
1580 expected_arity as u64,
1581 ),
1582 (
1583 diagnostic_code::DiagnosticFactTag::ActualArity,
1584 actual_arity as u64,
1585 ),
1586 ],
1587 )
1588 }
1589
1590 pub(crate) fn relation_target_key_decode_failed(
1592 _context_label: &str,
1593 _source_path: &str,
1594 _field_name: &str,
1595 _target_path: &str,
1596 _detail: impl Sized,
1597 ) -> Self {
1598 Self::identity_corruption()
1599 }
1600
1601 pub(crate) fn relation_target_entity_mismatch(
1603 _context_label: &str,
1604 _source_path: &str,
1605 _field_name: &str,
1606 _target_path: &str,
1607 _target_entity_name: &str,
1608 expected_tag: u64,
1609 actual_tag: u64,
1610 ) -> Self {
1611 Self::with_diagnostic_facts(
1612 ErrorClass::Corruption,
1613 ErrorOrigin::Store,
1614 None,
1615 vec![
1616 (
1617 diagnostic_code::DiagnosticFactTag::ExpectedEntityTag,
1618 expected_tag,
1619 ),
1620 (
1621 diagnostic_code::DiagnosticFactTag::ActualEntityTag,
1622 actual_tag,
1623 ),
1624 ],
1625 )
1626 }
1627
1628 pub(crate) fn relation_source_row_decode_failed(
1630 _source_path: &str,
1631 _field_name: &str,
1632 _target_path: &str,
1633 _detail: impl Sized,
1634 ) -> Self {
1635 Self::persisted_row_decode_corruption()
1636 }
1637
1638 pub(crate) fn relation_source_row_unsupported_scalar_relation_key(
1640 _source_path: &str,
1641 _field_name: &str,
1642 _target_path: &str,
1643 ) -> Self {
1644 Self::persisted_row_decode_corruption()
1645 }
1646
1647 pub(crate) fn relation_source_row_unsupported_key_kind(_field_kind: impl fmt::Debug) -> Self {
1649 Self::persisted_row_decode_corruption()
1650 }
1651
1652 pub(crate) fn bytes_covering_component_payload_empty() -> Self {
1654 Self::index_corruption()
1655 }
1656
1657 pub(crate) fn bytes_covering_bool_payload_truncated() -> Self {
1659 Self::index_corruption()
1660 }
1661
1662 pub(crate) fn bytes_covering_component_payload_invalid_length() -> Self {
1664 Self::index_corruption()
1665 }
1666
1667 pub(crate) fn bytes_covering_bool_payload_invalid_value() -> Self {
1669 Self::index_corruption()
1670 }
1671
1672 pub(crate) fn bytes_covering_text_payload_invalid_terminator() -> Self {
1674 Self::index_corruption()
1675 }
1676
1677 pub(crate) fn bytes_covering_text_payload_trailing_bytes() -> Self {
1679 Self::index_corruption()
1680 }
1681
1682 pub(crate) fn bytes_covering_text_payload_invalid_utf8() -> Self {
1684 Self::index_corruption()
1685 }
1686
1687 pub(crate) fn bytes_covering_text_payload_invalid_escape_byte() -> Self {
1689 Self::index_corruption()
1690 }
1691
1692 pub(crate) fn bytes_covering_text_payload_missing_terminator() -> Self {
1694 Self::index_corruption()
1695 }
1696
1697 pub(crate) fn identity_corruption() -> Self {
1699 Self::new(ErrorClass::Corruption, ErrorOrigin::Identity)
1700 }
1701
1702 pub(crate) fn identity_state_corruption() -> Self {
1704 Self::identity_corruption()
1705 }
1706
1707 pub(crate) fn identity_state_conflict() -> Self {
1709 Self::new(ErrorClass::Conflict, ErrorOrigin::Identity)
1710 }
1711
1712 pub(crate) fn identity_state_capacity_exhausted() -> Self {
1714 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1715 }
1716
1717 pub(crate) fn identity_exhausted() -> Self {
1719 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1720 }
1721
1722 pub(crate) fn identity_candidate_count_exhausted() -> Self {
1724 Self::new(ErrorClass::Unsupported, ErrorOrigin::Identity)
1725 }
1726
1727 #[cold]
1729 #[inline(never)]
1730 pub(crate) fn store_unsupported() -> Self {
1731 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store)
1732 }
1733
1734 pub(crate) fn schema_application_conflict() -> Self {
1736 Self::new(ErrorClass::Conflict, ErrorOrigin::Store)
1737 }
1738
1739 pub(crate) fn schema_migration(reason: diagnostic_code::SchemaMigrationCode) -> Self {
1741 let class = match reason.diagnostic_code() {
1742 diagnostic_code::DiagnosticCode::RuntimeConflict => ErrorClass::Conflict,
1743 diagnostic_code::DiagnosticCode::RuntimeCorruption => ErrorClass::Corruption,
1744 diagnostic_code::DiagnosticCode::RuntimeUnsupported => ErrorClass::Unsupported,
1745 _ => ErrorClass::Internal,
1746 };
1747 Self {
1748 class,
1749 origin: ErrorOrigin::Store,
1750 detail: Some(ErrorDetail::Store(StoreError::SchemaMigration { reason })),
1751 }
1752 }
1753
1754 pub(crate) fn schema_ddl_publication_race_lost(_entity_path: &str) -> Self {
1756 Self {
1757 class: ErrorClass::Unsupported,
1758 origin: ErrorOrigin::Store,
1759 detail: Some(ErrorDetail::Store(StoreError::SchemaDdlPublicationRaceLost)),
1760 }
1761 }
1762
1763 #[cfg(feature = "sql")]
1765 pub(crate) fn schema_ddl_rewrite_requires_migration(_entity_path: &str) -> Self {
1766 Self {
1767 class: ErrorClass::Unsupported,
1768 origin: ErrorOrigin::Store,
1769 detail: Some(ErrorDetail::Store(
1770 StoreError::SchemaDdlRewriteRequiresMigration,
1771 )),
1772 }
1773 }
1774
1775 pub(crate) fn journal_mutation_revision_exhausted() -> Self {
1777 Self {
1778 class: ErrorClass::Unsupported,
1779 origin: ErrorOrigin::Store,
1780 detail: Some(ErrorDetail::Store(
1781 StoreError::JournalMutationRevisionExhausted,
1782 )),
1783 }
1784 }
1785
1786 pub(crate) fn schema_transition_budget_exceeded(
1788 resource: SchemaTransitionBudgetResource,
1789 ) -> Self {
1790 Self {
1791 class: ErrorClass::Unsupported,
1792 origin: ErrorOrigin::Store,
1793 detail: Some(ErrorDetail::Store(
1794 StoreError::SchemaTransitionBudgetExceeded { resource },
1795 )),
1796 }
1797 }
1798
1799 pub(crate) fn unsupported_entity_tag_in_data_store(
1801 _entity_tag: crate::types::EntityTag,
1802 ) -> Self {
1803 Self::store_unsupported()
1804 }
1805
1806 pub(crate) fn commit_memory_id_registration_failed(_err: impl Sized) -> Self {
1808 Self::store_internal()
1809 }
1810
1811 pub(crate) fn index_unsupported() -> Self {
1813 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index)
1814 }
1815
1816 pub(crate) fn index_component_exceeds_max_size_at(
1818 entity_tag: u64,
1819 physical_generation: u64,
1820 component_index: usize,
1821 actual_length: usize,
1822 limit: usize,
1823 ) -> Self {
1824 Self::with_diagnostic_facts(
1825 ErrorClass::Unsupported,
1826 ErrorOrigin::Index,
1827 None,
1828 vec![
1829 (diagnostic_code::DiagnosticFactTag::EntityTag, entity_tag),
1830 (
1831 diagnostic_code::DiagnosticFactTag::PhysicalGeneration,
1832 physical_generation,
1833 ),
1834 (
1835 diagnostic_code::DiagnosticFactTag::ComponentIndex,
1836 component_index as u64,
1837 ),
1838 (
1839 diagnostic_code::DiagnosticFactTag::ComponentKind,
1840 diagnostic_code::DiagnosticComponentKind::IndexKeyComponent.raw(),
1841 ),
1842 (
1843 diagnostic_code::DiagnosticFactTag::ActualLength,
1844 actual_length as u64,
1845 ),
1846 (diagnostic_code::DiagnosticFactTag::Limit, limit as u64),
1847 ],
1848 )
1849 }
1850
1851 pub(crate) fn index_component_exceeds_max_size() -> Self {
1854 Self::index_unsupported()
1855 }
1856
1857 pub(crate) fn serialize_unsupported() -> Self {
1859 Self::new(ErrorClass::Unsupported, ErrorOrigin::Serialize)
1860 }
1861
1862 pub(crate) fn cursor_invalid_continuation() -> Self {
1864 Self::new(ErrorClass::Unsupported, ErrorOrigin::Cursor)
1865 }
1866
1867 pub(crate) fn serialize_incompatible_persisted_format() -> Self {
1869 Self::new(
1870 ErrorClass::IncompatiblePersistedFormat,
1871 ErrorOrigin::Serialize,
1872 )
1873 }
1874
1875 #[cfg(feature = "sql")]
1878 pub(crate) fn query_unsupported_sql_feature(feature: diagnostic_code::SqlFeatureCode) -> Self {
1879 Self {
1880 class: ErrorClass::Unsupported,
1881 origin: ErrorOrigin::Query,
1882 detail: Some(ErrorDetail::Query(
1883 QueryErrorDetail::UnsupportedSqlFeature { feature },
1884 )),
1885 }
1886 }
1887
1888 #[cfg(feature = "sql")]
1891 pub(crate) fn query_sql_lowering(reason: diagnostic_code::SqlLoweringCode) -> Self {
1892 Self {
1893 class: ErrorClass::Unsupported,
1894 origin: ErrorOrigin::Query,
1895 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlLowering { reason })),
1896 }
1897 }
1898
1899 #[cfg(feature = "sql")]
1901 pub(crate) fn query_sql_lowering_with_facts(
1902 reason: diagnostic_code::SqlLoweringCode,
1903 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1904 ) -> Self {
1905 Self::with_diagnostic_facts(
1906 ErrorClass::Unsupported,
1907 ErrorOrigin::Query,
1908 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason }),
1909 facts,
1910 )
1911 }
1912
1913 pub(crate) fn query_unsupported_projection(
1916 reason: diagnostic_code::QueryProjectionCode,
1917 ) -> Self {
1918 Self {
1919 class: ErrorClass::Unsupported,
1920 origin: ErrorOrigin::Query,
1921 detail: Some(ErrorDetail::Query(
1922 QueryErrorDetail::UnsupportedProjection { reason },
1923 )),
1924 }
1925 }
1926
1927 #[cfg(feature = "sql")]
1930 pub(crate) fn query_sql_surface_mismatch(
1931 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
1932 ) -> Self {
1933 Self {
1934 class: ErrorClass::Unsupported,
1935 origin: ErrorOrigin::Query,
1936 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlSurfaceMismatch {
1937 mismatch,
1938 })),
1939 }
1940 }
1941
1942 pub(crate) fn query_sql_write_boundary(
1944 boundary: diagnostic_code::SqlWriteBoundaryCode,
1945 ) -> Self {
1946 Self {
1947 class: ErrorClass::Unsupported,
1948 origin: ErrorOrigin::Query,
1949 detail: Some(ErrorDetail::Query(QueryErrorDetail::SqlWriteBoundary {
1950 boundary,
1951 })),
1952 }
1953 }
1954
1955 pub(crate) fn query_sql_write_boundary_with_facts(
1957 boundary: diagnostic_code::SqlWriteBoundaryCode,
1958 facts: Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
1959 ) -> Self {
1960 Self::with_diagnostic_facts(
1961 ErrorClass::Unsupported,
1962 ErrorOrigin::Query,
1963 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary { boundary }),
1964 facts,
1965 )
1966 }
1967
1968 pub fn store_not_found(_key: impl Sized) -> Self {
1969 Self {
1970 class: ErrorClass::NotFound,
1971 origin: ErrorOrigin::Store,
1972 detail: Some(ErrorDetail::Store(StoreError::NotFound)),
1973 }
1974 }
1975
1976 pub fn unsupported_entity_path(_path: impl Sized) -> Self {
1978 Self::store_unsupported()
1979 }
1980
1981 #[cold]
1983 #[inline(never)]
1984 pub(crate) fn index_plan_corruption(origin: ErrorOrigin) -> Self {
1985 Self::new(ErrorClass::Corruption, origin)
1986 }
1987
1988 #[cold]
1990 #[inline(never)]
1991 pub(crate) fn index_plan_index_corruption() -> Self {
1992 Self::index_plan_corruption(ErrorOrigin::Index)
1993 }
1994
1995 #[cold]
1997 #[inline(never)]
1998 pub(crate) fn index_plan_store_corruption() -> Self {
1999 Self::index_plan_corruption(ErrorOrigin::Store)
2000 }
2001
2002 #[cold]
2004 #[inline(never)]
2005 pub(crate) fn index_plan_serialize_corruption() -> Self {
2006 Self::index_plan_corruption(ErrorOrigin::Serialize)
2007 }
2008
2009 #[cfg(test)]
2011 pub(crate) fn index_plan_invariant(origin: ErrorOrigin) -> Self {
2012 Self::new(ErrorClass::InvariantViolation, origin)
2013 }
2014
2015 #[cfg(test)]
2017 pub(crate) fn index_plan_store_invariant() -> Self {
2018 Self::index_plan_invariant(ErrorOrigin::Store)
2019 }
2020
2021 pub(crate) fn index_conflict() -> Self {
2027 Self::new(ErrorClass::Conflict, ErrorOrigin::Index)
2028 }
2029}
2030
2031impl From<diagnostic_code::QueryReadAdmissionCode> for InternalError {
2032 fn from(reason: diagnostic_code::QueryReadAdmissionCode) -> Self {
2033 Self {
2034 class: ErrorClass::Unsupported,
2035 origin: ErrorOrigin::Query,
2036 detail: Some(ErrorDetail::Query(QueryErrorDetail::QueryReadAdmission {
2037 reason,
2038 })),
2039 }
2040 }
2041}
2042
2043impl fmt::Debug for InternalError {
2044 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2045 fmt_compact_diagnostic(
2046 f,
2047 self.diagnostic_code(),
2048 self.detail
2049 .as_ref()
2050 .and_then(ErrorDetail::diagnostic_detail),
2051 )
2052 }
2053}
2054
2055impl fmt::Display for InternalError {
2056 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2057 f.write_str(self.message())
2058 }
2059}
2060
2061impl std::error::Error for InternalError {}
2062
2063#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
2072pub enum ConstraintValuePathComponent {
2073 RootField { field_id: u32 },
2075
2076 RecordMember {
2078 composite_type_id: u32,
2079 member_id: u32,
2080 },
2081
2082 TupleElement {
2084 composite_type_id: u32,
2085 ordinal: u32,
2086 },
2087
2088 Newtype { composite_type_id: u32 },
2090
2091 EnumVariant { enum_type_id: u32, variant_id: u32 },
2093
2094 ListElement { index: u32 },
2096
2097 SetElement { index: u32 },
2099
2100 MapEntryKey { index: u32 },
2102
2103 MapEntryValue { index: u32 },
2105}
2106
2107impl fmt::Display for ConstraintValuePathComponent {
2108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2109 match self {
2110 Self::RootField { field_id } => write!(f, "field#{field_id}"),
2111 Self::RecordMember {
2112 composite_type_id,
2113 member_id,
2114 } => write!(f, "record#{composite_type_id}.member#{member_id}"),
2115 Self::TupleElement {
2116 composite_type_id,
2117 ordinal,
2118 } => write!(f, "tuple#{composite_type_id}[{ordinal}]"),
2119 Self::Newtype { composite_type_id } => write!(f, "newtype#{composite_type_id}"),
2120 Self::EnumVariant {
2121 enum_type_id,
2122 variant_id,
2123 } => write!(f, "enum#{enum_type_id}.variant#{variant_id}"),
2124 Self::ListElement { index } => write!(f, "list[{index}]"),
2125 Self::SetElement { index } => write!(f, "set[{index}]"),
2126 Self::MapEntryKey { index } => write!(f, "map[{index}].key"),
2127 Self::MapEntryValue { index } => write!(f, "map[{index}].value"),
2128 }
2129 }
2130}
2131
2132#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2139pub struct ConstraintValuePath {
2140 components: Vec<ConstraintValuePathComponent>,
2141}
2142
2143impl ConstraintValuePath {
2144 #[must_use]
2146 pub(crate) const fn new(components: Vec<ConstraintValuePathComponent>) -> Self {
2147 Self { components }
2148 }
2149
2150 #[must_use]
2152 pub const fn components(&self) -> &[ConstraintValuePathComponent] {
2153 self.components.as_slice()
2154 }
2155}
2156
2157impl fmt::Display for ConstraintValuePath {
2158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2159 for (ordinal, component) in self.components.iter().enumerate() {
2160 if ordinal != 0 {
2161 f.write_str("/")?;
2162 }
2163 component.fmt(f)?;
2164 }
2165 Ok(())
2166 }
2167}
2168
2169#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
2178pub struct ConstraintValidationFindingOutput {
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}
2187
2188impl ConstraintValidationFindingOutput {
2189 #[must_use]
2191 pub(crate) const fn new(
2192 accepted_schema_fingerprint: [u8; 16],
2193 entity_tag: u64,
2194 constraint_id: u32,
2195 primary_key: Vec<u8>,
2196 field_ids: Vec<u32>,
2197 value_path: Option<ConstraintValuePath>,
2198 error_code: u16,
2199 ) -> Self {
2200 Self {
2201 accepted_schema_fingerprint,
2202 entity_tag,
2203 constraint_id,
2204 primary_key,
2205 field_ids,
2206 value_path,
2207 error_code,
2208 }
2209 }
2210
2211 #[must_use]
2213 pub const fn accepted_schema_fingerprint(&self) -> [u8; 16] {
2214 self.accepted_schema_fingerprint
2215 }
2216
2217 #[must_use]
2219 pub const fn entity_tag(&self) -> u64 {
2220 self.entity_tag
2221 }
2222
2223 #[must_use]
2225 pub const fn constraint_id(&self) -> u32 {
2226 self.constraint_id
2227 }
2228
2229 #[must_use]
2231 pub const fn primary_key(&self) -> &[u8] {
2232 self.primary_key.as_slice()
2233 }
2234
2235 #[must_use]
2237 pub const fn field_ids(&self) -> &[u32] {
2238 self.field_ids.as_slice()
2239 }
2240
2241 #[must_use]
2243 pub const fn value_path(&self) -> Option<&ConstraintValuePath> {
2244 self.value_path.as_ref()
2245 }
2246
2247 #[must_use]
2249 pub const fn error_code(&self) -> diagnostic_code::ErrorCode {
2250 diagnostic_code::ErrorCode::from_raw(self.error_code)
2251 }
2252
2253 #[must_use]
2255 pub const fn error_class(&self) -> diagnostic_code::ErrorClass {
2256 self.error_code().class()
2257 }
2258}
2259
2260#[derive(Clone)]
2262pub(crate) struct AcceptedConstraintFactContext {
2263 fingerprint_method: u8,
2264 accepted_schema_fingerprint: [u8; 16],
2265 entity_tag: u64,
2266 constraint_id: u32,
2267 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2268 mutation: Option<MutationDiagnosticContext>,
2269 value_path: Option<ConstraintValuePath>,
2270}
2271
2272impl AcceptedConstraintFactContext {
2273 #[must_use]
2274 pub(crate) fn write_admission(
2275 fingerprint_method: u8,
2276 accepted_schema_fingerprint: [u8; 16],
2277 entity_tag: u64,
2278 constraint_id: u32,
2279 constraint_kind: diagnostic_code::DiagnosticConstraintKind,
2280 mutation: Option<MutationDiagnosticContext>,
2281 value_path: Option<ConstraintValuePath>,
2282 ) -> Self {
2283 debug_assert!(mutation.is_none_or(|context| context.entity_tag() == entity_tag));
2284 Self {
2285 fingerprint_method,
2286 accepted_schema_fingerprint,
2287 entity_tag,
2288 constraint_id,
2289 constraint_kind,
2290 mutation,
2291 value_path,
2292 }
2293 }
2294
2295 fn facts(self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2296 let path_len = self
2297 .value_path
2298 .as_ref()
2299 .map_or(0, |path| path.components().len());
2300 let mutation_fact_count = self.mutation.map_or(0, |mutation| {
2301 1 + usize::from(mutation.batch_position.is_some())
2302 });
2303 let mut facts = Vec::with_capacity(7 + mutation_fact_count + path_len);
2304 append_accepted_schema_facts(
2305 &mut facts,
2306 self.fingerprint_method,
2307 self.accepted_schema_fingerprint,
2308 );
2309 facts.push((
2310 diagnostic_code::DiagnosticFactTag::EntityTag,
2311 self.entity_tag,
2312 ));
2313 facts.push((
2314 diagnostic_code::DiagnosticFactTag::ConstraintId,
2315 u64::from(self.constraint_id),
2316 ));
2317 facts.push((
2318 diagnostic_code::DiagnosticFactTag::ConstraintKind,
2319 self.constraint_kind.raw(),
2320 ));
2321 facts.push((
2322 diagnostic_code::DiagnosticFactTag::ConstraintContext,
2323 diagnostic_code::DiagnosticConstraintContext::WriteAdmission.raw(),
2324 ));
2325 if let Some(mutation) = self.mutation {
2326 mutation.append_operation_facts(&mut facts);
2327 }
2328 if let Some(path) = self.value_path {
2329 for component in path.components {
2330 facts.push(constraint_value_path_fact(component));
2331 }
2332 }
2333 debug_assert!(facts.len() <= diagnostic_code::MAX_PUBLIC_DIAGNOSTIC_FACTS);
2334 facts
2335 }
2336}
2337
2338fn append_accepted_schema_facts(
2340 facts: &mut Vec<(diagnostic_code::DiagnosticFactTag, u64)>,
2341 method: u8,
2342 fingerprint: [u8; 16],
2343) {
2344 facts.extend([
2345 (
2346 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintMethod,
2347 u64::from(method),
2348 ),
2349 (
2350 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintHigh,
2351 u64::from_be_bytes([
2352 fingerprint[0],
2353 fingerprint[1],
2354 fingerprint[2],
2355 fingerprint[3],
2356 fingerprint[4],
2357 fingerprint[5],
2358 fingerprint[6],
2359 fingerprint[7],
2360 ]),
2361 ),
2362 (
2363 diagnostic_code::DiagnosticFactTag::AcceptedSchemaFingerprintLow,
2364 u64::from_be_bytes([
2365 fingerprint[8],
2366 fingerprint[9],
2367 fingerprint[10],
2368 fingerprint[11],
2369 fingerprint[12],
2370 fingerprint[13],
2371 fingerprint[14],
2372 fingerprint[15],
2373 ]),
2374 ),
2375 ]);
2376}
2377
2378fn constraint_value_path_fact(
2379 component: ConstraintValuePathComponent,
2380) -> (diagnostic_code::DiagnosticFactTag, u64) {
2381 use diagnostic_code::DiagnosticFactTag;
2382 match component {
2383 ConstraintValuePathComponent::RootField { field_id } => {
2384 (DiagnosticFactTag::RootField, u64::from(field_id))
2385 }
2386 ConstraintValuePathComponent::RecordMember {
2387 composite_type_id,
2388 member_id,
2389 } => (
2390 DiagnosticFactTag::RecordMember,
2391 diagnostic_code::pack_u32_pair(composite_type_id, member_id),
2392 ),
2393 ConstraintValuePathComponent::TupleElement {
2394 composite_type_id,
2395 ordinal,
2396 } => (
2397 DiagnosticFactTag::TupleElement,
2398 diagnostic_code::pack_u32_pair(composite_type_id, ordinal),
2399 ),
2400 ConstraintValuePathComponent::Newtype { composite_type_id } => {
2401 (DiagnosticFactTag::Newtype, u64::from(composite_type_id))
2402 }
2403 ConstraintValuePathComponent::EnumVariant {
2404 enum_type_id,
2405 variant_id,
2406 } => (
2407 DiagnosticFactTag::EnumVariant,
2408 diagnostic_code::pack_u32_pair(enum_type_id, variant_id),
2409 ),
2410 ConstraintValuePathComponent::ListElement { index } => {
2411 (DiagnosticFactTag::ListElement, u64::from(index))
2412 }
2413 ConstraintValuePathComponent::SetElement { index } => {
2414 (DiagnosticFactTag::SetElement, u64::from(index))
2415 }
2416 ConstraintValuePathComponent::MapEntryKey { index } => {
2417 (DiagnosticFactTag::MapEntryKey, u64::from(index))
2418 }
2419 ConstraintValuePathComponent::MapEntryValue { index } => {
2420 (DiagnosticFactTag::MapEntryValue, u64::from(index))
2421 }
2422 }
2423}
2424
2425pub enum ErrorDetail {
2433 DiagnosticFacts(Box<DiagnosticFactDetail>),
2435 Executor(ExecutorErrorDetail),
2437 Store(StoreError),
2438 Query(QueryErrorDetail),
2439 Recovery(RecoveryErrorDetail),
2440 }
2443
2444pub enum ExecutorErrorDetail {
2446 MutationRequiredFieldMissing,
2448 MutationManagedTimestampRegression,
2450 MutationDatabaseOwnedFieldExplicit,
2452 MutationBatchEmpty,
2454 MutationBatchTooManyItems,
2456 MutationBatchStagedBytesExceeded,
2458 MutationBatchResultBytesExceeded,
2460 MutationBatchStoreMismatch,
2462 MutationBatchTooManyEntities,
2464 MutationBatchDuplicateKey,
2466 AcceptedRowConstraintProgramCorrupt,
2468}
2469
2470pub enum RecoveryErrorDetail {
2477 UnsupportedFormatVersion { found: Option<u16>, required: u16 },
2478
2479 MalformedFormatMarker { reason: RecoveryFormatMarkerError },
2480}
2481
2482#[derive(Clone, Copy, Eq, PartialEq)]
2484pub enum RecoveryFormatMarkerError {
2485 Magic,
2486 Checksum,
2487 State,
2488}
2489
2490impl RecoveryFormatMarkerError {
2491 const fn diagnostic_decode_reason(self) -> diagnostic_code::DiagnosticDecodeReason {
2492 match self {
2493 Self::Magic => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerMagic,
2494 Self::Checksum => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerChecksum,
2495 Self::State => diagnostic_code::DiagnosticDecodeReason::RecoveryMarkerState,
2496 }
2497 }
2498}
2499
2500pub enum StoreError {
2508 NotFound,
2509
2510 Corrupt,
2511
2512 InvariantViolation,
2513
2514 SchemaDdlPublicationRaceLost,
2515
2516 SchemaDdlRewriteRequiresMigration,
2517
2518 SchemaMigration {
2519 reason: diagnostic_code::SchemaMigrationCode,
2520 },
2521
2522 SchemaRowLayoutVersionExhausted,
2523
2524 JournalMutationRevisionExhausted,
2525
2526 SchemaTransitionBudgetExceeded {
2527 resource: SchemaTransitionBudgetResource,
2528 },
2529
2530 SchemaGeneratedFieldAfterDdlField,
2532
2533 SchemaGeneratedConstraintActivationStale,
2535}
2536
2537pub enum QueryErrorDetail {
2544 ExactCountMetadataUnavailable,
2546
2547 NumericOverflow,
2548
2549 NumericNotRepresentable,
2550
2551 UnsupportedSqlFeature {
2552 feature: diagnostic_code::SqlFeatureCode,
2553 },
2554
2555 SqlLowering {
2556 reason: diagnostic_code::SqlLoweringCode,
2557 },
2558
2559 UnsupportedProjection {
2560 reason: diagnostic_code::QueryProjectionCode,
2561 },
2562
2563 UnknownAggregateTargetField,
2564
2565 QueryReadAdmission {
2566 reason: diagnostic_code::QueryReadAdmissionCode,
2567 },
2568
2569 SqlSurfaceMismatch {
2570 mismatch: diagnostic_code::SqlSurfaceMismatchCode,
2571 },
2572
2573 SqlWriteBoundary {
2574 boundary: diagnostic_code::SqlWriteBoundaryCode,
2575 },
2576
2577 SchemaDdlAdmission {
2578 error: SchemaDdlAdmissionError,
2579 },
2580
2581 StaleSchemaRevision,
2582}
2583
2584impl fmt::Display for QueryErrorDetail {
2585 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2586 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2587 }
2588}
2589
2590impl std::error::Error for QueryErrorDetail {}
2591
2592#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2600pub enum SchemaTransitionBudgetResource {
2601 DeletionKeys,
2603 ProjectionEntries,
2605 ProjectionWorkUnits,
2607 SourceRows,
2609 SourceRowBytes,
2611 StagedRawBytes,
2613}
2614
2615#[derive(Clone, Copy, Eq, PartialEq)]
2624pub enum SchemaDdlAdmissionError {
2625 MissingExpectedSchemaVersion,
2626
2627 MissingNextSchemaVersion,
2628
2629 StaleExpectedSchemaVersion,
2630
2631 InvalidExpectedSchemaVersion,
2632
2633 InvalidNextSchemaVersion,
2634
2635 AcceptedSchemaChangeWithoutVersionBump,
2636
2637 EmptyVersionBump,
2638
2639 VersionGap,
2640
2641 VersionRollback,
2642
2643 FingerprintMethodMismatch,
2644
2645 UnsupportedTransitionClass,
2646
2647 PhysicalRunnerMissing,
2648
2649 ValidationFailed,
2650
2651 PublicationRaceLost,
2652
2653 InvalidAddColumnDefault,
2654
2655 InvalidAlterColumnDefault,
2656
2657 RowLayoutVersionExhausted,
2658
2659 GeneratedIndexDropRejected,
2660
2661 SchemaRewriteRequiresMigration,
2662
2663 SchemaTransitionBudgetExceeded {
2664 resource: SchemaTransitionBudgetResource,
2665 },
2666
2667 GeneratedFieldDefaultChangeRejected,
2668
2669 GeneratedFieldNullabilityChangeRejected,
2670}
2671
2672impl fmt::Display for SchemaDdlAdmissionError {
2673 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2674 f.write_str(COMPACT_QUERY_DIAGNOSTIC_MESSAGE)
2675 }
2676}
2677
2678impl std::error::Error for SchemaDdlAdmissionError {}
2679
2680impl fmt::Debug for ErrorDetail {
2681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2682 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2683 }
2684}
2685
2686impl fmt::Debug for ExecutorErrorDetail {
2687 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2688 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2689 }
2690}
2691
2692impl fmt::Debug for StoreError {
2693 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2694 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2695 }
2696}
2697
2698impl fmt::Debug for QueryErrorDetail {
2699 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2700 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2701 }
2702}
2703
2704impl fmt::Debug for RecoveryErrorDetail {
2705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2706 fmt_compact_diagnostic(f, self.diagnostic_code(), self.diagnostic_detail())
2707 }
2708}
2709
2710impl fmt::Debug for RecoveryFormatMarkerError {
2711 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2712 fmt_compact_diagnostic(
2713 f,
2714 diagnostic_code::DiagnosticCode::RuntimeCorruption,
2715 Some(diagnostic_code::DiagnosticDetail::RuntimeKind {
2716 kind: diagnostic_code::RuntimeErrorKind::Corruption,
2717 }),
2718 )
2719 }
2720}
2721
2722impl fmt::Debug for SchemaDdlAdmissionError {
2723 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2724 fmt_compact_diagnostic(
2725 f,
2726 diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
2727 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2728 reason: self.diagnostic_code(),
2729 }),
2730 )
2731 }
2732}
2733
2734fn fmt_compact_diagnostic(
2735 f: &mut fmt::Formatter<'_>,
2736 code: diagnostic_code::DiagnosticCode,
2737 detail: Option<diagnostic_code::DiagnosticDetail>,
2738) -> fmt::Result {
2739 write!(
2740 f,
2741 "{}",
2742 diagnostic_code::ErrorCode::from_parts(code, detail).raw()
2743 )
2744}
2745
2746impl ErrorDetail {
2747 #[must_use]
2749 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2750 match self {
2751 Self::DiagnosticFacts(detail) => detail.diagnostic.code(),
2752 Self::Executor(error) => error.diagnostic_code(),
2753 Self::Store(error) => error.diagnostic_code(),
2754 Self::Query(error) => error.diagnostic_code(),
2755 Self::Recovery(error) => error.diagnostic_code(),
2756 }
2757 }
2758
2759 #[must_use]
2761 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2762 match self {
2763 Self::DiagnosticFacts(detail) => detail.diagnostic.detail().copied(),
2764 Self::Executor(error) => error.diagnostic_detail(),
2765 Self::Store(error) => error.diagnostic_detail(),
2766 Self::Query(error) => error.diagnostic_detail(),
2767 Self::Recovery(error) => error.diagnostic_detail(),
2768 }
2769 }
2770
2771 #[must_use]
2773 #[cold]
2774 #[inline(never)]
2775 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2776 match self {
2777 Self::DiagnosticFacts(detail) => detail.facts.clone(),
2778 Self::Executor(error) => error.diagnostic_facts(),
2779 Self::Query(error) => error.diagnostic_facts(),
2780 Self::Recovery(error) => error.diagnostic_facts(),
2781 Self::Store(_) => Vec::new(),
2782 }
2783 }
2784}
2785
2786impl ExecutorErrorDetail {
2787 #[must_use]
2789 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2790 match self {
2791 Self::MutationRequiredFieldMissing
2792 | Self::MutationDatabaseOwnedFieldExplicit
2793 | Self::MutationBatchEmpty
2794 | Self::MutationBatchTooManyItems
2795 | Self::MutationBatchTooManyEntities
2796 | Self::MutationBatchStagedBytesExceeded
2797 | Self::MutationBatchResultBytesExceeded => {
2798 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2799 }
2800 Self::MutationBatchStoreMismatch | Self::MutationBatchDuplicateKey => {
2801 diagnostic_code::DiagnosticCode::RuntimeConflict
2802 }
2803 Self::MutationManagedTimestampRegression => {
2804 diagnostic_code::DiagnosticCode::RuntimeInvariantViolation
2805 }
2806 Self::AcceptedRowConstraintProgramCorrupt => {
2807 diagnostic_code::DiagnosticCode::RuntimeCorruption
2808 }
2809 }
2810 }
2811
2812 #[must_use]
2814 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2815 match self {
2816 Self::MutationRequiredFieldMissing => {
2817 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2818 boundary: diagnostic_code::RuntimeBoundaryCode::MutationRequiredFieldMissing,
2819 })
2820 }
2821 Self::MutationDatabaseOwnedFieldExplicit => {
2822 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2823 boundary:
2824 diagnostic_code::RuntimeBoundaryCode::MutationDatabaseOwnedFieldExplicit,
2825 })
2826 }
2827 Self::MutationBatchEmpty => Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2828 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchEmpty,
2829 }),
2830 Self::MutationBatchTooManyItems => {
2831 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2832 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyItems,
2833 })
2834 }
2835 Self::MutationBatchStagedBytesExceeded => {
2836 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2837 boundary:
2838 diagnostic_code::RuntimeBoundaryCode::MutationBatchStagedBytesExceeded,
2839 })
2840 }
2841 Self::MutationBatchResultBytesExceeded => {
2842 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2843 boundary:
2844 diagnostic_code::RuntimeBoundaryCode::MutationBatchResultBytesExceeded,
2845 })
2846 }
2847 Self::MutationBatchStoreMismatch => {
2848 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2849 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchStoreMismatch,
2850 })
2851 }
2852 Self::MutationBatchTooManyEntities => {
2853 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2854 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchTooManyEntities,
2855 })
2856 }
2857 Self::MutationBatchDuplicateKey => {
2858 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2859 boundary: diagnostic_code::RuntimeBoundaryCode::MutationBatchDuplicateKey,
2860 })
2861 }
2862 Self::MutationManagedTimestampRegression => {
2863 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2864 boundary:
2865 diagnostic_code::RuntimeBoundaryCode::MutationManagedTimestampRegression,
2866 })
2867 }
2868 Self::AcceptedRowConstraintProgramCorrupt => {
2869 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2870 boundary:
2871 diagnostic_code::RuntimeBoundaryCode::AcceptedRowConstraintProgramCorrupt,
2872 })
2873 }
2874 }
2875 }
2876
2877 #[must_use]
2879 #[cold]
2880 #[inline(never)]
2881 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2882 Vec::new()
2883 }
2884}
2885
2886impl RecoveryErrorDetail {
2887 #[must_use]
2889 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2890 match self {
2891 Self::UnsupportedFormatVersion { .. } => {
2892 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
2893 }
2894 Self::MalformedFormatMarker { .. } => {
2895 diagnostic_code::DiagnosticCode::RuntimeCorruption
2896 }
2897 }
2898 }
2899
2900 #[must_use]
2902 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2903 let kind = match self {
2904 Self::UnsupportedFormatVersion { .. } => {
2905 diagnostic_code::RuntimeErrorKind::IncompatiblePersistedFormat
2906 }
2907 Self::MalformedFormatMarker { .. } => diagnostic_code::RuntimeErrorKind::Corruption,
2908 };
2909
2910 Some(diagnostic_code::DiagnosticDetail::RuntimeKind { kind })
2911 }
2912
2913 #[must_use]
2915 pub fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
2916 match self {
2917 Self::UnsupportedFormatVersion { found, required } => {
2918 let mut facts = Vec::with_capacity(usize::from(found.is_some()) + 1);
2919 facts.push((
2920 diagnostic_code::DiagnosticFactTag::ExpectedVersion,
2921 u64::from(*required),
2922 ));
2923 if let Some(found) = found {
2924 facts.push((
2925 diagnostic_code::DiagnosticFactTag::ActualVersion,
2926 u64::from(*found),
2927 ));
2928 }
2929 facts
2930 }
2931 Self::MalformedFormatMarker { reason } => vec![(
2932 diagnostic_code::DiagnosticFactTag::DecodeReason,
2933 reason.diagnostic_decode_reason().raw(),
2934 )],
2935 }
2936 }
2937}
2938
2939impl StoreError {
2940 #[must_use]
2942 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
2943 match self {
2944 Self::NotFound => diagnostic_code::DiagnosticCode::StoreNotFound,
2945 Self::Corrupt => diagnostic_code::DiagnosticCode::StoreCorruption,
2946 Self::InvariantViolation => diagnostic_code::DiagnosticCode::StoreInvariantViolation,
2947 Self::SchemaDdlPublicationRaceLost
2948 | Self::SchemaDdlRewriteRequiresMigration
2949 | Self::SchemaRowLayoutVersionExhausted
2950 | Self::SchemaTransitionBudgetExceeded { .. } => {
2951 diagnostic_code::DiagnosticCode::SchemaDdlAdmission
2952 }
2953 Self::JournalMutationRevisionExhausted | Self::SchemaGeneratedFieldAfterDdlField => {
2954 diagnostic_code::DiagnosticCode::RuntimeUnsupported
2955 }
2956 Self::SchemaGeneratedConstraintActivationStale => {
2957 diagnostic_code::DiagnosticCode::RuntimeConflict
2958 }
2959 Self::SchemaMigration { reason } => reason.diagnostic_code(),
2960 }
2961 }
2962
2963 #[must_use]
2965 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
2966 match self {
2967 Self::SchemaDdlPublicationRaceLost => {
2968 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2969 reason: diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost,
2970 })
2971 }
2972 Self::SchemaDdlRewriteRequiresMigration => {
2973 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2974 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration,
2975 })
2976 }
2977 Self::SchemaMigration { reason } => {
2978 Some(diagnostic_code::DiagnosticDetail::SchemaMigration { reason: *reason })
2979 }
2980 Self::SchemaRowLayoutVersionExhausted => {
2981 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2982 reason: diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted,
2983 })
2984 }
2985 Self::JournalMutationRevisionExhausted => {
2986 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2987 boundary:
2988 diagnostic_code::RuntimeBoundaryCode::JournalMutationRevisionExhausted,
2989 })
2990 }
2991 Self::SchemaTransitionBudgetExceeded { .. } => {
2992 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
2993 reason: diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded,
2994 })
2995 }
2996 Self::SchemaGeneratedFieldAfterDdlField => {
2997 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
2998 boundary: diagnostic_code::RuntimeBoundaryCode::GeneratedFieldAfterDdlField,
2999 })
3000 }
3001 Self::SchemaGeneratedConstraintActivationStale => {
3002 Some(diagnostic_code::DiagnosticDetail::RuntimeBoundary {
3003 boundary:
3004 diagnostic_code::RuntimeBoundaryCode::GeneratedConstraintActivationStale,
3005 })
3006 }
3007 Self::NotFound | Self::Corrupt | Self::InvariantViolation => None,
3008 }
3009 }
3010}
3011
3012impl QueryErrorDetail {
3013 #[must_use]
3015 pub const fn diagnostic_code(&self) -> diagnostic_code::DiagnosticCode {
3016 match self {
3017 Self::ExactCountMetadataUnavailable => {
3018 diagnostic_code::DiagnosticCode::QueryExactCountMetadataUnavailable
3019 }
3020 Self::NumericOverflow => diagnostic_code::DiagnosticCode::QueryNumericOverflow,
3021 Self::NumericNotRepresentable => {
3022 diagnostic_code::DiagnosticCode::QueryNumericNotRepresentable
3023 }
3024 Self::UnsupportedSqlFeature { .. } => {
3025 diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature
3026 }
3027 Self::SqlLowering { .. } => diagnostic_code::DiagnosticCode::QueryUnsupportedSqlFeature,
3028 Self::UnsupportedProjection { .. } => {
3029 diagnostic_code::DiagnosticCode::QueryUnsupportedProjection
3030 }
3031 Self::UnknownAggregateTargetField => {
3032 diagnostic_code::DiagnosticCode::QueryUnknownAggregateTargetField
3033 }
3034 Self::QueryReadAdmission { .. } => diagnostic_code::DiagnosticCode::QueryReadAdmission,
3035 Self::SqlSurfaceMismatch { .. } => {
3036 diagnostic_code::DiagnosticCode::QuerySqlSurfaceMismatch
3037 }
3038 Self::SqlWriteBoundary { .. } => diagnostic_code::DiagnosticCode::QuerySqlWriteBoundary,
3039 Self::SchemaDdlAdmission { .. } => diagnostic_code::DiagnosticCode::SchemaDdlAdmission,
3040 Self::StaleSchemaRevision => diagnostic_code::DiagnosticCode::RuntimeConflict,
3041 }
3042 }
3043
3044 #[must_use]
3046 pub const fn diagnostic_detail(&self) -> Option<diagnostic_code::DiagnosticDetail> {
3047 match self {
3048 Self::UnsupportedSqlFeature { feature } => {
3049 Some(diagnostic_code::DiagnosticDetail::UnsupportedSqlFeature { feature: *feature })
3050 }
3051 Self::SqlLowering { reason } => {
3052 Some(diagnostic_code::DiagnosticDetail::SqlLowering { reason: *reason })
3053 }
3054 Self::UnsupportedProjection { reason } => {
3055 Some(diagnostic_code::DiagnosticDetail::QueryProjection { reason: *reason })
3056 }
3057 Self::QueryReadAdmission { reason } => {
3058 Some(diagnostic_code::DiagnosticDetail::QueryReadAdmission { reason: *reason })
3059 }
3060 Self::SqlSurfaceMismatch { mismatch } => {
3061 Some(diagnostic_code::DiagnosticDetail::SqlSurfaceMismatch {
3062 mismatch: *mismatch,
3063 })
3064 }
3065 Self::SqlWriteBoundary { boundary } => {
3066 Some(diagnostic_code::DiagnosticDetail::SqlWriteBoundary {
3067 boundary: *boundary,
3068 })
3069 }
3070 Self::SchemaDdlAdmission { error } => {
3071 Some(diagnostic_code::DiagnosticDetail::SchemaDdlAdmission {
3072 reason: error.diagnostic_code(),
3073 })
3074 }
3075 Self::ExactCountMetadataUnavailable
3076 | Self::NumericOverflow
3077 | Self::NumericNotRepresentable
3078 | Self::UnknownAggregateTargetField
3079 | Self::StaleSchemaRevision => None,
3080 }
3081 }
3082
3083 #[must_use]
3085 #[cold]
3086 #[inline(never)]
3087 pub const fn diagnostic_facts(&self) -> Vec<(diagnostic_code::DiagnosticFactTag, u64)> {
3088 Vec::new()
3089 }
3090}
3091
3092impl SchemaDdlAdmissionError {
3093 #[must_use]
3095 pub const fn diagnostic_code(&self) -> diagnostic_code::SchemaDdlAdmissionCode {
3096 match self {
3097 Self::MissingExpectedSchemaVersion => {
3098 diagnostic_code::SchemaDdlAdmissionCode::MissingExpectedSchemaVersion
3099 }
3100 Self::MissingNextSchemaVersion => {
3101 diagnostic_code::SchemaDdlAdmissionCode::MissingNextSchemaVersion
3102 }
3103 Self::StaleExpectedSchemaVersion => {
3104 diagnostic_code::SchemaDdlAdmissionCode::StaleExpectedSchemaVersion
3105 }
3106 Self::InvalidExpectedSchemaVersion => {
3107 diagnostic_code::SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion
3108 }
3109 Self::InvalidNextSchemaVersion => {
3110 diagnostic_code::SchemaDdlAdmissionCode::InvalidNextSchemaVersion
3111 }
3112 Self::AcceptedSchemaChangeWithoutVersionBump => {
3113 diagnostic_code::SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump
3114 }
3115 Self::EmptyVersionBump => diagnostic_code::SchemaDdlAdmissionCode::EmptyVersionBump,
3116 Self::VersionGap => diagnostic_code::SchemaDdlAdmissionCode::VersionGap,
3117 Self::VersionRollback => diagnostic_code::SchemaDdlAdmissionCode::VersionRollback,
3118 Self::FingerprintMethodMismatch => {
3119 diagnostic_code::SchemaDdlAdmissionCode::FingerprintMethodMismatch
3120 }
3121 Self::UnsupportedTransitionClass => {
3122 diagnostic_code::SchemaDdlAdmissionCode::UnsupportedTransitionClass
3123 }
3124 Self::PhysicalRunnerMissing => {
3125 diagnostic_code::SchemaDdlAdmissionCode::PhysicalRunnerMissing
3126 }
3127 Self::ValidationFailed => diagnostic_code::SchemaDdlAdmissionCode::ValidationFailed,
3128 Self::PublicationRaceLost => {
3129 diagnostic_code::SchemaDdlAdmissionCode::PublicationRaceLost
3130 }
3131 Self::InvalidAddColumnDefault => {
3132 diagnostic_code::SchemaDdlAdmissionCode::InvalidAddColumnDefault
3133 }
3134 Self::InvalidAlterColumnDefault => {
3135 diagnostic_code::SchemaDdlAdmissionCode::InvalidAlterColumnDefault
3136 }
3137 Self::GeneratedIndexDropRejected => {
3138 diagnostic_code::SchemaDdlAdmissionCode::GeneratedIndexDropRejected
3139 }
3140 Self::SchemaRewriteRequiresMigration => {
3141 diagnostic_code::SchemaDdlAdmissionCode::SchemaRewriteRequiresMigration
3142 }
3143 Self::SchemaTransitionBudgetExceeded { .. } => {
3144 diagnostic_code::SchemaDdlAdmissionCode::SchemaTransitionBudgetExceeded
3145 }
3146 Self::GeneratedFieldDefaultChangeRejected => {
3147 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected
3148 }
3149 Self::GeneratedFieldNullabilityChangeRejected => {
3150 diagnostic_code::SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected
3151 }
3152 Self::RowLayoutVersionExhausted => {
3153 diagnostic_code::SchemaDdlAdmissionCode::RowLayoutVersionExhausted
3154 }
3155 }
3156 }
3157}
3158
3159#[repr(u8)]
3166#[derive(Clone, Copy, Eq, PartialEq)]
3167pub enum ErrorClass {
3168 Corruption,
3169 IncompatiblePersistedFormat,
3170 NotFound,
3171 Internal,
3172 Conflict,
3173 Unsupported,
3174 InvariantViolation,
3175}
3176
3177impl ErrorClass {
3178 #[must_use]
3180 pub const fn diagnostic_code(self, origin: ErrorOrigin) -> diagnostic_code::DiagnosticCode {
3181 match self {
3182 Self::Corruption if matches!(origin, ErrorOrigin::Store) => {
3183 diagnostic_code::DiagnosticCode::StoreCorruption
3184 }
3185 Self::Corruption => diagnostic_code::DiagnosticCode::RuntimeCorruption,
3186 Self::IncompatiblePersistedFormat => {
3187 diagnostic_code::DiagnosticCode::RuntimeIncompatiblePersistedFormat
3188 }
3189 Self::NotFound if matches!(origin, ErrorOrigin::Store) => {
3190 diagnostic_code::DiagnosticCode::StoreNotFound
3191 }
3192 Self::NotFound => diagnostic_code::DiagnosticCode::RuntimeNotFound,
3193 Self::Internal => diagnostic_code::DiagnosticCode::RuntimeInternal,
3194 Self::Conflict => diagnostic_code::DiagnosticCode::RuntimeConflict,
3195 Self::Unsupported if matches!(origin, ErrorOrigin::Cursor) => {
3196 diagnostic_code::DiagnosticCode::QueryInvalidContinuationCursor
3197 }
3198 Self::Unsupported => diagnostic_code::DiagnosticCode::RuntimeUnsupported,
3199 Self::InvariantViolation if matches!(origin, ErrorOrigin::Store) => {
3200 diagnostic_code::DiagnosticCode::StoreInvariantViolation
3201 }
3202 Self::InvariantViolation => diagnostic_code::DiagnosticCode::RuntimeInvariantViolation,
3203 }
3204 }
3205}
3206
3207impl fmt::Debug for ErrorClass {
3208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3209 write!(f, "{}", *self as u8)
3210 }
3211}
3212
3213#[repr(u8)]
3220#[derive(Clone, Copy, Eq, PartialEq)]
3221pub enum ErrorOrigin {
3222 Serialize,
3223 Store,
3224 Index,
3225 Identity,
3226 Query,
3227 Planner,
3228 Cursor,
3229 Recovery,
3230 Response,
3231 Executor,
3232 Interface,
3233}
3234
3235impl ErrorOrigin {
3236 #[must_use]
3238 pub const fn diagnostic_origin(self) -> diagnostic_code::ErrorOrigin {
3239 match self {
3240 Self::Serialize => diagnostic_code::ErrorOrigin::Serialize,
3241 Self::Store => diagnostic_code::ErrorOrigin::Store,
3242 Self::Index => diagnostic_code::ErrorOrigin::Index,
3243 Self::Identity => diagnostic_code::ErrorOrigin::Identity,
3244 Self::Query => diagnostic_code::ErrorOrigin::Query,
3245 Self::Planner => diagnostic_code::ErrorOrigin::Planner,
3246 Self::Cursor => diagnostic_code::ErrorOrigin::Cursor,
3247 Self::Recovery => diagnostic_code::ErrorOrigin::Recovery,
3248 Self::Response => diagnostic_code::ErrorOrigin::Response,
3249 Self::Executor => diagnostic_code::ErrorOrigin::Executor,
3250 Self::Interface => diagnostic_code::ErrorOrigin::Interface,
3251 }
3252 }
3253}
3254
3255impl fmt::Debug for ErrorOrigin {
3256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3257 write!(f, "{}", *self as u8)
3258 }
3259}