2016-09-23 121 views
0

我寫了下面的PL/SQL代碼來生成報告。PL/SQL:數值或值錯誤:字符串緩衝區太小

CREATE OR REPLACE 

PACKAGE CAcxref AS 
    PROCEDURE CAcxref_PROC (inp_str  IN VARCHAR2,out_retCode OUT NUMBER,out_rec OUT VARCHAR2); 
END CAcxref; 
/
CREATE OR REPLACE 
PACKAGE BODY CAcxref AS 
OutArr  custom.ArrayType; 
V_PROCESS1 VARCHAR2(100); 
V_PROCESS2 VARCHAR2(100); 
V_PROCESS3 VARCHAR2(100); 
V_PROCESS4 VARCHAR2(100); 
v_CutOff VARCHAR2(100); 
TYPE RecTyp IS RECORD (
rec_PROCESS_NAME custom.c_master_notify_tbl.PROCESS_NAME%type, 
rec_SOL_ID custom.c_master_notify_tbl.SOL_ID%type, 
rec_schm_type custom.c_master_notify_tbl.SCHM_TYPE%type, 
rec_foracid custom.c_master_notify_tbl.FORACID%type, 
rec_RCRE_TIME custom.c_master_notify_tbl.RCRE_TIME%type); 
    TYPE Cacxref_data IS TABLE OF RecTyp 
    INDEX BY BINARY_INTEGER; 
    Cacxref_FetchData Cacxref_data; 

    lv_variable    VARCHAR2 (5000) := ''; 
    lv_cnt     NUMBER  ; 
CURSOR GetDetails (v_Process1 VARCHAR2,v_Process2 VARCHAR2,v_Process3 VARCHAR2,v_Process4 VARCHAR2,v_CutOff VARCHAR2) IS 

SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (V_Process1) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process2) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process3) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process4) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B'; 
PROCEDURE CAcxref_PROC(inp_str IN VARCHAR2, out_retCode OUT NUMBER, out_rec OUT VARCHAR2) 
IS 
BEGIN 
    out_retCode := 0; 
    out_rec := ''; 
    custom.stringToArray.formInputArr (inp_str,OutArr); 
    V_Process1 := OutArr(0); 
    DBMS_OUTPUT.PUT_LINE('Process one:'||V_Process1); 
    V_Process2 := OutArr(1); 
    DBMS_OUTPUT.PUT_LINE('Process two:'||V_Process2); 
    V_Process3 := OutArr(2); 
    DBMS_OUTPUT.PUT_LINE('Process THREE:'||V_Process3); 
    V_Process4 := OutArr(3); 
    DBMS_OUTPUT.PUT_LINE('Process four:'||V_Process4); 
    v_CutOff := OutArr(4); 
    DBMS_OUTPUT.PUT_LINE('Cutoff Time:'||v_CutOff); 
    IF NOT GetDetails%ISOPEN then 
     OPEN GetDetails(v_Process1,v_Process2,v_Process3,v_Process4,v_CutOff); 
     DBMS_OUTPUT.PUT_LINE('CUSRSOR HAS BEEN OPENED'); 
    END IF; 
DBMS_OUTPUT.PUT_LINE('COUNT IS:'||Cacxref_FetchData.COUNT); 

LOOP 
    FETCH GetDetails 
    BULK COLLECT 
    INTO Cacxref_FetchData 
    LIMIT 10; /* WARNING: NUMBER OF RECORDS FETCHED SHOULD MATCH SIZE OF OUTREC VARIABLE */ 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE BULK COLLECT LOOP'); 
    EXIT WHEN GetDetails%NOTFOUND; 
END LOOP; 

FOR indx in 1 .. Cacxref_FetchData.COUNT 
LOOP 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE FOR LOOP'); 
    lv_variable := Cacxref_FetchData(indx).rec_PROCESS_NAME || '|' || Cacxref_FetchData(indx).rec_SOL_ID || '|' || 
    Cacxref_FetchData(indx).rec_SCHM_TYPE || '|' || Cacxref_FetchData(indx).rec_FORACID||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||Cacxref_FetchData(indx).rec_RCRE_TIME ; 
    DBMS_OUTPUT.PUT_LINE('lv_cnt is 1 and lv_variable is:'||lv_variable); 
    out_rec := lv_variable; 
END LOOP; 
END CAcxref_PROC; 
END CAcxref; 
/
DROP PUBLIC SYNONYM CAcxref 
/
CREATE PUBLIC SYNONYM CAcxref FOR CAcxref 
/
Grant EXECUTE ON CAcxref TO TBAADM, TBAUTIL,TBAGEN,SYSTEM 
/
SET SERVEROUTPUT ON 
/

在執行我收到character string buffer too small錯誤是第一次,第二次雖然我沒有得到任何錯誤,但沒有行越來越光標獲取無論是。

下面是我執行的截圖:

Screenshot

我不能夠理解爲哪個變量被拋出此錯誤。

執行提示:

SQL> SET SERVEROUTPUT ON 
SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec); 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
CUSRSOR HAS BEEN OPENED 
COUNT IS:0 
INSIDE THE BULK COLLECT LOOP 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACMOD|102|SBA|99101000036||||||||||||||||||||||12-APR-16 
BEGIN custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec); END; 

