为何不允许针对空self参数执行方法分发?
为什么不允许对空self参数执行方法分发操作?
错误核心原因
在PL/SQL中,json_object_t、json_array_t这类对象类型的方法(比如get_string()、get_size()),必须依赖对象实例(即self参数)的内部状态才能运行。如果对象实例是NULL,意味着这个对象从未被初始化、没有任何有效状态,Oracle会直接抛出“对空self参数执行方法分发操作”的错误——因为不存在可执行方法的载体。
你的代码中的问题点
代码里有两处明确会触发该错误的风险:
未校验
order_items是否为NULL:
当输入JSON中没有orderItems键,或者对应值是JSON null时,json_data.get_array('orderItems')会返回NULL。此时直接调用order_items.get_size(),相当于对一个空的json_array_t实例调用方法,触发空self错误。循环索引越界导致
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
相关产品推荐
相关产品推荐

