SQL * Plus, @ i ścieżki względne

9

Jakoś wydaje się, że SQL * Plus (przynajmniej w systemie Windows) nie jest w stanie zlokalizować skryptu ze ścieżką względną, gdy jest wywoływany za pomocą @@i gdy ścieżka zaczyna się od pojedynczej lub podwójnej kropki.

Na przykład w obszarze x:\some\whereMam następującą strukturę katalogów:

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

To znaczy: dwa, script.sqlale w różnych lokalizacjach.

Treść script.sqltuż poniżej x:\some\wherejest po prostu

prompt SCRIPT root

podczas gdy druga script.sqlstrona jest

prompt SCRIPT main-dir/main-subdir

call-script.sql czyta

@@script.sql
@ script.sql

oczekiwany wynik

Jeśli uruchomię SQL * Plus od, x:\some\wherea następnie zrobię

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

Wyjście będzie

SCRIPT main-dir/main-subdir
SCRIPT root 

Jest to oczekiwane, ponieważ singiel @ma przeszukiwać ścieżki, z których SQL * Plus został uruchomiony, i @@powinien przeszukiwać ścieżki z katalogu zawierającego skrypt.

nieoczekiwany wynik

Teraz , jeśli to zmienię call-scripts.sql:

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

double @@wydaje się zmieniać swoje zachowanie, ponieważ przeszukuje ścieżki, z których SQL * Plus został uruchomiony, a wynik będzie teraz

SCRIPT root
SCRIPT root

czego się nie spodziewałem.


Czy to zachowanie jest gdzieś udokumentowane, a co ważniejsze, jak muszę to zmienić, call-scripts.sqlaby @@../../other-dir/other-sub-dir/scriptpoprawnie wywoływało ścieżki względne ( )?

René Nyffenegger
źródło
Jaka jest twoja zmienna środowiskowa SQLPATH? Wpływa to na przeszukiwane katalogi.
Philᵀᴹ
To samo zachowanie w systemie Linux, FWIW. (A znak ampersand to &, not @;, który nie wydaje się mieć prawdziwego imienia ). Wygląda na błąd, ponieważ jest niespójny. Jedyne, co przychodzi mi na myśl, to ustawić zmienną na skrypt najwyższego poziomu z pełną ścieżką i zrobić wszystko na tej podstawie, ale nie jest to zbyt wygodne, chyba że struktura katalogów poniżej jest naprawiona.
Alex Poole
Dzięki za zwrócenie uwagi na @ vs ampersands ... Powinienem był to wiedzieć, ale kiedy napisałem ten post, nie zwracałem na to uwagi. Teraz jest to ustalone w tytule.
René Nyffenegger
2
Właśnie zaatakowałem sqlplus strace. Oto odpowiednie wywołania: pastebin.com/cVK1QQu4 Zauważ, że nie próbował on stat lub uzyskać dostępu do plików „script.sql” w żadnym innym katalogu przed próbą otwarcia plików widocznych w danych wyjściowych pastebin.
Philᵀᴹ

Odpowiedzi:

7

Tak, to błąd 2391334, który istnieje od dawna i prawdopodobnie nie zostanie naprawiony w najbliższej przyszłości.

Jednym ze sposobów obejścia tego jest „poznanie” ścieżki skryptów bez faktycznego kodowania tej ścieżki. Aby to zrobić w SQLPlus, należy zastosować lewę - jeśli spróbujesz uruchomić nieistniejący plik, otrzymasz komunikat o błędzie zawierający nazwę ścieżki.

Oto demo tego w akcji. Aby naśladować twój scenariusz, mam:

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

Co możemy zrobić, to dodać kilka poleceń z przodu call_script.sql, które wybiorą ścieżkę. Wygląda to trochę dziwnie, ale nie trzeba go zmieniać - to po prostu naprawiona rzecz, którą wklejasz

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

To, co się tutaj dzieje, to uruchamianie nieistniejącego skryptu, który zwraca:

„SP2-0310: nie można otworzyć pliku” ścieżka \ _nonexistent_script.sql ”

więc z małym wyrażeniem regularnym możemy wyodrębnić ścieżkę, zapisać ją w zmiennej SQLPlus, a następnie użyć od tego momentu.

Ostateczna wersja twojego call_script.sql wyglądałaby tak

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

a kiedy to uruchomimy, otrzymamy następujące informacje

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

i proszę bardzo :-)

Connor McDonald
źródło