Skip to main content

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