* 
ERROR at line 1: 
ORA-06502: PL/SQL: numeric or value error: character string buffer too small 
ORA-06512: at "CUSTOM.CACXREF", line 84 
ORA-06512: at line 1 


SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec); 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
COUNT IS:2 
INSIDE THE BULK COLLECT LOOP 

PL/SQL procedure successfully completed. 

SQL> print :out_rec 

OUT_REC 
-------------------------------- 

EDIT 我提出在PL/SQL一些變化,現在它是工作每個交替的時間,如果只有我設置具有大VARCHAR2值out_rec變量。

CREATE OR REPLACE 
PACKAGE CAcxref AS 
    PROCEDURE CAcxref_PROC (inp_str  IN VARCHAR2,out_retCode OUT NUMBER,out_rec OUT VARCHAR2); 
END CAcxref; 
/
CREATE OR REPLACE 
PACKAGE BODY CAcxref AS 
OutArr  tbaadm.basp0099.ArrayType; 
V_PROCESS1 VARCHAR2(20); 
V_PROCESS2 VARCHAR2(20); 
V_PROCESS3 VARCHAR2(20); 
V_PROCESS4 VARCHAR2(20); 
v_CutOff VARCHAR2(14); 
TYPE RecTyp IS RECORD (
rec_PROCESS_NAME custom.c_master_notify_tbl.PROCESS_NAME%type, 
rec_SOL_ID custom.c_master_notify_tbl.SOL_ID%type, 
rec_schm_type custom.c_master_notify_tbl.SCHM_TYPE%type, 
rec_foracid custom.c_master_notify_tbl.FORACID%type, 
rec_RCRE_TIME custom.c_master_notify_tbl.RCRE_TIME%type); 
    TYPE Cacxref_data IS TABLE OF RecTyp 
    INDEX BY BINARY_INTEGER; 
    Cacxref_FetchData Cacxref_data; 

    lv_variable    VARCHAR2 (3000) := ''; 
    lv_cnt     NUMBER  ; 
CURSOR GetDetails (v_Process1 VARCHAR2,v_Process2 VARCHAR2,v_Process3 VARCHAR2,v_Process4 VARCHAR2,v_CutOff VARCHAR2) IS 

SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (V_Process1) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process2) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process3) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process4) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B'; 
PROCEDURE CAcxref_PROC(inp_str IN VARCHAR2, out_retCode OUT NUMBER, out_rec OUT VARCHAR2) 
IS 
BEGIN 
    out_retCode := 0; 
    out_rec := ''; 
    tbaadm.basp0099.formInputArr (inp_str,OutArr); 
    V_Process1 := OutArr(0); 
    DBMS_OUTPUT.PUT_LINE('Process one:'||V_Process1); 
    V_Process2 := OutArr(1); 
    DBMS_OUTPUT.PUT_LINE('Process two:'||V_Process2); 
    V_Process3 := OutArr(2); 
    DBMS_OUTPUT.PUT_LINE('Process THREE:'||V_Process3); 
    V_Process4 := OutArr(3); 
    DBMS_OUTPUT.PUT_LINE('Process four:'||V_Process4); 
    v_CutOff := OutArr(4); 
    DBMS_OUTPUT.PUT_LINE('Cutoff Time:'||v_CutOff); 
    IF NOT GetDetails%ISOPEN then 
     OPEN GetDetails(v_Process1,v_Process2,v_Process3,v_Process4,v_CutOff); 
     DBMS_OUTPUT.PUT_LINE('CUSRSOR HAS BEEN OPENED'); 
    END IF; 
DBMS_OUTPUT.PUT_LINE('COUNT OF FETCHDATA IS:'||Cacxref_FetchData.COUNT); 

IF GetDetails%ISOPEN THEN 
--LOOP 
    FETCH GetDetails 
    BULK COLLECT 
    INTO Cacxref_FetchData 
    LIMIT 10; /* WARNING: NUMBER OF RECORDS FETCHED SHOULD MATCH SIZE OF OUTREC VARIABLE */ 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE BULK COLLECT LOOP'); 
       IF (Cacxref_FetchData.COUNT = 0) THEN 
        CLOSE GetDetails; 
        out_retcode := 1; 
        RETURN; 
       END IF; 
-- EXIT WHEN GetDetails%NOTFOUND; 
--END LOOP; 

FOR indx in 1 .. Cacxref_FetchData.COUNT 
LOOP 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE FOR LOOP'); 
    lv_variable := Cacxref_FetchData(indx).rec_PROCESS_NAME || '|' || Cacxref_FetchData(indx).rec_SOL_ID || '|' || 
    Cacxref_FetchData(indx).rec_SCHM_TYPE || '|' || Cacxref_FetchData(indx).rec_FORACID||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||Cacxref_FetchData(indx).rec_RCRE_TIME ; 
    DBMS_OUTPUT.PUT_LINE('lv_cnt is 1 and lv_variable is:'||lv_variable); 
    out_rec := out_rec || lv_variable; 
        IF (indx = Cacxref_FetchData.COUNT) THEN 
         out_rec := out_rec || lv_variable;    

        ELSE 

         out_rec := out_rec || lv_variable || CHR (10);    

        END IF; 
