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