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}