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