More on the stupid code:
Some_Func, which is called at the end, INSERTs the new batch number to the log TABLE and includes an EXCEPTION block catching DUP_VAL_ON_INDEX and OTHERS.
IOW, this PROCEDURE makes a best guess at what the batch number will be, writes it to a bunch of files, and only then attempts to put it into the log. If putting it into the log encounters any errors, it logs that and exits without any record in the log of the job! The job currently takes about an hour or two to run. Seriously, what were they thinking?
The current situation can be remedied via a SEQUENCE. As long as noone breaks the rule that all ids be popped off it (which can be enforced by removing rights to the TABLE and forcing all writes to go through a stored PROCEDURE) everything will be fine until the SEQUENCE runs out of numbers.
Of course, this entire approach is just plain wrong. The correct way to log a run with a generated number which is used in the output, is to start by logging first. This garantees the number is recorded and lets others job easily use a further number. This is basic stuff.
To use a SEQUENCE (or even the MAX() hack), INSERT the number, and find out what it is, just use the RETURNING clause:
INSERT INTO Log(Id, Name) SELECT Log_SEQ.NEXTVAL, 'Moo' FROM Dual RETURNING Id INTO Batch;