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 MutationBatchCommitWorkExceeded,
564}
565
566impl fmt::Debug for RuntimeBoundaryCode {
567 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568 fmt_compact_code(f, *self as u16)
569 }
570}
571
572#[repr(u16)]
580#[derive(Clone, Copy, Eq, Hash, PartialEq)]
581pub enum SqlFeatureCode {
582 AggregateFilterClause,
583 AlterStatementBeyondAlterTable,
584 AlterTableAddColumnDuplicateDefault,
585 AlterTableAddColumnModifiers,
586 AlterTableAddStatementBeyondAddColumn,
587 AlterTableAlterColumnDropUnsupportedAction,
588 AlterTableAlterColumnModifiers,
589 AlterTableAlterColumnSetUnsupportedAction,
590 AlterTableAlterColumnUnsupportedAction,
591 AlterTableAlterStatementBeyondAlterColumn,
592 AlterTableDropColumnIfExistsSyntax,
593 AlterTableDropColumnModifiers,
594 AlterTableDropStatementBeyondDropColumn,
595 AlterTableRenameColumnMissingTo,
596 AlterTableRenameColumnModifiers,
597 AlterTableRenameStatementBeyondRenameColumn,
598 AlterTableUnsupportedOperation,
599 ColumnAlias,
600 CreateIndexIfNotExistsSyntax,
601 CreateIndexKeyOrderingModifiers,
602 CreateIndexModifiers,
603 CreateStatementBeyondCreateIndex,
604 DescribeModifier,
605 DdlSchemaVersionDuplicateExpectedClause,
606 DdlSchemaVersionDuplicateSetClause,
607 DropIndexModifiers,
608 DropIndexIfExistsSyntax,
609 DropStatementBeyondDropIndex,
610 ExpressionIndexUnsupportedFunction,
611 Having,
612 Insert,
613 Join,
614 LikePatternBeyondTrailingPrefix,
615 LowerFieldPredicateUnsupported,
616 MultiStatementSql,
617 NestedAggregateInput,
618 NestedProjectionFunctionInArithmetic,
619 OrderByUnsupportedForm,
620 Other,
621 PredicateStartsWithFirstArgument,
622 QuotedIdentifiers,
623 ReturningUnsupportedShape,
624 ScalarFunctionExpressionPosition,
625 ScaleTakingNumericFunctionExpressionPosition,
626 SearchedCaseGroupedOrderBy,
627 ShowColumnsModifiers,
628 ShowEntitiesModifiers,
629 ShowIndexesModifiers,
630 ShowMemoryModifiers,
631 ShowStoresModifiers,
632 ShowUnsupportedCommand,
633 SimpleCaseExpression,
634 StandaloneLiteralProjectionItem,
635 SupportedGroupedOrderByExpressionFamily,
636 SupportedOrderByExpressionFamily,
637 UnionIntersectExcept,
638 UnsupportedFunctionNamespace,
639 Update,
640 UpperFieldPredicateUnsupported,
641 WindowFunction,
642 With,
643 NumericScaleFunctionArguments,
644 OrderByFieldNotOrderable,
645 ShowConstraintsModifiers,
646 AlterTableAddConstraintBeyondCheck,
647 AlterTableAddConstraintModifiers,
648 AlterTableDropConstraintIfExistsSyntax,
649 AlterTableDropConstraintModifiers,
650 AlterTableValidateBeyondConstraint,
651 AlterTableValidateConstraintModifiers,
652 ShowRelationsModifiers,
653}
654
655impl fmt::Debug for SqlFeatureCode {
656 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
657 fmt_compact_code(f, *self as u16)
658 }
659}
660
661#[repr(u16)]
670#[derive(Clone, Copy, Eq, Hash, PartialEq)]
671pub enum SqlLoweringCode {
672 EntityMismatch,
673 SelectProjectionShape,
674 SelectDistinct,
675 DistinctOrderByProjection,
676 GlobalAggregateProjection,
677 GlobalAggregateGroupBy,
678 SelectGroupByShape,
679 GroupedProjectionExplicitListRequired,
680 GroupedProjectionAggregateRequired,
681 GroupedProjectionNonGroupField,
682 GroupedProjectionScalarAfterAggregate,
683 HavingRequiresGroupBy,
684 SelectHavingShape,
685 AggregateInputExpressions,
686 WhereExpressionShape,
687 ParameterPlacement,
688 SqlDdlExecutionUnsupported,
689}
690
691impl fmt::Debug for SqlLoweringCode {
692 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 fmt_compact_code(f, *self as u16)
694 }
695}
696
697#[repr(u16)]
705#[derive(Clone, Copy, Eq, Hash, PartialEq)]
706pub enum SqlSurfaceMismatchCode {
707 QueryRejectsInsert,
708 QueryRejectsUpdate,
709 QueryRejectsDelete,
710 MutationRejectsSelect,
711 MutationRejectsExplain,
712 MutationRejectsDescribe,
713 MutationRejectsShowIndexes,
714 MutationRejectsShowColumns,
715 MutationRejectsShowEntities,
716 MutationRejectsShowStores,
717 MutationRejectsShowMemory,
718 MutationRequiresExplicitUpdateIntent,
719 MutationRejectsShowConstraints,
720 MutationRejectsShowRelations,
721}
722
723impl fmt::Debug for SqlSurfaceMismatchCode {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 fmt_compact_code(f, *self as u16)
726 }
727}
728
729#[repr(u16)]
737#[derive(Clone, Copy, Eq, Hash, PartialEq)]
738pub enum SqlWriteBoundaryCode {
739 PrimaryKeyLiteralShape,
740 PrimaryKeyLiteralIncompatible,
741 MissingPrimaryKey,
742 MissingRequiredFields,
743 ExplicitManagedField,
744 ExplicitGeneratedField,
745 InsertSelectRequiresScalar,
746 InsertSelectAggregateProjection,
747 InsertSelectWidthMismatch,
748 UpdatePrimaryKeyMutation,
749 InvalidFieldLiteral,
750 UnknownReturningField,
751 DuplicateReturningField,
752 UpdateMissingWherePredicate,
753 WriteOrderByUnsupportedShape,
754 ReturningResponseTooLarge,
755 ReturningRowsTooMany,
756 StagedRowsTooMany,
757 InsertDefaultRequiredField,
758 UpdateDefaultRequiredField,
759 UpdateDefaultDatabaseOwnedField,
760 ExactUpdateAssertionRequired,
761 ExactUpdateAssertionTooHigh,
762 ExactUpdateAffectedRowsExceeded,
763 ExactUpdateWindowUnsupported,
764 ExactUpdateScanBudgetExceeded,
765 ResumableUpdateWindowUnsupported,
766 ResumableUpdateReturningUnsupported,
767 ResumableUpdateRequiresJournaledStore,
768 ResumableUpdateAssignedFieldHasGlobalConstraint,
769 ResumableUpdateScopeDependsOnAssignedField,
770 ResumableUpdateScopeDependencyUnknown,
771 ResumableUpdateContinuationMalformed,
772 ResumableUpdateContinuationTargetMismatch,
773 ResumableUpdateContinuationSchemaMismatch,
774 ResumableUpdateContinuationScopeMismatch,
775 ResumableUpdateContinuationPatchMismatch,
776 ResumableUpdateContinuationBatchPolicyMismatch,
777 ResumableUpdateSingleRowResourceExceeded,
778 ResumableUpdateManagedFieldHasGlobalConstraint,
779 ResumableUpdateContinuationOperationMismatch,
780}
781
782impl fmt::Debug for SqlWriteBoundaryCode {
783 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784 fmt_compact_code(f, *self as u16)
785 }
786}
787
788#[repr(u16)]
796#[derive(Clone, Copy, Eq, Hash, PartialEq)]
797pub enum SchemaDdlAdmissionCode {
798 MissingExpectedSchemaVersion,
799 MissingNextSchemaVersion,
800 StaleExpectedSchemaVersion,
801 InvalidExpectedSchemaVersion,
802 InvalidNextSchemaVersion,
803 AcceptedSchemaChangeWithoutVersionBump,
804 EmptyVersionBump,
805 VersionGap,
806 VersionRollback,
807 FingerprintMethodMismatch,
808 UnsupportedTransitionClass,
809 PhysicalRunnerMissing,
810 ValidationFailed,
811 PublicationRaceLost,
812 InvalidAddColumnDefault,
813 InvalidAlterColumnDefault,
814 GeneratedIndexDropRejected,
815 SchemaRewriteRequiresMigration,
816 SchemaTransitionBudgetExceeded,
817 GeneratedFieldDefaultChangeRejected,
818 GeneratedFieldNullabilityChangeRejected,
819 RowLayoutVersionExhausted,
820}
821
822impl fmt::Debug for SchemaDdlAdmissionCode {
823 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824 fmt_compact_code(f, *self as u16)
825 }
826}
827
828#[repr(u16)]
830#[derive(Clone, Copy, Eq, Hash, PartialEq)]
831pub enum SchemaMigrationCode {
832 Unadopted,
833 MissingMigration,
834 VersionGap,
835 Downgrade,
836 EmptyEntityVersionBump,
837 DuplicateEntityTransition,
838 StaleAcceptedHead,
839 PlanChanged,
840 DuplicateRenameSource,
841 DuplicateRenameTarget,
842 UnknownFromObject,
843 UnknownToObject,
844 KindMismatch,
845 IdentityConflict,
846 IncompleteRenameCoverage,
847 UnexplainedSchemaDifference,
848 UnsupportedTransform,
849 TransformFinding,
850 UniqueIndexFinding,
851 RelationFinding,
852 ConstraintFinding,
853 PhysicalRunnerMissing,
854 MigrationInProgress,
855 AbortTooLate,
856 ProgressCorrupt,
857 CandidateMismatch,
858 PublicationRaceLost,
859}
860
861impl SchemaMigrationCode {
862 #[must_use]
864 pub const fn diagnostic_code(self) -> DiagnosticCode {
865 match self {
866 Self::StaleAcceptedHead
867 | Self::PlanChanged
868 | Self::IdentityConflict
869 | Self::MigrationInProgress
870 | Self::AbortTooLate
871 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
872 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
873 Self::Unadopted
874 | Self::MissingMigration
875 | Self::VersionGap
876 | Self::Downgrade
877 | Self::EmptyEntityVersionBump
878 | Self::DuplicateEntityTransition
879 | Self::DuplicateRenameSource
880 | Self::DuplicateRenameTarget
881 | Self::UnknownFromObject
882 | Self::UnknownToObject
883 | Self::KindMismatch
884 | Self::IncompleteRenameCoverage
885 | Self::UnexplainedSchemaDifference
886 | Self::UnsupportedTransform
887 | Self::TransformFinding
888 | Self::UniqueIndexFinding
889 | Self::RelationFinding
890 | Self::ConstraintFinding
891 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
892 }
893 }
894}
895
896impl fmt::Debug for SchemaMigrationCode {
897 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
898 fmt_compact_code(f, *self as u16)
899 }
900}
901
902#[remain::sorted]
909#[derive(Clone, Copy, Eq, PartialEq)]
910pub enum DiagnosticDetail {
911 QueryKind { kind: QueryErrorKind },
912 QueryProjection { reason: QueryProjectionCode },
913 QueryReadAdmission { reason: QueryReadAdmissionCode },
914 QueryResultShape { reason: QueryResultShapeCode },
915 RuntimeBoundary { boundary: RuntimeBoundaryCode },
916 RuntimeKind { kind: RuntimeErrorKind },
917 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
918 SchemaMigration { reason: SchemaMigrationCode },
919 SqlLowering { reason: SqlLoweringCode },
920 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
921 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
922 UnsupportedSqlFeature { feature: SqlFeatureCode },
923}
924
925impl fmt::Debug for DiagnosticDetail {
926 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
927 fmt_compact_code(
928 f,
929 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
930 )
931 }
932}
933
934#[derive(Clone, Eq, PartialEq)]
941pub struct Diagnostic {
942 code: DiagnosticCode,
943 origin: ErrorOrigin,
944 detail: Option<DiagnosticDetail>,
945}
946
947impl Diagnostic {
948 #[must_use]
950 pub const fn new(
951 code: DiagnosticCode,
952 origin: ErrorOrigin,
953 detail: Option<DiagnosticDetail>,
954 ) -> Self {
955 Self {
956 code,
957 origin,
958 detail,
959 }
960 }
961
962 #[must_use]
964 pub const fn from_code(code: DiagnosticCode) -> Self {
965 Self::new(code, code.origin(), None)
966 }
967
968 #[must_use]
970 pub const fn code(&self) -> DiagnosticCode {
971 self.code
972 }
973
974 #[must_use]
976 pub const fn class(&self) -> ErrorClass {
977 self.code.class()
978 }
979
980 #[must_use]
982 pub const fn origin(&self) -> ErrorOrigin {
983 self.origin
984 }
985
986 #[must_use]
988 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
989 self.detail.as_ref()
990 }
991
992 #[must_use]
994 pub const fn error_code(&self) -> ErrorCode {
995 ErrorCode::from_parts(self.code, self.detail)
996 }
997}
998
999impl fmt::Debug for Diagnostic {
1000 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1001 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
1002 }
1003}
1004
1005fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
1006 write!(f, "{raw}")
1007}
1008
1009#[cfg(test)]
1010mod tests {
1011 use super::{
1012 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
1013 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
1014 SqlWriteBoundaryCode,
1015 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
1016 };
1017
1018 #[test]
1019 fn diagnostic_from_code_uses_default_origin() {
1020 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
1021
1022 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1023 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1024 }
1025
1026 #[test]
1027 fn diagnostic_code_reports_broad_class() {
1028 assert_eq!(
1029 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1030 ErrorClass::Unsupported
1031 );
1032 assert_eq!(
1033 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1034 ErrorClass::Unsupported
1035 );
1036 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1037 assert_eq!(
1038 DiagnosticCode::StoreCorruption.class(),
1039 ErrorClass::Corruption
1040 );
1041 }
1042
1043 #[test]
1044 fn class_and_origin_wire_codes_round_trip() {
1045 for (class, raw) in [
1046 (ErrorClass::Query, 1),
1047 (ErrorClass::Corruption, 2),
1048 (ErrorClass::IncompatiblePersistedFormat, 3),
1049 (ErrorClass::NotFound, 4),
1050 (ErrorClass::Internal, 5),
1051 (ErrorClass::Conflict, 6),
1052 (ErrorClass::Unsupported, 7),
1053 (ErrorClass::InvariantViolation, 8),
1054 ] {
1055 assert_eq!(class.wire_code(), raw);
1056 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1057 assert_eq!(format!("{class:?}"), raw.to_string());
1058 }
1059
1060 for (origin, raw) in [
1061 (ErrorOrigin::Cursor, 1),
1062 (ErrorOrigin::Executor, 2),
1063 (ErrorOrigin::Identity, 3),
1064 (ErrorOrigin::Index, 4),
1065 (ErrorOrigin::Interface, 5),
1066 (ErrorOrigin::Planner, 6),
1067 (ErrorOrigin::Query, 7),
1068 (ErrorOrigin::Recovery, 8),
1069 (ErrorOrigin::Response, 9),
1070 (ErrorOrigin::Runtime, 10),
1071 (ErrorOrigin::Serialize, 11),
1072 (ErrorOrigin::Store, 12),
1073 ] {
1074 assert_eq!(origin.wire_code(), raw);
1075 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1076 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1077 assert_eq!(format!("{origin:?}"), raw.to_string());
1078 }
1079
1080 assert_eq!(ErrorClass::from_wire_code(0), None);
1081 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1082 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1083 }
1084
1085 #[test]
1086 fn public_error_codes_are_sequential() {
1087 let first = ORDERED_ERROR_CODES
1088 .first()
1089 .expect("public error-code registry is non-empty")
1090 .raw();
1091
1092 assert_eq!(first, 1);
1093
1094 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1095 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1096 assert_eq!(code.raw(), expected);
1097 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1098 assert!(code.is_known());
1099 }
1100
1101 let last = ORDERED_ERROR_CODES
1102 .last()
1103 .expect("public error-code registry is non-empty")
1104 .raw();
1105
1106 assert_eq!(last, 283);
1107 }
1108
1109 #[test]
1110 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1111 let first = ORDERED_ERROR_CODES
1112 .first()
1113 .expect("public error-code registry is non-empty")
1114 .raw();
1115 let last = ORDERED_ERROR_CODES
1116 .last()
1117 .expect("public error-code registry is non-empty")
1118 .raw();
1119
1120 for raw in first..=last {
1121 let code = ErrorCode::from_raw(raw);
1122 let diagnostic_code = code.diagnostic_code();
1123 let diagnostic_detail = code.diagnostic_detail();
1124 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1125
1126 assert_eq!(rebuilt.raw(), raw);
1127
1128 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1129
1130 assert_eq!(diagnostic.code(), diagnostic_code);
1131 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1132 assert_eq!(diagnostic.error_code().raw(), raw);
1133 }
1134 }
1135
1136 #[test]
1137 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1138 let first_unknown = ORDERED_ERROR_CODES
1139 .last()
1140 .expect("public error-code registry is non-empty")
1141 .raw()
1142 .checked_add(1)
1143 .expect("public error-code registry retains an unknown successor");
1144
1145 for raw in [0, first_unknown, u16::MAX] {
1146 let code = ErrorCode::from_raw(raw);
1147
1148 assert_eq!(ErrorCode::known(raw), None);
1149 assert!(!code.is_known());
1150 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1151 assert_eq!(code.diagnostic_detail(), None);
1152 assert_eq!(code.class(), ErrorClass::Internal);
1153
1154 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1155
1156 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1157 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1158 assert_eq!(diagnostic.detail(), None);
1159 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1160 }
1161 }
1162
1163 #[test]
1164 fn from_parts_requires_detail_to_match_broad_code() {
1165 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1166 feature: SqlFeatureCode::Join,
1167 });
1168
1169 assert_eq!(
1170 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1171 ErrorCode::SQL_FEATURE_JOIN
1172 );
1173 assert_eq!(
1174 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1175 ErrorCode::QUERY_PLAN
1176 );
1177 }
1178
1179 #[test]
1180 fn detail_bearing_registry_entries_round_trip_directly() {
1181 assert!(!DETAIL_ERROR_CODES.is_empty());
1182
1183 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1184 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1185 assert_eq!(code.diagnostic_code(), diagnostic_code);
1186 assert_eq!(code.diagnostic_detail(), Some(detail));
1187 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1188 }
1189 }
1190
1191 #[test]
1192 fn diagnostic_detail_reports_generated_broad_code() {
1193 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1194 feature: SqlFeatureCode::Join,
1195 };
1196
1197 assert_eq!(
1198 detail.diagnostic_code(),
1199 DiagnosticCode::QueryUnsupportedSqlFeature
1200 );
1201 assert_eq!(format!("{detail:?}"), "65");
1202 }
1203
1204 #[test]
1205 fn public_error_codes_reconstruct_shifted_details() {
1206 assert_eq!(
1207 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1208 DiagnosticCode::QueryUnknownAggregateTargetField
1209 );
1210 assert_eq!(
1211 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1212 Some(DiagnosticDetail::UnsupportedSqlFeature {
1213 feature: SqlFeatureCode::Join,
1214 })
1215 );
1216 assert_eq!(
1217 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1218 Some(DiagnosticDetail::QueryProjection {
1219 reason: QueryProjectionCode::NumericLiteralRequired,
1220 })
1221 );
1222 assert_eq!(
1223 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1224 Some(DiagnosticDetail::QueryReadAdmission {
1225 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1226 })
1227 );
1228 assert_eq!(
1229 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1230 Some(DiagnosticDetail::SqlLowering {
1231 reason: SqlLoweringCode::DistinctOrderByProjection,
1232 })
1233 );
1234 assert_eq!(
1235 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1236 Some(DiagnosticDetail::SqlWriteBoundary {
1237 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1238 })
1239 );
1240 assert_eq!(
1241 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1242 Some(DiagnosticDetail::SqlWriteBoundary {
1243 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1244 })
1245 );
1246 }
1247}