PolarDB for PostgreSQL (Compatible with Oracle) supports both the native PostgreSQL error handling system and common Oracle PL/SQL error handling patterns, so you can use either style in your PL/SQL blocks.
Four mechanisms are supported:
Predefined exceptions: both PostgreSQL-style (e.g.,
division_by_zero) and Oracle-style (e.g.,zero_divide)Non-predefined exceptions: declare and bind unnamed Oracle error codes using
PRAGMA EXCEPTION_INITUser-defined exceptions: raise custom error codes and messages using
RAISE_APPLICATION_ERRORError codes and messages:
SQLSTATE(PostgreSQL),SQLCODE(Oracle-compatible), andSQLERRM
Predefined exceptions
Predefined exceptions are named conditions built into the database. PolarDB supports all native PostgreSQL predefined exceptions and the most common Oracle predefined exceptions, so you can use either style in a WHEN clause.
Raise an exception
Exceptions are raised in two ways:
Implicitly: a PL/SQL statement triggers an error at runtime
Explicitly: the
RAISEstatement raises a named exception
Implicitly raise by executing PL/SQL statements
-- Implicit: division by zero triggers an exception automatically
DECLARE
result INT;
BEGIN
result := 1 / 0;
END;Explicitly raise with the RAISE statement
-- Explicit: PostgreSQL style
BEGIN
RAISE division_by_zero;
END;
-- Explicit: Oracle style
BEGIN
RAISE zero_divide;
END;Catch an exception
Place an EXCEPTION section at the end of a BEGIN...END block to catch errors. When an exception is raised:
Execution of the statements in the block stops immediately.
Control passes to the
EXCEPTIONsection, which searches for the first matchingWHENclause.If a match is found, the corresponding handler runs, and then execution continues after
END.If no match is found, the exception propagates to the enclosing block. If there is no enclosing block, the subprogram aborts.
Use a named WHEN clause to catch a specific exception, or WHEN OTHERS to catch anything not already handled.
Catch a specific exception by name
-- Catch a specific exception: PostgreSQL style
DECLARE
result INT;
BEGIN
result := 1 / 0;
EXCEPTION
WHEN division_by_zero THEN
DBMS_OUTPUT.PUT_LINE('division by zero');
END;
-- Catch a specific exception: 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
-- Catch all exceptions
DECLARE
result INT;
BEGIN
result := 1 / 0;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('division by zero');
END;Non-predefined exceptions
Oracle defines many error codes that have no built-in name. To handle these by name, declare an exception variable and associate it with an Oracle error code using PRAGMA EXCEPTION_INIT.
Follow these three steps:
In the
DECLAREsection, declare an exception variable:my_exception EXCEPTION;Bind the variable to a specific
SQLCODEusingPRAGMA EXCEPTION_INIT:ImportantThe error code must be
100(for theno_data_foundexception) or a negative integer in the range-1000000to-1. Only the range-65535to-1maps to valid Oracle SQLCODEs.PRAGMA EXCEPTION_INIT(my_exception, -1476);In the
EXCEPTIONsection, catch the exception by name or withWHEN OTHERS:WHEN my_exception THEN ...
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;User-defined exceptions
Oracle reserves the error code range -20999 to -20000 for user-defined exceptions. Use RAISE_APPLICATION_ERROR to raise a custom error with a specific code and message from within this range.
Example
DECLARE
salary NUMBER := 4000;
BEGIN
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 messages
Inside an EXCEPTION section, three built-in variables provide information about the error:
| Variable | Type | Description |
|---|---|---|
SQLSTATE | Five-character string | Native PostgreSQL error code. The first two characters identify the error class. |
SQLCODE | Integer | Oracle-compatible error code. Values: 100 (no_data_found), -65535 to -1 (standard Oracle errors), or -99999 (unsupported scenario in PolarDB for PostgreSQL (Compatible with Oracle)). |
SQLERRM | String | Detailed description of the error. |
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 zeroNamed exceptions quick reference
The following table lists the Oracle exception names supported in PolarDB. Use this table when writing WHEN clauses to confirm which names are available.
| Oracle exception name | SQLCODE | Error description |
|---|---|---|
NO_DATA_FOUND | 100 | Query returned no results |
DUP_VAL_ON_INDEX | -1 | Unique constraint violation on insert |
INVALID_CURSOR | -1001 | Cursor is undefined or the cursor name is invalid |
TOO_MANY_ROWS | -1422 | Query returned too many rows |
ZERO_DIVIDE | -1476 | Division by zero |
INVALID_NUMBER | -1722 | Invalid TO_NUMBER function parameter |
VALUE_ERROR | -6502 | Invalid numeric format or value exceeds the upper limit |
CURSOR_ALREADY_OPEN | -6511 | Cursor is defined or opened multiple times |
COLLECTION_IS_NULL | -6531 | Collection is empty |
SUBSCRIPT_OUTSIDE_LIMIT | -6532 | Array index out of bounds |
SUBSCRIPT_BEYOND_COUNT | -6533 | Array index out of bounds |
CASE_NOT_FOUND | -6592 | CASE statement has no matching WHEN clause |
Error code mapping
The following table maps all supported Oracle-style SQLCODEs to their PostgreSQL equivalents. Use this table to cross-reference error codes when debugging or writing error handlers that need to handle both styles.
| Oracle exception name | SQLCODE | SQLSTATE | PostgreSQL exception name | Error description |
|---|---|---|---|---|
NO_DATA_FOUND | 100 | P0002 | no_data_found | Query returned no results |
DUP_VAL_ON_INDEX | -1 | 23505 | unique_violation | Unique constraint violation on insert |
| — | -54 | 55P03 | lock_not_available | Lock acquisition failed |
| — | -939 | 54023 | too_many_arguments | Too many function arguments |
| — | -957 | 42701 | duplicate_column | Duplicate column name |
| — | -960 | 42702 | ambiguous_column | Ambiguous column name |
INVALID_CURSOR | -1001 | 34000 | invalid_cursor_name | Cursor is undefined or the cursor name is invalid |
| — | -1031 | 42501 | insufficient_privilege | Insufficient permissions |
TOO_MANY_ROWS | -1422 | P0003 | too_many_rows | Query returned too many rows |
| — | -1428 | 2201E | invalid_argument_for_logarithm | Invalid log function parameter |
| — | -1428 | 2201F | invalid_argument_for_power_function | Invalid power function parameter |
ZERO_DIVIDE | -1476 | 22012 | division_by_zero | Division by zero |
| — | -1578 | XX001 | data_corrupted | Data corruption |
| — | -1821 | 22007 | invalid_datetime_format | Date format error |
INVALID_NUMBER | -1722 | — | — | Invalid TO_NUMBER function parameter |
| — | -1723 | — | — | Column length is 0 |
| — | -1724 | — | — | Invalid FLOAT type precision |
| — | -1727 | — | — | Invalid NUMBER type precision |
| — | -3125 | 08P01 | protocol_violation | Communication protocol error |
| — | -4020 | 40P01 | deadlock_detected | Deadlock detected |
| — | -6035 | 53000 | insufficient_resources | Insufficient resources |
| — | -6113 | 53300 | too_many_connections | Too many connections |
VALUE_ERROR | -6502 | — | — | Invalid numeric format or value exceeds the upper limit |
| — | -6503 | 2F005 | function_executed_no_return_statement | Function has no RETURN statement |
| — | -6508 | — | — | Package function undefined |
CURSOR_ALREADY_OPEN | -6511 | 42P03 | duplicate_cursor | Cursor is defined or opened multiple times |
COLLECTION_IS_NULL | -6531 | 2203G | collection_is_null | Collection is empty |
SUBSCRIPT_OUTSIDE_LIMIT | -6532 | 2202E | array_subscript_error | Array index out of bounds |
SUBSCRIPT_BEYOND_COUNT | -6533 | 2203H | subscript_beyond_count | Array index out of bounds |
CASE_NOT_FOUND | -6592 | 20000 | case_not_found | CASE statement has no matching WHEN clause |
| — | -24381 | P0005 | forall_dml_error | FORALL statement error |
| — | -27102 | 53200 | out_of_memory | Insufficient memory |
| — | -30110 | 42601 | syntax_error | Syntax error |
| — | -30156 | 53100 | disk_full | Disk full |
| — | -99999 | — | — | Current scenario not supported |