通常,具有相同名称、相同形参规格的同一类型(子存储过程或子函数)的子程序只要不是同辈块(即不在同一本地块中声明的子程序),就可以在同一独立程序中出现多次。

根据限定符的使用及执行子程序调用的位置,可以单独调用每个子程序,如前面章节所述。

但是,只要形参的某些方面不同,就可以声明具有相同子程序类型和名称的子程序,即使是同辈。这些特征(子程序类型、名称、和形参规格)通常称为程序签名。

除了形参规格的某些方面不同以外,签名相同的多个子程序的声明称为子程序重载。

因此,要调用哪个特定的重载子程序,将通过对由子程序调用指定的实参与重载子程序的形参列表进行匹配来确定。

以下任何差异都允许重载子程序:

  • 形参的数量不同。
  • 对应形参(即,根据在形参列表中出现的同一顺序进行比较)的至少一对数据类型不同,但不是别名不同。数据类型别名将在本节后面讲述。

请注意,只有以下差异时不允许重载子程序:

  • 形参名称不同。
  • 对应形参的参数模式(IN、INOUT、OUT)不同。
  • 对于子函数,RETURN 子句中的数据类型不同。

如上所述,允许重载子程序的差异之一是数据类型不同。

但是,某些数据类型具有其他名称(称为别名),这些名称可用于表定义。

例如,有固定长度的字符数据类型,可指定为 CHAR 或 CHARACTER。有可变长度的字符数据类型,可指定为 CHARVARYING、CHARACTER VARYING、VARCHAR 或 VARCHAR2。对于整数,有 BINARY_INTEGER、PLS_INTEGER 和 INTEGER 数据类型。对于数字,有 NUMBER、NUMERIC、DEC 和 DECIMAL 数据类型。

因此,在尝试创建重载子程序时,如果指定的数据类型是彼此的别名,则形参数据类型不会被认为不同。

通过显示包含相关数据类型的表定义,可以确定某些数据类型是否是其他类型的别名。

例如,下表定义包含一些数据类型及其别名。

CREATE TABLE data_type_aliases (
    dt_BLOB             BLOB,
    dt_LONG_RAW         LONG RAW,
    dt_RAW              RAW(4),
    dt_BYTEA            BYTEA,
    dt_INTEGER          INTEGER,
    dt_BINARY_INTEGER   BINARY_INTEGER,
    dt_PLS_INTEGER      PLS_INTEGER,
    dt_REAL             REAL,
    dt_DOUBLE_PRECISION DOUBLE PRECISION,
    dt_FLOAT            FLOAT,
    dt_NUMBER           NUMBER,
    dt_DECIMAL          DECIMAL,
    dt_NUMERIC          NUMERIC,
    dt_CHAR             CHAR,
    dt_CHARACTER        CHARACTER,
    dt_VARCHAR2         VARCHAR2(4),
    dt_CHAR_VARYING     CHAR VARYING(4),
    dt_VARCHAR          VARCHAR(4)
);

使用 PSQL \d 命令可显示表定义,“类型”列根据表定义中的数据类型显示内部分配给每个列的数据类型:

\d data_type_aliases
       Column        |         Type         | Modifiers
---------------------+----------------------+-----------
 dt_blob             | bytea                |
 dt_long_raw         | bytea                |
 dt_raw              | bytea(4)             |
 dt_bytea            | bytea                |
 dt_integer          | integer              |
 dt_binary_integer   | integer              |
 dt_pls_integer      | integer              |
 dt_real             | real                 |
 dt_double_precision | double precision     |
 dt_float            | double precision     |
 dt_number           | numeric              |
 dt_decimal          | numeric              |
 dt_numeric          | numeric              |
 dt_char             | character(1)         |
 dt_character        | character(1)         |
 dt_varchar2         | character varying(4) |
 dt_char_varying     | character varying(4) |
 dt_varchar          | character varying(4) |

在该示例中,基本数据类型组包括 bytea、integer、real、double precision、numeric、character 和 character varying。

在尝试声明重载子程序时,一对是别名的形参数据类型不足以允许子程序重载。因而,具有数据类型 INTEGER 和 PLS_INTEGER 的参数不能重载一对子程序,但数据类型 INTEGER 和 REAL、INTEGER 和 FLOAT 或 INTEGER 和 NUMBER 可重载子程序。

说明 基于形参数据类型的重载规则与 Oracle 数据库不兼容。通常,PolarDB PostgreSQL版(兼容Oracle)规则更为灵活,但尝试在 Oracle 数据库中创建存储过程或函数时,PolarDB PostgreSQL版(兼容Oracle)中允许的某些组合将会导致错误。

对于用于重载的某些数据类型对,可能需要强制转换由子程序调用指定的参数,以避免子程序运行时遇到错误。子程序的调用必须包括实参列表,该列表可专门标识数据类型。某些重载数据类型对可能需要 CAST 函数来显式标识数据类型。例如,调有期间可能需要强制转换的重载数据类型包括 CHAR 和 VARCHAR2 或 NUMBER 和 REAL。

以下示例显示从匿名块调用的一组重载子函数。匿名块的可执行部分包含使用 CAST 函数调用具有某些数据类型的重载函数。

DECLARE
    FUNCTION add_it (
        p_add_1     IN BINARY_INTEGER,
        p_add_2     IN BINARY_INTEGER
    ) RETURN VARCHAR2
    IS
    BEGIN
        RETURN 'add_it BINARY_INTEGER: ' || TO_CHAR(p_add_1 + p_add_2,9999.9999);
    END add_it;
    FUNCTION add_it (
        p_add_1     IN NUMBER,
        p_add_2     IN NUMBER
    ) RETURN VARCHAR2
    IS
    BEGIN
        RETURN 'add_it NUMBER: ' || TO_CHAR(p_add_1 + p_add_2,999.9999);
    END add_it;
    FUNCTION add_it (
        p_add_1     IN REAL,
        p_add_2     IN REAL
    ) RETURN VARCHAR2
    IS
    BEGIN
        RETURN 'add_it REAL: ' || TO_CHAR(p_add_1 + p_add_2,9999.9999);
    END add_it;
    FUNCTION add_it (
        p_add_1     IN DOUBLE PRECISION,
        p_add_2     IN DOUBLE PRECISION
    ) RETURN VARCHAR2
    IS
    BEGIN
        RETURN 'add_it DOUBLE PRECISION: ' || TO_CHAR(p_add_1 + p_add_2,9999.9999);
    END add_it;
BEGIN
    DBMS_OUTPUT.PUT_LINE(add_it (25, 50));
    DBMS_OUTPUT.PUT_LINE(add_it (25.3333, 50.3333));
    DBMS_OUTPUT.PUT_LINE(add_it (TO_NUMBER(25.3333), TO_NUMBER(50.3333)));
    DBMS_OUTPUT.PUT_LINE(add_it (CAST('25.3333' AS REAL), CAST('50.3333' AS REAL)));
    DBMS_OUTPUT.PUT_LINE(add_it (CAST('25.3333' AS DOUBLE PRECISION),
        CAST('50.3333' AS DOUBLE PRECISION)));
END;

下面是从匿名块显示的输出:

add_it BINARY_INTEGER:    75.0000
add_it NUMBER:   75.6666
add_it NUMBER:   75.6666
add_it REAL:    75.6666
add_it DOUBLE PRECISION:    75.6666