servers/postgres/types/error.rs
1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use common_error::status_code::StatusCode;
16use pgwire::error::ErrorInfo;
17use snafu::Snafu;
18use strum::{AsRefStr, Display, EnumIter, EnumMessage};
19
20#[derive(Display, Debug, PartialEq)]
21#[allow(dead_code)]
22pub enum PgErrorSeverity {
23 #[strum(serialize = "INFO")]
24 Info,
25 #[strum(serialize = "DEBUG")]
26 Debug,
27 #[strum(serialize = "NOTICE")]
28 Notice,
29 #[strum(serialize = "WARNING")]
30 Warning,
31 #[strum(serialize = "ERROR")]
32 Error,
33 #[strum(serialize = "FATAL")]
34 Fatal,
35 #[strum(serialize = "PANIC")]
36 Panic,
37}
38
39// refer to: https://www.postgresql.org/docs/16/errcodes-appendix.html
40#[derive(Snafu, Debug, AsRefStr, EnumIter, EnumMessage)]
41pub enum PgErrorCode {
42 // === Begin of Class 00 — Successful Completion ===
43 /// successful_completion
44 #[snafu(display("successful_completion"))]
45 Ec00000 = 0,
46 // === End of Class 00 — Successful Completion =====
47
48 // === Begin of Class 01 — Warning ===
49 /// warning
50 #[snafu(display("warning"))]
51 Ec01000 = 100,
52 // === End of Class 01 — Warning =====
53
54 // === Begin of Class 02 — No Data (this is also a warning class per the SQL standard) ===
55 /// no_data
56 #[snafu(display("no_data"))]
57 Ec02000 = 200,
58 // === End of Class 02 — No Data (this is also a warning class per the SQL standard) =====
59
60 // === Begin of Class 03 — SQL Statement Not Yet Complete ===
61 /// sql_statement_not_yet_complete
62 #[snafu(display("sql_statement_not_yet_complete"))]
63 Ec03000 = 300,
64 // === End of Class 03 — SQL Statement Not Yet Complete =====
65
66 // === Begin of Class 08 — Connection Exception ===
67 /// connection_exception
68 #[snafu(display("connection_exception"))]
69 Ec08000 = 400,
70 // === End of Class 08 — Connection Exception =====
71
72 // === Begin of Class 09 — Triggered Action Exception ===
73 /// triggered_action_exception
74 #[snafu(display("triggered_action_exception"))]
75 Ec09000 = 500,
76 // === End of Class 09 — Triggered Action Exception =====
77
78 // === Begin of Class 0A — Feature Not Supported ===
79 /// feature_not_supported
80 #[snafu(display("feature_not_supported"))]
81 Ec0A000 = 600,
82 // === End of Class 0A — Feature Not Supported =====
83
84 // === Begin of Class 0B — Invalid Transaction Initiation ===
85 /// invalid_transaction_initiation
86 #[snafu(display("invalid_transaction_initiation"))]
87 Ec0B000 = 700,
88 // === End of Class 0B — Invalid Transaction Initiation =====
89
90 // === Begin of Class 0F — Locator Exception ===
91 /// locator_exception
92 #[snafu(display("locator_exception"))]
93 Ec0F000 = 800,
94 // === End of Class 0F — Locator Exception =====
95
96 // === Begin of Class 0L — Invalid Grantor ===
97 /// invalid_grantor
98 #[snafu(display("invalid_grantor"))]
99 Ec0L000 = 900,
100 // === End of Class 0L — Invalid Grantor =====
101
102 // === Begin of Class 0P — Invalid Role Specification ===
103 /// invalid_role_specification
104 #[snafu(display("invalid_role_specification"))]
105 Ec0P000 = 1000,
106 // === End of Class 0P — Invalid Role Specification =====
107
108 // === Begin of Class 0Z — Diagnostics Exception ===
109 /// diagnostics_exception
110 #[snafu(display("diagnostics_exception"))]
111 Ec0Z000 = 1100,
112 // === End of Class 0Z — Diagnostics Exception =====
113
114 // === Begin of Class 20 — Case Not Found ===
115 /// case_not_found
116 #[snafu(display("case_not_found"))]
117 Ec20000 = 1200,
118 // === End of Class 20 — Case Not Found =====
119
120 // === Begin of Class 21 — Cardinality Violation ===
121 /// cardinality_violation
122 #[snafu(display("cardinality_violation"))]
123 Ec21000 = 1300,
124 // === End of Class 21 — Cardinality Violation =====
125
126 // === Begin of Class 22 — Data Exception ===
127 /// data_exception
128 #[snafu(display("data_exception"))]
129 Ec22000 = 1400,
130 /// invalid_parameter_value
131 #[snafu(display("invalid_parameter_value"))]
132 Ec22023 = 1401,
133 // === End of Class 22 — Data Exception =====
134
135 // === Begin of Class 23 — Integrity Constraint Violation ===
136 /// integrity_constraint_violation
137 #[snafu(display("integrity_constraint_violation"))]
138 Ec23000 = 1500,
139 // === End of Class 23 — Integrity Constraint Violation =====
140
141 // === Begin of Class 24 — Invalid Cursor State ===
142 /// invalid_cursor_state
143 #[snafu(display("invalid_cursor_state"))]
144 Ec24000 = 1600,
145 // === End of Class 24 — Invalid Cursor State =====
146
147 // === Begin of Class 25 — Invalid Transaction State ===
148 /// invalid_transaction_state
149 #[snafu(display("invalid_transaction_state"))]
150 Ec25000 = 1700,
151 /// read_only_sql_transaction
152 #[snafu(display("read_only_sql_transaction"))]
153 Ec25006 = 1701,
154 // === End of Class 25 — Invalid Transaction State =====
155
156 // === Begin of Class 26 — Invalid SQL Statement Name ===
157 /// invalid_sql_statement_name
158 #[snafu(display("invalid_sql_statement_name"))]
159 Ec26000 = 1800,
160 // === End of Class 26 — Invalid SQL Statement Name =====
161
162 // === Begin of Class 27 — Triggered Data Change Violation ===
163 /// triggered_data_change_violation
164 #[snafu(display("triggered_data_change_violation"))]
165 Ec27000 = 1900,
166 // === End of Class 27 — Triggered Data Change Violation =====
167
168 // === Begin of Class 28 — Invalid Authorization Specification ===
169 /// invalid_authorization_specification
170 #[snafu(display("invalid_authorization_specification"))]
171 Ec28000 = 2000,
172 /// invalid_password
173 #[snafu(display("invalid_password"))]
174 Ec28P01 = 1901,
175 // === End of Class 28 — Invalid Authorization Specification =====
176
177 // === Begin of Class 2B — Dependent Privilege Descriptors Still Exist ===
178 /// dependent_privilege_descriptors_still_exist
179 #[snafu(display("dependent_privilege_descriptors_still_exist"))]
180 Ec2B000 = 2100,
181 // === End of Class 2B — Dependent Privilege Descriptors Still Exist =====
182
183 // === Begin of Class 2D — Invalid Transaction Termination ===
184 /// invalid_transaction_termination
185 #[snafu(display("invalid_transaction_termination"))]
186 Ec2D000 = 2200,
187 // === End of Class 2D — Invalid Transaction Termination =====
188
189 // === Begin of Class 2F — SQL Routine Exception ===
190 /// sql_routine_exception
191 #[snafu(display("sql_routine_exception"))]
192 Ec2F000 = 2300,
193 // === End of Class 2F — SQL Routine Exception =====
194
195 // === Begin of Class 34 — Invalid Cursor Name ===
196 /// invalid_cursor_name
197 #[snafu(display("invalid_cursor_name"))]
198 Ec34000 = 2400,
199 // === End of Class 34 — Invalid Cursor Name =====
200
201 // === Begin of Class 38 — External Routine Exception ===
202 /// external_routine_exception
203 #[snafu(display("external_routine_exception"))]
204 Ec38000 = 2500,
205 // === End of Class 38 — External Routine Exception =====
206
207 // === Begin of Class 39 — External Routine Invocation Exception ===
208 /// external_routine_invocation_exception
209 #[snafu(display("external_routine_invocation_exception"))]
210 Ec39000 = 2600,
211 // === End of Class 39 — External Routine Invocation Exception =====
212
213 // === Begin of Class 3B — Savepoint Exception ===
214 /// savepoint_exception
215 #[snafu(display("savepoint_exception"))]
216 Ec3B000 = 2700,
217 // === End of Class 3B — Savepoint Exception =====
218
219 // === Begin of Class 3D — Invalid Catalog Name ===
220 /// invalid_catalog_name
221 #[snafu(display("invalid_catalog_name"))]
222 Ec3D000 = 2800,
223 // === End of Class 3D — Invalid Catalog Name =====
224
225 // === Begin of Class 3F — Invalid Schema Name ===
226 /// invalid_schema_name
227 #[snafu(display("invalid_schema_name"))]
228 Ec3F000 = 2900,
229 // === End of Class 3F — Invalid Schema Name =====
230
231 // === Begin of Class 40 — Transaction Rollback ===
232 /// transaction_rollback
233 #[snafu(display("transaction_rollback"))]
234 Ec40000 = 3000,
235 // === End of Class 40 — Transaction Rollback =====
236
237 // === Begin of Class 42 — Syntax Error or Access Rule Violation ===
238 /// syntax_error_or_access_rule_violation
239 #[snafu(display("syntax_error_or_access_rule_violation"))]
240 Ec42000 = 3100,
241 /// syntax_error
242 #[snafu(display("syntax_error"))]
243 Ec42601 = 3101,
244 /// insufficient_privilege
245 #[snafu(display("insufficient_privilege"))]
246 Ec42501 = 3102,
247 /// undefined_column
248 #[snafu(display("undefined_column"))]
249 Ec42703 = 3103,
250 /// undefined_table
251 #[snafu(display("undefined_table"))]
252 Ec42P01 = 3104,
253 /// undefined_object
254 #[snafu(display("undefined_object"))]
255 Ec42704 = 3105,
256 /// duplicate_column
257 #[snafu(display("duplicate_column"))]
258 Ec42701 = 3106,
259 /// duplicate_database
260 #[snafu(display("duplicate_database"))]
261 Ec42P04 = 3107,
262 /// duplicate_table
263 #[snafu(display("duplicate_table"))]
264 Ec42P07 = 3108,
265 /// invalid_prepared_statement_definition
266 #[snafu(display("invalid_prepared_statement_definition"))]
267 Ec42P14 = 3109,
268 // === End of Class 42 — Syntax Error or Access Rule Violation =====
269
270 // === Begin of Class 44 — WITH CHECK OPTION Violation ===
271 /// with_check_option_violation
272 #[snafu(display("with_check_option_violation"))]
273 Ec44000 = 3200,
274 // === End of Class 44 — WITH CHECK OPTION Violation =====
275
276 // === Begin of Class 53 — Insufficient Resources ===
277 /// insufficient_resources
278 #[snafu(display("insufficient_resources"))]
279 Ec53000 = 3300,
280 // === End of Class 53 — Insufficient Resources =====
281
282 // === Begin of Class 54 — Program Limit Exceeded ===
283 /// program_limit_exceeded
284 #[snafu(display("program_limit_exceeded"))]
285 Ec54000 = 3400,
286 // === End of Class 54 — Program Limit Exceeded =====
287
288 // === Begin of Class 55 — Object Not In Prerequisite State ===
289 /// object_not_in_prerequisite_state
290 #[snafu(display("object_not_in_prerequisite_state"))]
291 Ec55000 = 3500,
292 // === End of Class 55 — Object Not In Prerequisite State =====
293
294 // === Begin of Class 57 — Operator Intervention ===
295 /// operator_intervention
296 #[snafu(display("operator_intervention"))]
297 Ec57000 = 3600,
298 // === End of Class 57 — Operator Intervention =====
299
300 // === Begin of Class 58 — System Error (errors external to PostgreSQL itself) ===
301 /// system_error
302 #[snafu(display("system_error"))]
303 Ec58000 = 3700,
304 // === End of Class 58 — System Error (errors external to PostgreSQL itself) =====
305
306 // === Begin of Class 72 — Snapshot Failure ===
307 /// snapshot_too_old
308 #[snafu(display("snapshot_too_old"))]
309 Ec72000 = 3800,
310 // === End of Class 72 — Snapshot Failure =====
311
312 // === Begin of Class F0 — Configuration File Error ===
313 /// config_file_error
314 #[snafu(display("config_file_error"))]
315 EcF0000 = 3900,
316 // === End of Class F0 — Configuration File Error =====
317
318 // === Begin of Class HV — Foreign Data Wrapper Error (SQL/MED) ===
319 /// fdw_error
320 #[snafu(display("fdw_error"))]
321 EcHV000 = 4000,
322 // === End of Class HV — Foreign Data Wrapper Error (SQL/MED) =====
323
324 // === Begin of Class P0 — PL/pgSQL Error ===
325 /// plpgsql_error
326 #[snafu(display("plpgsql_error"))]
327 EcP0000 = 4100,
328 // === End of Class P0 — PL/pgSQL Error =====
329
330 // === Begin of Class XX — Internal Error ===
331 /// internal_error
332 #[snafu(display("internal_error"))]
333 EcXX000 = 4200,
334 // === End of Class XX — Internal Error =====
335}
336
337impl PgErrorCode {
338 fn severity(&self) -> PgErrorSeverity {
339 match self {
340 PgErrorCode::Ec00000 => PgErrorSeverity::Info,
341 PgErrorCode::Ec01000 => PgErrorSeverity::Warning,
342
343 PgErrorCode::EcXX000 | PgErrorCode::Ec42P14 | PgErrorCode::Ec22023 => {
344 PgErrorSeverity::Error
345 }
346 PgErrorCode::Ec28000 | PgErrorCode::Ec28P01 | PgErrorCode::Ec3D000 => {
347 PgErrorSeverity::Fatal
348 }
349
350 _ => PgErrorSeverity::Error,
351 }
352 }
353
354 pub(crate) fn code(&self) -> String {
355 self.as_ref()[2..].to_string()
356 }
357
358 pub fn to_err_info(&self, msg: String) -> ErrorInfo {
359 ErrorInfo::new(self.severity().to_string(), self.code(), msg)
360 }
361}
362
363impl From<PgErrorCode> for ErrorInfo {
364 fn from(code: PgErrorCode) -> ErrorInfo {
365 code.to_err_info(code.to_string())
366 }
367}
368
369impl From<StatusCode> for PgErrorCode {
370 fn from(code: StatusCode) -> PgErrorCode {
371 match code {
372 // ====== Begin of common status code ==============
373 StatusCode::Success => PgErrorCode::Ec00000,
374 StatusCode::Unsupported => PgErrorCode::Ec0A000,
375 StatusCode::InvalidArguments => PgErrorCode::Ec22023,
376 StatusCode::Cancelled => PgErrorCode::Ec57000,
377 StatusCode::DeadlineExceeded => PgErrorCode::Ec57000,
378 StatusCode::External => PgErrorCode::Ec58000,
379
380 StatusCode::Unknown
381 | StatusCode::Unexpected
382 | StatusCode::IllegalState
383 | StatusCode::Internal => PgErrorCode::EcXX000,
384 // ====== End of common status code ================
385
386 // ====== Begin of SQL & query related status code =========
387 StatusCode::InvalidSyntax => PgErrorCode::Ec42601,
388 StatusCode::PlanQuery | StatusCode::EngineExecuteQuery => PgErrorCode::EcP0000,
389 // ====== End of SQL & query related status code ===========
390
391 // ====== Begin of catalog & flow related status code =====
392 StatusCode::TableNotFound | StatusCode::FlowNotFound | StatusCode::RegionNotFound => {
393 PgErrorCode::Ec42P01
394 }
395 StatusCode::TableAlreadyExists
396 | StatusCode::FlowAlreadyExists
397 | StatusCode::RegionAlreadyExists => PgErrorCode::Ec42P07,
398
399 StatusCode::TableColumnNotFound => PgErrorCode::Ec42703,
400 StatusCode::TableColumnExists => PgErrorCode::Ec42701,
401 StatusCode::DatabaseNotFound => PgErrorCode::Ec42704,
402 StatusCode::DatabaseAlreadyExists => PgErrorCode::Ec42P04,
403 StatusCode::RegionReadonly => PgErrorCode::Ec25006,
404
405 StatusCode::RegionNotReady | StatusCode::RegionBusy | StatusCode::TableUnavailable => {
406 PgErrorCode::Ec55000
407 }
408 // ====== End of catalog & flow related status code =======
409
410 // ====== Begin of storage & server related status code =====
411 StatusCode::StorageUnavailable | StatusCode::RequestOutdated => PgErrorCode::EcXX000,
412 StatusCode::RuntimeResourcesExhausted => PgErrorCode::Ec53000,
413 StatusCode::RateLimited => PgErrorCode::Ec54000,
414 // ====== End of storage & server related status code =======
415
416 // ====== Begin of auth related status code =====
417 StatusCode::UserNotFound
418 | StatusCode::UnsupportedPasswordType
419 | StatusCode::UserPasswordMismatch => PgErrorCode::Ec28P01,
420
421 StatusCode::AuthHeaderNotFound | StatusCode::InvalidAuthHeader => PgErrorCode::Ec28000,
422 StatusCode::AccessDenied | StatusCode::PermissionDenied => PgErrorCode::Ec42501,
423 // ====== End of auth related status code =====
424 }
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use common_error::status_code::StatusCode;
431 use strum::{EnumMessage, IntoEnumIterator};
432
433 use super::{ErrorInfo, PgErrorCode, PgErrorSeverity};
434
435 #[test]
436 fn test_error_severity() {
437 // test for ErrorSeverity enum
438 assert_eq!("INFO", PgErrorSeverity::Info.to_string());
439 assert_eq!("DEBUG", PgErrorSeverity::Debug.to_string());
440 assert_eq!("NOTICE", PgErrorSeverity::Notice.to_string());
441 assert_eq!("WARNING", PgErrorSeverity::Warning.to_string());
442
443 assert_eq!("ERROR", PgErrorSeverity::Error.to_string());
444 assert_eq!("FATAL", PgErrorSeverity::Fatal.to_string());
445 assert_eq!("PANIC", PgErrorSeverity::Panic.to_string());
446
447 // test for severity method
448 for code in PgErrorCode::iter() {
449 let name = code.as_ref();
450 assert_eq!("Ec", &name[0..2]);
451
452 if name.starts_with("Ec00") {
453 assert_eq!(PgErrorSeverity::Info, code.severity());
454 } else if name.starts_with("Ec01") {
455 assert_eq!(PgErrorSeverity::Warning, code.severity());
456 } else if name.starts_with("Ec28") || name.starts_with("Ec3D") {
457 assert_eq!(PgErrorSeverity::Fatal, code.severity());
458 } else {
459 assert_eq!(PgErrorSeverity::Error, code.severity());
460 }
461 }
462 }
463
464 #[test]
465 fn test_pg_error_code() {
466 let code = PgErrorCode::Ec00000;
467 assert_eq!("00000", code.code());
468 assert_eq!("successful_completion", code.to_string());
469
470 let code = PgErrorCode::Ec01000;
471 assert_eq!("01000", code.code());
472 assert_eq!("warning", code.to_string());
473
474 // test display is correct
475 for code in PgErrorCode::iter() {
476 assert_eq!(&code.to_string(), code.get_documentation().unwrap())
477 }
478 }
479
480 #[test]
481 fn test_pg_err_info() {
482 let err_info = ErrorInfo::from(PgErrorCode::Ec00000);
483 assert_eq!("INFO", err_info.severity);
484 assert_eq!("00000", err_info.code);
485 assert_eq!("successful_completion", err_info.message);
486
487 let err_info = ErrorInfo::from(PgErrorCode::Ec01000);
488 assert_eq!("WARNING", err_info.severity);
489 assert_eq!("01000", err_info.code);
490 assert_eq!("warning", err_info.message);
491
492 let err_info =
493 PgErrorCode::Ec28P01.to_err_info("password authentication failed".to_string());
494 assert_eq!("FATAL", err_info.severity);
495 assert_eq!("28P01", err_info.code);
496 assert_eq!("password authentication failed", err_info.message);
497
498 let err_info =
499 PgErrorCode::Ec42P14.to_err_info("invalid_prepared_statement_definition".to_string());
500 assert_eq!("ERROR", err_info.severity);
501 assert_eq!("42P14", err_info.code);
502 assert_eq!("invalid_prepared_statement_definition", err_info.message);
503 }
504
505 fn assert_status_code(msg: &str, code: StatusCode) {
506 let code = PgErrorCode::from(code);
507 assert_eq!(msg, &code.to_string());
508 }
509
510 #[test]
511 fn test_from_status_code() {
512 assert_status_code("successful_completion", StatusCode::Success);
513 assert_status_code("invalid_parameter_value", StatusCode::InvalidArguments);
514 assert_status_code("undefined_table", StatusCode::TableNotFound);
515 assert_status_code("internal_error", StatusCode::Unknown);
516 assert_status_code("invalid_password", StatusCode::UserPasswordMismatch);
517 }
518}