У меня есть хранимая процедура, которая, как мне показалось, была поймана в бесконечном цикле, но после ее разборки и отдельного запуска различных циклов выясняется, что мой код вызывает
ORA-01000: превышено максимальное количество открытых курсоров
Проблема, кажется, возникает с тем, как я заполняю первые два курсора. Это может показаться глупым вопросом, но я надеялся, что кто-нибудь может дать мне несколько советов о том, как лучше справиться с населением этих курсоров?
Ниже вы найдете мою процедуру полностью, а затем я разбью область, которая, кажется, вызывает проблему.
Полная процедура:
procedure SplitIntrvlsAtShiftBoundaries is
vRecCount number;
RC number;
vShiftIDAtIntervalStart number;
vShiftIDAtIntervalEnd number;
vDummyRecSecs number(6,4) := 0.0;
vStartTimestamp timestamp with time zone;
vEndTimestamp timestamp with time zone;
cCurs Sys_refcursor;
vCurrentRec TMP_SHIFT_LIST_TBL%rowtype;
vCurrentInterval MACHINE_INTERVAL%rowtype;
vNewInterval MACHINE_INTERVAL%rowtype;
lProcName CONST.PBString;
vIntervalDOW smallint; -- intervals never span a midnite boundary
-- are split over midnite in prior steps.
CURSOR C1 IS SELECT * FROM TMP_SHIFT_MI_TBL ORDER BY START_DATE_TIME ASC, MACHINE_ID;
CURSOR C2 IS SELECT * FROM TMP_SHIFT_LIST_TBL ORDER BY SHIFT_START_DAY ASC, SHIFT_START_TIME;
BEGIN
lProcName := 'TRANSFORM_PROCESS_2.SplitIntrvlsAtShiftBoundaries';
pb_util.logdata(3, lProcName, 'Process Started ' );
DELETE FROM TMP_SHIFT_MI_TBL;
DELETE FROM TMP_SHIFT_LIST_TBL;
INSERT INTO TMP_SHIFT_MI_TBL
SELECT *
FROM MACHINE_INTERVAL
WHERE interval_state = 0
AND start_date_time <> CONST.STARTDATE
AND trunc(calc_end_time) < trunc( CONST.ENDDATE) - 144;
BEGIN
FOR R1 IN C1
LOOP
-- gets the current interval from the machine interval table by using the interval id found from the tmp_table
SELECT * INTO vCurrentInterval
FROM Machine_Interval MI
WHERE R1.Machine_Interval_ID = MI.Machine_Interval_Id;
-- gets the shifts containning the start and end dates obtained from the machine interval
Shift_pkg.getShiftsContaining(R1.start_date_time, R1.calc_end_time, cCurs, vRecCount);
FETCH cCurs INTO vCurrentRec;
LOOP
-- populates the tmp_shift_list_tbl dynamically
BEGIN
EXIT WHEN cCurs%notfound;
EXECUTE IMMEDIATE 'insert into tmp_shift_list_tbl
(shift_id_pk, shift_name, shift_start_day, shift_start_time,
shift_end_day, shift_end_time, site_id_fk, shift_day_id,
startoffset, endoffset)
VALUES(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10)'
USING vCurrentRec.SHIFT_ID_PK, vCurrentRec.SHIFT_NAME,
vCurrentRec.SHIFT_START_DAY, vCurrentRec.SHIFT_START_TIME,
vCurrentRec.SHIFT_END_DAY, vCurrentRec.SHIFT_END_TIME,
vCurrentRec.SITE_ID_FK, vCurrentRec.SHIFT_DAY_ID,
vCurrentRec.STARTOFFSET, vCurrentRec.ENDOFFSET;
END;
END LOOP;
pb_util.logdata(3, lProcName, 'FOUND: ', 'found ' || vRecCount ||
' shifts in machine interval: ' || R1.MACHINE_INTERVAL_ID);
-- depending on the # of shifts found in vRecCount different cases are applied.
CASE
WHEN vRecCount = 1 -- apply shift id to interval
THEN
BEGIN
FOR R2 IN C2
LOOP
UPDATE MACHINE_INTERVAL MI
SET MI.SHIFT_ID = R2.SHIFT_ID_PK
WHERE MI.MACHINE_INTERVAL_ID = R1.MACHINE_INTERVAL_ID;
END LOOP;
END;
WHEN vRecCount > 1 -- split up the interval between the shifts i.e. create intervals
THEN
BEGIN
FOR R2 IN C2
LOOP
-- make copy of the current interval.
vNewInterval := vCurrentInterval;
-- set the new interval duration
vCurrentInterval.Interval_Duration := pb_util.intervaltosecond(R2.shift_Start_Time -
vCurrentInterval.Start_Date_Time);
-- set the new shift id for the machine interval table
vCurrentInterval.Shift_ID := R2.Shift_ID_PK;
-- update the record.
DM.MachineIntervalRecordUpdate(MachineIntervalID => vCurrentInterval.Machine_Interval_ID,
StartDateTime => vCurrentInterval.Start_Date_Time,
IntervalDuration => vCurrentInterval.Interval_Duration,
IntervalCategory => vCurrentInterval.INTERVAL_CATEGORY,
NPTCategoryID => vCurrentInterval.NPT_CATEGORY_ID,
NPTControlledID => vCurrentInterval.CATEGORYTYPENUMERIC,
NPTOPStateID => vCurrentInterval.OPERATIONALSTATENUMERIC,
pExecutionSecs => vDummyRecsecs);
UPDATE MACHINE_INTERVAL MI
SET MI.Shift_ID = vCurrentInterval.Shift_ID
WHERE MI.Machine_Interval_ID = vCurrentInterval.Machine_Interval_ID;
-- set new start date time & interval duration
vNewInterval.Start_Date_Time := R2.Shift_End_Time;
vNewInterval.Interval_Duration := pb_util.intervaltosecond(vNewInterval.Calc_End_Time -
vNewInterval.Start_Date_Time);
-- create new record in interval table.
RC := DM.MachineIntervalRecordInsert(MachineIntervalRecord_IN => vNewInterval,
pExecutionSecs => vDummyRecsecs);
-- set current interval to the newly created interval and loop.
vCurrentInterval := vNewInterval;
END LOOP;
END;
ELSE -- if no shifts are found then set id to null
UPDATE MACHINE_INTERVAL MI
SET SHIFT_ID = 0
WHERE MI.MACHINE_INTERVAL_ID = R1.MACHINE_INTERVAL_ID;
END CASE;
END LOOP;
pb_util.logdata(3, lProcName, 'Process Completed ' );
COMMIT;
END;
exception when others then
pb_util.logdata(1, 'TRANSFORM_PROCESS_2.SplitIntrvlsAtShiftBoundaries', 'EXCEPTION THROWN (880B)', SQLERRM || ' STACK: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END SplitIntrvlsAtShiftBoundaries;
Курсоры, которые, я уверен, вызывает проблему, вот эти два:
CURSOR C1 IS SELECT * FROM TMP_SHIFT_MI_TBL ORDER BY START_DATE_TIME ASC, MACHINE_ID;
CURSOR C2 IS SELECT * FROM TMP_SHIFT_LIST_TBL ORDER BY SHIFT_START_DAY ASC, SHIFT_START_TIME;
Область, в которой процедура, кажется, достигает максимального открытого курсора, превышает:
FOR R1 IN C1
LOOP
-- gets the current interval from the machine interval table by using the interval id found from the tmp_table
SELECT * INTO vCurrentInterval
FROM Machine_Interval MI
WHERE R1.Machine_Interval_ID = MI.Machine_Interval_Id;
-- gets the shifts containning the start and end dates obtained from the machine interval
Shift_pkg.getShiftsContaining(R1.start_date_time, R1.calc_end_time, cCurs, vRecCount);
FETCH cCurs INTO vCurrentRec;
LOOP
-- populates the tmp_shift_list_tbl dynamically
BEGIN
EXIT WHEN cCurs%notfound;
EXECUTE IMMEDIATE 'insert into tmp_shift_list_tbl
(shift_id_pk, shift_name, shift_start_day, shift_start_time,
shift_end_day, shift_end_time, site_id_fk, shift_day_id,
startoffset, endoffset)
VALUES(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10)'
USING vCurrentRec.SHIFT_ID_PK, vCurrentRec.SHIFT_NAME,
vCurrentRec.SHIFT_START_DAY, vCurrentRec.SHIFT_START_TIME,
vCurrentRec.SHIFT_END_DAY, vCurrentRec.SHIFT_END_TIME,
vCurrentRec.SITE_ID_FK, vCurrentRec.SHIFT_DAY_ID,
vCurrentRec.STARTOFFSET, vCurrentRec.ENDOFFSET;
END;
END LOOP;
pb_util.logdata(3, lProcName, 'FOUND: ', 'found ' || vRecCount ||
' shifts in machine interval: ' || R1.MACHINE_INTERVAL_ID);