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