sqlstate/
standard.rs

1//! Abstractions for standard return codes.
2
3use sqlstate_macros::state;
4
5use crate::Category;
6
7pub mod class;
8
9use self::class::*;
10
11/// A representation for a standard `SQLSTATE` code.
12#[state(standard)]
13#[derive(Clone, Eq, PartialEq, Hash, Debug)]
14#[non_exhaustive]
15pub enum SqlState {
16    #[class("00")]
17    Success(Option<Success>),
18    #[class("01")]
19    Warning(Option<Warning>),
20    #[class("02")]
21    NoData(Option<NoData>),
22    #[class("07")]
23    DynamicSqlError(Option<DynamicSqlError>),
24    #[class("08")]
25    ConnectionException(Option<ConnectionException>),
26    #[class("09")]
27    TriggeredActionException(Option<TriggeredActionException>),
28    #[class("0A")]
29    FeatureNotSupported(Option<FeatureNotSupported>),
30    #[class("0D")]
31    InvalidTargetTypeSpecification(Option<InvalidTargetTypeSpecification>),
32    #[class("0E")]
33    InvalidSchemaNameListSpecification(Option<InvalidSchemaNameListSpecification>),
34    #[class("0F")]
35    LocatorException(Option<LocatorException>),
36    #[class("0K")]
37    ResignalWhenHandlerNotActive(Option<ResignalWhenHandlerNotActive>),
38    #[class("0L")]
39    InvalidGrantor(Option<InvalidGrantor>),
40    #[class("0M")]
41    InvalidSqlInvokedProcedureReference(Option<InvalidSqlInvokedProcedureReference>),
42    #[class("0N")]
43    SqlXmlMappingError(Option<SqlXmlMappingError>),
44    #[class("0P")]
45    InvalidRoleSpecification(Option<InvalidRoleSpecification>),
46    #[class("0S")]
47    InvalidTransformGroupNameSpecification(Option<InvalidTransformGroupNameSpecification>),
48    #[class("0T")]
49    TargetTableDisagreesWithCursorSpecification(
50        Option<TargetTableDisagreesWithCursorSpecification>,
51    ),
52    #[class("0U")]
53    AttemptToAssignToNonUpdatableColumn(Option<AttemptToAssignToNonUpdatableColumn>),
54    #[class("0V")]
55    AttemptToAssignToOrderingColumn(Option<AttemptToAssignToOrderingColumn>),
56    #[class("0W")]
57    ProhibitedStatementDuringTriggerExecution(Option<ProhibitedStatementDuringTriggerExecution>),
58    #[class("0X")]
59    InvalidForeignServerSpecification(Option<InvalidForeignServerSpecification>),
60    #[class("0Y")]
61    PassthroughSpecificCondition(Option<PassthroughSpecificCondition>),
62    #[class("0Z")]
63    DiagnosticsException(Option<DiagnosticsException>),
64    #[class("10")]
65    XQueryError(Option<XQueryError>),
66    #[class("20")]
67    CaseNotFoundForCaseStatement(Option<CaseNotFoundForCaseStatement>),
68    #[class("21")]
69    CardinalityViolation(Option<CardinalityViolation>),
70    #[class("22")]
71    DataException(Option<DataException>),
72    #[class("23")]
73    IntegrityConstraintViolation(Option<IntegrityConstraintViolation>),
74    #[class("24")]
75    InvalidCursorState(Option<InvalidCursorState>),
76    #[class("25")]
77    InvalidTransactionState(Option<InvalidTransactionState>),
78    #[class("26")]
79    InvalidSqlStatementName(Option<InvalidSqlStatementName>),
80    #[class("27")]
81    TriggeredDataChangeViolation(Option<TriggeredDataChangeViolation>),
82    #[class("28")]
83    InvalidAuthorizationSpecification(Option<InvalidAuthorizationSpecification>),
84    #[class("2B")]
85    DependentPrivilegeDescriptorsExist(Option<DependentPrivilegeDescriptorsExist>),
86    #[class("2C")]
87    InvalidCharsetName(Option<InvalidCharsetName>),
88    #[class("2D")]
89    InvalidTransactionTermination(Option<InvalidTransactionTermination>),
90    #[class("2E")]
91    InvalidConnectionName(Option<InvalidConnectionName>),
92    #[class("2F")]
93    SqlRoutineException(Option<SqlRoutineException>),
94    #[class("2H")]
95    InvalidCollationName(Option<InvalidCollationName>),
96    #[class("30")]
97    InvalidSqlStatementIdentifier(Option<InvalidSqlStatementIdentifier>),
98    #[class("33")]
99    InvalidSqlDescriptorName(Option<InvalidSqlDescriptorName>),
100    #[class("34")]
101    InvalidCursorName(Option<InvalidCursorName>),
102    #[class("35")]
103    InvalidConditionNumber(Option<InvalidConditionNumber>),
104    #[class("36")]
105    CursorSensitivityException(Option<CursorSensitivityException>),
106    #[class("38")]
107    ExternalRoutineException(Option<ExternalRoutineException>),
108    #[class("39")]
109    ExternalRoutineInvocationException(Option<ExternalRoutineInvocationException>),
110    #[class("3B")]
111    SavepointException(Option<SavepointException>),
112    #[class("3C")]
113    AmbiguousCursorName(Option<AmbiguousCursorName>),
114    #[class("3D")]
115    InvalidCatalogName(Option<InvalidCatalogName>),
116    #[class("3F")]
117    InvalidSchemaName(Option<InvalidSchemaName>),
118    #[class("40")]
119    TransactionRollback(Option<TransactionRollback>),
120    #[class("42")]
121    SyntaxErrorOrAccessRuleViolation(Option<SyntaxErrorOrAccessRuleViolation>),
122    #[class("44")]
123    WithCheckOptionViolation(Option<WithCheckOptionViolation>),
124    #[class("45")]
125    UnhandledUserDefinedException(Option<UnhandledUserDefinedException>),
126    #[class("46")]
127    OlbSpecificError(Option<OlbSpecificError>),
128    #[class("HW")]
129    DatalinkException(Option<DatalinkException>),
130    #[class("HV")]
131    FdwSpecificCondition(Option<FdwSpecificCondition>),
132    #[class("HY")]
133    CliSpecificCondition(Option<CliSpecificCondition>),
134    #[class("HZ")]
135    RemoteDatabaseAccess(Option<RemoteDatabaseAccess>),
136}
137
138impl SqlState {
139    pub fn category(&self) -> Category {
140        match self {
141            Self::Success(_) => Category::Success,
142            Self::Warning(_) => Category::Warning,
143            Self::NoData(_) => Category::NoData,
144            _ => Category::Exception,
145        }
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    use crate::error::ParseError;
154
155    fn check(state: &str, value: SqlState) {
156        assert_eq!(state.parse::<SqlState>().unwrap(), value);
157    }
158
159    #[test]
160    fn class() {
161        assert_eq!(SqlState::Success(None).class(), "00");
162        assert_eq!(SqlState::Warning(None).class(), "01");
163        assert_eq!(SqlState::DynamicSqlError(None).class(), "07");
164    }
165
166    #[test]
167    fn subclass() {
168        assert_eq!(SqlState::Success(None).subclass(), None);
169        assert_eq!(
170            SqlState::Warning(Some(Warning::InsufficientItemDescriptorAreas)).subclass(),
171            Some("005")
172        );
173        assert_eq!(
174            SqlState::DynamicSqlError(Some(DynamicSqlError::InvalidDataTarget)).subclass(),
175            Some("00D")
176        );
177    }
178
179    #[test]
180    fn category() {
181        assert_eq!(SqlState::Success(None).category(), Category::Success);
182        assert_eq!(SqlState::Warning(None).category(), Category::Warning);
183        assert_eq!(SqlState::NoData(None).category(), Category::NoData);
184        assert_eq!(
185            SqlState::DynamicSqlError(Some(DynamicSqlError::InvalidDataTarget)).category(),
186            Category::Exception
187        );
188    }
189
190    #[test]
191    fn invalid_length() {
192        for i in 0..5 {
193            assert_eq!(
194                "0".repeat(i).parse::<SqlState>(),
195                Err(ParseError::InvalidLength(i))
196            );
197        }
198    }
199
200    #[test]
201    fn empty_class() {
202        check("00000", SqlState::Success(None));
203        check(
204            "00001",
205            SqlState::Success(Some(Success::Other(String::from("001")))),
206        );
207    }
208
209    #[test]
210    fn unknown_class() {
211        check("QQ999", SqlState::Other(String::from("QQ999")));
212    }
213
214    #[test]
215    fn one_subclass() {
216        check("02000", SqlState::NoData(None));
217        check(
218            "02001",
219            SqlState::NoData(Some(NoData::NoAdditionalResultSetsReturned)),
220        );
221        check(
222            "0200F",
223            SqlState::NoData(Some(NoData::Other(String::from("00F")))),
224        );
225    }
226
227    #[test]
228    fn many_subclasses() {
229        check("01000", SqlState::Warning(None));
230        check(
231            "01005",
232            SqlState::Warning(Some(Warning::InsufficientItemDescriptorAreas)),
233        );
234        check(
235            "0100A",
236            SqlState::Warning(Some(Warning::QueryExpressionTooLongForInformationSchema)),
237        );
238        check(
239            "0102F",
240            SqlState::Warning(Some(Warning::ArrayDataRightTruncation)),
241        );
242        check(
243            "01FFF",
244            SqlState::Warning(Some(Warning::Other(String::from("FFF")))),
245        )
246    }
247}