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