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 QueryIntent,
41 QueryInvalidContinuationCursor,
42 QueryNotFound,
43 QueryNotUnique,
44 QueryNumericNotRepresentable,
45 QueryNumericOverflow,
46 QueryPlan,
47 QueryReadAdmission,
48 QuerySqlSurfaceMismatch,
49 QuerySqlWriteBoundary,
50 QueryUnknownAggregateTargetField,
51 QueryUnorderedPagination,
52 QueryUnsupportedProjection,
53 QueryUnsupportedSqlFeature,
54 QueryValidate,
55 RuntimeConflict,
56 RuntimeCorruption,
57 RuntimeIncompatiblePersistedFormat,
58 RuntimeInternal,
59 RuntimeInvariantViolation,
60 RuntimeNotFound,
61 RuntimeUnsupported,
62 SchemaDdlAdmission,
63 StoreCorruption,
64 StoreInvariantViolation,
65 StoreNotFound,
66}
67
68impl DiagnosticCode {
69 #[must_use]
71 pub const fn class(self) -> ErrorClass {
72 match self {
73 Self::StoreCorruption | Self::RuntimeCorruption => ErrorClass::Corruption,
74 Self::RuntimeIncompatiblePersistedFormat => ErrorClass::IncompatiblePersistedFormat,
75 Self::QueryNotFound | Self::StoreNotFound | Self::RuntimeNotFound => {
76 ErrorClass::NotFound
77 }
78 Self::RuntimeConflict => ErrorClass::Conflict,
79 Self::QueryUnsupportedSqlFeature
80 | Self::QueryUnknownAggregateTargetField
81 | Self::QueryUnsupportedProjection
82 | Self::QuerySqlSurfaceMismatch
83 | Self::QuerySqlWriteBoundary
84 | Self::RuntimeUnsupported => ErrorClass::Unsupported,
85 Self::StoreInvariantViolation | Self::RuntimeInvariantViolation => {
86 ErrorClass::InvariantViolation
87 }
88 Self::RuntimeInternal => ErrorClass::Internal,
89 Self::QueryValidate
90 | Self::QueryIntent
91 | Self::QueryPlan
92 | Self::QueryReadAdmission
93 | Self::QueryUnorderedPagination
94 | Self::QueryInvalidContinuationCursor
95 | Self::QueryNotUnique
96 | Self::QueryNumericOverflow
97 | Self::QueryNumericNotRepresentable
98 | Self::SchemaDdlAdmission => ErrorClass::Query,
99 }
100 }
101
102 #[must_use]
104 pub const fn origin(self) -> ErrorOrigin {
105 match self {
106 Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
107 ErrorOrigin::Store
108 }
109 Self::RuntimeCorruption
110 | Self::RuntimeIncompatiblePersistedFormat
111 | Self::RuntimeInvariantViolation
112 | Self::RuntimeConflict
113 | Self::RuntimeNotFound
114 | Self::RuntimeUnsupported
115 | Self::RuntimeInternal => ErrorOrigin::Runtime,
116 Self::QueryValidate
117 | Self::QueryIntent
118 | Self::QueryPlan
119 | Self::QueryReadAdmission
120 | Self::QueryUnorderedPagination
121 | Self::QueryInvalidContinuationCursor
122 | Self::QueryNotFound
123 | Self::QueryNotUnique
124 | Self::QueryNumericOverflow
125 | Self::QueryNumericNotRepresentable
126 | Self::QueryUnknownAggregateTargetField
127 | Self::QueryUnsupportedProjection
128 | Self::QueryUnsupportedSqlFeature
129 | Self::QuerySqlSurfaceMismatch
130 | Self::QuerySqlWriteBoundary
131 | Self::SchemaDdlAdmission => ErrorOrigin::Query,
132 }
133 }
134
135 #[must_use]
137 pub const fn error_code(self) -> ErrorCode {
138 match self {
139 Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
140 Self::QueryIntent => ErrorCode::QUERY_INTENT,
141 Self::QueryPlan => ErrorCode::QUERY_PLAN,
142 Self::QueryReadAdmission => ErrorCode::QUERY_READ_ADMISSION,
143 Self::QueryUnorderedPagination => ErrorCode::QUERY_UNORDERED_PAGINATION,
144 Self::QueryInvalidContinuationCursor => ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
145 Self::QueryNotFound => ErrorCode::QUERY_NOT_FOUND,
146 Self::QueryNotUnique => ErrorCode::QUERY_NOT_UNIQUE,
147 Self::QueryNumericOverflow => ErrorCode::QUERY_NUMERIC_OVERFLOW,
148 Self::QueryNumericNotRepresentable => ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
149 Self::QueryUnknownAggregateTargetField => {
150 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD
151 }
152 Self::QueryUnsupportedProjection => ErrorCode::QUERY_UNSUPPORTED_PROJECTION,
153 Self::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
154 Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
155 Self::QuerySqlWriteBoundary => ErrorCode::QUERY_SQL_WRITE_BOUNDARY,
156 Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
157 Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
158 Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
159 Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
160 Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
161 Self::RuntimeIncompatiblePersistedFormat => {
162 ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
163 }
164 Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
165 Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
166 Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
167 Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
168 Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
169 }
170 }
171}
172
173impl fmt::Debug for DiagnosticCode {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 fmt_compact_code(f, self.error_code().raw())
176 }
177}
178
179#[derive(Clone, Copy, Eq, Hash, PartialEq)]
191pub struct ErrorCode(u16);
192
193mod registry;
194
195impl ErrorCode {
196 #[must_use]
198 pub const fn from_raw(raw: u16) -> Self {
199 Self(raw)
200 }
201
202 #[must_use]
204 pub const fn raw(self) -> u16 {
205 self.0
206 }
207}
208
209impl fmt::Debug for ErrorCode {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 fmt_compact_code(f, self.raw())
212 }
213}
214
215#[remain::sorted]
222#[derive(Clone, Copy, Eq, Hash, PartialEq)]
223pub enum ErrorClass {
224 Conflict,
225 Corruption,
226 IncompatiblePersistedFormat,
227 Internal,
228 InvariantViolation,
229 NotFound,
230 Query,
231 Unsupported,
232}
233
234impl ErrorClass {
235 #[must_use]
237 pub const fn wire_code(self) -> u8 {
238 match self {
239 Self::Query => 1,
240 Self::Corruption => 2,
241 Self::IncompatiblePersistedFormat => 3,
242 Self::NotFound => 4,
243 Self::Internal => 5,
244 Self::Conflict => 6,
245 Self::Unsupported => 7,
246 Self::InvariantViolation => 8,
247 }
248 }
249
250 #[must_use]
252 pub const fn from_wire_code(code: u8) -> Option<Self> {
253 match code {
254 1 => Some(Self::Query),
255 2 => Some(Self::Corruption),
256 3 => Some(Self::IncompatiblePersistedFormat),
257 4 => Some(Self::NotFound),
258 5 => Some(Self::Internal),
259 6 => Some(Self::Conflict),
260 7 => Some(Self::Unsupported),
261 8 => Some(Self::InvariantViolation),
262 _ => None,
263 }
264 }
265}
266
267impl fmt::Debug for ErrorClass {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 fmt_compact_code(f, u16::from(self.wire_code()))
270 }
271}
272
273#[remain::sorted]
280#[derive(Clone, Copy, Eq, Hash, PartialEq)]
281pub enum ErrorOrigin {
282 Cursor,
283 Executor,
284 Identity,
285 Index,
286 Interface,
287 Planner,
288 Query,
289 Recovery,
290 Response,
291 Runtime,
292 Serialize,
293 Store,
294}
295
296impl ErrorOrigin {
297 #[must_use]
299 pub const fn wire_code(self) -> u8 {
300 match self {
301 Self::Cursor => 1,
302 Self::Executor => 2,
303 Self::Identity => 3,
304 Self::Index => 4,
305 Self::Interface => 5,
306 Self::Planner => 6,
307 Self::Query => 7,
308 Self::Recovery => 8,
309 Self::Response => 9,
310 Self::Runtime => 10,
311 Self::Serialize => 11,
312 Self::Store => 12,
313 }
314 }
315
316 #[must_use]
318 pub const fn from_known_wire_code(code: u8) -> Option<Self> {
319 match code {
320 1 => Some(Self::Cursor),
321 2 => Some(Self::Executor),
322 3 => Some(Self::Identity),
323 4 => Some(Self::Index),
324 5 => Some(Self::Interface),
325 6 => Some(Self::Planner),
326 7 => Some(Self::Query),
327 8 => Some(Self::Recovery),
328 9 => Some(Self::Response),
329 10 => Some(Self::Runtime),
330 11 => Some(Self::Serialize),
331 12 => Some(Self::Store),
332 _ => None,
333 }
334 }
335
336 #[must_use]
341 pub const fn from_wire_code(code: u8) -> Self {
342 match Self::from_known_wire_code(code) {
343 Some(origin) => origin,
344 None => Self::Runtime,
345 }
346 }
347}
348
349impl fmt::Debug for ErrorOrigin {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 fmt_compact_code(f, u16::from(self.wire_code()))
352 }
353}
354
355#[repr(u16)]
362#[derive(Clone, Copy, Eq, Hash, PartialEq)]
363pub enum QueryErrorKind {
364 Validate,
365 Intent,
366 Plan,
367 UnorderedPagination,
368 InvalidContinuationCursor,
369 NotFound,
370 NotUnique,
371}
372
373impl fmt::Debug for QueryErrorKind {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 fmt_compact_code(f, *self as u16)
376 }
377}
378
379#[repr(u16)]
387#[derive(Clone, Copy, Eq, Hash, PartialEq)]
388pub enum QueryProjectionCode {
389 NumericLiteralRequired,
390 NumericScaleArguments,
391 NestedFieldPathPreview,
392 CaseConditionBooleanRequired,
393 NumericInputRequired,
394 TextOrBlobInputRequired,
395 TextInputRequired,
396 TextOrNullArgumentRequired,
397 IntegerOrNullArgumentRequired,
398 UnaryOperandIncompatible,
399 BinaryOperandsIncompatible,
400}
401
402impl fmt::Debug for QueryProjectionCode {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 fmt_compact_code(f, *self as u16)
405 }
406}
407
408#[repr(u16)]
416#[derive(Clone, Copy, Eq, Hash, PartialEq)]
417pub enum QueryReadAdmissionCode {
418 PublicQueryRequiresLimit,
419 PublicQueryRequiresIndex,
420 UnboundedFullScanRejected,
421 SortRequiresMaterialization,
422 GroupedQueryRequiresLimits,
423 GroupedQueryExceedsBudget,
424 DiagnosticLaneDoesNotExecute,
425 ReturnedRowBoundExceedsPolicy,
426 PrimaryKeyInputExceedsPolicy,
427}
428
429impl fmt::Debug for QueryReadAdmissionCode {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 fmt_compact_code(f, *self as u16)
432 }
433}
434
435#[repr(u16)]
442#[derive(Clone, Copy, Eq, Hash, PartialEq)]
443pub enum RuntimeErrorKind {
444 Corruption,
445 IncompatiblePersistedFormat,
446 InvariantViolation,
447 Conflict,
448 NotFound,
449 Unsupported,
450 Internal,
451}
452
453impl fmt::Debug for RuntimeErrorKind {
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 fmt_compact_code(f, *self as u16)
456 }
457}
458
459#[repr(u16)]
467#[derive(Clone, Copy, Eq, Hash, PartialEq)]
468pub enum RuntimeBoundaryCode {
469 SqlSurfaceControllerRequired,
470 SchemaSurfaceControllerRequired,
471 SqlQueryNoConfiguredEntities,
472 SqlQueryEntityNotFound,
473 SqlDdlTargetRequired,
474 SqlDdlEntityNotConfigured,
475 SqlIntrospectionDisabled,
476 MutationRequiredFieldMissing,
478 MutationManagedTimestampRegression,
480 PersistedRowLayoutOutsideAcceptedWindow,
482 PersistedRowSlotCountMismatch,
484 GeneratedFieldAfterDdlField,
486 JournalMutationRevisionExhausted,
488 ConstraintViolation,
490 AcceptedRowConstraintProgramCorrupt,
492 ConstraintActivationWriteBlocked,
494 GeneratedConstraintActivationStale,
496 MutationDatabaseOwnedFieldExplicit,
498 MutationBatchEmpty,
500 MutationBatchTooManyItems,
502 MutationBatchStagedBytesExceeded,
504 MutationBatchResultBytesExceeded,
506 MutationBatchStoreMismatch,
508 MutationBatchTooManyEntities,
510 MutationBatchDuplicateKey,
512 OperationalSurfaceControllerRequired,
514 ExactKeyBatchTooManyItems,
516 ExactKeyBatchInputBytesExceeded,
518 ExactKeyBatchStoredBytesExceeded,
520 ExactKeyBatchResultBytesExceeded,
522 ExecutionBudgetExceeded,
524 PageUnitTooLarge,
526 RequestExecutionScopeRequired,
528 RequestExecutionRootMismatch,
530 SqlQueryReplyBytesExceeded,
532 DatabaseStartupRecoveryPending,
534 SqlSurfacePolicyDenied,
536 SchemaSurfacePolicyDenied,
538 MutationBatchCommitWorkExceeded,
540 ConvergenceBacklogPressure,
542}
543
544impl fmt::Debug for RuntimeBoundaryCode {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 fmt_compact_code(f, *self as u16)
547 }
548}
549
550#[repr(u16)]
558#[derive(Clone, Copy, Eq, Hash, PartialEq)]
559pub enum SqlFeatureCode {
560 AggregateFilterClause,
561 AlterStatementBeyondAlterTable,
562 AlterTableAddColumnDuplicateDefault,
563 AlterTableAddColumnModifiers,
564 AlterTableAddStatementBeyondAddColumn,
565 AlterTableAlterColumnDropUnsupportedAction,
566 AlterTableAlterColumnModifiers,
567 AlterTableAlterColumnSetUnsupportedAction,
568 AlterTableAlterColumnUnsupportedAction,
569 AlterTableAlterStatementBeyondAlterColumn,
570 AlterTableDropColumnIfExistsSyntax,
571 AlterTableDropColumnModifiers,
572 AlterTableDropStatementBeyondDropColumn,
573 AlterTableRenameColumnMissingTo,
574 AlterTableRenameColumnModifiers,
575 AlterTableRenameStatementBeyondRenameColumn,
576 AlterTableUnsupportedOperation,
577 ColumnAlias,
578 CreateIndexIfNotExistsSyntax,
579 CreateIndexKeyOrderingModifiers,
580 CreateIndexModifiers,
581 CreateStatementBeyondCreateIndex,
582 DescribeModifier,
583 DdlSchemaVersionDuplicateExpectedClause,
584 DdlSchemaVersionDuplicateSetClause,
585 DropIndexModifiers,
586 DropIndexIfExistsSyntax,
587 DropStatementBeyondDropIndex,
588 ExpressionIndexUnsupportedFunction,
589 Having,
590 Insert,
591 Join,
592 LikePatternBeyondTrailingPrefix,
593 LowerFieldPredicateUnsupported,
594 MultiStatementSql,
595 NestedAggregateInput,
596 NestedProjectionFunctionInArithmetic,
597 OrderByUnsupportedForm,
598 Other,
599 PredicateStartsWithFirstArgument,
600 QuotedIdentifiers,
601 ReturningUnsupportedShape,
602 ScalarFunctionExpressionPosition,
603 ScaleTakingNumericFunctionExpressionPosition,
604 ShowColumnsModifiers,
605 ShowEntitiesModifiers,
606 ShowIndexesModifiers,
607 ShowMemoryModifiers,
608 ShowStoresModifiers,
609 ShowUnsupportedCommand,
610 SimpleCaseExpression,
611 StandaloneLiteralProjectionItem,
612 UnionIntersectExcept,
613 UnsupportedFunctionNamespace,
614 Update,
615 UpperFieldPredicateUnsupported,
616 WindowFunction,
617 With,
618 NumericScaleFunctionArguments,
619 OrderByFieldNotOrderable,
620 ShowConstraintsModifiers,
621 AlterTableAddConstraintBeyondCheck,
622 AlterTableAddConstraintModifiers,
623 AlterTableDropConstraintIfExistsSyntax,
624 AlterTableDropConstraintModifiers,
625 AlterTableValidateBeyondConstraint,
626 AlterTableValidateConstraintModifiers,
627 ShowRelationsModifiers,
628}
629
630impl fmt::Debug for SqlFeatureCode {
631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632 fmt_compact_code(f, *self as u16)
633 }
634}
635
636#[repr(u16)]
645#[derive(Clone, Copy, Eq, Hash, PartialEq)]
646pub enum SqlLoweringCode {
647 EntityMismatch,
648 SelectProjectionShape,
649 SelectDistinct,
650 DistinctOrderByProjection,
651 GlobalAggregateProjection,
652 GlobalAggregateGroupBy,
653 SelectGroupByShape,
654 GroupedProjectionExplicitListRequired,
655 GroupedProjectionAggregateRequired,
656 GroupedProjectionNonGroupField,
657 GroupedProjectionScalarAfterAggregate,
658 HavingRequiresGroupBy,
659 SelectHavingShape,
660 AggregateInputExpressions,
661 WhereExpressionShape,
662 ParameterPlacement,
663 SqlDdlExecutionUnsupported,
664 BindingCount,
665 BindingFamily,
666 BindingLimit,
667}
668
669impl fmt::Debug for SqlLoweringCode {
670 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
671 fmt_compact_code(f, *self as u16)
672 }
673}
674
675#[repr(u16)]
683#[derive(Clone, Copy, Eq, Hash, PartialEq)]
684pub enum SqlSurfaceMismatchCode {
685 QueryRejectsInsert,
686 QueryRejectsUpdate,
687 QueryRejectsDelete,
688 MutationRejectsSelect,
689 MutationRejectsExplain,
690 MutationRejectsDescribe,
691 MutationRejectsShowIndexes,
692 MutationRejectsShowColumns,
693 MutationRejectsShowEntities,
694 MutationRejectsShowStores,
695 MutationRejectsShowMemory,
696 MutationRequiresExplicitUpdateIntent,
697 MutationRejectsShowConstraints,
698 MutationRejectsShowRelations,
699}
700
701impl fmt::Debug for SqlSurfaceMismatchCode {
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 SqlWriteBoundaryCode {
717 PrimaryKeyLiteralIncompatible,
718 MissingPrimaryKey,
719 MissingRequiredFields,
720 ExplicitManagedField,
721 ExplicitGeneratedField,
722 InsertSelectRequiresScalar,
723 InsertSelectAggregateProjection,
724 InsertSelectWidthMismatch,
725 UpdatePrimaryKeyMutation,
726 InvalidFieldLiteral,
727 UnknownReturningField,
728 DuplicateReturningField,
729 UpdateMissingWherePredicate,
730 WriteOrderByUnsupportedShape,
731 ReturningResponseTooLarge,
732 ReturningRowsTooMany,
733 StagedRowsTooMany,
734 InsertDefaultRequiredField,
735 UpdateDefaultRequiredField,
736 UpdateDefaultDatabaseOwnedField,
737 ExactUpdateAssertionRequired,
738 ExactUpdateAssertionTooHigh,
739 ExactUpdateAffectedRowsExceeded,
740 ExactUpdateWindowUnsupported,
741 ExactUpdateScanBudgetExceeded,
742 ResumableUpdateWindowUnsupported,
743 ResumableUpdateReturningUnsupported,
744 ResumableUpdateRequiresJournaledStore,
745 ResumableUpdateAssignedFieldHasGlobalConstraint,
746 ResumableUpdateScopeDependsOnAssignedField,
747 ResumableUpdateScopeDependencyUnknown,
748 ResumableUpdateContinuationMalformed,
749 ResumableUpdateContinuationTargetMismatch,
750 ResumableUpdateContinuationSchemaMismatch,
751 ResumableUpdateContinuationScopeMismatch,
752 ResumableUpdateContinuationPatchMismatch,
753 ResumableUpdateContinuationBatchPolicyMismatch,
754 ResumableUpdateManagedFieldHasGlobalConstraint,
755}
756
757impl fmt::Debug for SqlWriteBoundaryCode {
758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
759 fmt_compact_code(f, *self as u16)
760 }
761}
762
763#[repr(u16)]
771#[derive(Clone, Copy, Eq, Hash, PartialEq)]
772pub enum SchemaDdlAdmissionCode {
773 MissingExpectedSchemaVersion,
774 MissingNextSchemaVersion,
775 StaleExpectedSchemaVersion,
776 InvalidExpectedSchemaVersion,
777 InvalidNextSchemaVersion,
778 AcceptedSchemaChangeWithoutVersionBump,
779 EmptyVersionBump,
780 VersionGap,
781 VersionRollback,
782 FingerprintMethodMismatch,
783 UnsupportedTransitionClass,
784 PhysicalRunnerMissing,
785 ValidationFailed,
786 PublicationRaceLost,
787 InvalidAddColumnDefault,
788 InvalidAlterColumnDefault,
789 GeneratedIndexDropRejected,
790 SchemaRewriteRequiresMigration,
791 SchemaTransitionBudgetExceeded,
792 GeneratedFieldDefaultChangeRejected,
793 GeneratedFieldNullabilityChangeRejected,
794 RowLayoutVersionExhausted,
795}
796
797impl fmt::Debug for SchemaDdlAdmissionCode {
798 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
799 fmt_compact_code(f, *self as u16)
800 }
801}
802
803#[repr(u16)]
805#[derive(Clone, Copy, Eq, Hash, PartialEq)]
806pub enum SchemaMigrationCode {
807 Unadopted,
808 MissingMigration,
809 VersionGap,
810 Downgrade,
811 EmptyEntityVersionBump,
812 StaleAcceptedHead,
813 PlanChanged,
814 UnknownFromObject,
815 UnknownToObject,
816 KindMismatch,
817 IdentityConflict,
818 UnexplainedSchemaDifference,
819 UnsupportedTransform,
820 PhysicalRunnerMissing,
821 MigrationInProgress,
822 AbortTooLate,
823 ProgressCorrupt,
824 CandidateMismatch,
825 PublicationRaceLost,
826}
827
828impl SchemaMigrationCode {
829 #[must_use]
831 pub const fn diagnostic_code(self) -> DiagnosticCode {
832 match self {
833 Self::StaleAcceptedHead
834 | Self::PlanChanged
835 | Self::IdentityConflict
836 | Self::MigrationInProgress
837 | Self::AbortTooLate
838 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
839 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
840 Self::Unadopted
841 | Self::MissingMigration
842 | Self::VersionGap
843 | Self::Downgrade
844 | Self::EmptyEntityVersionBump
845 | Self::UnknownFromObject
846 | Self::UnknownToObject
847 | Self::KindMismatch
848 | Self::UnexplainedSchemaDifference
849 | Self::UnsupportedTransform
850 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
851 }
852 }
853}
854
855impl fmt::Debug for SchemaMigrationCode {
856 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
857 fmt_compact_code(f, *self as u16)
858 }
859}
860
861#[remain::sorted]
868#[derive(Clone, Copy, Eq, PartialEq)]
869pub enum DiagnosticDetail {
870 QueryKind { kind: QueryErrorKind },
871 QueryProjection { reason: QueryProjectionCode },
872 QueryReadAdmission { reason: QueryReadAdmissionCode },
873 RuntimeBoundary { boundary: RuntimeBoundaryCode },
874 RuntimeKind { kind: RuntimeErrorKind },
875 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
876 SchemaMigration { reason: SchemaMigrationCode },
877 SqlLowering { reason: SqlLoweringCode },
878 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
879 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
880 UnsupportedSqlFeature { feature: SqlFeatureCode },
881}
882
883impl fmt::Debug for DiagnosticDetail {
884 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
885 fmt_compact_code(
886 f,
887 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
888 )
889 }
890}
891
892#[derive(Clone, Eq, PartialEq)]
899pub struct Diagnostic {
900 code: DiagnosticCode,
901 origin: ErrorOrigin,
902 detail: Option<DiagnosticDetail>,
903}
904
905impl Diagnostic {
906 #[must_use]
908 pub const fn new(
909 code: DiagnosticCode,
910 origin: ErrorOrigin,
911 detail: Option<DiagnosticDetail>,
912 ) -> Self {
913 Self {
914 code,
915 origin,
916 detail,
917 }
918 }
919
920 #[must_use]
922 pub const fn from_code(code: DiagnosticCode) -> Self {
923 Self::new(code, code.origin(), None)
924 }
925
926 #[must_use]
928 pub const fn code(&self) -> DiagnosticCode {
929 self.code
930 }
931
932 #[must_use]
934 pub const fn class(&self) -> ErrorClass {
935 self.code.class()
936 }
937
938 #[must_use]
940 pub const fn origin(&self) -> ErrorOrigin {
941 self.origin
942 }
943
944 #[must_use]
946 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
947 self.detail.as_ref()
948 }
949
950 #[must_use]
952 pub const fn error_code(&self) -> ErrorCode {
953 ErrorCode::from_parts(self.code, self.detail)
954 }
955}
956
957impl fmt::Debug for Diagnostic {
958 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
959 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
960 }
961}
962
963fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
964 write!(f, "{raw}")
965}
966
967#[cfg(test)]
968mod tests {
969 use super::{
970 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
971 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
972 SqlWriteBoundaryCode,
973 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
974 };
975
976 #[test]
977 fn diagnostic_from_code_uses_default_origin() {
978 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
979
980 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
981 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
982 }
983
984 #[test]
985 fn diagnostic_code_reports_broad_class() {
986 assert_eq!(
987 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
988 ErrorClass::Unsupported
989 );
990 assert_eq!(
991 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
992 ErrorClass::Unsupported
993 );
994 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
995 assert_eq!(
996 DiagnosticCode::StoreCorruption.class(),
997 ErrorClass::Corruption
998 );
999 }
1000
1001 #[test]
1002 fn class_and_origin_wire_codes_round_trip() {
1003 for (class, raw) in [
1004 (ErrorClass::Query, 1),
1005 (ErrorClass::Corruption, 2),
1006 (ErrorClass::IncompatiblePersistedFormat, 3),
1007 (ErrorClass::NotFound, 4),
1008 (ErrorClass::Internal, 5),
1009 (ErrorClass::Conflict, 6),
1010 (ErrorClass::Unsupported, 7),
1011 (ErrorClass::InvariantViolation, 8),
1012 ] {
1013 assert_eq!(class.wire_code(), raw);
1014 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1015 assert_eq!(format!("{class:?}"), raw.to_string());
1016 }
1017
1018 for (origin, raw) in [
1019 (ErrorOrigin::Cursor, 1),
1020 (ErrorOrigin::Executor, 2),
1021 (ErrorOrigin::Identity, 3),
1022 (ErrorOrigin::Index, 4),
1023 (ErrorOrigin::Interface, 5),
1024 (ErrorOrigin::Planner, 6),
1025 (ErrorOrigin::Query, 7),
1026 (ErrorOrigin::Recovery, 8),
1027 (ErrorOrigin::Response, 9),
1028 (ErrorOrigin::Runtime, 10),
1029 (ErrorOrigin::Serialize, 11),
1030 (ErrorOrigin::Store, 12),
1031 ] {
1032 assert_eq!(origin.wire_code(), raw);
1033 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1034 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1035 assert_eq!(format!("{origin:?}"), raw.to_string());
1036 }
1037
1038 assert_eq!(ErrorClass::from_wire_code(0), None);
1039 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1040 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1041 }
1042
1043 #[test]
1044 fn public_error_codes_are_sequential() {
1045 let first = ORDERED_ERROR_CODES
1046 .first()
1047 .expect("public error-code registry is non-empty")
1048 .raw();
1049
1050 assert_eq!(first, 1);
1051
1052 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1053 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1054 assert_eq!(code.raw(), expected);
1055 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1056 assert!(code.is_known());
1057 }
1058
1059 let last = ORDERED_ERROR_CODES
1060 .last()
1061 .expect("public error-code registry is non-empty")
1062 .raw();
1063
1064 assert_eq!(last, 267);
1065 }
1066
1067 #[test]
1068 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1069 let first = ORDERED_ERROR_CODES
1070 .first()
1071 .expect("public error-code registry is non-empty")
1072 .raw();
1073 let last = ORDERED_ERROR_CODES
1074 .last()
1075 .expect("public error-code registry is non-empty")
1076 .raw();
1077
1078 for raw in first..=last {
1079 let code = ErrorCode::from_raw(raw);
1080 let diagnostic_code = code.diagnostic_code();
1081 let diagnostic_detail = code.diagnostic_detail();
1082 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1083
1084 assert_eq!(rebuilt.raw(), raw);
1085
1086 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1087
1088 assert_eq!(diagnostic.code(), diagnostic_code);
1089 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1090 assert_eq!(diagnostic.error_code().raw(), raw);
1091 }
1092 }
1093
1094 #[test]
1095 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1096 let first_unknown = ORDERED_ERROR_CODES
1097 .last()
1098 .expect("public error-code registry is non-empty")
1099 .raw()
1100 .checked_add(1)
1101 .expect("public error-code registry retains an unknown successor");
1102
1103 for raw in [0, first_unknown, u16::MAX] {
1104 let code = ErrorCode::from_raw(raw);
1105
1106 assert_eq!(ErrorCode::known(raw), None);
1107 assert!(!code.is_known());
1108 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1109 assert_eq!(code.diagnostic_detail(), None);
1110 assert_eq!(code.class(), ErrorClass::Internal);
1111
1112 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1113
1114 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1115 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1116 assert_eq!(diagnostic.detail(), None);
1117 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1118 }
1119 }
1120
1121 #[test]
1122 fn from_parts_requires_detail_to_match_broad_code() {
1123 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1124 feature: SqlFeatureCode::Join,
1125 });
1126
1127 assert_eq!(
1128 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1129 ErrorCode::SQL_FEATURE_JOIN
1130 );
1131 assert_eq!(
1132 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1133 ErrorCode::QUERY_PLAN
1134 );
1135 }
1136
1137 #[test]
1138 fn detail_bearing_registry_entries_round_trip_directly() {
1139 assert!(!DETAIL_ERROR_CODES.is_empty());
1140
1141 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1142 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1143 assert_eq!(code.diagnostic_code(), diagnostic_code);
1144 assert_eq!(code.diagnostic_detail(), Some(detail));
1145 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1146 }
1147 }
1148
1149 #[test]
1150 fn diagnostic_detail_reports_generated_broad_code() {
1151 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1152 feature: SqlFeatureCode::Join,
1153 };
1154
1155 assert_eq!(
1156 detail.diagnostic_code(),
1157 DiagnosticCode::QueryUnsupportedSqlFeature
1158 );
1159 assert_eq!(format!("{detail:?}"), "61");
1160 }
1161
1162 #[test]
1163 fn public_error_codes_reconstruct_shifted_details() {
1164 assert_eq!(
1165 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1166 DiagnosticCode::QueryUnknownAggregateTargetField
1167 );
1168 assert_eq!(
1169 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1170 Some(DiagnosticDetail::UnsupportedSqlFeature {
1171 feature: SqlFeatureCode::Join,
1172 })
1173 );
1174 assert_eq!(
1175 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1176 Some(DiagnosticDetail::QueryProjection {
1177 reason: QueryProjectionCode::NumericLiteralRequired,
1178 })
1179 );
1180 assert_eq!(
1181 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1182 Some(DiagnosticDetail::QueryReadAdmission {
1183 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1184 })
1185 );
1186 assert_eq!(
1187 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1188 Some(DiagnosticDetail::SqlLowering {
1189 reason: SqlLoweringCode::DistinctOrderByProjection,
1190 })
1191 );
1192 assert_eq!(
1193 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1194 Some(DiagnosticDetail::SqlWriteBoundary {
1195 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1196 })
1197 );
1198 assert_eq!(
1199 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1200 Some(DiagnosticDetail::SqlWriteBoundary {
1201 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1202 })
1203 );
1204 }
1205}