PolarDB for PostgreSQL (Compatible with Oracle) supports the native PostgreSQL error handling system and is also compatible with common error handling mechanisms in Oracle syntax.
The main error handling mechanisms include the following types:
Predefined exceptions: Supports all predefined exceptions in native PostgreSQL and is compatible with common predefined exceptions in Oracle syntax.
Non-predefined exceptions: Compatible with exception variables in Oracle syntax and supports setting error codes for exception variables through
EXCEPTION_INIT.Custom Exception (RAISE_APPLICATION_ERROR): Compatible with the
RAISE_APPLICATION_ERRORfunction in Oracle syntax, used to raise custom error codes and error messages.Error codes and error messages: Supports both native PostgreSQL
SQLSTATEerror codes and is compatible with commonSQLCODEerror codes in Oracle syntax. It also supportsSQLERRMfor viewing detailed error messages.
Predefined exceptions
You can use predefined exceptions from both PostgreSQL, such as division_by_zero, and Oracle, such as zero_divide. You can raise and catch these exceptions in your SQL blocks.
Raise an exception
You can raise an exception in two ways: implicitly by executing a PL/SQL statement that causes an error or explicitly by using the RAISE statement.
The following examples show how to raise an exception:
Implicitly raise by executing PL/SQL statements
DECLARE
result INT;
BEGIN
result := 1 / 0;
END;Explicitly raise with the RAISE statement
-- PostgreSQL style
BEGIN
RAISE division_by_zero;
END;
-- Oracle style
BEGIN
RAISE zero_divide;
END;Catch an exception
You can catch exceptions using an EXCEPTION block. Use a WHEN clause to catch a specific exception by name or use WHEN OTHERS to catch all exceptions.
Catch a specific exception by name
-- PostgreSQL style
DECLARE
result INT;
BEGIN
result := 1 / 0;
EXCEPTION
WHEN division_by_zero THEN
DBMS_OUTPUT.PUT_LINE('division by zero');
END;
-- Oracle style
DECLARE
result INT;
BEGIN
result := 1 / 0;
EXCEPTION
WHEN zero_divide THEN
DBMS_OUTPUT.PUT_LINE('zero divide');
END;Catch all exceptions with WHEN OTHERS
DECLARE
result INT;
BEGIN
result := 1 / 0;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('division by zero');
END;Non-predefined exceptions
Oracle syntax includes many error codes that are not named, predefined exceptions. To handle these errors by name, you can declare an exception variable and associate it with an Oracle error code.
The process involves three steps:
In the
DECLAREsection, declare an exception, such asmy_exception EXCEPTION;.Use the
PRAGMA EXCEPTION_INITstatement to bind the variable to a specificSQLCODE, such asPRAGMA EXCEPTION_INIT(my_exception, -1476);.ImportantThe associated error code must be 100 (for the
no_data_foundexception) or a negative integer between -1000000 and -1. Only the range from -65535 to -1 maps to valid Oracle SQLCODEs.In the
EXCEPTIONsection, useWHEN my_exceptionorWHEN OTHERSto catch the exception.
Example
DECLARE
result INT;
my_exception EXCEPTION;
PRAGMA EXCEPTION_INIT(my_exception, -66666);
BEGIN
result := 1 / 0;
EXCEPTION
WHEN my_exception THEN
DBMS_OUTPUT.PUT_LINE('zero divide');
END;Custom Exception (RAISE_APPLICATION_ERROR)
Oracle reserves the integer range from -20999 to -20000 for predefined exceptions and non-predefined exceptions. You can use the RAISE_APPLICATION_ERROR procedure to raise a custom exception with a specific error code and message from within this range.
Example
DECLARE
salary NUMBER := 4000;
BEGIN
-- Validate business rules, trigger an error when conditions are not met
IF salary < 5000 THEN
RAISE_APPLICATION_ERROR(-20001, 'Salary is below the allowed minimum.');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('Custom Error: ' || SQLERRM);
END;Error codes and error messages
Within an EXCEPTION block, you can use the following built-in functions to get information about an error:
SQLSTATE: The native PostgreSQL error code. This is a five-character string where the first two characters represent the error class.
SQLCODE: The Oracle-compatible integer error code. It falls into one of three categories:
100: Indicates the
no_data_foundexception, indicating that a query statement returned no results.-65535 to -1: Indicates a standard Oracle error.
-99999: Indicates an invalid value or unsupported scenario in PolarDB for PostgreSQL (Compatible with Oracle).
SQLERRM: The error message that provides a detailed description of the exception.
Example
DECLARE
result INT;
BEGIN
result := 1 / 0;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('SQLSTATE: ' || SQLSTATE);
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
END;The output is:
SQLCODE: -1476
SQLSTATE: 22012
SQLERRM: division by zeroError code mapping
The following table lists supported error scenarios and maps the Oracle-style SQLCODE to its corresponding PostgreSQL-style SQLSTATE:
SQLCODE | Oracle exception name | SQLSTATE | PostgreSQL exception name | Error description |
100 | NO_DATA_FOUND | P0002 | no_data_found | Query statement returns no results |
-1 | DUP_VAL_ON_INDEX | 23505 | unique_violation | Violation of unique constraint when inserting duplicate keys |
-54 | None | 55P03 | lock_not_available | Lock acquisition failed |
-939 | None | 54023 | too_many_arguments | Too many function arguments |
-957 | None | 42701 | duplicate_column | Duplicate column name |
-960 | None | 42702 | ambiguous_column | Ambiguous column name |
-1001 | INVALID_CURSOR | 34000 | invalid_cursor_name | Cursor is undefined or cursor name is invalid |
-1031 | None | 42501 | insufficient_privilege | Insufficient permissions |
-1422 | TOO_MANY_ROWS | P0003 | too_many_rows | Query statement returns too many rows |
-1428 | None | 2201E | invalid_argument_for_logarithm | Invalid log function parameter |
-1428 | None | 2201F | invalid_argument_for_power_function | Invalid power function parameter |
-1476 | ZERO_DIVIDE | 22012 | division_by_zero | Division by zero |
-1578 | None | XX001 | data_corrupted | Data corruption |
-1821 | None | 22007 | invalid_datetime_format | Date format error |
-3125 | None | 08P01 | protocol_violation | Communication protocol error |
-4020 | None | 40P01 | deadlock_detected | Deadlock detected |
-6035 | None | 53000 | insufficient_resources | Insufficient resources |
-6113 | None | 53300 | too_many_connections | Too many connections |
-6503 | None | 2F005 | function_executed_no_return_statement | Function has no RETURN statement |
-6511 | CURSOR_ALREADY_OPEN | 42P03 | duplicate_cursor | Cursor is defined or opened multiple times |
-6531 | COLLECTION_IS_NULL | 2203G | collection_is_null | Collection is empty |
-6532 | SUBSCRIPT_OUTSIDE_LIMIT | 2202E | array_subscript_error | Array index out of bounds |
-6533 | SUBSCRIPT_BEYOND_COUNT | 2203H | subscript_beyond_count | Array index out of bounds |
-6592 | CASE_NOT_FOUND | 20000 | case_not_found | CASE statement has no matching WHEN clause |
-24381 | None | P0005 | forall_dml_error | FOR ALL statement error |
-27102 | None | 53200 | out_of_memory | Insufficient memory |
-30110 | None | 42601 | syntax_error | Syntax error |
-30156 | None | 53100 | disk_full | Disk full |
-1722 | INVALID_NUMBER | - | - | Invalid TO_NUMBER function parameter |
-1723 | None | - | - | Column length is 0 |
-1724 | None | - | - | Invalid FLOAT type precision |
-1727 | None | - | - | Invalid NUMBER type precision |
-6502 | VALUE_ERROR | - | - | Invalid numeric format or exceeds upper limit |
-6508 | None | - | - | Package function undefined |
-99999 | None | - | - | Current scenario not supported |