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