FUNCTION next_task RETURN task.task_id%TYPE IS /* Cursor of all open tasks, assigned and unassigned */ CURSOR task_cur IS SELECT task_id FROM task WHERE task_status = 'OPEN' ORDER BY task_priority, date_entered DESC; /* The record for the above cursor */ task_rec task_cur%ROWTYPE; /* || An exception for error ORA-00054: || "resource busy and acquire with NOWAIT specified" */ record_locked EXCEPTION PRAGMA EXCEPTION_INIT (record_locked, -54); /* || Variables which determine whether function should continue || to loop through the cursor's records. */ found_unassigned_task BOOLEAN := TRUE; more_tasks BOOLEAN := TRUE; /* The primary key of the unassigned task to be returned */ return_value task.task_id%TYPE := NULL; BEGIN /* Open the cursor and start up the loop through its records */ OPEN task_cur; WHILE NOT found_unassigned_task AND more_tasks LOOP /* Fetch the next record. If nothing found, we are done */ FETCH task_cur INTO task_rec; more_tasks := task_cur%NOTFOUND; IF more_tasks THEN /* || A record was fetched. Create an anonymous block within || the function so that I can trap the record_locked || exception and still stay inside the cursor loop. */ BEGIN /* Try to get a lock on the current task */ SELECT task_id INTO return_value FROM task WHERE task_id = task_rec.task_id FOR UPDATE OF task_id NOWAIT; /* || If I get to this line then I was able to get a lock || on this particular task. Notice that the SELECT INTO || has therefore already set the function's return value. || Now set the Boolean to stop the loop. */ found_unassigned_task := TRUE; EXCEPTION WHEN record_locked THEN /* Record was already locked, so just keep on going */ NULL; END; END IF; END LOOP; /* || Return the task id. Notice that if an unassigned task was NOT || found, I will simply return NULL. */ CLOSE task_cur; RETURN return_value; EXCEPTION /* || General exception handler for the function: if an error occurred, || then close the cursor and return NULL for the task ID. */ WHEN OTHERS THEN CLOSE task_cur; RETURN NULL; END;