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