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