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