The current locking concept of my application assumes to get hold of 2 locks and perform code. But I always get an error when I try to release the first lockhandle. Is there a way to do this or am I wrong using dbms_lock to get 2 locks at one time?
Best regards!
DECLARE
l_handle_1 VARCHAR2(128);
l_handle_2 VARCHAR2(128);
l_result NUMBER;
BEGIN
-- >>> LOCK1
dbms_lock.allocate_unique('lock_1', l_handle_1);
l_result := dbms_lock.request(l_handle_1, dbms_lock.x_mode, 10, true);
BEGIN
-- >>> LOCK2
dbms_lock.allocate_unique('lock_2', l_handle_2);
l_result := dbms_lock.request(l_handle_2, dbms_lock.x_mode, 10, true);
BEGIN
/*
* PLSQL-Code with both locks held
*/
-- LOCK-2 release
l_result := dbms_lock.release(l_handle_2);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 2');
END IF;
-- LOCK-1 release
l_result := dbms_lock.release(l_handle_1);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 1');
END IF;
EXCEPTION
WHEN OTHERS THEN
l_result := dbms_lock.release(l_handle_2);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 3');
END IF;
RAISE;
END;
EXCEPTION
WHEN OTHERS THEN
l_result := dbms_lock.release(l_handle_1);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 4');
END IF;
RAISE;
END;
END;
you call dbms_lock.request with release_on_commit = TRUE for the first lock handle and then call allocate_unique.
allocate_unique performs a commit and hence releases the first lock.
You will not get an error if you change you code as follows:
DECLARE
l_handle_1 VARCHAR2(128);
l_handle_2 VARCHAR2(128);
l_result NUMBER;
BEGIN
dbms_lock.allocate_unique('lock_1', l_handle_1);
dbms_lock.allocate_unique('lock_2', l_handle_2);
-- >>> LOCK1
l_result := dbms_lock.request(l_handle_1, dbms_lock.x_mode, 10, true);
BEGIN
-- >>> LOCK2
-- dbms_lock.allocate_unique('lock_2', l_handle_2);
l_result := dbms_lock.request(l_handle_2, dbms_lock.x_mode, 10, true);
BEGIN
/*
* PLSQL-Code with both locks held
*/
-- LOCK-2 release
l_result := dbms_lock.release(l_handle_2);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 2');
END IF;
-- LOCK-1 release
l_result := dbms_lock.release(l_handle_1);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 1');
END IF;
EXCEPTION
WHEN OTHERS THEN
l_result := dbms_lock.release(l_handle_2);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 3');
END IF;
RAISE;
END;
EXCEPTION
WHEN OTHERS THEN
l_result := dbms_lock.release(l_handle_1);
IF (l_result > 0) THEN
dbms_output.put_line('Fail 4');
END IF;
RAISE;
END;
END;
Related
I am getting error while I compile this function:
PLS-00049: bad bind variable 'RETURN_VALUE'
I need help with this please.
FUNCTION GECM_ROUND_FNC
(P_FIELD_VALUE IN NUMBER,
P_ORG_ID IN NUMBER)
RETURN VARCHAR2
IS
v_ret_val NUMBER := P_FIELD_VALUE;
V_OU_NAME hr_operating_units.name%type;
v_round_dec NUMBER;
BEGIN
BEGIN
SELECT NAME INTO V_OU_NAME
FROM HR_ALL_ORGANIZATION_UNITS
WHERE ORGANIZATION_ID = P_ORG_ID;
EXCEPTION WHEN OTHERS THEN
V_OU_NAME := '';
END;
--
IF V_OU_NAME IS NOT NULL AND NVL(GECM_ICP_PKG.gecm_get_process_value_fnc('GECM_ERP_VALIDATIONS',V_OU_NAME,'','',''),'N')='Y' THEN
BEGIN
IF NVL(GECM_ICP_PKG.GECM_GET_PARAMETER_VALUE_FNC('GECM_ERP_VALIDATIONS','DECIMAL_ROUNDING_INTERFACES',V_OU_NAME,'',''),0) = 'Y' THEN
BEGIN
SELECT NVL(GECM_ICP_PKG.GECM_GET_PARAMETER_VALUE_FNC('GECM_ERP_VALIDATIONS','DECIMAL_PLACE_LIMIT',V_OU_NAME,'',''),0)
INTO v_round_dec from dual;
EXCEPTION
WHEN OTHERS THEN
v_round_dec := 0;
END;
IF v_round_dec <> 0 THEN
v_ret_val:= TO_CHAR(ROUND(v_ret_val,v_round_dec));
ELSE
v_ret_val:=v_ret_val;
END IF;
END IF;
END;
END IF;
SELECT to_char(decode(sign(v_ret_val-1),-1,decode('0'||to_number(v_ret_val),'00','0','0'||to_number(v_ret_val)),v_ret_val)) INTO v_ret_val FROM DUAL;
:return_value := v_ret_val;
END;
Instead of
:return_value := v_ret_val;
use
return v_ret_val;
My code is:
set serveroutput on size unlimited;
DECLARE
v_line_unclean VARCHAR2(32767); -- 32767 BYTES
v_line_clean VARCHAR2(32767);
v_clean_val VARCHAR2(32767);
SQLSMT VARCHAR2(32767);
v_line_in_record INTEGER;
pattern varchar2(15) := '("[^"]*"|[^,]+)';
v_name VARCHAR2(50);
v_first_column VARCHAR2(200);
EMP_FILE UTL_FILE.FILE_TYPE;
BEGIN
DBMS_OUTPUT.ENABLE(9000000);
EMP_FILE := UTL_FILE.FOPEN('EGIS_FILE_DIR','TEST.csv','R', 32767); -- open the file from oracle directory
v_line_in_record := 0; --we skip the first line
IF UTL_FILE.IS_OPEN(EMP_FILE) THEN
LOOP
v_line_in_record := v_line_in_record + 1;
--DBMS_OUTPUT.PUT_LINE(v_line_in_record);
BEGIN
UTL_FILE.GET_LINE(EMP_FILE,v_line_unclean);
IF v_line_in_record = 1 THEN-- first record here
DBMS_OUTPUT.PUT_LINE('');
ELSIF v_line_in_record = 2 THEN-- second record here (header)
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE(v_line_unclean);
v_first_column := SUBSTR(v_line_unclean,1,instr(v_line_unclean,',',10,1)-1);
dbms_output.put_line('1st '||REGEXP_SUBSTR(v_line_unclean, '[^,]+', 1, 1));
ELSE -- body records here);
SELECT REPLACE(v_line_unclean,'((\)|^).*?(\(|$))|,', '\1')INTO v_line_clean FROM DUAL;
SQLSMT := 'INSERT INTO SITE_CONFIG_2G VALUES('''||v_line_clean||''')';
EXECUTE IMMEDIATE SQLSMT;
END IF;
COMMIT;
DBMS_OUTPUT.PUT_lINE(SQLSMT);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_lINE('NO DATA FOUND EXCEPTION');
EXIT;
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_lINE('TO MANY ROW EXCEPTION');
EXIT;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlcode||sqlerrm);
ROLLBACK;
EXIT;
END;--EXCEPTION
END LOOP;
END IF;
UTL_FILE.FCLOSE(EMP_FILE);
END;
Result :
INSERT INTO SITE_CONFIG_2G VALUES('1,gold,benz,2018,1,blue,"34,000,000",6.4,new,CSV')
INSERT INTO SITE_CONFIG_2G VALUES('2,silver,bmw,2016,1,silver,"51,000,000",6.5,New,CSV')
INSERT INTO SITE_CONFIG_2G VALUES('3,bronze,range,2017,1,light-blue,"24,000,000",7.8,New,RVS')
I would like to remove commas between quotes in "24,000,000" to give me "24000000"
Current result is:
3,bronze,range,2017,1,light-blue,"24,000,000",7.8,New,RVS
Expected result is:
3,bronze,range,2017,1,light-blue,"24000000",7.8,New,RVS
can you try this.
select regexp_replace('1,gold,benz,2018,1,blue,"34,000,000",6.4,new,CSV',
'(")([^"|,]+)(,)([^"|,]+)(,)([^"|,]+)(")',
'\1\2\4\6\7') from dual;
I have assembled a procedure to dump a query containing CLOB columns to a csv file.
It seems to be working fine until I encounter a query containing dates.
ORA-00932: inconsistent datatypes: expected CLOB got DATE
Is there a way to dynamically convert those dates to some default string format to be able to use the procedure as it is now. Or how can I refactor it if necessary?
create or replace
PROCEDURE export_query_csv(
p_query IN VARCHAR2,
p_filename IN VARCHAR2)
IS
l_separator VARCHAR2 (10 CHAR) := ';';
l_dir VARCHAR2 (128 CHAR) := 'MY_DIR';
l_output utl_file.file_type;
l_theCursor INTEGER DEFAULT dbms_sql.open_cursor;
l_columnValue CLOB;
l_status INTEGER;
l_colCnt NUMBER DEFAULT 0;
l_cnt NUMBER DEFAULT 0;
l_descTbl dbms_sql.desc_tab;
l_substrVal VARCHAR2(4000) ;
l_offset NUMBER :=1;
l_amount NUMBER := 3000;
l_clobLen NUMBER :=0;
BEGIN
EXECUTE IMMEDIATE 'alter session set nls_date_format = ''dd-mon-yyyy hh24:mi:ss''';
l_output := utl_file.fopen(l_dir, p_filename, 'wb');
dbms_sql.parse(l_theCursor, p_query, dbms_sql.native);
FOR i IN 1 .. 1000
LOOP
BEGIN
dbms_sql.define_column(l_theCursor, i, l_columnValue);
l_colCnt := i;
EXCEPTION
WHEN OTHERS THEN
IF ( SQLCODE = -1007 ) THEN
EXIT;
ELSE
RAISE;
END IF;
END;
END LOOP;
dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );
FOR i IN 1 .. l_colCnt
LOOP
utl_file.put_raw(l_output,utl_raw.cast_to_raw('"'));
utl_file.put_raw(l_output,utl_raw.cast_to_raw(l_descTbl(i).col_name));
utl_file.put_raw(l_output,utl_raw.cast_to_raw('"'));
IF i < l_colCnt THEN
utl_file.put_raw(l_output,utl_raw.cast_to_raw(l_separator));
END IF;
END LOOP;
utl_file.put_raw(l_output,utl_raw.cast_to_raw(chr(13) || chr(10)));
l_status := dbms_sql.execute(l_theCursor);
LOOP
EXIT WHEN (dbms_sql.fetch_rows(l_theCursor) <= 0);
FOR i IN 1 .. l_colCnt
LOOP
dbms_sql.column_value(l_theCursor, i, l_columnValue);
l_clobLen := dbms_lob.getlength(l_columnValue);
WHILE l_offset <= l_clobLen
LOOP
l_substrVal := dbms_lob.substr(l_columnValue,l_amount,l_offset);
utl_file.put_raw(l_output,utl_raw.cast_to_raw('"'));
utl_file.put_raw(l_output,utl_raw.cast_to_raw(l_substrVal));
utl_file.put_raw(l_output,utl_raw.cast_to_raw('"'));
l_offset:=l_offset+l_amount;
END LOOP;
l_offset := 1;
IF i < l_colCnt THEN
utl_file.put_raw(l_output,utl_raw.cast_to_raw(l_separator));
END IF;
END LOOP;
utl_file.put_raw(l_output,utl_raw.cast_to_raw(chr(13) || chr(10)));
l_cnt := l_cnt + 1;
END LOOP;
dbms_sql.close_cursor(l_theCursor);
utl_file.fclose(l_output);
END;
Found it myself, following this pattern:
-- Define columns
FOR i IN 1 .. colcnt LOOP
IF desctab(i).col_type = 2 THEN
DBMS_SQL.DEFINE_COLUMN(curid, i, numvar);
ELSIF desctab(i).col_type = 12 THEN
DBMS_SQL.DEFINE_COLUMN(curid, i, datevar);
......
ELSE
DBMS_SQL.DEFINE_COLUMN(curid, i, namevar);
END IF;
END LOOP;
I've read this article about Tuning UTL_FILE
Technically the approach is to concatenate records while the size is less than maximum length of the buffer and write the entire buffer when the length is greater
Excerpt from site (code):
IF LENGTH(v_buffer) + c_eollen + LENGTH(r.csv) <= c_maxline THEN
v_buffer := v_buffer || c_eol || r.csv;
ELSE
IF v_buffer IS NOT NULL THEN
UTL_FILE.PUT_LINE(v_file, v_buffer);
END IF;
v_buffer := r.csv;
END IF;
So, I've decided to to move this one in a function
-- constants
C_CHR CONSTANT VARCHAR2(2) := CHR(10);
C_CHRLEN CONSTANT PLS_INTEGER := LENGTH(C_CHR);
C_MAXLEN CONSTANT PLS_INTEGER := 32767;
function FN_GET_BUFFER(p_rec IN VARCHAR2, p_buffer IN VARCHAR2) RETURN VARCHAR2
is
begin
IF LENGTH(p_buffer) + C_CHRLEN + LENGTH(p_rec) <= C_MAXLEN THEN
RETURN p_buffer || C_CHR || p_rec;
ELSE
IF p_buffer IS NOT NULL THEN
RETURN p_buffer;
END IF;
RETURN p_rec;
END IF;
end FN_GET_BUFFER;
And here's how I call my function which doesn't work as expected..
procedure export as
l_tmp_file_name VARCHAR2(30);
l_csv_file_name VARCHAR2(30);
l_file UTL_FILE.FILE_TYPE;
l_buffer VARCHAR2(32767);
CURSOR cur_table
IS
SELECT * FROM table
begin
l_tmp_file_name := 'file.tmp';
BEGIN
l_file := UTL_FILE.FOPEN(C_DIRECTORY_PATH, l_tmp_file_name,'A',C_MAXLEN);
FOR rec IN cur_table
LOOP
l_rec := CONVERT(rec.id || ',' || rec.user ,'AL32UTF8');
l_buffer := l_buffer || FN_GET_BUFFER(l_rec, l_buffer);
if l_buffer is NOT NULL then
UTL_FILE.PUT_LINE(l_file, l_buffer);
l_buffer := NULL;
end if;
END LOOP rec;
UTL_FILE.FCLOSE(l_file);
l_csv_file_name := 'file.csv';
UTL_FILE.FRENAME(src_location => C_DIRECTORY_PATH, src_filename => l_tmp_file_name, dest_location => C_DIRECTORY_PATH, dest_filename => l_csv_file_name, overwrite => FALSE);
EXCEPTION
WHEN OTHERS THEN
UTL_FILE.FCLOSE(l_file);
UTL_FILE.FREMOVE(location => C_DIRECTORY_PATH, filename => l_tmp_file_name);
END;
end export;
The problem is that I get
1,user1
2,user2
3,user3
4,user4
5,
user5
6,user6
7,user7
8,user8
9,user9
10,user10
11,user11
12,user12
13,user13
14,
user14
15,user15
16,user16
17,user17
18,user19
As you can see, after 4 records the buffer is 'full' so it writes instead
the buffer which is user14 instead of writing all on the same line
Thank you
The problem is not your function as such, it's the test you make after the call:
if l_buffer is NOT NULL then
UTL_FILE.PUT_LINE(l_file, l_buffer);
l_buffer := NULL;
end if;
l_buffer is always populated, it's never null. So the test is always true and you write to the file for each row in the table. You need to test for the length of l_buffer and only write when the length is greater than your limit.
But don't just change the test. You need to unpick the logic of FN_GET_BUFFER() to include the buffer population and flushing in a single subroutine, otherwise you will lose data. Something like this:
FOR rec IN cur_table
LOOP
l_rec := CONVERT(rec.id || ',' || rec.user ,'AL32UTF8');
IF LENGTH(l_buffer) + LENGTH(C_CHRLEN) + LENGTH(l_rec) > C_MAXLEN THEN
-- buffer full, write to file
UTL_FILE.PUT_LINE(l_file, l_buffer);
l_buffer := l_rec;
ELSIF LENGTH(l_buffer) = 0 THEN
-- first record
l_buffer := l_rec;
ELSE
-- buffer not full
l_buffer := _l_buffer || C_CHRLEN || l_rec;
END IF;
END LOOP rec;
if LENGTH(l_buffer) > 0 THEN
-- end of table, write last record
UTL_FILE.PUT_LINE(l_file, l_buffer);
end if;
warning coded wildstyle, not tested
I'm getting this Oracle error Ora-06502 PL/SQL: numeric or value error: invalid LOB locate when two users try to commit at the same time.
I actually tried hard to solve this problem but I couldn't find a solution.
Please see the code for more details.
PROCEDURE CHECK_POP_DATA_PCC(RETURN_STATUS IN OUT NUMBER) IS LAST BOOLEAN;
REC_NUMBER NUMBER;
MESS_CTR NUMBER;
NO_DETAIL EXCEPTION;
SWF_FAIL EXCEPTION;
USA_STATUS NUMBER;
TEXT_STATUS NUMBER;
FIRST_ROUND NUMBER;
OERR NUMBER;
FILE_NAME VARCHAR2(100);
FILE_NAME1 VARCHAR2(100);
FILE_NAME2 VARCHAR2(100);
FILE_DIR VARCHAR2(100);
PRINT_ERR EXCEPTION;
PRINT_ERR1 EXCEPTION;
MESS_TEXT VARCHAR2(1000);
CTR NUMBER;
LEN NUMBER;
SUB NUMBER;
OPEN_TYPE NUMBER;
J NUMBER;
STR1 VARCHAR2(100);
STR2 VARCHAR2(100);
SPC NUMBER;
ESCP VARCHAR2(512);
FIRST_SEQ NUMBER;
REM NUMBER;
CLOSE_TYPE NUMBER;
SWF_ADD VARCHAR2(100);
SWF_PASS VARCHAR2(100);
SWF_UNAME VARCHAR2(100);
COMP_FILE TEXT_IO.FILE_TYPE;
FIRST_FILE TEXT_IO.FILE_TYPE;
SECOND_FILE TEXT_IO.FILE_TYPE;
cur_hdl integer;
rows_p integer;
tmp_chr VARCHAR2(2);
SWF_FTP_COM VARCHAR2(100);
File_status NUMBER;
ret_sta NUMBER;
key_all_data CLOB;
RTGS_IPADD VARCHAR2(100);
RTGS_FLA NUMBER (1,0);
RTGS_UNAME VARCHAR2(100);
RTGS_PASS VARCHAR2(100);
IS_SEC NUMBER ;
CURSOR C2 IS
SELECT MESS_TYPE_CODE,
SEQ_NUM,
FROM_SWF_CODE,
TO_SWF_CODE,
PRTY_CODE
FROM SWF_MESS
WHERE BRA_CODE = :SYS.BRA_CODE
AND REF_TYPE = :SYS.REF_TYPE
AND REF_YEAR = :SYS.REF_YEAR
AND REF_NUM = :SYS.REF_NUM
AND NVL(FILE_NUM,0) = :SYS.FILE_NUM
AND MESS_STA_CODE NOT IN (1,
2,
3,
5,
6,
7,
8);
BEGIN RET_STA := 0;
SELECT SWF_IPADDRESS,
SWF_USERNAME,
SWF_PASSWORD,
nvl(SWF_EOL_CHR,'CHR(10)'),
FTP_COM,
RTGS_IPADDRESS,
RTGS_FLAG,
RTGS_USERNAME,
RTGS_PASSWORD,
IS_SECURE INTO SWF_ADD,
SWF_UNAME,
SWF_PASS,
:TIT.EOL_SWF,
SWF_FTP_COM,
RTGS_IPADD,
RTGS_FLA,
RTGS_UNAME,
RTGS_PASS,
IS_SEC ---SHAZA(BANK/27/4540)
FROM web_par
WHERE app_ipaddress = nvl(:GLOBAL.APP_IPADDRESS,'0.0.0.0') ;
/* *************************************** */ FIRST_ROUND := 0;
RETURN_STATUS := 0;
FIRST_SEQ := 0;
key_all_data := '';
IF :GLOBAL.BRA_BRA_CODE = :GLOBAL.BAN_HO_REG_CODE THEN GO_BLOCK('SYS');
FIRST_RECORD;
LAST := FALSE;
WHILE NOT LAST LOOP IF :SYS.FLAG = 1 THEN
FOR C2REC IN C2 LOOP A07SWF00(:SYS.BRA_CODE,:SYS.REF_TYPE,:SYS.REF_YEAR,:SYS.REF_NUM, C2REC.MESS_TYPE_CODE,C2REC.SEQ_NUM,RETURN_STATUS);
IF RETURN_STATUS = 0 THEN
COMMIT;
CHECK_FRM_STATS;
ELSE RAISE SWF_FAIL;
END IF;
END LOOP;
END IF;
IF :SYSTEM.LAST_RECORD = 'TRUE' THEN LAST := TRUE;
ELSE NEXT_RECORD;
END IF;
END LOOP;
END IF;
/*****************************************************/ GO_BLOCK('SYS');
FIRST_RECORD;
LAST := FALSE;
WHILE NOT LAST LOOP IF :SYS.FLAG = 1 THEN key_all_data := '';
FIRST_ROUND := 0;
SELECT SWF_SEQ.NEXTVAL INTO :KEY.SWF_SEQ
FROM DUAL;
IF FIRST_SEQ = 0 THEN :KEY.FROM_SWF_SEQ := :KEY.SWF_SEQ;
FIRST_SEQ := 1;
END IF;
FOR C2REC IN C2 LOOP /*******************************/
SELECT COUNT(*) INTO MESS_CTR
FROM SWF_DETL
WHERE BRA_CODE = :SYS.BRA_CODE
AND REF_TYPE = :SYS.REF_TYPE
AND REF_YEAR = :SYS.REF_YEAR
AND REF_NUM = :SYS.REF_NUM
AND MESS_TYPE_CODE = C2REC.MESS_TYPE_CODE
AND SEQ_NUM = C2REC.SEQ_NUM;
IF MESS_CTR > 0 THEN CHECK_MESS_USA(:SYS.BRA_CODE,:SYS.REF_TYPE,:SYS.REF_YEAR, :SYS.REF_NUM,C2REC.MESS_TYPE_CODE,C2REC.SEQ_NUM, USA_STATUS);
IF USA_STATUS = 0 THEN CHECK_MESS_TEXT(C2REC.MESS_TYPE_CODE,C2REC.SEQ_NUM, C2REC.FROM_SWF_CODE,C2REC.TO_SWF_CODE, C2REC.PRTY_CODE,TEXT_STATUS);
IF TEXT_STATUS = 0 THEN A07SWF60 ( :sys.BRA_CODE, :sys.REF_TYPE, :sys.REF_YEAR, :sys.REF_NUM, c2rec.MESS_TYPE_CODE, c2rec.SEQ_NUM, :global.WST_TELL_ID, :key.SWF_SEQ, :GLOBAL.CLI_BANK_DATE, :SYS.ALL_DATA, RETURN_STATUS);
IF RETURN_STATUS <> 0 THEN RETURN_STATUS := -SQLCODE;
RETURN;
END IF;
UPDATE SWF_MESS
SET RTGS_FLAG = :SYS.RTGS_FLAG
WHERE BRA_CODE = :SYS.BRA_CODE
AND REF_TYPE = :SYS.REF_TYPE
AND REF_YEAR = :SYS.REF_YEAR
AND REF_NUM = :SYS.REF_NUM
AND MESS_TYPE_CODE = C2REC.MESS_TYPE_CODE
AND SEQ_NUM = C2REC.SEQ_NUM;
IF FIRST_ROUND = 0 THEN dbms_lob.createtemporary(key_all_data, TRUE);
dbms_lob.open(key_all_data, 1);
dbms_lob.append(key_all_data,:SYS.ALL_DATA);
FIRST_ROUND := 1;
ELSE ESCP := '';
IF :SYS.PRE_LEN <> 0 THEN REM := :SYS.PRE_LEN/512;
IF (REM - TRUNC(REM)) <> 0 THEN SPC := 512 - (:SYS.PRE_LEN - (TRUNC(REM) * 512));
FOR I IN 1..SPC LOOP ESCP := ESCP||CHR(32);
END LOOP;
END IF;
ELSE ESCP := '';
END IF;
/*********************************************/ dbms_lob.append(key_all_data,ESCP);
dbms_lob.append(key_all_data,:SYS.ALL_DATA);
END IF;
ELSE RETURN_STATUS := TEXT_STATUS;
RAISE SWF_FAIL;
END IF;
ELSE RETURN_STATUS := USA_STATUS;
RAISE SWF_FAIL;
END IF;
ELSE RAISE NO_DETAIL;
END IF;
END LOOP;
IF :TIT.INP_SECU_CODE = 2 THEN FILE_NAME := 'OUT'||LPAD(TO_CHAR(:KEY.SWF_SEQ),5,'0')||'.ABI';
ELSE --alliance
FILE_NAME := 'OUT'||LPAD(TO_CHAR(:KEY.SWF_SEQ),5,'0')||'.MSG';
END IF;
-- FILE_DIR := '/u/oracle/dev/spool';
--LEN := NVL(LENGTH(key_all_data), 0);
LEN := NVL(dbms_lob.getlength(key_all_data),0);--
CTR := LEN / 1000 ;
IF CTR <= 1 THEN CTR := 1;
SUB := LEN;
ELSE IF (CTR - TRUNC(CTR)) <> 0 THEN CTR := TRUNC(CTR) + 1;
END IF ;
SUB := 1000;
END IF;
OPEN_TYPE := 1;
J := 1;
IF :tit.eol_swf <> 'CHR(13)||CHR(10)' THEN BEGIN key_all_data := replace(key_all_data,chr(13)||chr(10),chr(substr(:tit.eol_swf,5,2)));
exception WHEN others THEN NULL;
END;
END IF;
comp_file := TEXT_IO.FOPEN(NAME_IN('GLOBAL.PRINT_PATH')||FILE_NAME, 'W');
FOR I IN 1..CTR LOOP MESS_TEXT := dbms_lob.substr(key_all_data,1000,j);--
TEXT_IO.PUT (comp_file, mess_text);
OPEN_TYPE := 2;
IF return_status = 0 THEN J := J + 1000;
ELSIF RETURN_STATUS IN(1196,
1197,
1198,
1199) THEN RAISE PRINT_ERR;
ELSE RAISE PRINT_ERR1;
END IF ;
END LOOP;
/************** CLOSING THE FILE *****************************/ IF :SYS.LEN <> 0 THEN REM := :SYS.LEN/512;
IF (REM - TRUNC(REM)) <> 0 THEN SPC := 512 - (:SYS.LEN - (TRUNC(REM) * 512));
CLOSE_TYPE := 1;
ELSE CLOSE_TYPE := 3;
END IF;
ELSE CLOSE_TYPE := 3;
END IF;
OERR := 0;
IF CLOSE_TYPE = 1 THEN
FOR I IN 1..SPC LOOP ESCP := CHR(32);
Text_IO.PUT(COMP_FILE,ESCP);
END LOOP;
END IF;
TEXT_IO.FCLOSE(comp_file);
RETURN_STATUS := OERR;
IF OERR <> 0 THEN IF OERR = 1199 THEN RAISE PRINT_ERR;
ELSE RAISE PRINT_ERR1;
END IF ;
END IF;
IF NVL(RTGS_FLA,0)=2
AND :SYS.RTGS_FLAG=1 THEN send_swf_mess(FILE_NAME, RTGS_IPADD, RTGS_UNAME, RTGS_PASS, SWF_FTP_COM,IS_SEC, RET_STA);
ELSE send_swf_mess(FILE_NAME, SWF_ADD, SWF_UNAME, SWF_PASS, SWF_FTP_COM, IS_SEC, RET_STA);
END IF;
:SYS.LEN := 0;
GO_BLOCK('SYS');
END IF;
IF :SYSTEM.LAST_RECORD = 'TRUE' THEN LAST := TRUE;
ELSE NEXT_RECORD;
END IF;
END LOOP;
dbms_lob.close(key_all_data);
FIRST_RECORD;
:KEY.TO_SWF_SEQ := :KEY.SWF_SEQ;
EXCEPTION WHEN FORM_TRIGGER_FAILURE THEN RAISE FORM_TRIGGER_FAILURE ;
WHEN NO_DETAIL THEN :TIT.COMMIT := 1;
ROLLDATA;
RETURN_STATUS := 374;
:GLOBAL.TAB_ENT := '0374';
DISPLAY_MSG;
RETURN;
WHEN SWF_FAIL THEN :TIT.COMMIT := 1;
ROLLDATA;
display_err(return_status);
RETURN;
WHEN PRINT_ERR THEN ROLLDATA;
:global.tab_ent :=return_status ;
display_msg ;
:TIT.COMMIT := 1 ;
WHEN PRINT_ERR1 THEN ROLLDATA;
display_err(return_status);
:TIT.COMMIT := 1 ;
WHEN OTHERS THEN :TIT.COMMIT := 1;
ROLLDATA;
RETURN_STATUS := -SQLCODE;
display_err(return_status);
RETURN;
END;
This is a screenshot of the error message that displays to one of the users whilst the other user sees Operation successful.
You will get that error if your C2 cursor doesn't find anything; the CLOB is never opened because you don't go into the loop, but you still do the dbms_lob.close, and that will throw that ORA-22275 error:
DECLARE
key_all_data CLOB;
BEGIN
dbms_lob.close(key_all_data);
END;
/
ORA-06502: PL/SQL: numeric or value error: invalid LOB locator specified: ORA-22275
You don't really need to open your temporary CLOB, which means you don't need to close it either; but you should free it either way. So you can remove the line:
dbms_lob.open(key_all_data, 1);
and change:
dbms_lob.close(key_all_data);
to:
if dbms_lob.istemporary(key_all_data) = 1 then
dbms_lob.freetemporary(key_all_data);
end if;
If you want to keep the open then test the close part too:
if dbms_lob.istemporary(key_all_data) = 1 then
if dbms_lob.isopen(key_all_data) = 1 then
dbms_lob.close(key_all_data);
end if;
dbms_lob.freetemporary(key_all_data);
end if;
You might think that if you you have created the temporary CLOB and opened it then it will be open and therefore can be closed; but this:
key_all_data := replace(...);
... is replacing one temporary CLOB with another, which is not explicitly open. You can look at the istemporary and isopen values to see what is happening. You could look at dbms_lob.fragment_replace etc. instead, or skip the open/close and don't worry about it...
It isn't clear if one call to this procedure is changing what the next call sees in the cursor (since the update doesn't seem to do anything) but the form or something this calls might be doing more work that does.
There are probably lots of other issues and comments - exception when others then null jumps out as a really bad idea - but they're getting a bit off-topic.
I think that you are trying append null values to clob variable.
declare
key_all_data clob := 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
v varchar2(10);
begin
begin
dbms_lob.append(key_all_data,v); -- exception
exception when others then
dbms_output.put_line(sqlerrm);
end;
for rec in ( select empty_clob() c from dual) loop -- run - ok
dbms_lob.append(key_all_data,rec.c);
end loop;
begin
for rec in ( select to_clob(null) c from dual) loop -- exception
dbms_lob.append(key_all_data,rec.c);
end loop;
exception when others then
dbms_output.put_line(sqlerrm);
end;
end;