1use sqlstate_macros::state;
4
5use crate::Category;
6
7pub mod class;
8
9use self::class::*;
10
11#[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}