You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何不允许针对空self参数执行方法分发?

为什么不允许对空self参数执行方法分发操作?

错误核心原因

在PL/SQL中,json_object_t、json_array_t这类对象类型的方法(比如get_string()、get_size()),必须依赖对象实例(即self参数)的内部状态才能运行。如果对象实例是NULL,意味着这个对象从未被初始化、没有任何有效状态,Oracle会直接抛出“对空self参数执行方法分发操作”的错误——因为不存在可执行方法的载体。

你的代码中的问题点

代码里有两处明确会触发该错误的风险:

  1. 未校验order_items是否为NULL:
    当输入JSON中没有orderItems键,或者对应值是JSON null时,json_data.get_array('orderItems')会返回NULL。此时直接调用order_items.get_size(),相当于对一个空的json_array_t实例调用方法,触发空self错误。

  2. 循环索引越界导致order_item为NULL:
    json_array_t.get_size()返回的是数组元素总数,数组的合法索引范围是0到get_size()-1。你的循环写为FOR i IN 0..order_items.get_size() LOOP,当i等于get_size()时,order_items.get(i)会返回NULL,后续order_item为NULL时调用get_string()等方法,同样触发空self错误。

修复后的代码

CREATE OR REPLACE PACKAGE BODY MSA_SCHEMA.PKG_ORDER AS
    PROCEDURE PROCESS_JSON_DATA(P_JSON_DATA IN VARCHAR2) IS
        V_RRN VARCHAR2(50);
        V_STAN VARCHAR2(50);
        V_NATIONAL_CODE VARCHAR2(100);
        V_CARD_NUMBER VARCHAR2(50);
        V_TERMINAL_NUMBER VARCHAR2(50);
        V_CHANNEL_TYPE NUMBER;
        V_REQUEST_DATE DATE;
        V_AMOUNT NUMBER;
        V_COMMODITY_CODE VARCHAR2(50);
        V_QUANTITY NUMBER;
        V_UNIT_CODE VARCHAR2(10);
        V_ORDER_ID NUMBER;
        json_data json_object_t;
        order_items json_array_t;
        order_item json_object_t;
        v_array_size NUMBER; -- 存储数组长度,避免重复调用方法
    BEGIN
        IF P_JSON_DATA IS NOT NULL THEN
            json_data := json_object_t(P_JSON_DATA);
            
            IF json_data IS NOT NULL THEN
                V_RRN := json_data.get_string('rrn');
                V_STAN := json_data.get_string('stan');
                V_NATIONAL_CODE := json_data.get_string('nationalCode');
                V_CARD_NUMBER := json_data.get_string('cardNumber');
                V_TERMINAL_NUMBER := json_data.get_string('terminalNumber');
                V_CHANNEL_TYPE := json_data.get_number('channelType');
                V_REQUEST_DATE := TO_DATE(json_data.get_number('requestDate'), 'YYYYMMDDHH24MISS');
                V_AMOUNT := json_data.get_number('amount');
                order_items := json_data.get_array('orderItems');

                -- 新增:先校验order_items是否有效
                IF order_items IS NOT NULL THEN
                    v_array_size := order_items.get_size();
                    V_ORDER_ID := MSA_SCHEMA.ITEMORDER_SEQ.NEXTVAL;

                    -- 修正循环范围:避免索引越界
                    FOR i IN 0..v_array_size - 1 LOOP
                        order_item := json_object_t(order_items.get(i));
                        IF order_item IS NOT NULL THEN
                            V_COMMODITY_CODE := order_item.get_string('commodityCode');
                            V_QUANTITY := order_item.get_number('quantity');
                            V_UNIT_CODE := order_item.get_string('unitCode');

                            INSERT INTO MSA_SCHEMA.ITEMORDER (ORDER_ID, RRN, STAN, NATIONAL_CODE, CARD_NUMBER, TERMINAL_NUMBER, CHANNEL_TYPE, REQUEST_DATE, AMOUNT, COMMODITY_CODE, QUANTITY, UNIT_CODE)
                            VALUES (V_ORDER_ID, V_RRN, V_STAN, V_NATIONAL_CODE, V_CARD_NUMBER, V_TERMINAL_NUMBER, V_CHANNEL_TYPE, V_REQUEST_DATE, V_AMOUNT, V_COMMODITY_CODE, V_QUANTITY, V_UNIT_CODE);
                        END IF;
                    END LOOP;

                    COMMIT;
                END IF;
            END IF;
        END IF;
        
    EXCEPTION
        WHEN OTHERS THEN
            RAISE;
    END PROCESS_JSON_DATA;
END PKG_ORDER;

关键修复说明

  • 增加order_items IS NOT NULL的前置校验,避免对空数组实例调用方法。
  • 用变量存储数组长度,将循环范围修正为0..v_array_size-1,彻底避免索引越界获取NULL元素。
  • 保留order_item IS NOT NULL的校验,防止数组中存在NULL的JSON对象元素时触发错误。

内容的提问来源于stack exchange,提问作者Mahdi Shams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:04:53