Прерывистая ошибка ORA-22288 - неверная длина команды

У меня проблема с прерывистым веб-приложением, который часто должен открыть файл, расположенный на сервере базы данных, как часть регулярных операций. В большинстве случаев эти функции без проблем, однако, кажутся случайными, соответствующие запросы начинают возвращать ошибки HTTP 400. Отскок сервера apache часто устраняет проблему, но он неизменно возвращается через день или максимум неделю.

Я добавил некоторые записи в соответствующий код pl/sql (нет, не убегайте! возвращайтесь!), который я привел ниже для справки:

declare
  bl_blob blob;
  bf_file bfile := bfilename(<directory that totally exists>, <file that totally exists>);
begin
  dbms_lob.createTemporary(bl_blob, true);
  dbms_lob.open(bf_file, dbms_lob.lob_readonly);
  dbms_lob.open(bl_blob, dbms_lob.lob_readwrite);
  dbms_lob.loadfromfile(bl_blob, bf_file, dbms_lob.getLength(bf_file));
  dbms_lob.close(bf_file);
  return bl_blob;
end;

Оказывается, 400 ошибок соответствуют следующей ошибке ORA-22288:

file or LOB operation FILEOPEN failed
The program issued a command but the command length is incorrect

Мой вопрос: почему операция внезапно и неоднократно начиналась с ошибок, когда ранее один и тот же файл можно было открыть без проблем? Основной файл никогда не изменяется и только когда-либо открывается программно с разрешениями только для чтения.

Все форумы копания, которые я сделал до сих пор, дали в основном множество решений "отключайте и выключайте", которые... да.

Любая помощь очень ценится.

Ответ 1

Я не уверен, что это именно тот код, который вы используете, или если вы упростили его для SO. Ваш bfile в основном является указателем, поэтому я не уверен, что произойдет, если файл будет изменен на диске после установки указателя. Я также не уверен, что анонимные блоки, подобные этому, обрабатываются и кэшируются так же, как SQL-запросы. Короче говоря, попробуйте следующее:

declare
  bl_blob blob;
  bf_file bfile;
begin
  bf_file := bfilename(<directory that totally exists>, <file that totally exists>);
  dbms_lob.createTemporary(bl_blob, true);
  dbms_lob.open(bf_file, dbms_lob.lob_readonly);
  dbms_lob.open(bl_blob, dbms_lob.lob_readwrite);
  dbms_lob.loadfromfile(bl_blob, bf_file, dbms_lob.getLength(bf_file));
  dbms_lob.close(bf_file);
  return bl_blob;
end;

Ответ 2

Вместо того, чтобы использовать dbms_lob.getLength(bf_file) для загружаемой суммы, попробуйте использовать DBMS_LOB.LOBMAXSIZE. Это может помочь.

Ответ 3

Вы не отметили (или не видите) вашу инфраструктуру сервера приложений, но если вам посчастливилось запустить java на вашем сервере приложений, вы можете значительно упростить свой код. Я не знаю, исправит ли это вашу проблему, но, по крайней мере, избавится от необходимости знать длину файла bfile.

public void getFile (String oradir, String filename, String filesysdir) throws FileNotFoundException, IOException, SQLException, Exception {
    CallableStatement s = this.conn.prepareCall("select bfilename(?,?) from dual");
    s.setString(1, oradir);
    s.setString(2, filename);
    OracleResultSet r = (OracleResultSet) s.executeQuery();
    if (r.next())
        saveBFILE(r.getBFILE(1), filesysdir);
}

private void saveBFILE (BFILE b, String dir) throws FileNotFoundException, IOException, SQLException {
    b.openFile();
    InputStream s = b.getBinaryStream();
    InputStreamReader r = new InputStreamReader(s);
    String name = b.getName();
    String path = dir == null ? name : dir + '/' + name;
    System.out.println("creating " + name);
    FileOutputStream w = new FileOutputStream(new File(path));
    int nb;
    byte[] ba = new byte[4096];
    while ((nb = s.read(ba)) != -1)
        w.write(ba, 0, nb);
    w.close();
    b.closeFile();
}