SQL * Plus, @ и относительные пути

9

Почему-то кажется, что SQL * Plus (по крайней мере, в Windows) не может найти скрипт с относительным путем при вызове с помощью @@и когда путь начинается с одинарной или двойной точки.

Например, у x:\some\whereменя есть следующая структура каталогов:

script.sql
main-dir\main-sub-dir
              call-script.sql
              script.sql

То есть: два, script.sqlно в разных местах.

Содержание script.sqlпросто под x:\some\whereпросто

prompt SCRIPT root

в то время script.sqlкак содержание другого

prompt SCRIPT main-dir/main-subdir

call-script.sql читает

@@script.sql
@ script.sql

ожидаемый результат

Если я запускаю SQL * Plus с, x:\some\whereа затем делаю

@main-dir/main-sub-dir/call-scripts

Выход будет

SCRIPT main-dir/main-subdir
SCRIPT root 

Это ожидается, поскольку сингл @должен искать пути с того места, где был запущен SQL * Plus, и @@должен искать пути из директории содержащего скрипта.

неожиданный вывод

Теперь , если я изменю call-scripts.sqlтак:

@@./script.sql
@ ./script.sql

двойник, @@похоже, меняет свое поведение, поскольку он ищет пути, с которых был запущен SQL * Plus, и теперь вывод будет

SCRIPT root
SCRIPT root

это не то, что я ожидал.


Задокументировано ли это поведение где-то, и что более важно, как я должен изменить его, call-scripts.sqlчтобы он @@../../other-dir/other-sub-dir/scriptправильно вызывал относительные пути ( )?

Рене Ниффенеггер
источник
На что установлена ​​переменная среды SQLPATH? Это влияет на то, какие каталоги ищутся.
Philᵀᴹ
Такое же поведение под Linux, FWIW. (А амперсанд - &, а не @; похоже, у него нет настоящего имени ). Кажется, это ошибка, так как это противоречиво. Единственное, что приходит на ум, - это установить переменную в скрипте верхнего уровня с полным путем и делать все, основываясь на этом, но это не очень удобно, если только структура каталогов ниже не исправлена.
Алекс Пул
Спасибо за то, что указали на @ vs ampersands ... Я должен был это знать, но когда я писал пост, я не обращал особого внимания. Это теперь исправлено в заголовке.
Рене Ниффенеггер
2
Я только что атаковал sqlplus с strace. Вот соответствующие вызовы: pastebin.com/cVK1QQu4 Обратите внимание, что он не пытался выполнить стат или доступ к файлам «script.sql» в любых других каталогах, прежде чем пытаться открыть те, которые видны в выводе pastebin.
Philᵀᴹ

Ответы:

7

Да, это ошибка 2391334, которая существует уже долгое время и, вероятно, не будет исправлена ​​в ближайшем будущем.

Один из способов работы вокруг этого «знать» путь для сценариев без фактически жесткого кодирования по этому пути. Для этого в SQLPlus требуется хитрость - если вы попытаетесь запустить несуществующий файл, вы получите сообщение об ошибке, содержащее имя пути.

Итак, вот демонстрация этого в действии. Чтобы подражать вашему сценарию, у меня есть:

c:\temp\demo
   script.sql
   maindir
      subdir
         call_script.sql
         script.sql

Что мы можем сделать, это добавить некоторые команды в начало call_script.sql, которые будут выбирать путь. Это выглядит немного странно, но вам не нужно менять его - это просто фиксированная вещь, которую вы вставляете в

set termout off
spool _path_finder.sql
@@_nonexistent_script.sql
spool off;

var path varchar2(100);
set serverout on
declare
  output varchar2(1000) := regexp_replace(replace(q'{
@_path_finder.sql
}',chr(10)),'.*"(.*)".*','\1');
begin 
  :path:=substr(output,1,length(output)-24);
end;
/
col path new_val path
select :path path from dual;
set termout on

Здесь происходит то, что мы запускаем несуществующий скрипт, который возвращает:

«SP2-0310: невозможно открыть файл« путь \ _nonexistent_script.sql »

поэтому с помощью небольшого регулярного выражения мы можем извлечь путь, сохранить его в переменной SQLPlus и затем использовать с этого момента.

Таким образом, окончательная версия вашего call_script.sql будет выглядеть так

set termout off
spool _path_finder.sql
@@_nonexistent_script.sql
spool off;

var path varchar2(100);
set serverout on
declare
  output varchar2(1000) := regexp_replace(replace(q'{
@_path_finder.sql
}',chr(10)),'.*"(.*)".*','\1');
begin 
  :path:=substr(output,1,length(output)-24);
end;
/
col path new_val path
select :path path from dual;
set termout on
prompt path was &path      

@@&path\script.sql
@&path\script.sql

и когда мы запустим это, мы получим следующее

SQL> @maindir\mainsubdir\call_script
path was maindir\mainsubdir
script in subdir
script in subdir

и там вы идете :-)

Коннор Макдональд
источник