1use std::fmt;
13
14mod fact;
15mod query_field;
16
17pub use fact::{
18 DiagnosticAggregateKind, DiagnosticBacklogResource, DiagnosticComponentKind,
19 DiagnosticConstraintContext, DiagnosticConstraintKind, DiagnosticDecodeReason,
20 DiagnosticExecutionBudgetResource, DiagnosticExecutionBudgetScope, DiagnosticExecutionLane,
21 DiagnosticFactSchemaMismatch, DiagnosticFactTag, DiagnosticFunctionKind,
22 DiagnosticMutationOperation, DiagnosticOperatorKind, DiagnosticTypeFamily,
23 MAX_PUBLIC_DIAGNOSTIC_FACTS, pack_u32_pair, unpack_u32_pair,
24 validate_known_diagnostic_fact_schema, validate_raw_diagnostic_fact_schema,
25};
26pub use query_field::{
27 MAX_PUBLIC_QUERY_FIELD_BYTES, QueryFieldRole, QueryFieldSchemaMismatch,
28 validate_query_field_schema,
29};
30
31#[remain::sorted]
38#[derive(Clone, Copy, Eq, Hash, PartialEq)]
39pub enum DiagnosticCode {
40 QueryExactCountMetadataUnavailable,
42 QueryIntent,
43 QueryInvalidContinuationCursor,
44 QueryNotFound,
45 QueryNotUnique,
46 QueryNumericNotRepresentable,
47 QueryNumericOverflow,
48 QueryPlan,
49 QueryReadAdmission,
50 QuerySqlSurfaceMismatch,
51 QuerySqlWriteBoundary,
52 QueryUnknownAggregateTargetField,
53 QueryUnorderedPagination,
54 QueryUnsupportedProjection,
55 QueryUnsupportedSqlFeature,
56 QueryValidate,
57 RuntimeConflict,
58 RuntimeCorruption,
59 RuntimeIncompatiblePersistedFormat,
60 RuntimeInternal,
61 RuntimeInvariantViolation,
62 RuntimeNotFound,
63 RuntimeUnsupported,
64 SchemaDdlAdmission,
65 StoreCorruption,
66 StoreInvariantViolation,
67 StoreNotFound,
68}
69
70impl DiagnosticCode {
71 #[must_use]
73 pub const fn class(self) -> ErrorClass {
74 match self {
75 Self::StoreCorruption | Self::RuntimeCorruption => ErrorClass::Corruption,
76 Self::RuntimeIncompatiblePersistedFormat => ErrorClass::IncompatiblePersistedFormat,
77 Self::QueryNotFound | Self::StoreNotFound | Self::RuntimeNotFound => {
78 ErrorClass::NotFound
79 }
80 Self::RuntimeConflict => ErrorClass::Conflict,
81 Self::QueryExactCountMetadataUnavailable
82 | Self::QueryUnsupportedSqlFeature
83 | Self::QueryUnknownAggregateTargetField
84 | Self::QueryUnsupportedProjection
85 | Self::QuerySqlSurfaceMismatch
86 | Self::QuerySqlWriteBoundary
87 | Self::RuntimeUnsupported => ErrorClass::Unsupported,
88 Self::StoreInvariantViolation | Self::RuntimeInvariantViolation => {
89 ErrorClass::InvariantViolation
90 }
91 Self::RuntimeInternal => ErrorClass::Internal,
92 Self::QueryValidate
93 | Self::QueryIntent
94 | Self::QueryPlan
95 | Self::QueryReadAdmission
96 | Self::QueryUnorderedPagination
97 | Self::QueryInvalidContinuationCursor
98 | Self::QueryNotUnique
99 | Self::QueryNumericOverflow
100 | Self::QueryNumericNotRepresentable
101 | Self::SchemaDdlAdmission => ErrorClass::Query,
102 }
103 }
104
105 #[must_use]
107 pub const fn origin(self) -> ErrorOrigin {
108 match self {
109 Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
110 ErrorOrigin::Store
111 }
112 Self::RuntimeCorruption
113 | Self::RuntimeIncompatiblePersistedFormat
114 | Self::RuntimeInvariantViolation
115 | Self::RuntimeConflict
116 | Self::RuntimeNotFound
117 | Self::RuntimeUnsupported
118 | Self::RuntimeInternal => ErrorOrigin::Runtime,
119 Self::QueryExactCountMetadataUnavailable
120 | Self::QueryValidate
121 | Self::QueryIntent
122 | Self::QueryPlan
123 | Self::QueryReadAdmission
124 | Self::QueryUnorderedPagination
125 | Self::QueryInvalidContinuationCursor
126 | Self::QueryNotFound
127 | Self::QueryNotUnique
128 | Self::QueryNumericOverflow
129 | Self::QueryNumericNotRepresentable
130 | Self::QueryUnknownAggregateTargetField
131 | Self::QueryUnsupportedProjection
132 | Self::QueryUnsupportedSqlFeature
133 | Self::QuerySqlSurfaceMismatch
134 | Self::QuerySqlWriteBoundary
135 | Self::SchemaDdlAdmission => ErrorOrigin::Query,
136 }
137 }
138
139 #[must_use]
141 pub const fn error_code(self) -> ErrorCode {
142 match self {
143 Self::QueryExactCountMetadataUnavailable => {
144 ErrorCode::QUERY_EXACT_COUNT_METADATA_UNAVAILABLE
145 }
146 Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
147 Self::QueryIntent => ErrorCode::QUERY_INTENT,
148 Self::QueryPlan => ErrorCode::QUERY_PLAN,
149 Self::QueryReadAdmission => ErrorCode::QUERY_READ_ADMISSION,
150 Self::QueryUnorderedPagination => ErrorCode::QUERY_UNORDERED_PAGINATION,
151 Self::QueryInvalidContinuationCursor => ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
152 Self::QueryNotFound => ErrorCode::QUERY_NOT_FOUND,
153 Self::QueryNotUnique => ErrorCode::QUERY_NOT_UNIQUE,
154 Self::QueryNumericOverflow => ErrorCode::QUERY_NUMERIC_OVERFLOW,
155 Self::QueryNumericNotRepresentable => ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
156 Self::QueryUnknownAggregateTargetField => {
157 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD
158 }
159 Self::QueryUnsupportedProjection => ErrorCode::QUERY_UNSUPPORTED_PROJECTION,
160 Self::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
161 Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
162 Self::QuerySqlWriteBoundary => ErrorCode::QUERY_SQL_WRITE_BOUNDARY,
163 Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
164 Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
165 Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
166 Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
167 Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
168 Self::RuntimeIncompatiblePersistedFormat => {
169 ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
170 }
171 Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
172 Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
173 Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
174 Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
175 Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
176 }
177 }
178}
179
180impl fmt::Debug for DiagnosticCode {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 fmt_compact_code(f, self.error_code().raw())
183 }
184}
185
186#[derive(Clone, Copy, Eq, Hash, PartialEq)]
198pub struct ErrorCode(u16);
199
200mod registry;
201
202impl ErrorCode {
203 #[must_use]
205 pub const fn from_raw(raw: u16) -> Self {
206 Self(raw)
207 }
208
209 #[must_use]
211 pub const fn raw(self) -> u16 {
212 self.0
213 }
214}
215
216impl fmt::Debug for ErrorCode {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 fmt_compact_code(f, self.raw())
219 }
220}
221
222#[remain::sorted]
229#[derive(Clone, Copy, Eq, Hash, PartialEq)]
230pub enum ErrorClass {
231 Conflict,
232 Corruption,
233 IncompatiblePersistedFormat,
234 Internal,
235 InvariantViolation,
236 NotFound,
237 Query,
238 Unsupported,
239}
240
241impl ErrorClass {
242 #[must_use]
244 pub const fn wire_code(self) -> u8 {
245 match self {
246 Self::Query => 1,
247 Self::Corruption => 2,
248 Self::IncompatiblePersistedFormat => 3,
249 Self::NotFound => 4,
250 Self::Internal => 5,
251 Self::Conflict => 6,
252 Self::Unsupported => 7,
253 Self::InvariantViolation => 8,
254 }
255 }
256
257 #[must_use]
259 pub const fn from_wire_code(code: u8) -> Option<Self> {
260 match code {
261 1 => Some(Self::Query),
262 2 => Some(Self::Corruption),
263 3 => Some(Self::IncompatiblePersistedFormat),
264 4 => Some(Self::NotFound),
265 5 => Some(Self::Internal),
266 6 => Some(Self::Conflict),
267 7 => Some(Self::Unsupported),
268 8 => Some(Self::InvariantViolation),
269 _ => None,
270 }
271 }
272}
273
274impl fmt::Debug for ErrorClass {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 fmt_compact_code(f, u16::from(self.wire_code()))
277 }
278}
279
280#[remain::sorted]
287#[derive(Clone, Copy, Eq, Hash, PartialEq)]
288pub enum ErrorOrigin {
289 Cursor,
290 Executor,
291 Identity,
292 Index,
293 Interface,
294 Planner,
295 Query,
296 Recovery,
297 Response,
298 Runtime,
299 Serialize,
300 Store,
301}
302
303impl ErrorOrigin {
304 #[must_use]
306 pub const fn wire_code(self) -> u8 {
307 match self {
308 Self::Cursor => 1,
309 Self::Executor => 2,
310 Self::Identity => 3,
311 Self::Index => 4,
312 Self::Interface => 5,
313 Self::Planner => 6,
314 Self::Query => 7,
315 Self::Recovery => 8,
316 Self::Response => 9,
317 Self::Runtime => 10,
318 Self::Serialize => 11,
319 Self::Store => 12,
320 }
321 }
322
323 #[must_use]
325 pub const fn from_known_wire_code(code: u8) -> Option<Self> {
326 match code {
327 1 => Some(Self::Cursor),
328 2 => Some(Self::Executor),
329 3 => Some(Self::Identity),
330 4 => Some(Self::Index),
331 5 => Some(Self::Interface),
332 6 => Some(Self::Planner),
333 7 => Some(Self::Query),
334 8 => Some(Self::Recovery),
335 9 => Some(Self::Response),
336 10 => Some(Self::Runtime),
337 11 => Some(Self::Serialize),
338 12 => Some(Self::Store),
339 _ => None,
340 }
341 }
342
343 #[must_use]
348 pub const fn from_wire_code(code: u8) -> Self {
349 match Self::from_known_wire_code(code) {
350 Some(origin) => origin,
351 None => Self::Runtime,
352 }
353 }
354}
355
356impl fmt::Debug for ErrorOrigin {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 fmt_compact_code(f, u16::from(self.wire_code()))
359 }
360}
361
362#[repr(u16)]
369#[derive(Clone, Copy, Eq, Hash, PartialEq)]
370pub enum QueryErrorKind {
371 Validate,
372 Intent,
373 Plan,
374 UnorderedPagination,
375 InvalidContinuationCursor,
376 NotFound,
377 NotUnique,
378}
379
380impl fmt::Debug for QueryErrorKind {
381 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
382 fmt_compact_code(f, *self as u16)
383 }
384}
385
386#[repr(u16)]
394#[derive(Clone, Copy, Eq, Hash, PartialEq)]
395pub enum QueryProjectionCode {
396 NumericLiteralRequired,
397 NumericScaleArguments,
398 NestedFieldPathPreview,
399 CaseConditionBooleanRequired,
400 NumericInputRequired,
401 TextOrBlobInputRequired,
402 TextInputRequired,
403 TextOrNullArgumentRequired,
404 IntegerOrNullArgumentRequired,
405 UnaryOperandIncompatible,
406 BinaryOperandsIncompatible,
407}
408
409impl fmt::Debug for QueryProjectionCode {
410 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411 fmt_compact_code(f, *self as u16)
412 }
413}
414
415#[repr(u16)]
423#[derive(Clone, Copy, Eq, Hash, PartialEq)]
424pub enum QueryReadAdmissionCode {
425 PublicQueryRequiresLimit,
426 PublicQueryRequiresIndex,
427 UnboundedFullScanRejected,
428 SortRequiresMaterialization,
429 GroupedQueryRequiresLimits,
430 GroupedQueryExceedsBudget,
431 DiagnosticLaneDoesNotExecute,
432 ReturnedRowBoundExceedsPolicy,
433 PrimaryKeyInputExceedsPolicy,
434 InputDepthExceeded,
436 InputNodesExceeded,
438 InputBytesExceeded,
440 ExplainDoesNotAcceptCursor,
442}
443
444impl fmt::Debug for QueryReadAdmissionCode {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 fmt_compact_code(f, *self as u16)
447 }
448}
449
450#[repr(u16)]
457#[derive(Clone, Copy, Eq, Hash, PartialEq)]
458pub enum RuntimeErrorKind {
459 Corruption,
460 IncompatiblePersistedFormat,
461 InvariantViolation,
462 Conflict,
463 NotFound,
464 Unsupported,
465 Internal,
466}
467
468impl fmt::Debug for RuntimeErrorKind {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 fmt_compact_code(f, *self as u16)
471 }
472}
473
474#[repr(u16)]
482#[derive(Clone, Copy, Eq, Hash, PartialEq)]
483pub enum RuntimeBoundaryCode {
484 SqlSurfaceControllerRequired,
485 SchemaSurfaceControllerRequired,
486 SqlQueryNoConfiguredEntities,
487 SqlQueryEntityNotFound,
488 SqlDdlTargetRequired,
489 SqlDdlEntityNotConfigured,
490 SqlIntrospectionDisabled,
491 MutationRequiredFieldMissing,
493 MutationManagedTimestampRegression,
495 PersistedRowLayoutOutsideAcceptedWindow,
497 PersistedRowSlotCountMismatch,
499 GeneratedFieldAfterDdlField,
501 JournalMutationRevisionExhausted,
503 ConstraintViolation,
505 AcceptedRowConstraintProgramCorrupt,
507 ConstraintActivationWriteBlocked,
509 GeneratedConstraintActivationStale,
511 MutationDatabaseOwnedFieldExplicit,
513 MutationBatchEmpty,
515 MutationBatchTooManyItems,
517 MutationBatchStagedBytesExceeded,
519 MutationBatchResultBytesExceeded,
521 MutationBatchStoreMismatch,
523 MutationBatchTooManyEntities,
525 MutationBatchDuplicateKey,
527 OperationalSurfaceControllerRequired,
529 ExactKeyBatchTooManyItems,
531 ExactKeyBatchInputBytesExceeded,
533 ExactKeyBatchStoredBytesExceeded,
535 ExactKeyBatchResultBytesExceeded,
537 ExecutionBudgetExceeded,
539 PageUnitTooLarge,
541 RequestExecutionScopeRequired,
543 RequestExecutionRootMismatch,
545 SqlQueryReplyBytesExceeded,
547 QueryExplainOutputExceeded,
548 QueryExplainDepthExceeded,
550 DatabaseStartupRecoveryPending,
552 SqlSurfacePolicyDenied,
554 SchemaSurfacePolicyDenied,
556 MutationBatchCommitWorkExceeded,
558 ConvergenceBacklogPressure,
560 MemoryBucketSizeMismatch,
562 MemoryAllocationResolutionFailed,
564 MemoryNamespaceRemoved,
566 MemoryAllocationRolesIncomplete,
568 MemoryDeclarationInvalid,
570 MemoryDeclarationSnapshotMismatch,
572 MemoryHistoricalJournalUnavailable,
574}
575
576impl fmt::Debug for RuntimeBoundaryCode {
577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578 fmt_compact_code(f, *self as u16)
579 }
580}
581
582#[repr(u16)]
590#[derive(Clone, Copy, Eq, Hash, PartialEq)]
591pub enum SqlFeatureCode {
592 AggregateFilterClause,
593 AlterStatementBeyondAlterTable,
594 AlterTableAddColumnDuplicateDefault,
595 AlterTableAddColumnModifiers,
596 AlterTableAddStatementBeyondAddColumn,
597 AlterTableAlterColumnDropUnsupportedAction,
598 AlterTableAlterColumnModifiers,
599 AlterTableAlterColumnSetUnsupportedAction,
600 AlterTableAlterColumnUnsupportedAction,
601 AlterTableAlterStatementBeyondAlterColumn,
602 AlterTableDropColumnIfExistsSyntax,
603 AlterTableDropColumnModifiers,
604 AlterTableDropStatementBeyondDropColumn,
605 AlterTableRenameColumnMissingTo,
606 AlterTableRenameColumnModifiers,
607 AlterTableRenameStatementBeyondRenameColumn,
608 AlterTableUnsupportedOperation,
609 ColumnAlias,
610 CreateIndexIfNotExistsSyntax,
611 CreateIndexKeyOrderingModifiers,
612 CreateIndexModifiers,
613 CreateStatementBeyondCreateIndex,
614 DescribeModifier,
615 DdlSchemaVersionDuplicateExpectedClause,
616 DdlSchemaVersionDuplicateSetClause,
617 DropIndexModifiers,
618 DropIndexIfExistsSyntax,
619 DropStatementBeyondDropIndex,
620 ExpressionIndexUnsupportedFunction,
621 Having,
622 Insert,
623 Join,
624 LikePatternBeyondTrailingPrefix,
625 LowerFieldPredicateUnsupported,
626 MultiStatementSql,
627 NestedAggregateInput,
628 NestedProjectionFunctionInArithmetic,
629 OrderByUnsupportedForm,
630 Other,
631 PredicateStartsWithFirstArgument,
632 QuotedIdentifiers,
633 ReturningUnsupportedShape,
634 ScalarFunctionExpressionPosition,
635 ScaleTakingNumericFunctionExpressionPosition,
636 ShowColumnsModifiers,
637 ShowEntitiesModifiers,
638 ShowIndexesModifiers,
639 ShowMemoryModifiers,
640 ShowStoresModifiers,
641 ShowUnsupportedCommand,
642 SimpleCaseExpression,
643 StandaloneLiteralProjectionItem,
644 UnionIntersectExcept,
645 UnsupportedFunctionNamespace,
646 Update,
647 UpperFieldPredicateUnsupported,
648 WindowFunction,
649 With,
650 NumericScaleFunctionArguments,
651 OrderByFieldNotOrderable,
652 ShowConstraintsModifiers,
653 AlterTableAddConstraintBeyondCheck,
654 AlterTableAddConstraintModifiers,
655 AlterTableDropConstraintIfExistsSyntax,
656 AlterTableDropConstraintModifiers,
657 AlterTableValidateBeyondConstraint,
658 AlterTableValidateConstraintModifiers,
659 ShowRelationsModifiers,
660}
661
662impl fmt::Debug for SqlFeatureCode {
663 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
664 fmt_compact_code(f, *self as u16)
665 }
666}
667
668#[repr(u16)]
677#[derive(Clone, Copy, Eq, Hash, PartialEq)]
678pub enum SqlLoweringCode {
679 EntityMismatch,
680 SelectProjectionShape,
681 SelectDistinct,
682 DistinctOrderByProjection,
683 GlobalAggregateProjection,
684 GlobalAggregateGroupBy,
685 SelectGroupByShape,
686 GroupedProjectionExplicitListRequired,
687 GroupedProjectionAggregateRequired,
688 GroupedProjectionNonGroupField,
689 GroupedProjectionScalarAfterAggregate,
690 HavingRequiresGroupBy,
691 SelectHavingShape,
692 AggregateInputExpressions,
693 WhereExpressionShape,
694 ParameterPlacement,
695 SqlDdlExecutionUnsupported,
696 BindingCount,
697 BindingFamily,
698 BindingLimit,
699}
700
701impl fmt::Debug for SqlLoweringCode {
702 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
703 fmt_compact_code(f, *self as u16)
704 }
705}
706
707#[repr(u16)]
715#[derive(Clone, Copy, Eq, Hash, PartialEq)]
716pub enum SqlSurfaceMismatchCode {
717 QueryRejectsInsert,
718 QueryRejectsUpdate,
719 QueryRejectsDelete,
720 MutationRejectsSelect,
721 MutationRejectsExplain,
722 MutationRejectsDescribe,
723 MutationRejectsShowIndexes,
724 MutationRejectsShowColumns,
725 MutationRejectsShowEntities,
726 MutationRejectsShowStores,
727 MutationRejectsShowMemory,
728 MutationRequiresExplicitUpdateIntent,
729 MutationRejectsShowConstraints,
730 MutationRejectsShowRelations,
731}
732
733impl fmt::Debug for SqlSurfaceMismatchCode {
734 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
735 fmt_compact_code(f, *self as u16)
736 }
737}
738
739#[repr(u16)]
747#[derive(Clone, Copy, Eq, Hash, PartialEq)]
748pub enum SqlWriteBoundaryCode {
749 PrimaryKeyLiteralIncompatible,
750 MissingPrimaryKey,
751 MissingRequiredFields,
752 ExplicitManagedField,
753 ExplicitGeneratedField,
754 InsertSelectRequiresScalar,
755 InsertSelectAggregateProjection,
756 InsertSelectWidthMismatch,
757 UpdatePrimaryKeyMutation,
758 InvalidFieldLiteral,
759 UnknownReturningField,
760 DuplicateReturningField,
761 UpdateMissingWherePredicate,
762 WriteOrderByUnsupportedShape,
763 ReturningResponseTooLarge,
764 ReturningRowsTooMany,
765 StagedRowsTooMany,
766 InsertDefaultRequiredField,
767 UpdateDefaultRequiredField,
768 UpdateDefaultDatabaseOwnedField,
769 ExactUpdateAssertionRequired,
770 ExactUpdateAssertionTooHigh,
771 ExactUpdateAffectedRowsExceeded,
772 ExactUpdateWindowUnsupported,
773 ExactUpdateScanBudgetExceeded,
774 ResumableUpdateWindowUnsupported,
775 ResumableUpdateReturningUnsupported,
776 ResumableUpdateRequiresJournaledStore,
777 ResumableUpdateAssignedFieldHasGlobalConstraint,
778 ResumableUpdateScopeDependsOnAssignedField,
779 ResumableUpdateScopeDependencyUnknown,
780 ResumableUpdateContinuationMalformed,
781 ResumableUpdateContinuationTargetMismatch,
782 ResumableUpdateContinuationSchemaMismatch,
783 ResumableUpdateContinuationScopeMismatch,
784 ResumableUpdateContinuationPatchMismatch,
785 ResumableUpdateContinuationBatchPolicyMismatch,
786 ResumableUpdateManagedFieldHasGlobalConstraint,
787}
788
789impl fmt::Debug for SqlWriteBoundaryCode {
790 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
791 fmt_compact_code(f, *self as u16)
792 }
793}
794
795#[repr(u16)]
803#[derive(Clone, Copy, Eq, Hash, PartialEq)]
804pub enum SchemaDdlAdmissionCode {
805 MissingExpectedSchemaVersion,
806 MissingNextSchemaVersion,
807 StaleExpectedSchemaVersion,
808 InvalidExpectedSchemaVersion,
809 InvalidNextSchemaVersion,
810 AcceptedSchemaChangeWithoutVersionBump,
811 EmptyVersionBump,
812 VersionGap,
813 VersionRollback,
814 FingerprintMethodMismatch,
815 UnsupportedTransitionClass,
816 PhysicalRunnerMissing,
817 ValidationFailed,
818 PublicationRaceLost,
819 InvalidAddColumnDefault,
820 InvalidAlterColumnDefault,
821 GeneratedIndexDropRejected,
822 SchemaRewriteRequiresMigration,
823 SchemaTransitionBudgetExceeded,
824 GeneratedFieldDefaultChangeRejected,
825 GeneratedFieldNullabilityChangeRejected,
826 RowLayoutVersionExhausted,
827}
828
829impl fmt::Debug for SchemaDdlAdmissionCode {
830 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831 fmt_compact_code(f, *self as u16)
832 }
833}
834
835#[repr(u16)]
837#[derive(Clone, Copy, Eq, Hash, PartialEq)]
838pub enum SchemaMigrationCode {
839 Unadopted,
840 MissingMigration,
841 VersionGap,
842 Downgrade,
843 EmptyEntityVersionBump,
844 StaleAcceptedHead,
845 PlanChanged,
846 UnknownFromObject,
847 UnknownToObject,
848 KindMismatch,
849 IdentityConflict,
850 UnexplainedSchemaDifference,
851 UnsupportedTransform,
852 PhysicalRunnerMissing,
853 MigrationInProgress,
854 AbortTooLate,
855 ProgressCorrupt,
856 CandidateMismatch,
857 PublicationRaceLost,
858}
859
860impl SchemaMigrationCode {
861 #[must_use]
863 pub const fn diagnostic_code(self) -> DiagnosticCode {
864 match self {
865 Self::StaleAcceptedHead
866 | Self::PlanChanged
867 | Self::IdentityConflict
868 | Self::MigrationInProgress
869 | Self::AbortTooLate
870 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
871 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
872 Self::Unadopted
873 | Self::MissingMigration
874 | Self::VersionGap
875 | Self::Downgrade
876 | Self::EmptyEntityVersionBump
877 | Self::UnknownFromObject
878 | Self::UnknownToObject
879 | Self::KindMismatch
880 | Self::UnexplainedSchemaDifference
881 | Self::UnsupportedTransform
882 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
883 }
884 }
885}
886
887impl fmt::Debug for SchemaMigrationCode {
888 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889 fmt_compact_code(f, *self as u16)
890 }
891}
892
893#[remain::sorted]
900#[derive(Clone, Copy, Eq, PartialEq)]
901pub enum DiagnosticDetail {
902 QueryKind { kind: QueryErrorKind },
903 QueryProjection { reason: QueryProjectionCode },
904 QueryReadAdmission { reason: QueryReadAdmissionCode },
905 RuntimeBoundary { boundary: RuntimeBoundaryCode },
906 RuntimeKind { kind: RuntimeErrorKind },
907 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
908 SchemaMigration { reason: SchemaMigrationCode },
909 SqlLowering { reason: SqlLoweringCode },
910 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
911 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
912 UnsupportedSqlFeature { feature: SqlFeatureCode },
913}
914
915impl fmt::Debug for DiagnosticDetail {
916 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
917 fmt_compact_code(
918 f,
919 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
920 )
921 }
922}
923
924#[derive(Clone, Eq, PartialEq)]
931pub struct Diagnostic {
932 code: DiagnosticCode,
933 origin: ErrorOrigin,
934 detail: Option<DiagnosticDetail>,
935}
936
937impl Diagnostic {
938 #[must_use]
940 pub const fn new(
941 code: DiagnosticCode,
942 origin: ErrorOrigin,
943 detail: Option<DiagnosticDetail>,
944 ) -> Self {
945 Self {
946 code,
947 origin,
948 detail,
949 }
950 }
951
952 #[must_use]
954 pub const fn from_code(code: DiagnosticCode) -> Self {
955 Self::new(code, code.origin(), None)
956 }
957
958 #[must_use]
960 pub const fn code(&self) -> DiagnosticCode {
961 self.code
962 }
963
964 #[must_use]
966 pub const fn class(&self) -> ErrorClass {
967 self.code.class()
968 }
969
970 #[must_use]
972 pub const fn origin(&self) -> ErrorOrigin {
973 self.origin
974 }
975
976 #[must_use]
978 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
979 self.detail.as_ref()
980 }
981
982 #[must_use]
984 pub const fn error_code(&self) -> ErrorCode {
985 ErrorCode::from_parts(self.code, self.detail)
986 }
987}
988
989impl fmt::Debug for Diagnostic {
990 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
991 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
992 }
993}
994
995fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
996 write!(f, "{raw}")
997}
998
999#[cfg(test)]
1000mod tests {
1001 use super::{
1002 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
1003 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
1004 SqlWriteBoundaryCode,
1005 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
1006 };
1007
1008 #[test]
1009 fn diagnostic_from_code_uses_default_origin() {
1010 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
1011
1012 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1013 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1014 }
1015
1016 #[test]
1017 fn diagnostic_code_reports_broad_class() {
1018 assert_eq!(
1019 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1020 ErrorClass::Unsupported
1021 );
1022 assert_eq!(
1023 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1024 ErrorClass::Unsupported
1025 );
1026 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1027 assert_eq!(
1028 DiagnosticCode::StoreCorruption.class(),
1029 ErrorClass::Corruption
1030 );
1031 }
1032
1033 #[test]
1034 fn class_and_origin_wire_codes_round_trip() {
1035 for (class, raw) in [
1036 (ErrorClass::Query, 1),
1037 (ErrorClass::Corruption, 2),
1038 (ErrorClass::IncompatiblePersistedFormat, 3),
1039 (ErrorClass::NotFound, 4),
1040 (ErrorClass::Internal, 5),
1041 (ErrorClass::Conflict, 6),
1042 (ErrorClass::Unsupported, 7),
1043 (ErrorClass::InvariantViolation, 8),
1044 ] {
1045 assert_eq!(class.wire_code(), raw);
1046 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1047 assert_eq!(format!("{class:?}"), raw.to_string());
1048 }
1049
1050 for (origin, raw) in [
1051 (ErrorOrigin::Cursor, 1),
1052 (ErrorOrigin::Executor, 2),
1053 (ErrorOrigin::Identity, 3),
1054 (ErrorOrigin::Index, 4),
1055 (ErrorOrigin::Interface, 5),
1056 (ErrorOrigin::Planner, 6),
1057 (ErrorOrigin::Query, 7),
1058 (ErrorOrigin::Recovery, 8),
1059 (ErrorOrigin::Response, 9),
1060 (ErrorOrigin::Runtime, 10),
1061 (ErrorOrigin::Serialize, 11),
1062 (ErrorOrigin::Store, 12),
1063 ] {
1064 assert_eq!(origin.wire_code(), raw);
1065 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1066 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1067 assert_eq!(format!("{origin:?}"), raw.to_string());
1068 }
1069
1070 assert_eq!(ErrorClass::from_wire_code(0), None);
1071 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1072 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1073 }
1074
1075 #[test]
1076 fn public_error_codes_are_sequential() {
1077 let first = ORDERED_ERROR_CODES
1078 .first()
1079 .expect("public error-code registry is non-empty")
1080 .raw();
1081
1082 assert_eq!(first, 1);
1083
1084 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1085 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1086 assert_eq!(code.raw(), expected);
1087 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1088 assert!(code.is_known());
1089 }
1090
1091 let last = ORDERED_ERROR_CODES
1092 .last()
1093 .expect("public error-code registry is non-empty")
1094 .raw();
1095
1096 assert_eq!(last, 281);
1097 }
1098
1099 #[test]
1100 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1101 let first = ORDERED_ERROR_CODES
1102 .first()
1103 .expect("public error-code registry is non-empty")
1104 .raw();
1105 let last = ORDERED_ERROR_CODES
1106 .last()
1107 .expect("public error-code registry is non-empty")
1108 .raw();
1109
1110 for raw in first..=last {
1111 let code = ErrorCode::from_raw(raw);
1112 let diagnostic_code = code.diagnostic_code();
1113 let diagnostic_detail = code.diagnostic_detail();
1114 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1115
1116 assert_eq!(rebuilt.raw(), raw);
1117
1118 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1119
1120 assert_eq!(diagnostic.code(), diagnostic_code);
1121 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1122 assert_eq!(diagnostic.error_code().raw(), raw);
1123 }
1124 }
1125
1126 #[test]
1127 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1128 let first_unknown = ORDERED_ERROR_CODES
1129 .last()
1130 .expect("public error-code registry is non-empty")
1131 .raw()
1132 .checked_add(1)
1133 .expect("public error-code registry retains an unknown successor");
1134
1135 for raw in [0, first_unknown, u16::MAX] {
1136 let code = ErrorCode::from_raw(raw);
1137
1138 assert_eq!(ErrorCode::known(raw), None);
1139 assert!(!code.is_known());
1140 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1141 assert_eq!(code.diagnostic_detail(), None);
1142 assert_eq!(code.class(), ErrorClass::Internal);
1143
1144 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1145
1146 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1147 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1148 assert_eq!(diagnostic.detail(), None);
1149 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1150 }
1151 }
1152
1153 #[test]
1154 fn from_parts_requires_detail_to_match_broad_code() {
1155 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1156 feature: SqlFeatureCode::Join,
1157 });
1158
1159 assert_eq!(
1160 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1161 ErrorCode::SQL_FEATURE_JOIN
1162 );
1163 assert_eq!(
1164 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1165 ErrorCode::QUERY_PLAN
1166 );
1167 }
1168
1169 #[test]
1170 fn detail_bearing_registry_entries_round_trip_directly() {
1171 assert!(!DETAIL_ERROR_CODES.is_empty());
1172
1173 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1174 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1175 assert_eq!(code.diagnostic_code(), diagnostic_code);
1176 assert_eq!(code.diagnostic_detail(), Some(detail));
1177 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1178 }
1179 }
1180
1181 #[test]
1182 fn diagnostic_detail_reports_generated_broad_code() {
1183 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1184 feature: SqlFeatureCode::Join,
1185 };
1186
1187 assert_eq!(
1188 detail.diagnostic_code(),
1189 DiagnosticCode::QueryUnsupportedSqlFeature
1190 );
1191 assert_eq!(format!("{detail:?}"), "61");
1192 }
1193
1194 #[test]
1195 fn public_error_codes_reconstruct_shifted_details() {
1196 assert_eq!(
1197 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1198 DiagnosticCode::QueryUnknownAggregateTargetField
1199 );
1200 assert_eq!(
1201 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1202 Some(DiagnosticDetail::UnsupportedSqlFeature {
1203 feature: SqlFeatureCode::Join,
1204 })
1205 );
1206 assert_eq!(
1207 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1208 Some(DiagnosticDetail::QueryProjection {
1209 reason: QueryProjectionCode::NumericLiteralRequired,
1210 })
1211 );
1212 assert_eq!(
1213 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1214 Some(DiagnosticDetail::QueryReadAdmission {
1215 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1216 })
1217 );
1218 assert_eq!(
1219 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1220 Some(DiagnosticDetail::SqlLowering {
1221 reason: SqlLoweringCode::DistinctOrderByProjection,
1222 })
1223 );
1224 assert_eq!(
1225 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1226 Some(DiagnosticDetail::SqlWriteBoundary {
1227 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1228 })
1229 );
1230 assert_eq!(
1231 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1232 Some(DiagnosticDetail::SqlWriteBoundary {
1233 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1234 })
1235 );
1236 }
1237}