END LOOP; 
RETURN; 
END IF; 
END CAcxref_PROC; 
END CAcxref; 
/
GRANT EXECUTE ON CUSTOM.CAcxref TO TBAGEN; 
GRANT EXECUTE ON CUSTOM.CAcxref TO TBAADM WITH GRANT OPTION; 
GRANT EXECUTE ON CUSTOM.CAcxref TO TBAUTIL; 

而現在的結果設定out_rec VARCHAR2(4000)後,看起來是這樣的:使用

SQL> set serveroutput on 
SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec) 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
CUSRSOR HAS BEEN OPENED 
COUNT OF FETCHDATA IS:0 
INSIDE THE BULK COLLECT LOOP 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACMOD|102|SBA|99101000036||||||||||||||||||||||12-APR-16 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACOPN|101|SBA|99101000116||||||||||||||||||||||12-APR-16 

PL/SQL procedure successfully completed. 

SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec) 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
COUNT OF FETCHDATA IS:2 
INSIDE THE BULK COLLECT LOOP 

PL/SQL procedure successfully completed. 

SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec) 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
CUSRSOR HAS BEEN OPENED 
COUNT OF FETCHDATA IS:0 
INSIDE THE BULK COLLECT LOOP 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACMOD|102|SBA|99101000036||||||||||||||||||||||12-APR-16 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACOPN|101|SBA|99101000116||||||||||||||||||||||12-APR-16 

PL/SQL procedure successfully completed. 
+0

也許您應該閱讀「CUSTOM.CACXREF」第84行「ORA-06512:」的行。祝你好運。 –

+0

@BobJarvis,第84行是'CUSTOM \t CACXREF \t PACKAGE BODY 「out_rec:= lv_variable; 」'from dba_source。但我無法理解out_rec怎麼可能變小? – Mistu4u

+0

如何:out_rec定義? –

回答

1

(原「字符串緩衝區太小」的錯誤是由於SQL * Plus的綁定變量以捕獲輸出聲明太小 - 這在評論中被清除了,下面的幾點涉及代碼給出交替運行結果的後續問題。)

我可以看到幾個問題代碼(除了未格式化,這使得它h以便發現錯誤 - 我建議整齊排列所有代碼並用全局變量前綴g_,程序參數爲p_,遊標參數爲cp_等)。

首先,光標getdetails是全局的(在包體層聲明),但它永遠不會關閉,所以我假設全局數組cacxref_fetchdata保留了會話剩餘部分的第一個值。這是打算嗎?

全局數組outarr讓我有點困惑,因爲它不是'out'參數,但似乎在解析inp_str的過程中使用。

有一個全局變量lv_cnt(爲什麼lv?)這是從來沒有使用,但你有一個輸出消息說'lv_cnt is 1'

v_cutoff作爲遊標參數傳遞,但不在遊標中使用。

光標getdetails可以從四個union s內簡化爲:

cursor getdetails 
    (v_process1 varchar2 
    , v_process2 varchar2 
    , v_process3 varchar2 
    , v_process4 varchar2 
    ) -- not used: v_cutoff varchar2) 
is 
    select distinct process_name, sol_id, schm_type, foracid, rcre_time 
    from custom.c_master_notify_tbl 
    where process_name in (v_process1, v_process2, v_process3, v_process4) 
    and to_char(rcre_time,'DD-MM-YYYY HH24:MI:SS') 
      <= to_char(to_date('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
    and cxref_status = 'O' 
    and del_flg = 'N' 
    and online_or_batch = 'B'; 

日期看起來比較錯誤的,除非你想1-DEC-2016 00:00:00到 '前' 2-JAN-1997 23:59:59是。假設rcre_timedate,我認爲你需要將其更改爲:

and rcre_time <= to_date('12-04-2016 22:00:00','DD-MM-YYYY HH24:MI:SS') 

而且光標參數具有相同的名稱爲一些全局變量,這是混亂的,但編譯器將使用的參數(我將前綴爲了清楚起見,它們爲cp_)。

批量讀取循環看起來很奇怪 - 您一次讀取10行,直到您點擊一個%notfound,但您在最後一次讀取之前不對數據執行任何操作。

loop 
    fetch getdetails bulk collect into cacxref_fetchdata limit 10; 
    /* warning: number of records fetched should match size of out_rec variable */ 
    dbms_output.put_line('inside the bulk collect loop'); 
    exit when getdetails%notfound; 
end loop; 

然後你遍歷cacxref_fetchdata但你只使用最後一個(再次使用全局變量,這可能會影響後續調用)。

如果不通過調試器對錶和數據運行它很難說,但是由於全局變量在過程調用之間保留了它們的值,並且您的光標只被獲取了一次,所以我猜測一次運行的某個全局值會影響下一個的邏輯。我會整理代碼,確保變量只有在必須是全局變量時纔有效,並明確地重新初始化您不希望保留的任何內容。

相關問題