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 QueryExactCountMetadataUnavailable,
42 QueryIntent,
43 QueryInvalidContinuationCursor,
44 QueryNotFound,
45 QueryNotUnique,
46 QueryNumericNotRepresentable,
47 QueryNumericOverflow,
48 QueryPlan,
49 QueryReadAdmission,
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::QueryExactCountMetadataUnavailable
82 | Self::QueryUnsupportedSqlFeature
83 | Self::QueryUnknownAggregateTargetField
84 | Self::QueryUnsupportedProjection
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::QueryUnorderedPagination
97 | Self::QueryInvalidContinuationCursor
98 | Self::QueryNotUnique
99 | Self::QueryNumericOverflow
100 | Self::QueryNumericNotRepresentable
101 | Self::SchemaDdlAdmission => ErrorClass::Query,
102 }
103 }
104
105 #[must_use]
107 pub const fn origin(self) -> ErrorOrigin {
108 match self {
109 Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
110 ErrorOrigin::Store
111 }
112 Self::RuntimeCorruption
113 | Self::RuntimeIncompatiblePersistedFormat
114 | Self::RuntimeInvariantViolation
115 | Self::RuntimeConflict
116 | Self::RuntimeNotFound
117 | Self::RuntimeUnsupported
118 | Self::RuntimeInternal => ErrorOrigin::Runtime,
119 Self::QueryExactCountMetadataUnavailable
120 | Self::QueryValidate
121 | Self::QueryIntent
122 | Self::QueryPlan
123 | Self::QueryReadAdmission
124 | Self::QueryUnorderedPagination
125 | Self::QueryInvalidContinuationCursor
126 | Self::QueryNotFound
127 | Self::QueryNotUnique
128 | Self::QueryNumericOverflow
129 | Self::QueryNumericNotRepresentable
130 | Self::QueryUnknownAggregateTargetField
131 | Self::QueryUnsupportedProjection
132 | Self::QueryUnsupportedSqlFeature
133 | Self::QuerySqlSurfaceMismatch
134 | Self::QuerySqlWriteBoundary
135 | Self::SchemaDdlAdmission => ErrorOrigin::Query,
136 }
137 }
138
139 #[must_use]
141 pub const fn error_code(self) -> ErrorCode {
142 match self {
143 Self::QueryExactCountMetadataUnavailable => {
144 ErrorCode::QUERY_EXACT_COUNT_METADATA_UNAVAILABLE
145 }
146 Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
147 Self::QueryIntent => ErrorCode::QUERY_INTENT,
148 Self::QueryPlan => ErrorCode::QUERY_PLAN,
149 Self::QueryReadAdmission => ErrorCode::QUERY_READ_ADMISSION,
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::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
161 Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
162 Self::QuerySqlWriteBoundary => ErrorCode::QUERY_SQL_WRITE_BOUNDARY,
163 Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
164 Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
165 Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
166 Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
167 Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
168 Self::RuntimeIncompatiblePersistedFormat => {
169 ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
170 }
171 Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
172 Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
173 Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
174 Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
175 Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
176 }
177 }
178}
179
180impl fmt::Debug for DiagnosticCode {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 fmt_compact_code(f, self.error_code().raw())
183 }
184}
185
186#[derive(Clone, Copy, Eq, Hash, PartialEq)]
198pub struct ErrorCode(u16);
199
200mod registry;
201
202impl ErrorCode {
203 #[must_use]
205 pub const fn from_raw(raw: u16) -> Self {
206 Self(raw)
207 }
208
209 #[must_use]
211 pub const fn raw(self) -> u16 {
212 self.0
213 }
214}
215
216impl fmt::Debug for ErrorCode {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 fmt_compact_code(f, self.raw())
219 }
220}
221
222#[remain::sorted]
229#[derive(Clone, Copy, Eq, Hash, PartialEq)]
230pub enum ErrorClass {
231 Conflict,
232 Corruption,
233 IncompatiblePersistedFormat,
234 Internal,
235 InvariantViolation,
236 NotFound,
237 Query,
238 Unsupported,
239}
240
241impl ErrorClass {
242 #[must_use]
244 pub const fn wire_code(self) -> u8 {
245 match self {
246 Self::Query => 1,
247 Self::Corruption => 2,
248 Self::IncompatiblePersistedFormat => 3,
249 Self::NotFound => 4,
250 Self::Internal => 5,
251 Self::Conflict => 6,
252 Self::Unsupported => 7,
253 Self::InvariantViolation => 8,
254 }
255 }
256
257 #[must_use]
259 pub const fn from_wire_code(code: u8) -> Option<Self> {
260 match code {
261 1 => Some(Self::Query),
262 2 => Some(Self::Corruption),
263 3 => Some(Self::IncompatiblePersistedFormat),
264 4 => Some(Self::NotFound),
265 5 => Some(Self::Internal),
266 6 => Some(Self::Conflict),
267 7 => Some(Self::Unsupported),
268 8 => Some(Self::InvariantViolation),
269 _ => None,
270 }
271 }
272}
273
274impl fmt::Debug for ErrorClass {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 fmt_compact_code(f, u16::from(self.wire_code()))
277 }
278}
279
280#[remain::sorted]
287#[derive(Clone, Copy, Eq, Hash, PartialEq)]
288pub enum ErrorOrigin {
289 Cursor,
290 Executor,
291 Identity,
292 Index,
293 Interface,
294 Planner,
295 Query,
296 Recovery,
297 Response,
298 Runtime,
299 Serialize,
300 Store,
301}
302
303impl ErrorOrigin {
304 #[must_use]
306 pub const fn wire_code(self) -> u8 {
307 match self {
308 Self::Cursor => 1,
309 Self::Executor => 2,
310 Self::Identity => 3,
311 Self::Index => 4,
312 Self::Interface => 5,
313 Self::Planner => 6,
314 Self::Query => 7,
315 Self::Recovery => 8,
316 Self::Response => 9,
317 Self::Runtime => 10,
318 Self::Serialize => 11,
319 Self::Store => 12,
320 }
321 }
322
323 #[must_use]
325 pub const fn from_known_wire_code(code: u8) -> Option<Self> {
326 match code {
327 1 => Some(Self::Cursor),
328 2 => Some(Self::Executor),
329 3 => Some(Self::Identity),
330 4 => Some(Self::Index),
331 5 => Some(Self::Interface),
332 6 => Some(Self::Planner),
333 7 => Some(Self::Query),
334 8 => Some(Self::Recovery),
335 9 => Some(Self::Response),
336 10 => Some(Self::Runtime),
337 11 => Some(Self::Serialize),
338 12 => Some(Self::Store),
339 _ => None,
340 }
341 }
342
343 #[must_use]
348 pub const fn from_wire_code(code: u8) -> Self {
349 match Self::from_known_wire_code(code) {
350 Some(origin) => origin,
351 None => Self::Runtime,
352 }
353 }
354}
355
356impl fmt::Debug for ErrorOrigin {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 fmt_compact_code(f, u16::from(self.wire_code()))
359 }
360}
361
362#[repr(u16)]
369#[derive(Clone, Copy, Eq, Hash, PartialEq)]
370pub enum QueryErrorKind {
371 Validate,
372 Intent,
373 Plan,
374 UnorderedPagination,
375 InvalidContinuationCursor,
376 NotFound,
377 NotUnique,
378}
379
380impl fmt::Debug for QueryErrorKind {
381 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
382 fmt_compact_code(f, *self as u16)
383 }
384}
385
386#[repr(u16)]
394#[derive(Clone, Copy, Eq, Hash, PartialEq)]
395pub enum QueryProjectionCode {
396 NumericLiteralRequired,
397 NumericScaleArguments,
398 NestedFieldPathPreview,
399 CaseConditionBooleanRequired,
400 NumericInputRequired,
401 TextOrBlobInputRequired,
402 TextInputRequired,
403 TextOrNullArgumentRequired,
404 IntegerOrNullArgumentRequired,
405 UnaryOperandIncompatible,
406 BinaryOperandsIncompatible,
407}
408
409impl fmt::Debug for QueryProjectionCode {
410 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411 fmt_compact_code(f, *self as u16)
412 }
413}
414
415#[repr(u16)]
423#[derive(Clone, Copy, Eq, Hash, PartialEq)]
424pub enum QueryReadAdmissionCode {
425 PublicQueryRequiresLimit,
426 PublicQueryRequiresIndex,
427 UnboundedFullScanRejected,
428 SortRequiresMaterialization,
429 GroupedQueryRequiresLimits,
430 GroupedQueryExceedsBudget,
431 DiagnosticLaneDoesNotExecute,
432 ReturnedRowBoundExceedsPolicy,
433 PrimaryKeyInputExceedsPolicy,
434 InputDepthExceeded,
436 InputNodesExceeded,
438 InputBytesExceeded,
440 ExplainDoesNotAcceptCursor,
442}
443
444impl fmt::Debug for QueryReadAdmissionCode {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 fmt_compact_code(f, *self as u16)
447 }
448}
449
450#[repr(u16)]
457#[derive(Clone, Copy, Eq, Hash, PartialEq)]
458pub enum RuntimeErrorKind {
459 Corruption,
460 IncompatiblePersistedFormat,
461 InvariantViolation,
462 Conflict,
463 NotFound,
464 Unsupported,
465 Internal,
466}
467
468impl fmt::Debug for RuntimeErrorKind {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 fmt_compact_code(f, *self as u16)
471 }
472}
473
474#[repr(u16)]
482#[derive(Clone, Copy, Eq, Hash, PartialEq)]
483pub enum RuntimeBoundaryCode {
484 SqlSurfaceControllerRequired,
485 SchemaSurfaceControllerRequired,
486 SqlQueryNoConfiguredEntities,
487 SqlQueryEntityNotFound,
488 SqlDdlTargetRequired,
489 SqlDdlEntityNotConfigured,
490 SqlIntrospectionDisabled,
491 MutationRequiredFieldMissing,
493 MutationManagedTimestampRegression,
495 PersistedRowLayoutOutsideAcceptedWindow,
497 PersistedRowSlotCountMismatch,
499 GeneratedFieldAfterDdlField,
501 JournalMutationRevisionExhausted,
503 ConstraintViolation,
505 AcceptedRowConstraintProgramCorrupt,
507 ConstraintActivationWriteBlocked,
509 GeneratedConstraintActivationStale,
511 MutationDatabaseOwnedFieldExplicit,
513 MutationBatchEmpty,
515 MutationBatchTooManyItems,
517 MutationBatchStagedBytesExceeded,
519 MutationBatchResultBytesExceeded,
521 MutationBatchStoreMismatch,
523 MutationBatchTooManyEntities,
525 MutationBatchDuplicateKey,
527 OperationalSurfaceControllerRequired,
529 ExactKeyBatchTooManyItems,
531 ExactKeyBatchInputBytesExceeded,
533 ExactKeyBatchStoredBytesExceeded,
535 ExactKeyBatchResultBytesExceeded,
537 ExecutionBudgetExceeded,
539 PageUnitTooLarge,
541 RequestExecutionScopeRequired,
543 RequestExecutionRootMismatch,
545 SqlQueryReplyBytesExceeded,
547 QueryExplainOutputExceeded,
548 QueryExplainDepthExceeded,
550 DatabaseStartupRecoveryPending,
552 SqlSurfacePolicyDenied,
554 SchemaSurfacePolicyDenied,
556 MutationBatchCommitWorkExceeded,
558 ConvergenceBacklogPressure,
560 MemoryBucketSizeMismatch,
562}
563
564impl fmt::Debug for RuntimeBoundaryCode {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 fmt_compact_code(f, *self as u16)
567 }
568}
569
570#[repr(u16)]
578#[derive(Clone, Copy, Eq, Hash, PartialEq)]
579pub enum SqlFeatureCode {
580 AggregateFilterClause,
581 AlterStatementBeyondAlterTable,
582 AlterTableAddColumnDuplicateDefault,
583 AlterTableAddColumnModifiers,
584 AlterTableAddStatementBeyondAddColumn,
585 AlterTableAlterColumnDropUnsupportedAction,
586 AlterTableAlterColumnModifiers,
587 AlterTableAlterColumnSetUnsupportedAction,
588 AlterTableAlterColumnUnsupportedAction,
589 AlterTableAlterStatementBeyondAlterColumn,
590 AlterTableDropColumnIfExistsSyntax,
591 AlterTableDropColumnModifiers,
592 AlterTableDropStatementBeyondDropColumn,
593 AlterTableRenameColumnMissingTo,
594 AlterTableRenameColumnModifiers,
595 AlterTableRenameStatementBeyondRenameColumn,
596 AlterTableUnsupportedOperation,
597 ColumnAlias,
598 CreateIndexIfNotExistsSyntax,
599 CreateIndexKeyOrderingModifiers,
600 CreateIndexModifiers,
601 CreateStatementBeyondCreateIndex,
602 DescribeModifier,
603 DdlSchemaVersionDuplicateExpectedClause,
604 DdlSchemaVersionDuplicateSetClause,
605 DropIndexModifiers,
606 DropIndexIfExistsSyntax,
607 DropStatementBeyondDropIndex,
608 ExpressionIndexUnsupportedFunction,
609 Having,
610 Insert,
611 Join,
612 LikePatternBeyondTrailingPrefix,
613 LowerFieldPredicateUnsupported,
614 MultiStatementSql,
615 NestedAggregateInput,
616 NestedProjectionFunctionInArithmetic,
617 OrderByUnsupportedForm,
618 Other,
619 PredicateStartsWithFirstArgument,
620 QuotedIdentifiers,
621 ReturningUnsupportedShape,
622 ScalarFunctionExpressionPosition,
623 ScaleTakingNumericFunctionExpressionPosition,
624 ShowColumnsModifiers,
625 ShowEntitiesModifiers,
626 ShowIndexesModifiers,
627 ShowMemoryModifiers,
628 ShowStoresModifiers,
629 ShowUnsupportedCommand,
630 SimpleCaseExpression,
631 StandaloneLiteralProjectionItem,
632 UnionIntersectExcept,
633 UnsupportedFunctionNamespace,
634 Update,
635 UpperFieldPredicateUnsupported,
636 WindowFunction,
637 With,
638 NumericScaleFunctionArguments,
639 OrderByFieldNotOrderable,
640 ShowConstraintsModifiers,
641 AlterTableAddConstraintBeyondCheck,
642 AlterTableAddConstraintModifiers,
643 AlterTableDropConstraintIfExistsSyntax,
644 AlterTableDropConstraintModifiers,
645 AlterTableValidateBeyondConstraint,
646 AlterTableValidateConstraintModifiers,
647 ShowRelationsModifiers,
648}
649
650impl fmt::Debug for SqlFeatureCode {
651 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
652 fmt_compact_code(f, *self as u16)
653 }
654}
655
656#[repr(u16)]
665#[derive(Clone, Copy, Eq, Hash, PartialEq)]
666pub enum SqlLoweringCode {
667 EntityMismatch,
668 SelectProjectionShape,
669 SelectDistinct,
670 DistinctOrderByProjection,
671 GlobalAggregateProjection,
672 GlobalAggregateGroupBy,
673 SelectGroupByShape,
674 GroupedProjectionExplicitListRequired,
675 GroupedProjectionAggregateRequired,
676 GroupedProjectionNonGroupField,
677 GroupedProjectionScalarAfterAggregate,
678 HavingRequiresGroupBy,
679 SelectHavingShape,
680 AggregateInputExpressions,
681 WhereExpressionShape,
682 ParameterPlacement,
683 SqlDdlExecutionUnsupported,
684 BindingCount,
685 BindingFamily,
686 BindingLimit,
687}
688
689impl fmt::Debug for SqlLoweringCode {
690 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
691 fmt_compact_code(f, *self as u16)
692 }
693}
694
695#[repr(u16)]
703#[derive(Clone, Copy, Eq, Hash, PartialEq)]
704pub enum SqlSurfaceMismatchCode {
705 QueryRejectsInsert,
706 QueryRejectsUpdate,
707 QueryRejectsDelete,
708 MutationRejectsSelect,
709 MutationRejectsExplain,
710 MutationRejectsDescribe,
711 MutationRejectsShowIndexes,
712 MutationRejectsShowColumns,
713 MutationRejectsShowEntities,
714 MutationRejectsShowStores,
715 MutationRejectsShowMemory,
716 MutationRequiresExplicitUpdateIntent,
717 MutationRejectsShowConstraints,
718 MutationRejectsShowRelations,
719}
720
721impl fmt::Debug for SqlSurfaceMismatchCode {
722 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
723 fmt_compact_code(f, *self as u16)
724 }
725}
726
727#[repr(u16)]
735#[derive(Clone, Copy, Eq, Hash, PartialEq)]
736pub enum SqlWriteBoundaryCode {
737 PrimaryKeyLiteralIncompatible,
738 MissingPrimaryKey,
739 MissingRequiredFields,
740 ExplicitManagedField,
741 ExplicitGeneratedField,
742 InsertSelectRequiresScalar,
743 InsertSelectAggregateProjection,
744 InsertSelectWidthMismatch,
745 UpdatePrimaryKeyMutation,
746 InvalidFieldLiteral,
747 UnknownReturningField,
748 DuplicateReturningField,
749 UpdateMissingWherePredicate,
750 WriteOrderByUnsupportedShape,
751 ReturningResponseTooLarge,
752 ReturningRowsTooMany,
753 StagedRowsTooMany,
754 InsertDefaultRequiredField,
755 UpdateDefaultRequiredField,
756 UpdateDefaultDatabaseOwnedField,
757 ExactUpdateAssertionRequired,
758 ExactUpdateAssertionTooHigh,
759 ExactUpdateAffectedRowsExceeded,
760 ExactUpdateWindowUnsupported,
761 ExactUpdateScanBudgetExceeded,
762 ResumableUpdateWindowUnsupported,
763 ResumableUpdateReturningUnsupported,
764 ResumableUpdateRequiresJournaledStore,
765 ResumableUpdateAssignedFieldHasGlobalConstraint,
766 ResumableUpdateScopeDependsOnAssignedField,
767 ResumableUpdateScopeDependencyUnknown,
768 ResumableUpdateContinuationMalformed,
769 ResumableUpdateContinuationTargetMismatch,
770 ResumableUpdateContinuationSchemaMismatch,
771 ResumableUpdateContinuationScopeMismatch,
772 ResumableUpdateContinuationPatchMismatch,
773 ResumableUpdateContinuationBatchPolicyMismatch,
774 ResumableUpdateManagedFieldHasGlobalConstraint,
775}
776
777impl fmt::Debug for SqlWriteBoundaryCode {
778 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
779 fmt_compact_code(f, *self as u16)
780 }
781}
782
783#[repr(u16)]
791#[derive(Clone, Copy, Eq, Hash, PartialEq)]
792pub enum SchemaDdlAdmissionCode {
793 MissingExpectedSchemaVersion,
794 MissingNextSchemaVersion,
795 StaleExpectedSchemaVersion,
796 InvalidExpectedSchemaVersion,
797 InvalidNextSchemaVersion,
798 AcceptedSchemaChangeWithoutVersionBump,
799 EmptyVersionBump,
800 VersionGap,
801 VersionRollback,
802 FingerprintMethodMismatch,
803 UnsupportedTransitionClass,
804 PhysicalRunnerMissing,
805 ValidationFailed,
806 PublicationRaceLost,
807 InvalidAddColumnDefault,
808 InvalidAlterColumnDefault,
809 GeneratedIndexDropRejected,
810 SchemaRewriteRequiresMigration,
811 SchemaTransitionBudgetExceeded,
812 GeneratedFieldDefaultChangeRejected,
813 GeneratedFieldNullabilityChangeRejected,
814 RowLayoutVersionExhausted,
815}
816
817impl fmt::Debug for SchemaDdlAdmissionCode {
818 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
819 fmt_compact_code(f, *self as u16)
820 }
821}
822
823#[repr(u16)]
825#[derive(Clone, Copy, Eq, Hash, PartialEq)]
826pub enum SchemaMigrationCode {
827 Unadopted,
828 MissingMigration,
829 VersionGap,
830 Downgrade,
831 EmptyEntityVersionBump,
832 StaleAcceptedHead,
833 PlanChanged,
834 UnknownFromObject,
835 UnknownToObject,
836 KindMismatch,
837 IdentityConflict,
838 UnexplainedSchemaDifference,
839 UnsupportedTransform,
840 PhysicalRunnerMissing,
841 MigrationInProgress,
842 AbortTooLate,
843 ProgressCorrupt,
844 CandidateMismatch,
845 PublicationRaceLost,
846}
847
848impl SchemaMigrationCode {
849 #[must_use]
851 pub const fn diagnostic_code(self) -> DiagnosticCode {
852 match self {
853 Self::StaleAcceptedHead
854 | Self::PlanChanged
855 | Self::IdentityConflict
856 | Self::MigrationInProgress
857 | Self::AbortTooLate
858 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
859 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
860 Self::Unadopted
861 | Self::MissingMigration
862 | Self::VersionGap
863 | Self::Downgrade
864 | Self::EmptyEntityVersionBump
865 | Self::UnknownFromObject
866 | Self::UnknownToObject
867 | Self::KindMismatch
868 | Self::UnexplainedSchemaDifference
869 | Self::UnsupportedTransform
870 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
871 }
872 }
873}
874
875impl fmt::Debug for SchemaMigrationCode {
876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877 fmt_compact_code(f, *self as u16)
878 }
879}
880
881#[remain::sorted]
888#[derive(Clone, Copy, Eq, PartialEq)]
889pub enum DiagnosticDetail {
890 QueryKind { kind: QueryErrorKind },
891 QueryProjection { reason: QueryProjectionCode },
892 QueryReadAdmission { reason: QueryReadAdmissionCode },
893 RuntimeBoundary { boundary: RuntimeBoundaryCode },
894 RuntimeKind { kind: RuntimeErrorKind },
895 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
896 SchemaMigration { reason: SchemaMigrationCode },
897 SqlLowering { reason: SqlLoweringCode },
898 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
899 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
900 UnsupportedSqlFeature { feature: SqlFeatureCode },
901}
902
903impl fmt::Debug for DiagnosticDetail {
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905 fmt_compact_code(
906 f,
907 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
908 )
909 }
910}
911
912#[derive(Clone, Eq, PartialEq)]
919pub struct Diagnostic {
920 code: DiagnosticCode,
921 origin: ErrorOrigin,
922 detail: Option<DiagnosticDetail>,
923}
924
925impl Diagnostic {
926 #[must_use]
928 pub const fn new(
929 code: DiagnosticCode,
930 origin: ErrorOrigin,
931 detail: Option<DiagnosticDetail>,
932 ) -> Self {
933 Self {
934 code,
935 origin,
936 detail,
937 }
938 }
939
940 #[must_use]
942 pub const fn from_code(code: DiagnosticCode) -> Self {
943 Self::new(code, code.origin(), None)
944 }
945
946 #[must_use]
948 pub const fn code(&self) -> DiagnosticCode {
949 self.code
950 }
951
952 #[must_use]
954 pub const fn class(&self) -> ErrorClass {
955 self.code.class()
956 }
957
958 #[must_use]
960 pub const fn origin(&self) -> ErrorOrigin {
961 self.origin
962 }
963
964 #[must_use]
966 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
967 self.detail.as_ref()
968 }
969
970 #[must_use]
972 pub const fn error_code(&self) -> ErrorCode {
973 ErrorCode::from_parts(self.code, self.detail)
974 }
975}
976
977impl fmt::Debug for Diagnostic {
978 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
979 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
980 }
981}
982
983fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
984 write!(f, "{raw}")
985}
986
987#[cfg(test)]
988mod tests {
989 use super::{
990 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
991 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
992 SqlWriteBoundaryCode,
993 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
994 };
995
996 #[test]
997 fn diagnostic_from_code_uses_default_origin() {
998 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
999
1000 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1001 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1002 }
1003
1004 #[test]
1005 fn diagnostic_code_reports_broad_class() {
1006 assert_eq!(
1007 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1008 ErrorClass::Unsupported
1009 );
1010 assert_eq!(
1011 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1012 ErrorClass::Unsupported
1013 );
1014 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1015 assert_eq!(
1016 DiagnosticCode::StoreCorruption.class(),
1017 ErrorClass::Corruption
1018 );
1019 }
1020
1021 #[test]
1022 fn class_and_origin_wire_codes_round_trip() {
1023 for (class, raw) in [
1024 (ErrorClass::Query, 1),
1025 (ErrorClass::Corruption, 2),
1026 (ErrorClass::IncompatiblePersistedFormat, 3),
1027 (ErrorClass::NotFound, 4),
1028 (ErrorClass::Internal, 5),
1029 (ErrorClass::Conflict, 6),
1030 (ErrorClass::Unsupported, 7),
1031 (ErrorClass::InvariantViolation, 8),
1032 ] {
1033 assert_eq!(class.wire_code(), raw);
1034 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1035 assert_eq!(format!("{class:?}"), raw.to_string());
1036 }
1037
1038 for (origin, raw) in [
1039 (ErrorOrigin::Cursor, 1),
1040 (ErrorOrigin::Executor, 2),
1041 (ErrorOrigin::Identity, 3),
1042 (ErrorOrigin::Index, 4),
1043 (ErrorOrigin::Interface, 5),
1044 (ErrorOrigin::Planner, 6),
1045 (ErrorOrigin::Query, 7),
1046 (ErrorOrigin::Recovery, 8),
1047 (ErrorOrigin::Response, 9),
1048 (ErrorOrigin::Runtime, 10),
1049 (ErrorOrigin::Serialize, 11),
1050 (ErrorOrigin::Store, 12),
1051 ] {
1052 assert_eq!(origin.wire_code(), raw);
1053 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1054 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1055 assert_eq!(format!("{origin:?}"), raw.to_string());
1056 }
1057
1058 assert_eq!(ErrorClass::from_wire_code(0), None);
1059 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1060 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1061 }
1062
1063 #[test]
1064 fn public_error_codes_are_sequential() {
1065 let first = ORDERED_ERROR_CODES
1066 .first()
1067 .expect("public error-code registry is non-empty")
1068 .raw();
1069
1070 assert_eq!(first, 1);
1071
1072 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1073 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1074 assert_eq!(code.raw(), expected);
1075 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1076 assert!(code.is_known());
1077 }
1078
1079 let last = ORDERED_ERROR_CODES
1080 .last()
1081 .expect("public error-code registry is non-empty")
1082 .raw();
1083
1084 assert_eq!(last, 275);
1085 }
1086
1087 #[test]
1088 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1089 let first = ORDERED_ERROR_CODES
1090 .first()
1091 .expect("public error-code registry is non-empty")
1092 .raw();
1093 let last = ORDERED_ERROR_CODES
1094 .last()
1095 .expect("public error-code registry is non-empty")
1096 .raw();
1097
1098 for raw in first..=last {
1099 let code = ErrorCode::from_raw(raw);
1100 let diagnostic_code = code.diagnostic_code();
1101 let diagnostic_detail = code.diagnostic_detail();
1102 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1103
1104 assert_eq!(rebuilt.raw(), raw);
1105
1106 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1107
1108 assert_eq!(diagnostic.code(), diagnostic_code);
1109 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1110 assert_eq!(diagnostic.error_code().raw(), raw);
1111 }
1112 }
1113
1114 #[test]
1115 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1116 let first_unknown = ORDERED_ERROR_CODES
1117 .last()
1118 .expect("public error-code registry is non-empty")
1119 .raw()
1120 .checked_add(1)
1121 .expect("public error-code registry retains an unknown successor");
1122
1123 for raw in [0, first_unknown, u16::MAX] {
1124 let code = ErrorCode::from_raw(raw);
1125
1126 assert_eq!(ErrorCode::known(raw), None);
1127 assert!(!code.is_known());
1128 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1129 assert_eq!(code.diagnostic_detail(), None);
1130 assert_eq!(code.class(), ErrorClass::Internal);
1131
1132 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1133
1134 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1135 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1136 assert_eq!(diagnostic.detail(), None);
1137 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1138 }
1139 }
1140
1141 #[test]
1142 fn from_parts_requires_detail_to_match_broad_code() {
1143 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1144 feature: SqlFeatureCode::Join,
1145 });
1146
1147 assert_eq!(
1148 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1149 ErrorCode::SQL_FEATURE_JOIN
1150 );
1151 assert_eq!(
1152 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1153 ErrorCode::QUERY_PLAN
1154 );
1155 }
1156
1157 #[test]
1158 fn detail_bearing_registry_entries_round_trip_directly() {
1159 assert!(!DETAIL_ERROR_CODES.is_empty());
1160
1161 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1162 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1163 assert_eq!(code.diagnostic_code(), diagnostic_code);
1164 assert_eq!(code.diagnostic_detail(), Some(detail));
1165 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1166 }
1167 }
1168
1169 #[test]
1170 fn diagnostic_detail_reports_generated_broad_code() {
1171 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1172 feature: SqlFeatureCode::Join,
1173 };
1174
1175 assert_eq!(
1176 detail.diagnostic_code(),
1177 DiagnosticCode::QueryUnsupportedSqlFeature
1178 );
1179 assert_eq!(format!("{detail:?}"), "61");
1180 }
1181
1182 #[test]
1183 fn public_error_codes_reconstruct_shifted_details() {
1184 assert_eq!(
1185 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1186 DiagnosticCode::QueryUnknownAggregateTargetField
1187 );
1188 assert_eq!(
1189 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1190 Some(DiagnosticDetail::UnsupportedSqlFeature {
1191 feature: SqlFeatureCode::Join,
1192 })
1193 );
1194 assert_eq!(
1195 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1196 Some(DiagnosticDetail::QueryProjection {
1197 reason: QueryProjectionCode::NumericLiteralRequired,
1198 })
1199 );
1200 assert_eq!(
1201 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1202 Some(DiagnosticDetail::QueryReadAdmission {
1203 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1204 })
1205 );
1206 assert_eq!(
1207 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1208 Some(DiagnosticDetail::SqlLowering {
1209 reason: SqlLoweringCode::DistinctOrderByProjection,
1210 })
1211 );
1212 assert_eq!(
1213 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1214 Some(DiagnosticDetail::SqlWriteBoundary {
1215 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1216 })
1217 );
1218 assert_eq!(
1219 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1220 Some(DiagnosticDetail::SqlWriteBoundary {
1221 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1222 })
1223 );
1224 }
1225}