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